Skip to content

Commit c1d5c55

Browse files
ParidelPooyaPooya Paridel
andcommitted
feat(sdk): add comprehensive JSDoc documentation for DurableContext API (#84)
- Add detailed JSDoc comments for all DurableContext methods - Include comprehensive parameter descriptions and examples - Document return types and error conditions - Revert RetryDecision from discriminated union to interface for compatibility - Fix TypeScript compilation errors in examples package *Description of changes:* This commit significantly improves the developer experience in IDEs by providing comprehensive JSDoc documentation for the DurableContext API. Here's how it helps developers: ## IDE IntelliSense & Autocomplete Benefits 1. Rich Method Documentation • Hover over any context.step(), context.parallel(), etc. to see detailed descriptions • Clear explanations of what each method does and when to use it • Parameter descriptions with expected types and constraints 2. Interactive Code Examples • Real TypeScript code examples appear in IDE tooltips • Copy-paste ready snippets for common patterns • Shows proper usage patterns and best practices 3. Parameter Guidance • Detailed descriptions for each parameter (name, functions, configs) • Type information with constraints (e.g., "must be unique within execution") • Optional vs required parameter clarity 4. Return Type Documentation • Clear descriptions of what each method returns • Promise resolution types and error conditions • Helps with proper error handling and result processing ## Example IDE Experience When typing context.step(, developers now see: ``` step(fn: StepFunc<T>, config?: StepConfig<T>): Promise<T> Executes a step function with automatic retry and checkpointing capabilities. Steps are the fundamental unit of work in durable functions... Parameters: • fn - The function to execute as a step • config - Optional configuration for retry strategy and semantics Example: const result = await context.step(async () => { return await apiCall(); }, { retryStrategy: ... }); ``` This transforms the development experience from "figure it out yourself" to "guided development with rich context." Co-authored-by: Pooya Paridel <parpooya@amazon.com>
1 parent 38a927c commit c1d5c55

File tree

9 files changed

+815
-93
lines changed

9 files changed

+815
-93
lines changed

package-lock.json

Lines changed: 73 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

packages/aws-durable-execution-sdk-js-examples/src/examples/steps-with-retry.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,11 @@ const STEP_CONFIG_WITH_RETRY_FAILURES_AFTER_1_SECOND_5_TIMES = {
1212
error,
1313
`. Retry? ${shouldRetry}. `,
1414
);
15-
return { shouldRetry, delaySeconds: 1 };
15+
if (shouldRetry) {
16+
return { shouldRetry: true, delaySeconds: 1 };
17+
} else {
18+
return { shouldRetry: false };
19+
}
1620
},
1721
};
1822

packages/aws-durable-execution-sdk-js/bundle-size-history.json

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -243,5 +243,10 @@
243243
"timestamp": "2025-09-25T21:18:04.199Z",
244244
"size": 361361,
245245
"gitCommit": "2ea3ba34da20407b32cbeeb99cf71e61c758016e"
246+
},
247+
{
248+
"timestamp": "2025-09-27T19:52:39.277Z",
249+
"size": 361660,
250+
"gitCommit": "fed4cf7151607892268067a15ca3430c2f6abbbc"
246251
}
247252
]

packages/aws-durable-execution-sdk-js/eslint.config.js

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
const tsParser = require("@typescript-eslint/parser");
22
const typescriptEslint = require("@typescript-eslint/eslint-plugin");
33
const filenameConvention = require("eslint-plugin-filename-convention");
4+
const tsdoc = require("eslint-plugin-tsdoc");
45

56
module.exports = [
67
{
@@ -16,6 +17,7 @@ module.exports = [
1617
plugins: {
1718
"@typescript-eslint": typescriptEslint,
1819
"filename-convention": filenameConvention,
20+
"tsdoc": tsdoc,
1921
},
2022
rules: {
2123
...typescriptEslint.configs.recommended.rules,
@@ -26,6 +28,7 @@ module.exports = [
2628
"no-debugger": "warn",
2729
"no-duplicate-imports": "error",
2830
"filename-convention/kebab-case": "error",
31+
"tsdoc/syntax": "warn",
2932
},
3033
},
3134
{

packages/aws-durable-execution-sdk-js/package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,7 @@
6161
"aws-lambda": "^1.0.7",
6262
"eslint": "^9.21.0",
6363
"eslint-plugin-filename-convention": "file:scripts/eslint-plugin-filename-convention",
64+
"eslint-plugin-tsdoc": "^0.4.0",
6465
"globals": "^14.0.0",
6566
"husky": "^9.1.7",
6667
"jest": "^29.7.0",

packages/aws-durable-execution-sdk-js/src/context/durable-context/durable-context.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -159,7 +159,7 @@ export const createDurableContext = (
159159

160160
const map: DurableContext["map"] = <T>(
161161
nameOrItems: string | undefined | any[],
162-
itemsOrMapFunc?: any[] | MapFunc<T>,
162+
itemsOrMapFunc: any[] | MapFunc<T>,
163163
mapFuncOrConfig?: MapFunc<T> | MapConfig,
164164
maybeConfig?: MapConfig,
165165
) => {

packages/aws-durable-execution-sdk-js/src/handlers/concurrent-execution-handler/concurrent-execution-handler.test.ts

Lines changed: 37 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -271,14 +271,21 @@ describe("Concurrent Execution Handler", () => {
271271

272272
// Mock the executeOperation function to capture the actual execution
273273
let capturedExecuteOperation: any;
274-
mockRunInChildContext.mockImplementation((name, executeOp, options) => {
275-
capturedExecuteOperation = executeOp;
276-
return Promise.resolve(
277-
new MockBatchResult([
278-
{ index: 0, result: "result", status: BatchItemStatus.SUCCEEDED },
279-
]) as any,
280-
);
281-
});
274+
mockRunInChildContext.mockImplementation(
275+
(nameOrFn: any, fnOrConfig?: any, maybeConfig?: any) => {
276+
// Handle the overloaded signature
277+
if (typeof nameOrFn === "string" || nameOrFn === undefined) {
278+
capturedExecuteOperation = fnOrConfig;
279+
} else {
280+
capturedExecuteOperation = nameOrFn;
281+
}
282+
return Promise.resolve(
283+
new MockBatchResult([
284+
{ index: 0, result: "result", status: BatchItemStatus.SUCCEEDED },
285+
]) as any,
286+
);
287+
},
288+
);
282289

283290
await concurrentExecutionHandler(items, executor, config);
284291

@@ -295,15 +302,22 @@ describe("Concurrent Execution Handler", () => {
295302
// Create a real execution context that will execute the actual path
296303
let actualExecuteOperation: any;
297304
mockRunInChildContext.mockImplementation(
298-
async (name, executeOp, options) => {
299-
actualExecuteOperation = executeOp;
305+
async (nameOrFn: any, fnOrConfig?: any, maybeConfig?: any) => {
306+
// Handle the overloaded signature
307+
let actualFn;
308+
if (typeof nameOrFn === "string" || nameOrFn === undefined) {
309+
actualFn = fnOrConfig;
310+
} else {
311+
actualFn = nameOrFn;
312+
}
313+
actualExecuteOperation = actualFn;
300314
// Execute the actual operation to cover the executeOperation function
301-
if (typeof executeOp === "function") {
315+
if (typeof actualFn === "function") {
302316
const mockDurableContext = {
303317
runInChildContext: jest.fn().mockResolvedValue("test-result"),
304318
} as any;
305319

306-
return await executeOp(mockDurableContext);
320+
return await actualFn(mockDurableContext);
307321
}
308322
return new MockBatchResult([]) as any;
309323
},
@@ -322,14 +336,21 @@ describe("Concurrent Execution Handler", () => {
322336
// Test with undefined config to cover the config || {} branch
323337
let actualExecuteOperation: any;
324338
mockRunInChildContext.mockImplementation(
325-
async (name, executeOp, options) => {
326-
actualExecuteOperation = executeOp;
327-
if (typeof executeOp === "function") {
339+
async (nameOrFn: any, fnOrConfig?: any, maybeConfig?: any) => {
340+
// Handle the overloaded signature
341+
let actualFn;
342+
if (typeof nameOrFn === "string" || nameOrFn === undefined) {
343+
actualFn = fnOrConfig;
344+
} else {
345+
actualFn = nameOrFn;
346+
}
347+
actualExecuteOperation = actualFn;
348+
if (typeof actualFn === "function") {
328349
const mockDurableContext = {
329350
runInChildContext: jest.fn().mockResolvedValue("test-result"),
330351
} as any;
331352

332-
return await executeOp(mockDurableContext);
353+
return await actualFn(mockDurableContext);
333354
}
334355
return new MockBatchResult([]) as any;
335356
},

packages/aws-durable-execution-sdk-js/src/handlers/parallel-handler/parallel-handler.test.ts

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -180,8 +180,18 @@ describe("Parallel Handler", () => {
180180
// Mock the executor being called
181181
let capturedExecutor: any;
182182
mockExecuteConcurrently.mockImplementation(
183-
async (name, items, executor, config) => {
184-
capturedExecutor = executor;
183+
async (
184+
nameOrItems: any,
185+
itemsOrExecutor?: any,
186+
executorOrConfig?: any,
187+
maybeConfig?: any,
188+
) => {
189+
// Handle the overloaded signature
190+
if (typeof nameOrItems === "string" || nameOrItems === undefined) {
191+
capturedExecutor = executorOrConfig;
192+
} else {
193+
capturedExecutor = itemsOrExecutor;
194+
}
185195
return new MockBatchResult([
186196
{ index: 0, result: "result1", status: BatchItemStatus.SUCCEEDED },
187197
]) as any;

0 commit comments

Comments
 (0)