Skip to content

feat(DT-3944): SignalWithStart system Nexus obfuscation — decode infrastructure + UI#3356

Draft
rossnelson wants to merge 15 commits into
mainfrom
decode-binary-protobuf-payloads
Draft

feat(DT-3944): SignalWithStart system Nexus obfuscation — decode infrastructure + UI#3356
rossnelson wants to merge 15 commits into
mainfrom
decode-binary-protobuf-payloads

Conversation

@rossnelson
Copy link
Copy Markdown
Collaborator

@rossnelson rossnelson commented Apr 29, 2026

Summary

Implements browser-side decode of system Nexus operation payloads for SignalWithStartWorkflowExecution, and replaces all raw Nexus wrapper exposure with user-friendly presentation.

Decode infrastructure

  • decode-binary-protobuf.ts — new utility: decodes binary/protobuf payloads via @bufbuild/protobuf + @buf/temporalio_api.bufbuild_es. decodeBinaryProtobuf(payload, recurse?) is the single public API; internal helpers are private. Schema registry keyed on fully-qualified messageType — adding a new operation type is one line.
  • @bufbuild/protobuf migration — no unsafe-eval required (replaces protobufjs runtime which used Function())
  • Phase 1.5 in parseRawPayloadToJSON — binary/protobuf payloads decode transparently through all existing render surfaces (event card, compact row, JSON view, copy)
  • Race-free codec server requests — retry with backoff (3×), AbortSignal support, 4xx vs 5xx distinction

System Nexus obfuscation (SignalWithStart only)

Event card:

  • Card heading: Nexus Operation ScheduledSignal With Start Workflow Execution Initiated
  • Hidden fields: endpoint, service, operation, requestId
  • Injected detail fields: Workflow ID, Signal Name (decoded from the binary/protobuf request payload)
  • Input panel: shows signal payload + workflow start input (labeled when both present)

Compact event row:

  • Label: Signal With Start Workflow Execution Initiated / Delivered
  • Signal icon and pink color (not Nexus star/indigo)
  • Primary attribute badge suppressed

Timeline:

  • Group label: Signal With Start Workflow Execution
  • Signal pink color and icon on bar endpoints

Completed event:

  • Card heading: Signal With Start Workflow Execution Delivered
  • Result: {runId, started: true} decoded from SignalWithStartWorkflowExecutionResponse
  • requestId hidden

Component architecture

  • SystemNexusOperationRenderer — dispatcher keyed on NexusEmbeddedOperationKind; adding a new operation type = new component file + one map entry
  • system-nexus/signal-with-start-renderer.svelte — renders signal input + workflow start input
  • system-nexus/default-renderer.svelte — fallback for other kinds

Scope

Only SignalWithStartWorkflowExecution is implemented and tested. Other system Nexus operation types (StartWorkflow, SignalWorkflow, QueryWorkflow) are not included — entries will be added when those operations are enabled server-side and testable.

Closes

DT-3945, DT-3946, DT-3947, DT-3948, DT-3949. Part of DT-3944.

Test plan

  • Caller workflow event history shows friendly labels, no system internals
  • Signal and workflow start payloads both render in the Input panel
  • Timeline bar uses signal pink color and icon
  • Non-system Nexus operations unaffected
  • pnpm test -- --run passes

@vercel
Copy link
Copy Markdown

vercel Bot commented Apr 29, 2026

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
holocene Ready Ready Preview, Comment Jun 5, 2026 3:52pm

Request Review

rossnelson added 10 commits June 3, 2026 16:03
Add a Phase 1.5 dispatch in parseRawPayloadToJSON: when a Payload's
metadata says encoding=binary/protobuf and carries a messageType, look
the type up by full name in @temporalio/proto's static namespace and
return the typed JSON. After the outer decode, walk the result tree
and recursively decode any nested {metadata, data} Payload nodes
through the same pipeline so user-side payloads (json/plain, json/
protobuf, json/external-storage-reference, etc.) come out fully
parsed. Unknown messageTypes and decode errors fall through to the
existing path so behavior for non-binary/protobuf payloads is
unchanged.

This is the proposal for handling System Nexus operations like
SignalWithStartWorkflowExecutionRequest, where the gRPC envelope
arrives as binary protobuf and the inner Payloads carry user data.

Tests cover round-tripping a real SignalWithStart fixture and the
graceful fallback for an unknown messageType. 27/27 passing.

Caveat: protobufjs builds its decoders with Function() and so needs
'unsafe-eval' in the script-src CSP. That's relaxed in a separate
commit so reviewers can drop it before merge if we want a different
proto runtime (@bufbuild/protobuf has no eval).
@temporalio/proto uses protobufjs, which compiles per-message
encoders/decoders via the Function() constructor. With the existing
'strict-dynamic' CSP and no 'unsafe-eval', binary/protobuf payload
decode silently fails in the browser.

Relax the dev/auto CSP to permit unsafe-eval so the new decode path
works end-to-end during the LOE evaluation. If the team decides to
ship browser-side proto decoding, the long-term option is to swap
@temporalio/proto for @bufbuild/protobuf (which doesn't use eval) and
drop this commit.

Open question for review: do we keep this, or migrate the runtime?
…-binary-protobuf

Moves lookupTemporalProtoType, base64ToUint8Array, looksLikeRawPayload,
recursivelyDecodeNestedPayloads, and the full decode path into a new
decode-binary-protobuf utility. The recursive walker now accepts a recurse
callback rather than calling parseRawPayloadToJSON directly, eliminating
the circular dependency. Adds unit tests covering successful decode, silent
null on unknown type, warn-on-throw, looksLikeRawPayload edge cases, and
the callback injection path.
…quests

Converts payload-decoder.svelte from {#await} to AbortController + $effect
so stale in-flight decodes cannot overwrite a newer result. Rewrites
codeServerRequest in data-encoder.ts to accept an optional AbortSignal and
retry transient errors (network/5xx) up to 3 attempts with 500ms/1000ms
delays, without retrying 4xx. Deletes the now-unused decode-payload-value
module (zero importers confirmed).
Adds a nexus-operation-registry that recognises the 4 system-level Nexus
operation types (StartWorkflow, SignalWorkflow, SignalWithStartWorkflow,
QueryWorkflow) and returns a human-readable descriptor with the embedded
input payloads. NexusOperationRenderer uses the registry to show the
embedded operation directly — users see "Signal With Start Workflow:
EchoWorkflow" and the decoded input, not the raw protobuf wrapper.
input-and-results-payload routes Nexus payloads through the renderer
automatically; all other content paths are unchanged. Adds 6 registry
tests covering the happy path and null returns for unknown types.
…bufbuild/protobuf

Replace protobufjs runtime (which requires unsafe-eval via Function()) with
@bufbuild/protobuf + @buf/temporalio_api.bufbuild_es. Static SCHEMA_REGISTRY
map replaces the dynamic lookupTemporalProtoType traversal — adding a new
operation type is a one-line entry. Removes unsafe-eval from the CSP.
Move the recurse callback into decodeBinaryProtobuf so the function fully
owns the "decode this payload including anything nested inside it" contract.
Make looksLikeRawPayload, base64ToUint8Array, and recursivelyDecodeNestedPayloads
module-private. decode-payload.ts now has a single call site with no knowledge
of the recursion internals.
Add *Response schemas for all four system Nexus operation types so completed
event payloads (NexusOperationCompleted result, WorkflowExecutionCompleted
result) decode alongside their corresponding request payloads.
Comment thread pnpm-lock.yaml Outdated
Resolves axios downgrade from 1.15.2 to 1.15.0 introduced by
using --theirs on the lockfile during rebase conflict resolution.
return response.json();

if (response.status >= 400 && response.status < 500) {
setLastDataEncoderFailure(err);
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  • ⚠️ Type 'PotentialPayloads' is not assignable to type 'IPayloads'.

}

return decoderResponse;
setLastDataEncoderFailure(lastErr);
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  • ⚠️ Type 'PotentialPayloads' is not assignable to type 'IPayloads'.

if (decoded) {
if (returnDataOnly) return decoded.data;
return {
metadata: {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  • ⚠️ Argument of type '{ [k: string]: Uint8Array; } | null | undefined' is not assignable to parameter of type 'Record<string, unknown>'.


try {
const data = parseWithBigInt(atob(String(payload?.data ?? '')));
if (returnDataOnly) return data;
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  • ⚠️ Argument of type '{ [k: string]: Uint8Array; } | null | undefined' is not assignable to parameter of type 'Record<string, unknown>'.

@temporal-cicd
Copy link
Copy Markdown
Contributor

temporal-cicd Bot commented Jun 3, 2026

Warnings
⚠️

📊 Strict Mode: 71 errors in 9 files (7.9% of 899 total)

src/lib/services/data-encoder.ts (4)
  • L52:27: Type 'PotentialPayloads' is not assignable to type 'IPayloads'.
  • L76:6: Type 'PotentialPayloads' is not assignable to type 'IPayloads'.
  • L125:33: Type 'PotentialPayloads' is not assignable to type 'IPayloads'.
  • L152:25: Type 'PotentialPayloads' is not assignable to type 'IPayloads'.
src/lib/utilities/decode-payload.ts (24)
  • L86:35: Argument of type '{ [k: string]: Uint8Array; } | null | undefined' is not assignable to parameter of type 'Record<string, unknown>'.
  • L89:9: 'payloadOrPayloads.payloads' is possibly 'null' or 'undefined'.
  • L90:28: Argument of type '{ [k: string]: Uint8Array; } | null | undefined' is not assignable to parameter of type 'Record<string, unknown>'.
  • L120:35: Argument of type '{ [k: string]: Uint8Array; } | null | undefined' is not assignable to parameter of type 'Record<string, unknown>'.
  • L130:45: Argument of type '{ [k: string]: Uint8Array; } | null | undefined' is not assignable to parameter of type 'Record<string, unknown>'.
  • L146:45: Argument of type '{ [k: string]: Uint8Array; } | null | undefined' is not assignable to parameter of type 'Record<string, unknown>'.
  • L180:19: No overload matches this call.
  • L181:6: 'searchAttributes' is of type 'unknown'.
  • L181:52: Argument of type 'unknown' is not assignable to parameter of type 'IPayload'.
  • L189:19: No overload matches this call.
  • L190:6: 'memo' is of type 'unknown'.
  • L190:40: Argument of type 'unknown' is not assignable to parameter of type 'IPayload'.
  • L198:19: No overload matches this call.
  • L199:6: 'header' is of type 'unknown'.
  • L199:42: Argument of type 'unknown' is not assignable to parameter of type 'IPayload'.
  • L208:19: No overload matches this call.
  • L209:6: 'queryResult' is of type 'unknown'.
  • L209:47: Argument of type 'unknown' is not assignable to parameter of type 'IPayload'.
  • L326:54: Argument of type 'IPayload[] | null | undefined' is not assignable to parameter of type 'unknown[]'.
  • L374:57: Element implicitly has an 'any' type because expression of type 'string' can't be used to index type '{ payloads?: IPayload[] | null | undefined; } | { id: string; attributes: EventAttribute; timestamp: string; classification: "Scheduled" | "Unspecified" | ... 12 more ... | "CancelRequested"; ... 70 more ...; eventId: string; } | ... 61 more ... | { ...; }'.
  • L375:29: Element implicitly has an 'any' type because expression of type 'string' can't be used to index type '{ payloads?: IPayload[] | null | undefined; } | { id: string; attributes: EventAttribute; timestamp: string; classification: "Scheduled" | "Unspecified" | ... 12 more ... | "CancelRequested"; ... 70 more ...; eventId: string; } | ... 61 more ... | { ...; }'.
  • L377:8: Element implicitly has an 'any' type because expression of type 'string' can't be used to index type '{ payloads?: IPayload[] | null | undefined; } | { id: string; attributes: EventAttribute; timestamp: string; classification: "Scheduled" | "Unspecified" | ... 12 more ... | "CancelRequested"; ... 70 more ...; eventId: string; } | ... 61 more ... | { ...; }'.
  • L379:21: Element implicitly has an 'any' type because expression of type 'string' can't be used to index type '{ payloads?: IPayload[] | null | undefined; } | { id: string; attributes: EventAttribute; timestamp: string; classification: "Scheduled" | "Unspecified" | ... 12 more ... | "CancelRequested"; ... 70 more ...; eventId: string; } | ... 61 more ... | { ...; }'.
  • L381:10: Element implicitly has an 'any' type because expression of type 'string' can't be used to index type '{ payloads?: IPayload[] | null | undefined; } | { id: string; attributes: EventAttribute; timestamp: string; classification: "Scheduled" | "Unspecified" | ... 12 more ... | "CancelRequested"; ... 70 more ...; eventId: string; } | ... 61 more ... | { ...; }'.
src/lib/models/event-groups/get-group-name.ts (14)
  • L20:62: Function lacks ending return statement and return type does not include 'undefined'.
  • L24:4: Type 'string | null | undefined' is not assignable to type 'string'.
  • L36:4: Type 'string | null | undefined' is not assignable to type 'string'.
  • L41:4: Type 'string | null | undefined' is not assignable to type 'string'.
  • L48:4: Type 'string | null | undefined' is not assignable to type 'string'.
  • L52:4: Type 'string | null | undefined' is not assignable to type 'string'.
  • L57:4: Type 'string | null | undefined' is not assignable to type 'string'.
  • L63:15: 'attrs' is possibly 'null' or 'undefined'.
  • L65:45: 'attrs' is possibly 'null' or 'undefined'.
  • L66:11: 'attrs' is possibly 'null' or 'undefined'.
  • L66:28: 'attrs' is possibly 'null' or 'undefined'.
  • L69:14: 'attrs' is possibly 'null' or 'undefined'.
  • L69:31: 'attrs' is possibly 'null' or 'undefined'.
  • L73:63: Function lacks ending return statement and return type does not include 'undefined'.
src/lib/utilities/get-system-nexus-event-display.ts (4)
  • L35:15: 'attrs' is possibly 'null' or 'undefined'.
  • L37:22: 'attrs' is possibly 'null' or 'undefined'.
  • L45:18: 'attrs' is possibly 'null' or 'undefined'.
  • L66:19: 'event.nexusOperationCompletedEventAttributes' is possibly 'null' or 'undefined'.
src/lib/components/payload/system-nexus/default-renderer.svelte (1)
  • L12:18: Type 'IPayload[] | null | undefined' is not assignable to type 'object | IPayloads | IPayload'.
src/lib/components/payload/system-nexus/signal-with-start-renderer.svelte (1)
  • L25:22: Type 'null' is not assignable to type 'object | IPayloads | IPayload'.
src/lib/components/event/event-card.svelte (11)
  • L165:37: Type 'string | null | undefined' is not assignable to type 'string'.
  • L165:48: 'link.workflowEvent' is possibly 'null' or 'undefined'.
  • L173:6: Type 'string | null | undefined' is not assignable to type 'string'.
  • L173:15: 'link.workflowEvent' is possibly 'null' or 'undefined'.
  • L176:10: 'link.workflowEvent' is possibly 'null' or 'undefined'.
  • L200:19: Parameter 'key' implicitly has an 'any' type.
  • L200:24: Parameter 'value' implicitly has an 'any' type.
  • L255:15: Parameter 'key' implicitly has an 'any' type.
  • L255:20: Parameter 'value' implicitly has an 'any' type.
  • L275:18: Parameter 'key' implicitly has an 'any' type.
  • L275:23: Parameter 'value' implicitly has an 'any' type.
src/lib/components/event/event-summary-row.svelte (5)
  • L151:6: Argument of type 'string | undefined' is not assignable to parameter of type 'string'.
  • L188:23: Parameter 'event' implicitly has an 'any' type.
  • L200:30: Parameter 'group' implicitly has an 'any' type.
  • L200:37: Parameter 'hoveredEventId' implicitly has an 'any' type.
  • L328:16: Type 'ITimestamp | null | undefined' is not assignable to type 'ITimestamp'.
src/lib/components/lines-and-dots/svg/timeline-graph-row.svelte (7)
  • L74:15: 'attrs' is possibly 'null' or 'undefined'.
  • L75:8: 'attrs' is possibly 'null' or 'undefined'.
  • L116:20: 'distance' is possibly 'null'.
  • L116:31: 'workflowDistance' is possibly 'null'.
  • L127:20: 'distance' is possibly 'null'.
  • L127:31: 'workflowDistance' is possibly 'null'.
  • L263:12: 'pendingActivity.attempt' is possibly 'null' or 'undefined'.

Generated by 🚫 dangerJS against ca8c043

@rossnelson rossnelson changed the title feat: decode binary/protobuf payloads with messageType (LOE) feat: decode binary/protobuf payloads with messageType Jun 5, 2026
)

* feat(DT-3945): wire NexusOperationRenderer into event-card.svelte

Detect system Nexus operation payloads in the payloads snippet and route
them through NexusOperationRenderer instead of PayloadCodeBlock. Users
see the embedded operation label and input instead of the raw protobuf
wrapper fields.

* feat(DT-3946): remap event name and suppress system fields for Nexus ops (#3499)

* feat(DT-3946): remap event name and suppress system fields for Nexus ops

For NexusOperationScheduled events where endpoint === '__temporal_system':
- Override displayName with friendly label from NexusOperationDescriptor
  (e.g. "Signal With Start Workflow: target-workflow Scheduled")
- Hide Endpoint, Service, Operation, RequestID from the detail fields
- Suppress the Operation primary attribute badge in the compact row

For NexusOperationCompleted events (detected via response payload messageType):
- Override displayName with "Signal With Start Operation Completed" etc.
- Hide RequestID from detail fields

Updates event-card.svelte, event-summary-row.svelte, and adds
getSystemNexusLabelFromResponsePayload to nexus-operation-registry.ts.

* feat(DT-3947): remap timeline label and icon for system Nexus operations (#3500)

* feat(DT-3947): remap timeline label and icon for system Nexus operations

- get-group-name.ts: return "Signal With Start Operation" etc. for system
  Nexus ops (__temporal_system endpoint) instead of service.operation string
- timeline-graph-row.svelte: derive effectiveCategory (signal/workflow) for
  system Nexus groups so they render with signal/workflow color and icon
  instead of the Nexus star and indigo treatment
- nexus-operation-registry.ts: simplify all labels to "X Operation" (no
  workflow type suffix) — consistent everywhere including the renderer
- event-summary-row.svelte: align compact row labels to use "Operation"
- event-card.svelte: align SYSTEM_NEXUS_LABELS to use "Operation"
- Update registry test to match new label format

* feat(DT-3949): SystemNexusOperationRenderer — component map, dual inputs, label finalization (#3501)

* feat(DT-3949): signal name sub-label and clickable workflow ID link in renderer

NexusOperationRenderer now shows:
- Signal name as a secondary line (Signal: test-signal) for signal kinds
- Clickable workflowId link to /namespaces/{ns}/workflows/{workflowId}
  when the descriptor has a workflowId (resolves to latest run naturally)

* feat: use 'other' category treatment for system Nexus ops in compact row

* refactor(DT-3949): move workflowId and signalName to left-column detail fields

Simplifies NexusOperationRenderer back to just label + embedded payload.
Signal name and workflow ID are now injected into the event card's
attribute map so they appear as standard left-column detail fields
(Workflow ID, Signal Name) — matching the pattern used by other event types.

* refactor: remove label from NexusOperationRenderer — redundant with card heading

* refactor: component-map dispatcher for system Nexus operation rendering

- Rename NexusOperationRenderer → SystemNexusOperationRenderer (explicit scope)
- Component map keyed on NexusEmbeddedOperationKind — adding a new operation
  type requires only a new component file + one map entry, zero dispatcher changes
- signal-with-start-renderer.svelte handles both signal and workflow start inputs
  with labels when both are present
- default-renderer.svelte handles all other kinds (embeddedInput only)
- Remove old nexus-operation-renderer.svelte

Also: extract signalInput (signal payload) and workflowInput (workflow start
input) separately in the SignalWithStart spec; update Go sample to include
both payloads so the UI can be verified with real data.

* fix: use signal category for system Nexus ops in compact row

* feat: finalize SignalWithStart labels and state verbs

- Label: 'Signal With Start Workflow Execution' (replaces 'Signal With Start Operation')
- State suffix: Scheduled → 'Initiated', Completed → 'Delivered'
- Both event-card.svelte and event-summary-row.svelte use NEXUS_STATE_VERBS
  map for signal/state verb mapping; other states (Failed, TimedOut, Canceled)
  fall back to spaceBetweenCapitalLetters

* fix: update timeline group label for SignalWithStart to match new naming

* fix: pass category prop to Dot so signal color applies on timeline endpoints
const effectiveCategory = $derived(systemNexusCategory ?? group.category);

let decodedLocalActivity: SummaryAttribute | undefined = $state(undefined);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  • ⚠️ 'attrs' is possibly 'null' or 'undefined'.


let { descriptor, maxHeight }: Props = $props();
</script>

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  • ⚠️ Type 'IPayload[] | null | undefined' is not assignable to type 'object | IPayloads | IPayload'.

<p class="text-xs text-secondary/70">Workflow Input</p>
<PayloadCodeBlock value={descriptor.workflowInput} {maxHeight} />
{/if}
{:else}
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  • ⚠️ Type 'null' is not assignable to type 'object | IPayloads | IPayload'.


if (isNexusOperationScheduledEvent(event)) {
return `${event.nexusOperationScheduledEventAttributes.service}.${event.nexusOperationScheduledEventAttributes.operation}`;
const attrs = event.nexusOperationScheduledEventAttributes;
Copy link
Copy Markdown
Contributor

@temporal-cicd temporal-cicd Bot Jun 5, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  • ⚠️ 'attrs' is possibly 'null' or 'undefined'.
  • ⚠️ 'attrs' is possibly 'null' or 'undefined'.

const attrs = event.nexusOperationScheduledEventAttributes;
if (String(attrs.endpoint ?? '') === '__temporal_system') {
return (
SYSTEM_NEXUS_OPERATION_LABELS[String(attrs.operation ?? '')] ??
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  • ⚠️ 'attrs' is possibly 'null' or 'undefined'.
  • ⚠️ 'attrs' is possibly 'null' or 'undefined'.

Remove Start, Signal, and Query operation entries from:
- SCHEMA_REGISTRY (decode-binary-protobuf.ts)
- NEXUS_OPERATIONS and SYSTEM_NEXUS_RESPONSE_LABELS (nexus-operation-registry.ts)
- NexusEmbeddedOperationKind union type (single member: signal-with-start-workflow)
- SYSTEM_NEXUS_LABELS maps (event-card.svelte, event-summary-row.svelte)
- SYSTEM_NEXUS_OPERATION_LABELS (get-group-name.ts)
- systemNexusCategory (timeline-graph-row.svelte — exact match instead of includes('Signal'))

Also remove unused workflowType and taskQueue from NexusOperationDescriptor
and OperationSpec — these were extracted but never read by any UI component.
const SYSTEM_NEXUS_OPERATION_LABELS: Record<string, string> = {
SignalWithStartWorkflowExecution: 'Signal With Start Workflow Execution',
};

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  • ⚠️ Function lacks ending return statement and return type does not include 'undefined'.


if (isNexusOperationScheduledEvent(event)) {
return `${event.nexusOperationScheduledEventAttributes.service}.${event.nexusOperationScheduledEventAttributes.operation}`;
const attrs = event.nexusOperationScheduledEventAttributes;
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  • ⚠️ 'attrs' is possibly 'null' or 'undefined'.

return `${event.nexusOperationScheduledEventAttributes.service}.${event.nexusOperationScheduledEventAttributes.operation}`;
const attrs = event.nexusOperationScheduledEventAttributes;
if (String(attrs.endpoint ?? '') === '__temporal_system') {
return (
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  • ⚠️ 'attrs' is possibly 'null' or 'undefined'.

return `${attrs.service}.${attrs.operation}`;
}
};

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  • ⚠️ Function lacks ending return statement and return type does not include 'undefined'.

@rossnelson rossnelson changed the title feat: decode binary/protobuf payloads with messageType feat(DT-3944): SignalWithStart system Nexus obfuscation — decode infrastructure + UI Jun 5, 2026
…ent-display utility

Move SYSTEM_NEXUS_LABELS, NEXUS_STATE_VERBS, detection logic, display name
computation, hidden fields, and extra attribute injection out of event-card.svelte
and event-summary-row.svelte into a shared utility.

Both components now call getSystemNexusEventDisplay(event) and consume the
{ displayName, hiddenFields, extraAttributes } result — no system Nexus
knowledge remains in the general-purpose components.

const secondaryAttribute = $derived(
getSecondaryAttributeForEvent(
isEventGroup(event) ? event.lastEvent : event,
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  • ⚠️ Argument of type 'string | undefined' is not assignable to parameter of type 'string'.

event: WorkflowEvent,
): SystemNexusEventDisplay | null => {
if (isNexusOperationScheduledEvent(event)) {
const attrs = event.nexusOperationScheduledEventAttributes;
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  • ⚠️ 'attrs' is possibly 'null' or 'undefined'.

if (isNexusOperationScheduledEvent(event)) {
const attrs = event.nexusOperationScheduledEventAttributes;
if (String(attrs.endpoint ?? '') !== '__temporal_system') return null;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  • ⚠️ 'attrs' is possibly 'null' or 'undefined'.

const rawState = event.name.replace('NexusOperation', '');
const state =
NEXUS_STATE_VERBS[rawState] ?? spaceBetweenCapitalLetters(rawState);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  • ⚠️ 'attrs' is possibly 'null' or 'undefined'.

};
}

if (isNexusOperationCompletedEvent(event)) {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  • ⚠️ 'event.nexusOperationCompletedEventAttributes' is possibly 'null' or 'undefined'.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant