From d64a45ca439669b7a6294e36d7096870389767fe Mon Sep 17 00:00:00 2001 From: hsilan Date: Tue, 14 Jul 2026 16:43:00 -0700 Subject: [PATCH] feat(plugin): Add executionStartTimestamp to InvocationBaseInfo Add optional executionStartTimestamp field to InvocationBaseInfo so it is available on all onInvocation* hook parameters (InvocationInfo and InvocationEndInfo). The timestamp is derived from initialExecutionEvent.StartTimestamp when available. Updated all test fixtures constructing InvocationInfo or InvocationEndInfo to include the new field. --- .../src/__tests__/context-extractors.test.ts | 1 + .../src/__tests__/plugin.test.ts | 2 ++ .../aws-durable-execution-sdk-js/src/types/plugin.ts | 6 ++++++ .../src/utils/plugin/plugin-runner.test.ts | 2 ++ .../src/with-durable-execution.plugin.test.ts | 11 ++++++++++- .../src/with-durable-execution.ts | 1 + 6 files changed, 22 insertions(+), 1 deletion(-) diff --git a/packages/aws-durable-execution-sdk-js-otel/src/__tests__/context-extractors.test.ts b/packages/aws-durable-execution-sdk-js-otel/src/__tests__/context-extractors.test.ts index 56c8ac74..806f15e1 100644 --- a/packages/aws-durable-execution-sdk-js-otel/src/__tests__/context-extractors.test.ts +++ b/packages/aws-durable-execution-sdk-js-otel/src/__tests__/context-extractors.test.ts @@ -12,6 +12,7 @@ const baseInfo: InvocationInfo = { executionInput: {}, operations: {}, updatedOperations: {}, + executionStartTimestamp: new Date("2024-01-01T00:00:00Z"), }; describe("xRayContextExtractor", () => { diff --git a/packages/aws-durable-execution-sdk-js-otel/src/__tests__/plugin.test.ts b/packages/aws-durable-execution-sdk-js-otel/src/__tests__/plugin.test.ts index 22316a2a..6582fcc7 100644 --- a/packages/aws-durable-execution-sdk-js-otel/src/__tests__/plugin.test.ts +++ b/packages/aws-durable-execution-sdk-js-otel/src/__tests__/plugin.test.ts @@ -42,6 +42,7 @@ function makeInvocationInfo( executionInput: {}, operations: {}, updatedOperations: {}, + executionStartTimestamp: new Date("2024-01-01T00:00:00Z"), ...overrides, }; } @@ -57,6 +58,7 @@ function makeInvocationEndInfo( status: "SUCCEEDED" as any, executionResult: undefined, executionError: undefined, + executionStartTimestamp: new Date("2024-01-01T00:00:00Z"), ...overrides, }; } diff --git a/packages/aws-durable-execution-sdk-js/src/types/plugin.ts b/packages/aws-durable-execution-sdk-js/src/types/plugin.ts index 3ca63b3c..7a736ff6 100644 --- a/packages/aws-durable-execution-sdk-js/src/types/plugin.ts +++ b/packages/aws-durable-execution-sdk-js/src/types/plugin.ts @@ -121,6 +121,12 @@ export interface InvocationBaseInfo { executionArn: string; executionInput: unknown; operations: Record; + /** + * The timestamp when the overall durable execution was first started, + * as reported by the backend. This remains the same across all + * invocations (including replays) of a given execution. + */ + executionStartTimestamp?: Date; } /** diff --git a/packages/aws-durable-execution-sdk-js/src/utils/plugin/plugin-runner.test.ts b/packages/aws-durable-execution-sdk-js/src/utils/plugin/plugin-runner.test.ts index 7592585d..958b238b 100644 --- a/packages/aws-durable-execution-sdk-js/src/utils/plugin/plugin-runner.test.ts +++ b/packages/aws-durable-execution-sdk-js/src/utils/plugin/plugin-runner.test.ts @@ -28,6 +28,7 @@ describe("createPluginRunner", () => { executionInput: { test: true }, operations: {}, updatedOperations: {}, + executionStartTimestamp: new Date("2024-01-01T00:00:00Z"), }; const operationInfo: OperationInfo = { @@ -723,6 +724,7 @@ describe("createPluginRunner", () => { executionResult: { data: "test" }, executionInput: { event: "input" }, operations: {}, + executionStartTimestamp: new Date("2024-01-01T00:00:00Z"), }; it.each([ diff --git a/packages/aws-durable-execution-sdk-js/src/with-durable-execution.plugin.test.ts b/packages/aws-durable-execution-sdk-js/src/with-durable-execution.plugin.test.ts index a2ba335c..f6ac0997 100644 --- a/packages/aws-durable-execution-sdk-js/src/with-durable-execution.plugin.test.ts +++ b/packages/aws-durable-execution-sdk-js/src/with-durable-execution.plugin.test.ts @@ -39,7 +39,14 @@ const mockTerminationManager = { setCheckpointTerminatingCallback: jest.fn(), }; const mockExecutionContext = { - _stepData: {}, + _stepData: { + "initial-op": { + StartTimestamp: new Date("2024-06-01T12:00:00Z"), + ExecutionDetails: { + InputPayload: "{}", + }, + }, + }, durableExecutionArn: "arn:test", requestId: "req-123", terminationManager: mockTerminationManager, @@ -89,6 +96,7 @@ describe("plugin hooks", () => { executionInput: expect.anything(), operations: expect.any(Object), updatedOperations: expect.any(Object), + executionStartTimestamp: new Date("2024-06-01T12:00:00Z"), }); }); @@ -111,6 +119,7 @@ describe("plugin hooks", () => { executionInput: expect.anything(), operations: expect.any(Object), updatedOperations: expect.any(Object), + executionStartTimestamp: new Date("2024-06-01T12:00:00Z"), }); }); diff --git a/packages/aws-durable-execution-sdk-js/src/with-durable-execution.ts b/packages/aws-durable-execution-sdk-js/src/with-durable-execution.ts index 1e2737e1..4f0b1720 100644 --- a/packages/aws-durable-execution-sdk-js/src/with-durable-execution.ts +++ b/packages/aws-durable-execution-sdk-js/src/with-durable-execution.ts @@ -95,6 +95,7 @@ async function runHandler< executionArn: executionContext.durableExecutionArn, executionInput: customerHandlerEvent, operations: allOperations, + executionStartTimestamp: initialExecutionEvent?.StartTimestamp ?? undefined, }; const invocationInfo: InvocationInfo = {