Skip to content

refactor(decode-payload): clean up decode-payload.ts API surface#3302

Merged
rossedfort merged 14 commits into
mainfrom
refactor-decode-payload-utils
Apr 16, 2026
Merged

refactor(decode-payload): clean up decode-payload.ts API surface#3302
rossedfort merged 14 commits into
mainfrom
refactor-decode-payload-utils

Conversation

@rossedfort

Copy link
Copy Markdown
Contributor

Description & motivation 💭

decode-payload.ts had grown several redundant abstractions over time: two nearly-identical recursive walk functions, a thin wrapper that added no
logic, an unused namespace parameter threaded through every call, and a returnDataOnly flag that only one caller ever set to false.

This PR removes the dead weight, renames functions to reflect what they actually do, and isolates the export-history code path that needed the
non-default behavior.

Changes

  • Remove convertPayloadToJsonWithCodec and decodeAllPotentialPayloadsWithCodec — replaced all call sites with decodeEventAttributes (the renamed
    cloneAllPotentialPayloadsWithCodec), eliminating the duplicate recursive walker and its misleadingly-named wrapper
  • Rename 6 functions for clarity — decodePayload → decodeRawPayload, decodeReadablePayloads → decodePayloadsWithCodec, decodePayloads →
    applyCodecToPayloads, decodeSingleReadablePayloadWithCodec → decodeUserMetadataPayload, cloneAllPotentialPayloadsWithCodec → decodeEventAttributes,
    isSinglePayload → isRawPayload
  • Drop the unused namespace parameter from decodeEventAttributes and all call sites
  • Isolate returnDataOnly = false into a dedicated decodeEventAttributesForExport function so the flag is no longer threaded through the default call
    chain
  • Unify the two searchAttributes branches in decodePayloadAttributes into a single conditional that resolves indexedFields vs flat structure before
    iterating

Screenshots (if applicable) 📸

Design Considerations 🎨

Testing 🧪

How was this tested 👻

  • Manual testing
  • E2E tests added
  • Unit tests added

Steps for others to test: 🚶🏽‍♂️🚶🏽‍♀️

Checklists

Draft Checklist

Merge Checklist

Issue(s) closed

Docs

Any docs updates needed?

…codeAllPotentialPayloadsWithCodec

Replace all call sites with cloneAllPotentialPayloadsWithCodec directly,
eliminating the duplicate recursive walker and its named-param wrapper.
decodePayload → decodeRawPayload
decodePayloads → applyCodecToPayloads
decodeReadablePayloads → decodePayloadsWithCodec
decodeSingleReadablePayloadWithCodec → decodeUserMetadataPayload
cloneAllPotentialPayloadsWithCodec → decodeEventAttributes
isSinglePayload → isRawPayload
…ibutes

The namespace argument was unused inside the function body. Removing it
simplifies all call sites and makes the signature match actual behavior.
…ntAttributesForExport

Remove the returnDataOnly parameter from the public decodeEventAttributes
API. Extract a dedicated decodeEventAttributesForExport function for the
two callers (export-history, workflow-service) that need to preserve the
full payload structure with metadata.
Collapse the two separate branches in decodePayloadAttributes — one for
indexedFields and one for flat searchAttributes — into a single branch
that selects the correct target object via ternary.

Fix stale test mocks in get-event-attributes and to-event-history that
still referenced the removed convertPayloadToJsonWithCodec export.
@vercel

vercel Bot commented Apr 13, 2026

Copy link
Copy Markdown

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

Project Deployment Actions Updated (UTC)
holocene Ready Ready Preview, Comment Apr 15, 2026 8:27pm

Request Review

false,
)) as PotentiallyDecodable;

let summary = '';

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.

  • ⚠️ 'workflow' is possibly 'undefined'.

}
}

let details = '';

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.

  • ⚠️ 'workflow' is possibly 'undefined'.

return groups
.map((group) => {
const rawStatus = decodePayload(
const rawStatus = decodeRawPayload(

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.

  • ⚠️ Property 'groupValues' does not exist on type 'never'.

const rawStatus = decodePayload(
const rawStatus = decodeRawPayload(
group?.groupValues[0],
) as unknown as ActivityStatus;

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.

  • ⚠️ Property 'count' does not exist on type 'never'.

return groups
.map((group) => {
const status = decodePayload(
const status = decodeRawPayload(

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.

  • ⚠️ Property 'groupValues' does not exist on type 'never'.

const status = decodePayload(
const status = decodeRawPayload(
group?.groupValues[0],
) as unknown as WorkflowStatus;

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.

  • ⚠️ Property 'count' does not exist on type 'never'.

): SummaryAttribute => {
if (typeof value === 'object') {
if (isSinglePayload(value)) {
if (isRawPayload(value)) {

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 'object | null' is not assignable to type 'string | Record<string, unknown> | IPayloads'.

if (isSinglePayload(value)) {
if (isRawPayload(value)) {
return { key, value };
}

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.

  • ⚠️ No overload matches this call.

@temporal-cicd

temporal-cicd Bot commented Apr 13, 2026

Copy link
Copy Markdown
Contributor
Warnings
⚠️

📊 Strict Mode: 177 errors in 23 files (16.9% of 1049 total)

src/lib/services/data-encoder.ts (2)
  • L48:8: Element implicitly has an 'any' type because expression of type '"Authorization"' can't be used to index type '{ 'Content-Type': string; 'X-Namespace': string; }'.
  • L51:8: Element implicitly has an 'any' type because expression of type '"Authorization-Extras"' can't be used to index type '{ 'Content-Type': string; 'X-Namespace': string; }'.
src/lib/utilities/decode-payload.ts (20)
  • L80:45: Argument of type '{ [k: string]: string; } | undefined' is not assignable to parameter of type 'Record<string, unknown>'.
  • L93:45: Argument of type '{ [k: string]: string; } | undefined' is not assignable to parameter of type 'Record<string, unknown>'.
  • L127:19: No overload matches this call.
  • L128:6: 'searchAttributes' is of type 'unknown'.
  • L128:52: Argument of type 'unknown' is not assignable to parameter of type 'Payload'.
  • L136:19: No overload matches this call.
  • L137:6: 'memo' is of type 'unknown'.
  • L137:40: Argument of type 'unknown' is not assignable to parameter of type 'Payload'.
  • L145:19: No overload matches this call.
  • L146:6: 'header' is of type 'unknown'.
  • L146:42: Argument of type 'unknown' is not assignable to parameter of type 'Payload'.
  • L155:19: No overload matches this call.
  • L156:6: 'queryResult' is of type 'unknown'.
  • L156:47: Argument of type 'unknown' is not assignable to parameter of type 'Payload'.
  • L174:26: Argument of type 'unknown' is not assignable to parameter of type 'Payload'.
  • L270:57: Element implicitly has an 'any' type because expression of type 'string' can't be used to index type '{ id: string; attributes: EventAttribute; timestamp: string; classification: "Scheduled" | "Unspecified" | "Open" | "New" | "Started" | "Initiated" | "Running" | ... 7 more ... | "CancelRequested"; ... 70 more ...; eventId: string; } | ... 62 more ... | { ...; }'.
  • L271:29: Element implicitly has an 'any' type because expression of type 'string' can't be used to index type '{ id: string; attributes: EventAttribute; timestamp: string; classification: "Scheduled" | "Unspecified" | "Open" | "New" | "Started" | "Initiated" | "Running" | ... 7 more ... | "CancelRequested"; ... 70 more ...; eventId: string; } | ... 62 more ... | { ...; }'.
  • L273:8: Element implicitly has an 'any' type because expression of type 'string' can't be used to index type '{ id: string; attributes: EventAttribute; timestamp: string; classification: "Scheduled" | "Unspecified" | "Open" | "New" | "Started" | "Initiated" | "Running" | ... 7 more ... | "CancelRequested"; ... 70 more ...; eventId: string; } | ... 62 more ... | { ...; }'.
  • L275:21: Element implicitly has an 'any' type because expression of type 'string' can't be used to index type '{ id: string; attributes: EventAttribute; timestamp: string; classification: "Scheduled" | "Unspecified" | "Open" | "New" | "Started" | "Initiated" | "Running" | ... 7 more ... | "CancelRequested"; ... 70 more ...; eventId: string; } | ... 62 more ... | { ...; }'.
  • L277:10: Element implicitly has an 'any' type because expression of type 'string' can't be used to index type '{ id: string; attributes: EventAttribute; timestamp: string; classification: "Scheduled" | "Unspecified" | "Open" | "New" | "Started" | "Initiated" | "Running" | ... 7 more ... | "CancelRequested"; ... 70 more ...; eventId: string; } | ... 62 more ... | { ...; }'.
src/lib/models/event-history/index.ts (6)
  • L37:45: Argument of type 'WorkflowEvent | EventAttribute | IMemo | PotentiallyDecodable' is not assignable to parameter of type 'Optional<WorkflowEvent | EventAttribute | PotentiallyDecodable>'.
  • L129:9: The operand of a 'delete' operator must be optional.
  • L130:9: The operand of a 'delete' operator must be optional.
  • L131:9: The operand of a 'delete' operator must be optional.
  • L132:9: The operand of a 'delete' operator must be optional.
  • L133:9: The operand of a 'delete' operator must be optional.
src/lib/utilities/get-single-attribute-for-event.ts (12)
  • L127:13: 'getStackTrace' implicitly has return type 'any' because it does not have a return type annotation and is referenced directly or indirectly in one of its return expressions.
  • L229:20: Type 'object | null' is not assignable to type 'string | Record<string, unknown> | IPayloads'.
  • L231:35: No overload matches this call.
  • L236:20: Type 'object | null' is not assignable to type 'string | Record<string, unknown> | IPayloads'.
  • L238:53: 'value' is possibly 'null'.
  • L238:53: Element implicitly has an 'any' type because expression of type 'string' can't be used to index type '{}'.
  • L240:25: 'value' is possibly 'undefined'.
  • L270:19: Function lacks ending return statement and return type does not include 'undefined'.
  • L271:44: No overload matches this call.
  • L309:41: Argument of type 'unknown' is not assignable to parameter of type 'Payload'.
  • L325:46: No overload matches this call.
  • L338:34: 'event.attempt' is possibly 'null' or 'undefined'.
src/lib/models/workflow-execution.ts (55)
  • L49:50: Argument of type 'PendingNexusOperationState | null | undefined' is not assignable to parameter of type 'PendingNexusOperationState | undefined'.
  • L57:4: Type '{ state: temporal.api.enums.v1.CallbackState; callback?: (temporal.api.common.v1.ICallback | null); trigger?: (temporal.api.workflow.v1.CallbackInfo.ITrigger | null); ... 5 more ...; blockedReason?: (string | null); }' is not assignable to type 'Callback'.
  • L59:37: Argument of type 'CallbackState | null | undefined' is not assignable to parameter of type 'CallbackState | undefined'.
  • L90:36: Type 'undefined' is not assignable to type 'string'.
  • L96:2: Type 'undefined' is not assignable to type 'string'.
  • L103:4: 'response' is possibly 'undefined'.
  • L103:4: 'response.workflowExecutionInfo' is possibly 'undefined'.
  • L103:4: Argument of type 'WorkflowSearchAttributes | undefined' is not assignable to parameter of type 'WorkflowSearchAttributes'.
  • L105:15: 'response' is possibly 'undefined'.
  • L105:15: 'response.workflowExecutionInfo' is possibly 'undefined'.
  • L106:15: 'response' is possibly 'undefined'.
  • L106:15: 'response.workflowExecutionInfo' is possibly 'undefined'.
  • L106:15: 'response.workflowExecutionInfo.type' is possibly 'null' or 'undefined'.
  • L107:13: 'response' is possibly 'undefined'.
  • L107:13: 'response.workflowExecutionInfo' is possibly 'undefined'.
  • L107:13: 'response.workflowExecutionInfo.execution' is possibly 'null' or 'undefined'.
  • L108:16: 'response' is possibly 'undefined'.
  • L108:16: 'response.workflowExecutionInfo' is possibly 'undefined'.
  • L108:16: 'response.workflowExecutionInfo.execution' is possibly 'null' or 'undefined'.
  • L109:20: 'response' is possibly 'undefined'.
  • L109:20: 'response.workflowExecutionInfo' is possibly 'undefined'.
  • L110:18: 'response' is possibly 'undefined'.
  • L110:18: 'response.workflowExecutionInfo' is possibly 'undefined'.
  • L111:24: 'response' is possibly 'undefined'.
  • L111:24: 'response.workflowExecutionInfo' is possibly 'undefined'.
  • L113:4: 'response' is possibly 'undefined'.
  • L113:4: 'response.workflowExecutionInfo' is possibly 'undefined'.
  • L117:24: 'response' is possibly 'undefined'.
  • L117:24: 'response.workflowExecutionInfo' is possibly 'undefined'.
  • L118:27: 'response' is possibly 'undefined'.
  • L118:27: 'response.workflowExecutionInfo' is possibly 'undefined'.
  • L129:4: 'response' is possibly 'undefined'.
  • L129:4: 'response.workflowExecutionInfo' is possibly 'undefined'.
  • L131:4: 'response' is possibly 'undefined'.
  • L133:4: 'response' is possibly 'undefined'.
  • L135:4: 'response' is possibly 'undefined'.
  • L142:24: 'response' is possibly 'undefined'.
  • L143:25: 'response' is possibly 'undefined'.
  • L144:19: 'response' is possibly 'undefined'.
  • L145:31: 'response' is possibly 'undefined'.
  • L160:4: Type 'string | null | undefined' is not assignable to type 'string'.
  • L161:4: Type 'string | null | undefined' is not assignable to type 'string'.
  • L162:4: Type 'string | null | undefined' is not assignable to type 'string'.
  • L172:4: Type 'IMemo | undefined' is not assignable to type 'IMemo'.
  • L173:4: Type 'IWorkflowExecution | null | undefined' is not assignable to type 'IWorkflowExecution | undefined'.
  • L175:4: Type 'string | null | undefined' is not assignable to type 'string | undefined'.
  • L177:4: Type 'IWorkerVersionStamp | null | undefined' is not assignable to type 'MostRecentWOrkflowVersionStamp | undefined'.
  • L181:4: Type 'IPendingWorkflowTaskInfo | undefined' is not assignable to type 'IPendingWorkflowTaskInfo'.
  • L182:4: Type 'Callbacks' is not assignable to type 'Callback[]'.
  • L184:4: Type 'IPriority | null | undefined' is not assignable to type 'IPriority | undefined'.
  • L185:4: Type 'IPayload | null | undefined' is not assignable to type 'Payload | undefined'.
  • L186:4: Type 'IPayload | null | undefined' is not assignable to type 'Payload | undefined'.
  • L187:4: Type 'string | null | undefined' is not assignable to type 'string | undefined'.
  • L188:4: Type 'IWorkflowExecution | null | undefined' is not assignable to type 'IWorkflowExecution | undefined'.
  • L192:4: Type 'Duration | undefined' is not assignable to type 'Duration'.
src/lib/models/event-history/get-event-attributes.test.ts (1)
  • L156:13: Element implicitly has an 'any' type because expression of type 'string' can't be used to index type 'WorkflowEvent'.
src/lib/models/event-history/to-event-history.test.ts (2)
  • L156:13: Element implicitly has an 'any' type because expression of type 'string' can't be used to index type 'WorkflowEvent'.
  • L180:13: Element implicitly has an 'any' type because expression of type 'string' can't be used to index type 'HistoryEvent'.
src/lib/services/query-service.ts (3)
  • L97:8: 'e' is of type 'unknown'.
  • L98:54: 'e' is of type 'unknown'.
  • L107:8: Type 'unknown' is not assignable to type 'Error | undefined'.
src/lib/services/workflow-service.ts (23)
  • L195:6: Type 'ErrorCallback' is not assignable to type '(error: unknown, toasts?: Toaster, errors?: Writable<NetworkError | null>, isBrowser?: boolean) => void'.
  • L257:4: Type 'ErrorCallback' is not assignable to type '(error: unknown, toasts?: Toaster, errors?: Writable<NetworkError | null>, isBrowser?: boolean) => void'.
  • L296:45: Argument of type 'unknown' is not assignable to parameter of type 'WorkflowExecutionAPIResponse | undefined'.
  • L429:28: No overload matches this call.
  • L649:4: Type 'ErrorCallback' is not assignable to type '(error: unknown, toasts?: Toaster, errors?: Writable<NetworkError | null>, isBrowser?: boolean) => void'.
  • L655:10: Argument of type '(response?: WorkflowExecutionAPIResponse) => WorkflowExecution' is not assignable to parameter of type '(value: unknown) => WorkflowExecution | PromiseLike'.
  • L685:4: Element implicitly has an 'any' type because expression of type 'string' can't be used to index type 'ISearchAttributes'.
  • L761:37: Argument of type 'SearchAttributeInput[]' is not assignable to parameter of type '{ type: "Unspecified" | "Keyword" | "Text" | "Int" | "Double" | "Bool" | "KeywordList" | "Datetime"; label: string; value?: any; }[]'.
  • L824:8: Type 'ErrorCallback' is not assignable to type '(error: unknown, toasts?: Toaster, errors?: Writable<NetworkError | null>, isBrowser?: boolean) => void'.
  • L844:8: 'workflow' is possibly 'undefined'.
  • L845:54: 'workflow' is possibly 'undefined'.
  • L852:8: 'workflow' is possibly 'undefined'.
  • L853:54: 'workflow' is possibly 'undefined'.
  • L859:28: Element implicitly has an 'any' type because expression of type '0' can't be used to index type '{}'.
  • L864:8: Element implicitly has an 'any' type because expression of type '0' can't be used to index type '{}'.
  • L866:10: Element implicitly has an 'any' type because expression of type '0' can't be used to index type '{}'.
  • L869:8: Element implicitly has an 'any' type because expression of type '0' can't be used to index type '{}'.
  • L1016:20: Argument of type 'WorkflowExecution | undefined' is not assignable to parameter of type 'WorkflowExecution'.
  • L1055:28: Argument of type 'string | undefined' is not assignable to parameter of type 'string'.
  • L1083:10: Property 'executions' does not exist on type 'WithoutNextPageToken'.
  • L1083:41: Argument of type '(token: string) => Promise' is not assignable to parameter of type '(token?: NextPageToken | undefined) => Promise'.
  • L1127:6: Type 'ErrorCallback' is not assignable to type '(error: unknown, toasts?: Toaster, errors?: Writable<NetworkError | null>, isBrowser?: boolean) => void'.
  • L1156:6: Type 'ErrorCallback' is not assignable to type '(error: unknown, toasts?: Toaster, errors?: Writable<NetworkError | null>, isBrowser?: boolean) => void'.
src/lib/utilities/decode-local-activity.ts (2)
  • L47:6: Argument of type 'WorkflowEvent | EventAttribute | IMemo | PotentiallyDecodable' is not assignable to parameter of type 'Optional<WorkflowEvent | EventAttribute | PotentiallyDecodable>'.
  • L52:41: Argument of type 'Payload | undefined' is not assignable to parameter of type 'Payload'.
src/lib/utilities/export-history.ts (3)
  • L20:34: Argument of type 'WorkflowEvent | EventAttribute | IMemo | PotentiallyDecodable' is not assignable to parameter of type 'Optional<WorkflowEvent | EventAttribute | PotentiallyDecodable>'.
  • L31:50: Argument of type 'null' is not assignable to parameter of type '((key: string, value: { events: HistoryEvent[]; }) => { events: HistoryEvent[]; }) | undefined'.
  • L66:15: Argument of type 'Replace<Optional<WorkflowEvent | EventAttribute | PotentiallyDecodable>, Optional<WorkflowEvent | EventAttribute | PotentiallyDecodable>>[]' is not assignable to parameter of type 'HistoryEvent[]'.
src/lib/utilities/get-activity-status-and-count.ts (2)
  • L43:15: Property 'groupValues' does not exist on type 'never'.
  • L45:35: Property 'count' does not exist on type 'never'.
src/lib/utilities/get-group-status-and-count.ts (2)
  • L9:15: Property 'groupValues' does not exist on type 'never'.
  • L11:35: Property 'count' does not exist on type 'never'.
src/routes/(app)/nexus/[id]/+layout.ts (1)
  • L24:4: 'endpoint.spec' is possibly 'undefined'.
src/lib/components/event/payload-decoder.svelte (5)
  • L21:26: Element implicitly has an 'any' type because expression of type 'string' can't be used to index type 'WorkflowEvent | IUserMetadata | IWorkflowExecutionStartedEventAttributes | IWorkflowExecutionCompletedEventAttributes | ... 59 more ... | Record<...>'.
  • L21:41: Element implicitly has an 'any' type because expression of type 'string' can't be used to index type 'WorkflowEvent | IUserMetadata | IWorkflowExecutionStartedEventAttributes | IWorkflowExecutionCompletedEventAttributes | ... 59 more ... | Record<...>'.
  • L34:8: Argument of type 'WorkflowEvent | EventAttribute | IMemo | PotentiallyDecodable' is not assignable to parameter of type 'Optional<WorkflowEvent | EventAttribute | PotentiallyDecodable>'.
  • L36:31: Element implicitly has an 'any' type because expression of type 'string' can't be used to index type '{}'.
  • L37:35: Element implicitly has an 'any' type because expression of type 'string' can't be used to index type '{}'.
src/lib/components/event/metadata-decoder.svelte (1)
  • L7:13: Type 'undefined' is not assignable to type '(decodedValue: string) => void | undefined'.
src/lib/components/event/event-summary-row.svelte (5)
  • L130:6: Argument of type 'string | undefined' is not assignable to parameter of type 'string'.
  • L167:23: Parameter 'event' implicitly has an 'any' type.
  • L179:30: Parameter 'group' implicitly has an 'any' type.
  • L179:37: Parameter 'hoveredEventId' implicitly has an 'any' type.
  • L304:16: Type 'ITimestamp | null | undefined' is not assignable to type 'ITimestamp'.
src/lib/components/lines-and-dots/svg/timeline-graph-row.svelte (7)
  • L95:20: 'distance' is possibly 'null'.
  • L95:31: 'workflowDistance' is possibly 'null'.
  • L106:20: 'distance' is possibly 'null'.
  • L106:31: 'workflowDistance' is possibly 'null'.
  • L146:29: 'activityTaskScheduled.attributes.attempt' is possibly 'null' or 'undefined'.
  • L239:12: 'pendingActivity.attempt' is possibly 'null' or 'undefined'.
  • L282:13: 'activityTaskScheduled' is possibly 'undefined'.
src/lib/components/schedule/schedules-table-row.svelte (5)
  • L45:6: Type 'string | null | undefined' is not assignable to type 'string'.
  • L68:33: Argument of type 'IScheduleActionResult[] | null | undefined' is not assignable to parameter of type 'IScheduleActionResult[]'.
  • L73:16: Type 'string | null | undefined' is not assignable to type 'string'.
  • L74:16: Type 'string | null | undefined' is not assignable to type 'string'.
  • L90:28: Type 'IScheduleSpec | null | undefined' is not assignable to type 'IScheduleSpec'.
src/lib/layouts/workflow-run-layout.svelte (7)
  • L97:39: Type 'string | undefined' is not assignable to type 'string'.
  • L146:6: Type 'WorkflowExecution | undefined' is not assignable to type 'WorkflowExecution | null'.
  • L160:4: Type 'undefined' is not assignable to type 'NetworkError | null'.
  • L163:18: No overload matches this call.
  • L172:28: Parameter 'fullHistory' implicitly has an 'any' type.
  • L172:41: Parameter 'pause' implicitly has an 'any' type.
  • L204:35: Argument of type 'null' is not assignable to parameter of type '((key: string, value: { eventHistory: WorkflowEvents; workflow: WorkflowExecution | null; workers: IDescribeTaskQueueResponse; workersLoaded: boolean; metadata: WorkflowMetadata | null; userMetadata: { ...; }; }) => { ...; }) | undefined'.
src/lib/pages/standalone-activity-metadata.svelte (1)
  • L34:23: Argument of type 'IUserMetadata | undefined' is not assignable to parameter of type 'IUserMetadata'.
src/lib/pages/workflow-call-stack.svelte (3)
  • L27:6: Type 'WorkflowExecution | null' is not assignable to type 'Eventual<{ id: string; runId: string; }>'.
  • L39:30: 'workers.pollers.length' is possibly 'undefined'.
  • L93:12: Type 'string | undefined' is not assignable to type 'string | number'.
src/lib/pages/workflow-query.svelte (9)
  • L49:5: Type 'string | undefined' is not assignable to type 'string'.
  • L58:32: 'a.name' is possibly 'undefined'.
  • L59:32: 'b.name' is possibly 'undefined'.
  • L64:13: 'a.name' is possibly 'undefined'.
  • L64:34: No overload matches this call.
  • L96:6: Type 'Promise | Promise<IPayload[]>' is not assignable to type 'Promise'.
  • L113:6: Type '{ payloads: IPayloads; } | null' is not assignable to type 'IPayloads | undefined'.
  • L155:12: Type '"retry" | null' is not assignable to type '"action" | "activity" | "add-square" | "add" | "apple" | "archives" | "arrow-down" | "arrow-left" | "arrow-up" | "arrow-right" | "ascending" | "astronaut" | "batch-operation" | ... 138 more ... | undefined'.
  • L183:12: Type 'false | "opacity-50"' is not assignable to type 'string | undefined'.

Generated by 🚫 dangerJS against 88cae1e

…coder cascade

data-encoder.ts now reads settings and namespace directly from page state
instead of accepting them as parameters. This removes the need to thread
settings through every call site in the chain: components → services →
decode-payload → data-encoder.

- codeServerRequest/decodePayloadsWithCodec/encodePayloadsWithCodec drop settings+namespace params
- decodeEventAttributes/decodeEventAttributesForExport drop settings param
- getEventAttributes takes HistoryEvent directly instead of EventWithMetadata
- EventRequestMetadata.settings field removed
- pending-activities model deleted (settings removal collapsed it to a no-op wrapper)
- All tests updated to set codecEndpoint/passAccessToken/includeCredentials stores directly
settings,
);
const convertedAttributes = await decodeEventAttributes(_value);
const decodedAttributes = decodePayloadAttributes(

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 'WorkflowEvent | EventAttribute | IMemo | PotentiallyDecodable' is not assignable to parameter of type 'Optional<WorkflowEvent | EventAttribute | PotentiallyDecodable>'.

const convertedAttributes = await decodeEventAttributes(_value);
const decodedAttributes = decodePayloadAttributes(
convertedAttributes,
) as object;

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.

  • ⚠️ Element implicitly has an 'any' type because expression of type 'string' can't be used to index type '{}'.

settings,
});
const convertedAttributes = await convertWithCodec(attributes);

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 'WorkflowEvent | EventAttribute | IMemo | PotentiallyDecodable' is not assignable to parameter of type 'Optional<WorkflowEvent | EventAttribute | PotentiallyDecodable>'.

false,
)) as PotentiallyDecodable;

let summary = '';

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.

  • ⚠️ 'workflow' is possibly 'undefined'.

}
}

let details = '';

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.

  • ⚠️ 'workflow' is possibly 'undefined'.

decodeSetting,
returnDataOnly,
);

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 'WorkflowEvent | EventAttribute | IMemo | PotentiallyDecodable' is not assignable to parameter of type 'Optional<WorkflowEvent | EventAttribute | PotentiallyDecodable>'.

);
const decodedEvent = await decodePayloads(event, decodeSetting);
decodedEvents.push(decodedEvent);
}

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 'Replace<Optional<WorkflowEvent | EventAttribute | PotentiallyDecodable>, Optional<WorkflowEvent | EventAttribute | PotentiallyDecodable>>[]' is not assignable to parameter of type 'HistoryEvent[]'.

const decodedAttributes = parsePayloadAttributes(
convertedAttributes,
) as object;
const keyExists = key && decodedAttributes?.[key];

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.

  • ⚠️ Element implicitly has an 'any' type because expression of type 'string' can't be used to index type '{}'.

await decodeUserMetadata(workflow);
await decodeWorkflowUserMetadata(workflow);

const { taskQueue } = workflow;

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 'string | undefined' is not assignable to type 'string'.

if (!payloads?.length) return undefined;

const decodedAttributes = decodePayloadAttributes(
const decodedAttributes = parsePayloadAttributes(

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 'WorkflowEvent | EventAttribute | IMemo | PotentiallyDecodable' is not assignable to parameter of type 'Optional<WorkflowEvent | EventAttribute | PotentiallyDecodable>'.

},
page.data?.settings,
);
getWorkflowStackTrace({

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 'WorkflowExecution | null' is not assignable to type 'Eventual<{ id: string; runId: string; }>'.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Would be nice to clear out this strict error but who knows probably it's fine.

queryResult = getQuery({
namespace,
workflow: params,
queryType,

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 '{ payloads: IPayloads; } | null' is not assignable to type 'IPayloads | undefined'.

@@ -76,7 +78,7 @@ export function decodePayload(
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]: string; } | undefined' is not assignable to parameter of type 'Record<string, unknown>'.

@@ -89,7 +91,7 @@ export function decodePayload(
const encoding = atob(String(payload?.metadata?.encoding ?? ''));
if (encoding === 'binary/null') {
if (returnDataOnly) 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.

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

'indexedFields',
)
? eventAttribute.searchAttributes.indexedFields
: eventAttribute.searchAttributes;

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.

  • ⚠️ No overload matches this call.

)
? eventAttribute.searchAttributes.indexedFields
: eventAttribute.searchAttributes;
Object.entries(searchAttributes).forEach(([key, value]) => {

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.

  • ⚠️ 'searchAttributes' is of type 'unknown'.
  • ⚠️ Argument of type 'unknown' is not assignable to parameter of type 'Payload'.

@@ -131,7 +135,7 @@ export const decodePayloadAttributes = <
const memo = eventAttribute.memo.fields;

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.

  • ⚠️ No overload matches this call.

@@ -150,132 +154,114 @@ export const decodePayloadAttributes = <
const queryResult = eventAttribute?.queryResult;

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.

  • ⚠️ No overload matches this call.

@@ -150,132 +154,114 @@ export const decodePayloadAttributes = <
const queryResult = eventAttribute?.queryResult;

Object.entries(queryResult).forEach(([key, value]) => {

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.

  • ⚠️ 'queryResult' is of type 'unknown'.
  • ⚠️ Argument of type 'unknown' is not assignable to parameter of type 'Payload'.

returnDataOnly: boolean = true,
): Promise<unknown[]> => {
const awaitData = await callCodecEndpoint({ payloads: { payloads } });
return (awaitData?.payloads ?? []).map((p) =>

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 'unknown' is not assignable to parameter of type 'Payload'.

@@ -289,10 +275,8 @@ export const cloneAllPotentialPayloadsWithCodec = async (
} 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.

  • ⚠️ Element implicitly has an 'any' type because expression of type 'string' can't be used to index type '{ id: string; attributes: EventAttribute; timestamp: string; classification: "Scheduled" | "Unspecified" | "Open" | "New" | "Started" | "Initiated" | "Running" | ... 7 more ... | "CancelRequested"; ... 70 more ...; eventId: string; } | ... 62 more ... | { ...; }'.

@@ -289,10 +275,8 @@ export const cloneAllPotentialPayloadsWithCodec = async (
} else {
const next = clone[key];
if (isObject(next)) {

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.

  • ⚠️ Element implicitly has an 'any' type because expression of type 'string' can't be used to index type '{ id: string; attributes: EventAttribute; timestamp: string; classification: "Scheduled" | "Unspecified" | "Open" | "New" | "Started" | "Initiated" | "Running" | ... 7 more ... | "CancelRequested"; ... 70 more ...; eventId: string; } | ... 62 more ... | { ...; }'.

@rossedfort
rossedfort marked this pull request as ready for review April 15, 2026 20:33
@rossedfort
rossedfort requested a review from a team as a code owner April 15, 2026 20:33
includeCredentials,
},
};

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

🚀

signal?: AbortSignal,
): Promise<ParsedQuery> {
return getQuery({ ...options, queryType: '__stack_trace' }, settings);
return getQuery({ ...options, queryType: '__stack_trace' }, signal);

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

👀 Signal lookin gooooood

namespace,
codecSettings,
);
const convertedAttributes = await decodeEventAttributes(event.attributes);

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

❤️

firstWorkflowTaskBackoff: '0s',
memo: null,
searchAttributes: { indexedFields: { CandidateEmail: 'whadup@lolcats.com' } },
searchAttributes: { indexedFields: { CandidateEmail: 'test@test.com' } },

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

0/10 the old email was much more better probably this will make the test suite less reliable

* Sends `payloads` through the remote codec server, then Base64-decodes each
* result with {@link parseRawPayloadToJSON}.
*/
const decodePayloadsWithRemoteCodecAndParseRawPayloadToJSON = async (

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Love this name

@rossedfort
rossedfort merged commit 256cd27 into main Apr 16, 2026
43 checks passed
@rossedfort
rossedfort deleted the refactor-decode-payload-utils branch April 16, 2026 17:38
rossnelson added a commit that referenced this pull request Apr 20, 2026
Auto-generated version bump from 2.48.3 to 2.48.4

Specific version: 2.48.4

Changes included:
- [`7cf1be53`](7cf1be5) Adjust breadcrumb spacing and min-height (#3304)
- [`c9834815`](c983481) Add missing Nexus Operation events to event groups (#3309)
- [`5c7aa86c`](5c7aa86) feat: add onItemsChange callback to PaginatedTable (#3300)
- [`66d3cf68`](66d3cf6) Update pre-release badge to secondary in Workers (#3310)
- [`393e84de`](393e84d) Keep Pending Activities/Operations at the top of Timeline and Compact view (#3307)
- [`9f721347`](9f72134) Update error link in codec-server-error-banner (#3313)
- [`e698bda3`](e698bda) Add class prop to BottomNav component (#3314)
- [`55767fc9`](55767fc) Add overrides (#3317)
- [`256cd274`](256cd27) refactor(decode-payload): clean up decode-payload.ts API surface (#3302)
- [`04f8c251`](04f8c25) Make input height full so its easier to click into the input (#3318)
- [`b2231056`](b223105) Workflows Table Row Density (#3285)
- [`0b2ce4fd`](0b2ce4f) PR Review Notifications (#3322)
- [`84618196`](8461819) feat: serverless worker deployment CRUD (#3236)

Co-authored-by: rossnelson <[email protected]>
rossedfort added a commit that referenced this pull request Apr 20, 2026
… components

Replace the 14-prop multi-mode payload.svelte with four single-purpose
components: PayloadCodeBlock, PayloadSummary, PayloadDecoder, and
PayloadInline. Each component carries only the props relevant to its
render mode, eliminating dead props at call sites.

Also updates the decode paths to use the renamed decode-payload.ts API
(decodeEventAttributes, parsePayloadAttributes) following the #3302
cleanup.
rossedfort added a commit that referenced this pull request May 14, 2026
…load component (#3299)

* refactor: replace PayloadDecoder and MetadataDecoder with unified Payload component

Consolidates two divergent payload display components into a single
`<Payload />` component at `src/lib/components/payload.svelte`.

Previously, `payload-decoder.svelte` (Svelte 5 runes, required a
`children` snippet, always decoded full attribute trees) and
`metadata-decoder.svelte` (Svelte 4 options API with slot syntax,
decoded single payloads to truncated summary strings) served different
display purposes but used inconsistent APIs and decoding paths across
65+ call sites.

The new component unifies both under a single `mode` prop:
- `code-block` (default): renders a CodeBlock with the decoded value,
  replacing all PayloadDecoder + CodeBlock snippet patterns
- `summary`: truncates to 120 chars and renders a Badge, replacing all
  MetadataDecoder usages
- `inline-truncated`: renders the compact .payload pre block used in
  event detail rows
- `children` snippet: escape hatch for callers that need custom
  rendering (schedule input, timeline SVG text elements)

Both old components used a single decoding path internally
(cloneAllPotentialPayloadsWithCodec -> decodePayloadAttributes ->
stringifyWithBigInt). MetadataDecoder previously used a separate
decodeSingleReadablePayloadWithCodec path; the new component uses the
same unified path for consistency.

The component is written in Svelte 5 runes throughout and imports from
$app/state instead of $app/stores, matching the newer direction of the
codebase.

Migrated files:
- src/lib/components/event/event-card.svelte
- src/lib/components/event/event-details-row.svelte (+ moved .payload CSS)
- src/lib/components/event/event-metadata-expanded.svelte
- src/lib/components/event/event-summary-row.svelte
- src/lib/components/lines-and-dots/svg/group-details-text.svelte
- src/lib/components/lines-and-dots/svg/timeline-graph-row.svelte
- src/lib/components/schedule/schedule-form/schedule-input-payload.svelte
- src/lib/components/standalone-activities/activity-input-and-outcome.svelte
- src/lib/components/workflow/client-actions/update-confirmation-modal.svelte
- src/lib/components/workflow/input-and-results-payload.svelte
- src/lib/components/workflow/metadata/metadata-events.svelte
- src/lib/components/workflow/pending-activity/pending-activity-card.svelte
- src/lib/components/workflow/workflow-json-navigator.svelte
- src/lib/pages/standalone-activity-details.svelte
- src/lib/pages/standalone-activity-search-attributes.svelte
- src/lib/pages/workflow-memo.svelte
- src/lib/pages/workflow-metadata.svelte
- src/lib/pages/workflow-search-attributes.svelte

All 1730 tests pass.

* remove unused component, fix css

* refactor: move Payload component into payload/ directory

Moves payload.svelte into src/lib/components/payload/ and adds a
USAGE.md report documenting all 31 call sites grouped by feature area.
Updates all 17 import paths accordingly.

* docs: add Payload component improvement suggestions

* docs: add decode-payload usage report and refactoring recommendations

* refactor(payload): split Payload component into focused mode-specific components

Replace the 14-prop multi-mode payload.svelte with four single-purpose
components: PayloadCodeBlock, PayloadSummary, PayloadDecoder, and
PayloadInline. Each component carries only the props relevant to its
render mode, eliminating dead props at call sites.

Also updates the decode paths to use the renamed decode-payload.ts API
(decodeEventAttributes, parsePayloadAttributes) following the #3302
cleanup.

* fix(payload-summary): use decodeUserMetadata and add onDecode prop

Replace decodeEventAttributes with decodeUserMetadata — the correct
decode path for a single raw Payload (Phase 2 codec only, no attribute
tree walking). Also add onDecode callback prop, called after a
successful decode, consistent with PayloadCodeBlock.

* refactor(payload): extract shared decode logic into decode-payload-value utility

Remove 3-way duplication of getInitialValue/onMount decode logic from
payload-code-block, payload-decoder, and payload-inline by extracting
getInitialPayloadValue and decodePayloadValue into
src/lib/utilities/decode-payload-value.ts.

* fix(payload): replace onMount with \$effect for reactive value updates

Components now re-decode when value or fieldName props change after
mount, fixing the reactivity gap that caused stale decoded content
when parent components updated their payload bindings.

* add workflow with user metadata

* remove unnecessary props from payload code block

* fix summary display

* add improvements

* fix heading levels

* add multi input workflow

* get rid of fieldName prop and fix most of the call sites

* fix remaining type errors

* fix tests

* rm inspect

* rm console.log

* fix CR feedback

* remove bad key

* fix export

* remove unused type

* cleanup unused stuff

* fix possibly duplicate key

* add language prop to PayloadCodeBlock

* add copyIconTitle and copySuccessIconTitle to codeblock instance

* refactor(payload): fix reactivity and race condition in payload-summary

Replace $effect+$state async pattern with $derived promise + $effect
cleanup to ensure all reactive deps (value, fallback, prefix,
maxSummaryLength) are tracked synchronously. Use $effect cleanup function
to cancel stale promise callbacks on re-run, preventing race conditions
when value changes rapidly. Remove unused onDecode prop.

* early return if no payloads in decode utils
rossedfort added a commit that referenced this pull request May 15, 2026
* refactor: replace PayloadDecoder and MetadataDecoder with unified Payload component

Consolidates two divergent payload display components into a single
`<Payload />` component at `src/lib/components/payload.svelte`.

Previously, `payload-decoder.svelte` (Svelte 5 runes, required a
`children` snippet, always decoded full attribute trees) and
`metadata-decoder.svelte` (Svelte 4 options API with slot syntax,
decoded single payloads to truncated summary strings) served different
display purposes but used inconsistent APIs and decoding paths across
65+ call sites.

The new component unifies both under a single `mode` prop:
- `code-block` (default): renders a CodeBlock with the decoded value,
  replacing all PayloadDecoder + CodeBlock snippet patterns
- `summary`: truncates to 120 chars and renders a Badge, replacing all
  MetadataDecoder usages
- `inline-truncated`: renders the compact .payload pre block used in
  event detail rows
- `children` snippet: escape hatch for callers that need custom
  rendering (schedule input, timeline SVG text elements)

Both old components used a single decoding path internally
(cloneAllPotentialPayloadsWithCodec -> decodePayloadAttributes ->
stringifyWithBigInt). MetadataDecoder previously used a separate
decodeSingleReadablePayloadWithCodec path; the new component uses the
same unified path for consistency.

The component is written in Svelte 5 runes throughout and imports from
$app/state instead of $app/stores, matching the newer direction of the
codebase.

Migrated files:
- src/lib/components/event/event-card.svelte
- src/lib/components/event/event-details-row.svelte (+ moved .payload CSS)
- src/lib/components/event/event-metadata-expanded.svelte
- src/lib/components/event/event-summary-row.svelte
- src/lib/components/lines-and-dots/svg/group-details-text.svelte
- src/lib/components/lines-and-dots/svg/timeline-graph-row.svelte
- src/lib/components/schedule/schedule-form/schedule-input-payload.svelte
- src/lib/components/standalone-activities/activity-input-and-outcome.svelte
- src/lib/components/workflow/client-actions/update-confirmation-modal.svelte
- src/lib/components/workflow/input-and-results-payload.svelte
- src/lib/components/workflow/metadata/metadata-events.svelte
- src/lib/components/workflow/pending-activity/pending-activity-card.svelte
- src/lib/components/workflow/workflow-json-navigator.svelte
- src/lib/pages/standalone-activity-details.svelte
- src/lib/pages/standalone-activity-search-attributes.svelte
- src/lib/pages/workflow-memo.svelte
- src/lib/pages/workflow-metadata.svelte
- src/lib/pages/workflow-search-attributes.svelte

All 1730 tests pass.

* remove unused component, fix css

* refactor: move Payload component into payload/ directory

Moves payload.svelte into src/lib/components/payload/ and adds a
USAGE.md report documenting all 31 call sites grouped by feature area.
Updates all 17 import paths accordingly.

* docs: add Payload component improvement suggestions

* docs: add decode-payload usage report and refactoring recommendations

* refactor(payload): split Payload component into focused mode-specific components

Replace the 14-prop multi-mode payload.svelte with four single-purpose
components: PayloadCodeBlock, PayloadSummary, PayloadDecoder, and
PayloadInline. Each component carries only the props relevant to its
render mode, eliminating dead props at call sites.

Also updates the decode paths to use the renamed decode-payload.ts API
(decodeEventAttributes, parsePayloadAttributes) following the #3302
cleanup.

* fix(payload-summary): use decodeUserMetadata and add onDecode prop

Replace decodeEventAttributes with decodeUserMetadata — the correct
decode path for a single raw Payload (Phase 2 codec only, no attribute
tree walking). Also add onDecode callback prop, called after a
successful decode, consistent with PayloadCodeBlock.

* refactor(payload): extract shared decode logic into decode-payload-value utility

Remove 3-way duplication of getInitialValue/onMount decode logic from
payload-code-block, payload-decoder, and payload-inline by extracting
getInitialPayloadValue and decodePayloadValue into
src/lib/utilities/decode-payload-value.ts.

* fix(payload): replace onMount with \$effect for reactive value updates

Components now re-decode when value or fieldName props change after
mount, fixing the reactivity gap that caused stale decoded content
when parent components updated their payload bindings.

* add workflow with user metadata

* remove unnecessary props from payload code block

* fix summary display

* add improvements

* fix heading levels

* add multi input workflow

* get rid of fieldName prop and fix most of the call sites

* fix remaining type errors

* fix tests

* rm inspect

* rm console.log

* WIP - download external payloads

* add support for downloading externally stored payloads

* add some error handling to downloads

* add support for filename

* fix CR feedback

* remove bad key

* fix export

* remove unused type

* cleanup unused stuff

* fix possibly duplicate key

* add language prop to PayloadCodeBlock

* add copyIconTitle and copySuccessIconTitle to codeblock instance

* refactor(payload): fix reactivity and race condition in payload-summary

Replace $effect+$state async pattern with $derived promise + $effect
cleanup to ensure all reactive deps (value, fallback, prefix,
maxSummaryLength) are tracked synchronously. Use $effect cleanup function
to cancel stale promise callbacks on re-run, preventing race conditions
when value changes rapidly. Remove unused onDecode prop.

* early return if no payloads in decode utils

* add type guards

* support inline external payloads

* fix download error and payload codeblock types

* fix schedule input

* rm console.log

* fix tests and strict mode

* fix spec

* fix typo

* add some optional chaining
tegan-temporal pushed a commit that referenced this pull request May 18, 2026
…load component (#3299)

* refactor: replace PayloadDecoder and MetadataDecoder with unified Payload component

Consolidates two divergent payload display components into a single
`<Payload />` component at `src/lib/components/payload.svelte`.

Previously, `payload-decoder.svelte` (Svelte 5 runes, required a
`children` snippet, always decoded full attribute trees) and
`metadata-decoder.svelte` (Svelte 4 options API with slot syntax,
decoded single payloads to truncated summary strings) served different
display purposes but used inconsistent APIs and decoding paths across
65+ call sites.

The new component unifies both under a single `mode` prop:
- `code-block` (default): renders a CodeBlock with the decoded value,
  replacing all PayloadDecoder + CodeBlock snippet patterns
- `summary`: truncates to 120 chars and renders a Badge, replacing all
  MetadataDecoder usages
- `inline-truncated`: renders the compact .payload pre block used in
  event detail rows
- `children` snippet: escape hatch for callers that need custom
  rendering (schedule input, timeline SVG text elements)

Both old components used a single decoding path internally
(cloneAllPotentialPayloadsWithCodec -> decodePayloadAttributes ->
stringifyWithBigInt). MetadataDecoder previously used a separate
decodeSingleReadablePayloadWithCodec path; the new component uses the
same unified path for consistency.

The component is written in Svelte 5 runes throughout and imports from
$app/state instead of $app/stores, matching the newer direction of the
codebase.

Migrated files:
- src/lib/components/event/event-card.svelte
- src/lib/components/event/event-details-row.svelte (+ moved .payload CSS)
- src/lib/components/event/event-metadata-expanded.svelte
- src/lib/components/event/event-summary-row.svelte
- src/lib/components/lines-and-dots/svg/group-details-text.svelte
- src/lib/components/lines-and-dots/svg/timeline-graph-row.svelte
- src/lib/components/schedule/schedule-form/schedule-input-payload.svelte
- src/lib/components/standalone-activities/activity-input-and-outcome.svelte
- src/lib/components/workflow/client-actions/update-confirmation-modal.svelte
- src/lib/components/workflow/input-and-results-payload.svelte
- src/lib/components/workflow/metadata/metadata-events.svelte
- src/lib/components/workflow/pending-activity/pending-activity-card.svelte
- src/lib/components/workflow/workflow-json-navigator.svelte
- src/lib/pages/standalone-activity-details.svelte
- src/lib/pages/standalone-activity-search-attributes.svelte
- src/lib/pages/workflow-memo.svelte
- src/lib/pages/workflow-metadata.svelte
- src/lib/pages/workflow-search-attributes.svelte

All 1730 tests pass.

* remove unused component, fix css

* refactor: move Payload component into payload/ directory

Moves payload.svelte into src/lib/components/payload/ and adds a
USAGE.md report documenting all 31 call sites grouped by feature area.
Updates all 17 import paths accordingly.

* docs: add Payload component improvement suggestions

* docs: add decode-payload usage report and refactoring recommendations

* refactor(payload): split Payload component into focused mode-specific components

Replace the 14-prop multi-mode payload.svelte with four single-purpose
components: PayloadCodeBlock, PayloadSummary, PayloadDecoder, and
PayloadInline. Each component carries only the props relevant to its
render mode, eliminating dead props at call sites.

Also updates the decode paths to use the renamed decode-payload.ts API
(decodeEventAttributes, parsePayloadAttributes) following the #3302
cleanup.

* fix(payload-summary): use decodeUserMetadata and add onDecode prop

Replace decodeEventAttributes with decodeUserMetadata — the correct
decode path for a single raw Payload (Phase 2 codec only, no attribute
tree walking). Also add onDecode callback prop, called after a
successful decode, consistent with PayloadCodeBlock.

* refactor(payload): extract shared decode logic into decode-payload-value utility

Remove 3-way duplication of getInitialValue/onMount decode logic from
payload-code-block, payload-decoder, and payload-inline by extracting
getInitialPayloadValue and decodePayloadValue into
src/lib/utilities/decode-payload-value.ts.

* fix(payload): replace onMount with \$effect for reactive value updates

Components now re-decode when value or fieldName props change after
mount, fixing the reactivity gap that caused stale decoded content
when parent components updated their payload bindings.

* add workflow with user metadata

* remove unnecessary props from payload code block

* fix summary display

* add improvements

* fix heading levels

* add multi input workflow

* get rid of fieldName prop and fix most of the call sites

* fix remaining type errors

* fix tests

* rm inspect

* rm console.log

* fix CR feedback

* remove bad key

* fix export

* remove unused type

* cleanup unused stuff

* fix possibly duplicate key

* add language prop to PayloadCodeBlock

* add copyIconTitle and copySuccessIconTitle to codeblock instance

* refactor(payload): fix reactivity and race condition in payload-summary

Replace $effect+$state async pattern with $derived promise + $effect
cleanup to ensure all reactive deps (value, fallback, prefix,
maxSummaryLength) are tracked synchronously. Use $effect cleanup function
to cancel stale promise callbacks on re-run, preventing race conditions
when value changes rapidly. Remove unused onDecode prop.

* early return if no payloads in decode utils
tegan-temporal pushed a commit that referenced this pull request May 18, 2026
* refactor: replace PayloadDecoder and MetadataDecoder with unified Payload component

Consolidates two divergent payload display components into a single
`<Payload />` component at `src/lib/components/payload.svelte`.

Previously, `payload-decoder.svelte` (Svelte 5 runes, required a
`children` snippet, always decoded full attribute trees) and
`metadata-decoder.svelte` (Svelte 4 options API with slot syntax,
decoded single payloads to truncated summary strings) served different
display purposes but used inconsistent APIs and decoding paths across
65+ call sites.

The new component unifies both under a single `mode` prop:
- `code-block` (default): renders a CodeBlock with the decoded value,
  replacing all PayloadDecoder + CodeBlock snippet patterns
- `summary`: truncates to 120 chars and renders a Badge, replacing all
  MetadataDecoder usages
- `inline-truncated`: renders the compact .payload pre block used in
  event detail rows
- `children` snippet: escape hatch for callers that need custom
  rendering (schedule input, timeline SVG text elements)

Both old components used a single decoding path internally
(cloneAllPotentialPayloadsWithCodec -> decodePayloadAttributes ->
stringifyWithBigInt). MetadataDecoder previously used a separate
decodeSingleReadablePayloadWithCodec path; the new component uses the
same unified path for consistency.

The component is written in Svelte 5 runes throughout and imports from
$app/state instead of $app/stores, matching the newer direction of the
codebase.

Migrated files:
- src/lib/components/event/event-card.svelte
- src/lib/components/event/event-details-row.svelte (+ moved .payload CSS)
- src/lib/components/event/event-metadata-expanded.svelte
- src/lib/components/event/event-summary-row.svelte
- src/lib/components/lines-and-dots/svg/group-details-text.svelte
- src/lib/components/lines-and-dots/svg/timeline-graph-row.svelte
- src/lib/components/schedule/schedule-form/schedule-input-payload.svelte
- src/lib/components/standalone-activities/activity-input-and-outcome.svelte
- src/lib/components/workflow/client-actions/update-confirmation-modal.svelte
- src/lib/components/workflow/input-and-results-payload.svelte
- src/lib/components/workflow/metadata/metadata-events.svelte
- src/lib/components/workflow/pending-activity/pending-activity-card.svelte
- src/lib/components/workflow/workflow-json-navigator.svelte
- src/lib/pages/standalone-activity-details.svelte
- src/lib/pages/standalone-activity-search-attributes.svelte
- src/lib/pages/workflow-memo.svelte
- src/lib/pages/workflow-metadata.svelte
- src/lib/pages/workflow-search-attributes.svelte

All 1730 tests pass.

* remove unused component, fix css

* refactor: move Payload component into payload/ directory

Moves payload.svelte into src/lib/components/payload/ and adds a
USAGE.md report documenting all 31 call sites grouped by feature area.
Updates all 17 import paths accordingly.

* docs: add Payload component improvement suggestions

* docs: add decode-payload usage report and refactoring recommendations

* refactor(payload): split Payload component into focused mode-specific components

Replace the 14-prop multi-mode payload.svelte with four single-purpose
components: PayloadCodeBlock, PayloadSummary, PayloadDecoder, and
PayloadInline. Each component carries only the props relevant to its
render mode, eliminating dead props at call sites.

Also updates the decode paths to use the renamed decode-payload.ts API
(decodeEventAttributes, parsePayloadAttributes) following the #3302
cleanup.

* fix(payload-summary): use decodeUserMetadata and add onDecode prop

Replace decodeEventAttributes with decodeUserMetadata — the correct
decode path for a single raw Payload (Phase 2 codec only, no attribute
tree walking). Also add onDecode callback prop, called after a
successful decode, consistent with PayloadCodeBlock.

* refactor(payload): extract shared decode logic into decode-payload-value utility

Remove 3-way duplication of getInitialValue/onMount decode logic from
payload-code-block, payload-decoder, and payload-inline by extracting
getInitialPayloadValue and decodePayloadValue into
src/lib/utilities/decode-payload-value.ts.

* fix(payload): replace onMount with \$effect for reactive value updates

Components now re-decode when value or fieldName props change after
mount, fixing the reactivity gap that caused stale decoded content
when parent components updated their payload bindings.

* add workflow with user metadata

* remove unnecessary props from payload code block

* fix summary display

* add improvements

* fix heading levels

* add multi input workflow

* get rid of fieldName prop and fix most of the call sites

* fix remaining type errors

* fix tests

* rm inspect

* rm console.log

* WIP - download external payloads

* add support for downloading externally stored payloads

* add some error handling to downloads

* add support for filename

* fix CR feedback

* remove bad key

* fix export

* remove unused type

* cleanup unused stuff

* fix possibly duplicate key

* add language prop to PayloadCodeBlock

* add copyIconTitle and copySuccessIconTitle to codeblock instance

* refactor(payload): fix reactivity and race condition in payload-summary

Replace $effect+$state async pattern with $derived promise + $effect
cleanup to ensure all reactive deps (value, fallback, prefix,
maxSummaryLength) are tracked synchronously. Use $effect cleanup function
to cancel stale promise callbacks on re-run, preventing race conditions
when value changes rapidly. Remove unused onDecode prop.

* early return if no payloads in decode utils

* add type guards

* support inline external payloads

* fix download error and payload codeblock types

* fix schedule input

* rm console.log

* fix tests and strict mode

* fix spec

* fix typo

* add some optional chaining
tegan-temporal pushed a commit that referenced this pull request May 29, 2026
* refactor: replace PayloadDecoder and MetadataDecoder with unified Payload component

Consolidates two divergent payload display components into a single
`<Payload />` component at `src/lib/components/payload.svelte`.

Previously, `payload-decoder.svelte` (Svelte 5 runes, required a
`children` snippet, always decoded full attribute trees) and
`metadata-decoder.svelte` (Svelte 4 options API with slot syntax,
decoded single payloads to truncated summary strings) served different
display purposes but used inconsistent APIs and decoding paths across
65+ call sites.

The new component unifies both under a single `mode` prop:
- `code-block` (default): renders a CodeBlock with the decoded value,
  replacing all PayloadDecoder + CodeBlock snippet patterns
- `summary`: truncates to 120 chars and renders a Badge, replacing all
  MetadataDecoder usages
- `inline-truncated`: renders the compact .payload pre block used in
  event detail rows
- `children` snippet: escape hatch for callers that need custom
  rendering (schedule input, timeline SVG text elements)

Both old components used a single decoding path internally
(cloneAllPotentialPayloadsWithCodec -> decodePayloadAttributes ->
stringifyWithBigInt). MetadataDecoder previously used a separate
decodeSingleReadablePayloadWithCodec path; the new component uses the
same unified path for consistency.

The component is written in Svelte 5 runes throughout and imports from
$app/state instead of $app/stores, matching the newer direction of the
codebase.

Migrated files:
- src/lib/components/event/event-card.svelte
- src/lib/components/event/event-details-row.svelte (+ moved .payload CSS)
- src/lib/components/event/event-metadata-expanded.svelte
- src/lib/components/event/event-summary-row.svelte
- src/lib/components/lines-and-dots/svg/group-details-text.svelte
- src/lib/components/lines-and-dots/svg/timeline-graph-row.svelte
- src/lib/components/schedule/schedule-form/schedule-input-payload.svelte
- src/lib/components/standalone-activities/activity-input-and-outcome.svelte
- src/lib/components/workflow/client-actions/update-confirmation-modal.svelte
- src/lib/components/workflow/input-and-results-payload.svelte
- src/lib/components/workflow/metadata/metadata-events.svelte
- src/lib/components/workflow/pending-activity/pending-activity-card.svelte
- src/lib/components/workflow/workflow-json-navigator.svelte
- src/lib/pages/standalone-activity-details.svelte
- src/lib/pages/standalone-activity-search-attributes.svelte
- src/lib/pages/workflow-memo.svelte
- src/lib/pages/workflow-metadata.svelte
- src/lib/pages/workflow-search-attributes.svelte

All 1730 tests pass.

* remove unused component, fix css

* refactor: move Payload component into payload/ directory

Moves payload.svelte into src/lib/components/payload/ and adds a
USAGE.md report documenting all 31 call sites grouped by feature area.
Updates all 17 import paths accordingly.

* docs: add Payload component improvement suggestions

* docs: add decode-payload usage report and refactoring recommendations

* refactor(payload): split Payload component into focused mode-specific components

Replace the 14-prop multi-mode payload.svelte with four single-purpose
components: PayloadCodeBlock, PayloadSummary, PayloadDecoder, and
PayloadInline. Each component carries only the props relevant to its
render mode, eliminating dead props at call sites.

Also updates the decode paths to use the renamed decode-payload.ts API
(decodeEventAttributes, parsePayloadAttributes) following the #3302
cleanup.

* fix(payload-summary): use decodeUserMetadata and add onDecode prop

Replace decodeEventAttributes with decodeUserMetadata — the correct
decode path for a single raw Payload (Phase 2 codec only, no attribute
tree walking). Also add onDecode callback prop, called after a
successful decode, consistent with PayloadCodeBlock.

* refactor(payload): extract shared decode logic into decode-payload-value utility

Remove 3-way duplication of getInitialValue/onMount decode logic from
payload-code-block, payload-decoder, and payload-inline by extracting
getInitialPayloadValue and decodePayloadValue into
src/lib/utilities/decode-payload-value.ts.

* fix(payload): replace onMount with \$effect for reactive value updates

Components now re-decode when value or fieldName props change after
mount, fixing the reactivity gap that caused stale decoded content
when parent components updated their payload bindings.

* add workflow with user metadata

* remove unnecessary props from payload code block

* fix summary display

* add improvements

* fix heading levels

* add multi input workflow

* get rid of fieldName prop and fix most of the call sites

* fix remaining type errors

* fix tests

* rm inspect

* rm console.log

* WIP - download external payloads

* add support for downloading externally stored payloads

* add some error handling to downloads

* add support for filename

* fix CR feedback

* remove bad key

* fix export

* remove unused type

* cleanup unused stuff

* fix possibly duplicate key

* add language prop to PayloadCodeBlock

* add copyIconTitle and copySuccessIconTitle to codeblock instance

* refactor(payload): fix reactivity and race condition in payload-summary

Replace $effect+$state async pattern with $derived promise + $effect
cleanup to ensure all reactive deps (value, fallback, prefix,
maxSummaryLength) are tracked synchronously. Use $effect cleanup function
to cancel stale promise callbacks on re-run, preventing race conditions
when value changes rapidly. Remove unused onDecode prop.

* early return if no payloads in decode utils

* add type guards

* support inline external payloads

* fix download error and payload codeblock types

* fix schedule input

* rm console.log

* fix tests and strict mode

* fix spec

* fix typo

* add some optional chaining
tegan-temporal pushed a commit that referenced this pull request Jun 3, 2026
* refactor: replace PayloadDecoder and MetadataDecoder with unified Payload component

Consolidates two divergent payload display components into a single
`<Payload />` component at `src/lib/components/payload.svelte`.

Previously, `payload-decoder.svelte` (Svelte 5 runes, required a
`children` snippet, always decoded full attribute trees) and
`metadata-decoder.svelte` (Svelte 4 options API with slot syntax,
decoded single payloads to truncated summary strings) served different
display purposes but used inconsistent APIs and decoding paths across
65+ call sites.

The new component unifies both under a single `mode` prop:
- `code-block` (default): renders a CodeBlock with the decoded value,
  replacing all PayloadDecoder + CodeBlock snippet patterns
- `summary`: truncates to 120 chars and renders a Badge, replacing all
  MetadataDecoder usages
- `inline-truncated`: renders the compact .payload pre block used in
  event detail rows
- `children` snippet: escape hatch for callers that need custom
  rendering (schedule input, timeline SVG text elements)

Both old components used a single decoding path internally
(cloneAllPotentialPayloadsWithCodec -> decodePayloadAttributes ->
stringifyWithBigInt). MetadataDecoder previously used a separate
decodeSingleReadablePayloadWithCodec path; the new component uses the
same unified path for consistency.

The component is written in Svelte 5 runes throughout and imports from
$app/state instead of $app/stores, matching the newer direction of the
codebase.

Migrated files:
- src/lib/components/event/event-card.svelte
- src/lib/components/event/event-details-row.svelte (+ moved .payload CSS)
- src/lib/components/event/event-metadata-expanded.svelte
- src/lib/components/event/event-summary-row.svelte
- src/lib/components/lines-and-dots/svg/group-details-text.svelte
- src/lib/components/lines-and-dots/svg/timeline-graph-row.svelte
- src/lib/components/schedule/schedule-form/schedule-input-payload.svelte
- src/lib/components/standalone-activities/activity-input-and-outcome.svelte
- src/lib/components/workflow/client-actions/update-confirmation-modal.svelte
- src/lib/components/workflow/input-and-results-payload.svelte
- src/lib/components/workflow/metadata/metadata-events.svelte
- src/lib/components/workflow/pending-activity/pending-activity-card.svelte
- src/lib/components/workflow/workflow-json-navigator.svelte
- src/lib/pages/standalone-activity-details.svelte
- src/lib/pages/standalone-activity-search-attributes.svelte
- src/lib/pages/workflow-memo.svelte
- src/lib/pages/workflow-metadata.svelte
- src/lib/pages/workflow-search-attributes.svelte

All 1730 tests pass.

* remove unused component, fix css

* refactor: move Payload component into payload/ directory

Moves payload.svelte into src/lib/components/payload/ and adds a
USAGE.md report documenting all 31 call sites grouped by feature area.
Updates all 17 import paths accordingly.

* docs: add Payload component improvement suggestions

* docs: add decode-payload usage report and refactoring recommendations

* refactor(payload): split Payload component into focused mode-specific components

Replace the 14-prop multi-mode payload.svelte with four single-purpose
components: PayloadCodeBlock, PayloadSummary, PayloadDecoder, and
PayloadInline. Each component carries only the props relevant to its
render mode, eliminating dead props at call sites.

Also updates the decode paths to use the renamed decode-payload.ts API
(decodeEventAttributes, parsePayloadAttributes) following the #3302
cleanup.

* fix(payload-summary): use decodeUserMetadata and add onDecode prop

Replace decodeEventAttributes with decodeUserMetadata — the correct
decode path for a single raw Payload (Phase 2 codec only, no attribute
tree walking). Also add onDecode callback prop, called after a
successful decode, consistent with PayloadCodeBlock.

* refactor(payload): extract shared decode logic into decode-payload-value utility

Remove 3-way duplication of getInitialValue/onMount decode logic from
payload-code-block, payload-decoder, and payload-inline by extracting
getInitialPayloadValue and decodePayloadValue into
src/lib/utilities/decode-payload-value.ts.

* fix(payload): replace onMount with \$effect for reactive value updates

Components now re-decode when value or fieldName props change after
mount, fixing the reactivity gap that caused stale decoded content
when parent components updated their payload bindings.

* add workflow with user metadata

* remove unnecessary props from payload code block

* fix summary display

* add improvements

* fix heading levels

* add multi input workflow

* get rid of fieldName prop and fix most of the call sites

* fix remaining type errors

* fix tests

* rm inspect

* rm console.log

* WIP - download external payloads

* add support for downloading externally stored payloads

* add some error handling to downloads

* add support for filename

* fix CR feedback

* remove bad key

* fix export

* remove unused type

* cleanup unused stuff

* fix possibly duplicate key

* add language prop to PayloadCodeBlock

* add copyIconTitle and copySuccessIconTitle to codeblock instance

* refactor(payload): fix reactivity and race condition in payload-summary

Replace $effect+$state async pattern with $derived promise + $effect
cleanup to ensure all reactive deps (value, fallback, prefix,
maxSummaryLength) are tracked synchronously. Use $effect cleanup function
to cancel stale promise callbacks on re-run, preventing race conditions
when value changes rapidly. Remove unused onDecode prop.

* early return if no payloads in decode utils

* add type guards

* support inline external payloads

* fix download error and payload codeblock types

* fix schedule input

* rm console.log

* fix tests and strict mode

* fix spec

* fix typo

* add some optional chaining
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.

2 participants