lambda-deadline-middleware 0.0.0 → 1.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (51) hide show
  1. package/LICENSE +1 -1
  2. package/LICENSES/MIT.txt +18 -0
  3. package/README.md +107 -153
  4. package/REUSE.toml +9 -0
  5. package/SECURITY.md +34 -38
  6. package/dist/config.d.ts +1 -1
  7. package/dist/config.d.ts.map +1 -1
  8. package/dist/config.js +5 -3
  9. package/dist/config.js.map +1 -1
  10. package/dist/context-store.d.ts +2 -2
  11. package/dist/context-store.d.ts.map +1 -1
  12. package/dist/context-store.js +5 -5
  13. package/dist/context-store.js.map +1 -1
  14. package/dist/error.d.ts +1 -1
  15. package/dist/error.d.ts.map +1 -1
  16. package/dist/error.js +2 -2
  17. package/dist/error.js.map +1 -1
  18. package/dist/handler-wrapper.d.ts +2 -2
  19. package/dist/handler-wrapper.d.ts.map +1 -1
  20. package/dist/handler-wrapper.js +2 -4
  21. package/dist/handler-wrapper.js.map +1 -1
  22. package/dist/index.d.ts +1 -1
  23. package/dist/index.d.ts.map +1 -1
  24. package/dist/index.js +2 -2
  25. package/dist/index.js.map +1 -1
  26. package/dist/middleware.d.ts +7 -4
  27. package/dist/middleware.d.ts.map +1 -1
  28. package/dist/middleware.js +33 -33
  29. package/dist/middleware.js.map +1 -1
  30. package/dist/registration.d.ts +4 -6
  31. package/dist/registration.d.ts.map +1 -1
  32. package/dist/registration.js +5 -11
  33. package/dist/registration.js.map +1 -1
  34. package/dist/telemetry.d.ts +1 -1
  35. package/dist/telemetry.d.ts.map +1 -1
  36. package/dist/telemetry.js +4 -4
  37. package/dist/telemetry.js.map +1 -1
  38. package/dist/types.d.ts +2 -2
  39. package/dist/types.d.ts.map +1 -1
  40. package/dist/types.js +4 -4
  41. package/dist/types.js.map +1 -1
  42. package/package.json +36 -30
  43. package/src/config.ts +5 -3
  44. package/src/context-store.ts +7 -5
  45. package/src/error.ts +3 -3
  46. package/src/handler-wrapper.ts +7 -7
  47. package/src/index.ts +2 -2
  48. package/src/middleware.ts +43 -41
  49. package/src/registration.ts +9 -18
  50. package/src/telemetry.ts +9 -6
  51. package/src/types.ts +7 -5
package/dist/error.js CHANGED
@@ -12,10 +12,10 @@ export class DeadlineExceededError extends Error {
12
12
  }
13
13
  // Structural check rather than instanceof — works across module boundaries
14
14
  // and serialization boundaries where prototype chain may be broken.
15
- export function isDeadlineExceeded(error) {
15
+ export const isDeadlineExceeded = (error) => {
16
16
  if (error === null || error === undefined) return false;
17
17
  if (typeof error !== "object") return false;
18
18
  return error.name === "DeadlineExceededError";
19
- }
19
+ };
20
20
 
21
21
  //# sourceMappingURL=error.js.map
package/dist/error.js.map CHANGED
@@ -1 +1 @@
1
- {"mappings":"AAWA,OAAO,MAAM,8BAA8B,MAAM;CAC/C,AAAkB,OAAO;CACzB,AAAS;CACT,AAAS;CACT,AAAS;CAET,YAAY,MAA4B;EACtC,MACE,8BAA8B,KAAK,WAAW,eAAe,KAAK,cAAc,iBAClF;EACA,KAAK,aAAa,KAAK;EACvB,KAAK,gBAAgB,KAAK;EAC1B,KAAK,cAAc,KAAK;CAC1B;AACF;;;AAIA,OAAO,SAAS,mBAAmB,OAAgD;CACjF,IAAI,UAAU,QAAQ,UAAU,WAAW,OAAO;CAClD,IAAI,OAAO,UAAU,UAAU,OAAO;CACtC,OAAQ,MAA6B,SAAS;AAChD","names":[],"sources":["src/error.ts"],"version":3,"sourcesContent":["// SPDX-FileCopyrightText: 2024 lambda-deadline-middleware contributors\n// SPDX-License-Identifier: MIT\n\nimport type { FlushBufferMs, Milliseconds } from \"./types.js\";\n\ninterface DeadlineExceededInit {\n readonly deadlineMs: Milliseconds;\n readonly flushBufferMs: FlushBufferMs;\n readonly remainingMs: Milliseconds;\n}\n\nexport class DeadlineExceededError extends Error {\n override readonly name = \"DeadlineExceededError\" as const;\n readonly deadlineMs: Milliseconds;\n readonly flushBufferMs: FlushBufferMs;\n readonly remainingMs: Milliseconds;\n\n constructor(init: DeadlineExceededInit) {\n super(\n `Request deadline exceeded: ${init.deadlineMs}ms deadline (${init.flushBufferMs}ms flush buffer)`,\n );\n this.deadlineMs = init.deadlineMs;\n this.flushBufferMs = init.flushBufferMs;\n this.remainingMs = init.remainingMs;\n }\n}\n\n// Structural check rather than instanceof — works across module boundaries\n// and serialization boundaries where prototype chain may be broken.\nexport function isDeadlineExceeded(error: unknown): error is DeadlineExceededError {\n if (error === null || error === undefined) return false;\n if (typeof error !== \"object\") return false;\n return (error as { name?: unknown }).name === \"DeadlineExceededError\";\n}\n"]}
1
+ {"mappings":"AAWA,OAAO,MAAM,8BAA8B,MAAM;CAC/C,AAAkB,OAAO;CACzB,AAAS;CACT,AAAS;CACT,AAAS;CAET,YAAY,MAA4B;EACtC,MACE,8BAA8B,KAAK,WAAW,eAAe,KAAK,cAAc,iBAClF;EACA,KAAK,aAAa,KAAK;EACvB,KAAK,gBAAgB,KAAK;EAC1B,KAAK,cAAc,KAAK;CAC1B;AACF;;;AAIA,OAAO,MAAM,sBAAsB,UAAmD;CACpF,IAAI,UAAU,QAAQ,UAAU,WAAW,OAAO;CAClD,IAAI,OAAO,UAAU,UAAU,OAAO;CACtC,OAAQ,MAA6B,SAAS;AAChD","names":[],"sources":["src/error.ts"],"version":3,"sourcesContent":["// SPDX-FileCopyrightText: 2026 lambda-deadline-middleware contributors\n// SPDX-License-Identifier: MIT\n\nimport type { FlushBufferMs, Milliseconds } from \"./types.js\";\n\ninterface DeadlineExceededInit {\n readonly deadlineMs: Milliseconds;\n readonly flushBufferMs: FlushBufferMs;\n readonly remainingMs: Milliseconds;\n}\n\nexport class DeadlineExceededError extends Error {\n override readonly name = \"DeadlineExceededError\" as const;\n readonly deadlineMs: Milliseconds;\n readonly flushBufferMs: FlushBufferMs;\n readonly remainingMs: Milliseconds;\n\n constructor(init: DeadlineExceededInit) {\n super(\n `Request deadline exceeded: ${init.deadlineMs}ms deadline (${init.flushBufferMs}ms flush buffer)`,\n );\n this.deadlineMs = init.deadlineMs;\n this.flushBufferMs = init.flushBufferMs;\n this.remainingMs = init.remainingMs;\n }\n}\n\n// Structural check rather than instanceof — works across module boundaries\n// and serialization boundaries where prototype chain may be broken.\nexport const isDeadlineExceeded = (error: unknown): error is DeadlineExceededError => {\n if (error === null || error === undefined) return false;\n if (typeof error !== \"object\") return false;\n return (error as { name?: unknown }).name === \"DeadlineExceededError\";\n};\n"]}
@@ -4,10 +4,10 @@ type AsyncHandler<
4
4
  TEvent,
5
5
  TResult
6
6
  > = (event: TEvent, context: LambdaContextLike) => Promise<TResult>;
7
- export declare function withLambdaDeadline<
7
+ export declare const withLambdaDeadline: <
8
8
  TEvent,
9
9
  TResult
10
- >(handler: AsyncHandler<TEvent, TResult>, _options?: DeadlineOptions): AsyncHandler<TEvent, TResult>;
10
+ >(handler: AsyncHandler<TEvent, TResult>, _options?: DeadlineOptions) => AsyncHandler<TEvent, TResult>;
11
11
  export {};
12
12
 
13
13
  //# sourceMappingURL=handler-wrapper.d.ts.map
@@ -1 +1 @@
1
- {"mappings":"AAIA,cAAc,yBAAyB;AACvC,cAAc,uBAAuB;KAEhC;CAAa;CAAQ;KACxB,OAAO,QACP,SAAS,sBACN,QAAQ;AAEb,OAAO,iBAAS;CAAmB;CAAQ;EACzC,SAAS,aAAa,QAAQ,UAC9B,WAAW,kBACV,aAAa,QAAQ","names":[],"sources":["src/handler-wrapper.ts"],"version":3,"sourcesContent":["// SPDX-FileCopyrightText: 2024 lambda-deadline-middleware contributors\n// SPDX-License-Identifier: MIT\n\nimport { run } from \"./context-store.js\";\nimport type { LambdaContextLike } from \"./context-store.js\";\nimport type { DeadlineOptions } from \"./types.js\";\n\ntype AsyncHandler<TEvent, TResult> = (\n event: TEvent,\n context: LambdaContextLike,\n) => Promise<TResult>;\n\nexport function withLambdaDeadline<TEvent, TResult>(\n handler: AsyncHandler<TEvent, TResult>,\n _options?: DeadlineOptions,\n): AsyncHandler<TEvent, TResult> {\n return async (event: TEvent, context: LambdaContextLike): Promise<TResult> =>\n run(context, async () => handler(event, context));\n}\n"]}
1
+ {"mappings":"AAIA,cAAc,yBAAyB;AACvC,cAAc,uBAAuB;KAEhC;CAAa;CAAQ;KACxB,OAAO,QACP,SAAS,sBACN,QAAQ;AAEb,OAAO,cAAM;CACV;CAAQ;EACP,SAAS,aAAa,QAAQ,UAC9B,WAAW,oBACV,aAAa,QAAQ","names":[],"sources":["src/handler-wrapper.ts"],"version":3,"sourcesContent":["// SPDX-FileCopyrightText: 2026 lambda-deadline-middleware contributors\n// SPDX-License-Identifier: MIT\n\nimport { run } from \"./context-store.js\";\nimport type { LambdaContextLike } from \"./context-store.js\";\nimport type { DeadlineOptions } from \"./types.js\";\n\ntype AsyncHandler<TEvent, TResult> = (\n event: TEvent,\n context: LambdaContextLike,\n) => Promise<TResult>;\n\nexport const withLambdaDeadline =\n <TEvent, TResult>(\n handler: AsyncHandler<TEvent, TResult>,\n _options?: DeadlineOptions,\n ): AsyncHandler<TEvent, TResult> =>\n async (event: TEvent, context: LambdaContextLike): Promise<TResult> =>\n run(context, async () => handler(event, context));\n"]}
@@ -1,8 +1,6 @@
1
- // SPDX-FileCopyrightText: 2024 lambda-deadline-middleware contributors
1
+ // SPDX-FileCopyrightText: 2026 lambda-deadline-middleware contributors
2
2
  // SPDX-License-Identifier: MIT
3
3
  import { run } from "./context-store.js";
4
- export function withLambdaDeadline(handler, _options) {
5
- return async (event, context) => run(context, async () => handler(event, context));
6
- }
4
+ export const withLambdaDeadline = (handler, _options) => async (event, context) => run(context, async () => handler(event, context));
7
5
 
8
6
  //# sourceMappingURL=handler-wrapper.js.map
@@ -1 +1 @@
1
- {"mappings":";;AAGA,SAAS,WAAW;AASpB,OAAO,SAAS,mBACd,SACA,UAC+B;CAC/B,OAAO,OAAO,OAAe,YAC3B,IAAI,SAAS,YAAY,QAAQ,OAAO,OAAO,CAAC;AACpD","names":[],"sources":["src/handler-wrapper.ts"],"version":3,"sourcesContent":["// SPDX-FileCopyrightText: 2024 lambda-deadline-middleware contributors\n// SPDX-License-Identifier: MIT\n\nimport { run } from \"./context-store.js\";\nimport type { LambdaContextLike } from \"./context-store.js\";\nimport type { DeadlineOptions } from \"./types.js\";\n\ntype AsyncHandler<TEvent, TResult> = (\n event: TEvent,\n context: LambdaContextLike,\n) => Promise<TResult>;\n\nexport function withLambdaDeadline<TEvent, TResult>(\n handler: AsyncHandler<TEvent, TResult>,\n _options?: DeadlineOptions,\n): AsyncHandler<TEvent, TResult> {\n return async (event: TEvent, context: LambdaContextLike): Promise<TResult> =>\n run(context, async () => handler(event, context));\n}\n"]}
1
+ {"mappings":";;AAGA,SAAS,WAAW;AASpB,OAAO,MAAM,sBAET,SACA,aAEF,OAAO,OAAe,YACpB,IAAI,SAAS,YAAY,QAAQ,OAAO,OAAO,CAAC","names":[],"sources":["src/handler-wrapper.ts"],"version":3,"sourcesContent":["// SPDX-FileCopyrightText: 2026 lambda-deadline-middleware contributors\n// SPDX-License-Identifier: MIT\n\nimport { run } from \"./context-store.js\";\nimport type { LambdaContextLike } from \"./context-store.js\";\nimport type { DeadlineOptions } from \"./types.js\";\n\ntype AsyncHandler<TEvent, TResult> = (\n event: TEvent,\n context: LambdaContextLike,\n) => Promise<TResult>;\n\nexport const withLambdaDeadline =\n <TEvent, TResult>(\n handler: AsyncHandler<TEvent, TResult>,\n _options?: DeadlineOptions,\n ): AsyncHandler<TEvent, TResult> =>\n async (event: TEvent, context: LambdaContextLike): Promise<TResult> =>\n run(context, async () => handler(event, context));\n"]}
package/dist/index.d.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  export { withLambdaDeadline } from "./handler-wrapper.js";
2
- export { deadlineMiddleware, withDeadline } from "./registration.js";
2
+ export { deadlineMiddleware } from "./registration.js";
3
3
  export { DeadlineExceededError, isDeadlineExceeded } from "./error.js";
4
4
  export { getRemainingTimeInMillis } from "./context-store.js";
5
5
  export type { Milliseconds, FlushBufferMs, RequestDeadlineMs, DeadlineComputation, DeadlineMiddlewareConfig, DeadlineOptions } from "./types.js";
@@ -1 +1 @@
1
- {"mappings":"AAGA,SAAS,0BAA0B;AACnC,SAAS,oBAAoB,oBAAoB;AACjD,SAAS,uBAAuB,0BAA0B;AAC1D,SAAS,gCAAgC;AAEzC,cACE,cACA,eACA,mBACA,qBACA,0BACA,uBACK;AAEP,cAAc,yBAAyB","names":[],"sources":["src/index.ts"],"version":3,"sourcesContent":["// SPDX-FileCopyrightText: 2024 lambda-deadline-middleware contributors\n// SPDX-License-Identifier: MIT\n\nexport { withLambdaDeadline } from \"./handler-wrapper.js\";\nexport { deadlineMiddleware, withDeadline } from \"./registration.js\";\nexport { DeadlineExceededError, isDeadlineExceeded } from \"./error.js\";\nexport { getRemainingTimeInMillis } from \"./context-store.js\";\n\nexport type {\n Milliseconds,\n FlushBufferMs,\n RequestDeadlineMs,\n DeadlineComputation,\n DeadlineMiddlewareConfig,\n DeadlineOptions,\n} from \"./types.js\";\n\nexport type { LambdaContextLike } from \"./context-store.js\";\n"]}
1
+ {"mappings":"AAGA,SAAS,0BAA0B;AACnC,SAAS,0BAA0B;AACnC,SAAS,uBAAuB,0BAA0B;AAC1D,SAAS,gCAAgC;AAEzC,cACE,cACA,eACA,mBACA,qBACA,0BACA,uBACK;AAEP,cAAc,yBAAyB","names":[],"sources":["src/index.ts"],"version":3,"sourcesContent":["// SPDX-FileCopyrightText: 2026 lambda-deadline-middleware contributors\n// SPDX-License-Identifier: MIT\n\nexport { withLambdaDeadline } from \"./handler-wrapper.js\";\nexport { deadlineMiddleware } from \"./registration.js\";\nexport { DeadlineExceededError, isDeadlineExceeded } from \"./error.js\";\nexport { getRemainingTimeInMillis } from \"./context-store.js\";\n\nexport type {\n Milliseconds,\n FlushBufferMs,\n RequestDeadlineMs,\n DeadlineComputation,\n DeadlineMiddlewareConfig,\n DeadlineOptions,\n} from \"./types.js\";\n\nexport type { LambdaContextLike } from \"./context-store.js\";\n"]}
package/dist/index.js CHANGED
@@ -1,7 +1,7 @@
1
- // SPDX-FileCopyrightText: 2024 lambda-deadline-middleware contributors
1
+ // SPDX-FileCopyrightText: 2026 lambda-deadline-middleware contributors
2
2
  // SPDX-License-Identifier: MIT
3
3
  export { withLambdaDeadline } from "./handler-wrapper.js";
4
- export { deadlineMiddleware, withDeadline } from "./registration.js";
4
+ export { deadlineMiddleware } from "./registration.js";
5
5
  export { DeadlineExceededError, isDeadlineExceeded } from "./error.js";
6
6
  export { getRemainingTimeInMillis } from "./context-store.js";
7
7
 
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"mappings":";;AAGA,SAAS,0BAA0B;AACnC,SAAS,oBAAoB,oBAAoB;AACjD,SAAS,uBAAuB,0BAA0B;AAC1D,SAAS,gCAAgC","names":[],"sources":["src/index.ts"],"version":3,"sourcesContent":["// SPDX-FileCopyrightText: 2024 lambda-deadline-middleware contributors\n// SPDX-License-Identifier: MIT\n\nexport { withLambdaDeadline } from \"./handler-wrapper.js\";\nexport { deadlineMiddleware, withDeadline } from \"./registration.js\";\nexport { DeadlineExceededError, isDeadlineExceeded } from \"./error.js\";\nexport { getRemainingTimeInMillis } from \"./context-store.js\";\n\nexport type {\n Milliseconds,\n FlushBufferMs,\n RequestDeadlineMs,\n DeadlineComputation,\n DeadlineMiddlewareConfig,\n DeadlineOptions,\n} from \"./types.js\";\n\nexport type { LambdaContextLike } from \"./context-store.js\";\n"]}
1
+ {"mappings":";;AAGA,SAAS,0BAA0B;AACnC,SAAS,0BAA0B;AACnC,SAAS,uBAAuB,0BAA0B;AAC1D,SAAS,gCAAgC","names":[],"sources":["src/index.ts"],"version":3,"sourcesContent":["// SPDX-FileCopyrightText: 2026 lambda-deadline-middleware contributors\n// SPDX-License-Identifier: MIT\n\nexport { withLambdaDeadline } from \"./handler-wrapper.js\";\nexport { deadlineMiddleware } from \"./registration.js\";\nexport { DeadlineExceededError, isDeadlineExceeded } from \"./error.js\";\nexport { getRemainingTimeInMillis } from \"./context-store.js\";\n\nexport type {\n Milliseconds,\n FlushBufferMs,\n RequestDeadlineMs,\n DeadlineComputation,\n DeadlineMiddlewareConfig,\n DeadlineOptions,\n} from \"./types.js\";\n\nexport type { LambdaContextLike } from \"./context-store.js\";\n"]}
@@ -1,12 +1,15 @@
1
1
  import type { DeadlineComputation, DeadlineMiddlewareConfig, RequestDeadlineMs } from "./types.js";
2
2
  import type { FinalizeRequestMiddleware } from "@smithy/types";
3
- export declare function computeDeadline(config: DeadlineMiddlewareConfig): DeadlineComputation;
3
+ export declare const computeDeadline: (config: DeadlineMiddlewareConfig) => DeadlineComputation;
4
4
  export interface DeadlineTimer {
5
5
  readonly controller: AbortController;
6
6
  [Symbol.dispose]: () => void;
7
7
  }
8
- export declare function createDeadlineTimer(deadlineMs: RequestDeadlineMs, config: DeadlineMiddlewareConfig): DeadlineTimer;
9
- export declare function composeSignals(existing: AbortSignal | undefined, deadline: AbortSignal): AbortSignal;
10
- export declare function deadlineMiddlewareHandler(config: DeadlineMiddlewareConfig): FinalizeRequestMiddleware<object, object>;
8
+ export declare const createDeadlineTimer: (deadlineMs: RequestDeadlineMs, config: DeadlineMiddlewareConfig) => DeadlineTimer;
9
+ export declare const composeSignals: (existing: AbortSignal | undefined, deadline: AbortSignal) => AbortSignal;
10
+ export declare const deadlineMiddlewareHandler: <
11
+ Input extends object,
12
+ Output extends object
13
+ >(config: DeadlineMiddlewareConfig) => FinalizeRequestMiddleware<Input, Output>;
11
14
 
12
15
  //# sourceMappingURL=middleware.d.ts.map
@@ -1 +1 @@
1
- {"mappings":"AAKA,cAAc,qBAAqB,0BAA0B,yBAAyB;AAGtF,cAIE,iCAEK;AAEP,OAAO,iBAAS,gBAAgB,QAAQ,2BAA2B;AAqBnE,iBAAiB,cAAc;UACpB,YAAY;EACpB,OAAO;AACV;AAEA,OAAO,iBAAS,oBACd,YAAY,mBACZ,QAAQ,2BACP;AAmBH,OAAO,iBAAS,eACd,UAAU,yBACV,UAAU,cACT;AAKH,OAAO,iBAAS,0BACd,QAAQ,2BACP","names":[],"sources":["src/middleware.ts"],"version":3,"sourcesContent":["// SPDX-FileCopyrightText: 2024 lambda-deadline-middleware contributors\n// SPDX-License-Identifier: MIT\n\nimport { getRemainingTimeInMillis } from \"./context-store.js\";\nimport { DeadlineExceededError } from \"./error.js\";\nimport type { DeadlineComputation, DeadlineMiddlewareConfig, RequestDeadlineMs } from \"./types.js\";\nimport { milliseconds } from \"./types.js\";\n\nimport type {\n FinalizeHandler,\n FinalizeHandlerArguments,\n FinalizeHandlerOutput,\n FinalizeRequestMiddleware,\n HandlerExecutionContext,\n} from \"@smithy/types\";\n\nexport function computeDeadline(config: DeadlineMiddlewareConfig): DeadlineComputation {\n const remaining = getRemainingTimeInMillis();\n\n if (remaining === undefined) {\n return { kind: \"no-context\" };\n }\n\n const deadline = remaining - config.flushBufferMs;\n\n if (deadline <= 0) {\n return {\n kind: \"insufficient-time\",\n remaining: milliseconds(remaining),\n buffer: config.flushBufferMs,\n };\n }\n\n // oxlint-disable-next-line typescript/no-unsafe-type-assertion -- branded narrowing: deadline is validated > 0 above\n return { kind: \"deadline\", value: deadline as RequestDeadlineMs };\n}\n\nexport interface DeadlineTimer {\n readonly controller: AbortController;\n [Symbol.dispose]: () => void;\n}\n\nexport function createDeadlineTimer(\n deadlineMs: RequestDeadlineMs,\n config: DeadlineMiddlewareConfig,\n): DeadlineTimer {\n const controller = new AbortController();\n const remaining = milliseconds(deadlineMs + config.flushBufferMs);\n const error = new DeadlineExceededError({\n deadlineMs: milliseconds(deadlineMs),\n flushBufferMs: config.flushBufferMs,\n remainingMs: remaining,\n });\n const timeoutId = setTimeout(() => {\n controller.abort(error);\n }, deadlineMs);\n return {\n controller,\n [Symbol.dispose]() {\n clearTimeout(timeoutId);\n },\n };\n}\n\nexport function composeSignals(\n existing: AbortSignal | undefined,\n deadline: AbortSignal,\n): AbortSignal {\n if (existing === undefined) return deadline;\n return AbortSignal.any([existing, deadline]);\n}\n\nexport function deadlineMiddlewareHandler(\n config: DeadlineMiddlewareConfig,\n): FinalizeRequestMiddleware<object, object> {\n return (\n next: FinalizeHandler<object, object>,\n _context: HandlerExecutionContext,\n ): FinalizeHandler<object, object> =>\n // oxlint-disable-next-line typescript/consistent-return -- switch is exhaustive over DeadlineComputation discriminated union\n async (args: FinalizeHandlerArguments<object>): Promise<FinalizeHandlerOutput<object>> => {\n const computation = computeDeadline(config);\n\n switch (computation.kind) {\n case \"no-context\":\n return next(args);\n\n case \"insufficient-time\":\n throw new DeadlineExceededError({\n deadlineMs: milliseconds(0),\n flushBufferMs: computation.buffer,\n remainingMs: computation.remaining,\n });\n\n case \"deadline\": {\n using timer = createDeadlineTimer(computation.value, config);\n // oxlint-disable-next-line typescript/no-unsafe-type-assertion -- Smithy request is an opaque object; we access optional signal property\n const request = args.request as { signal?: AbortSignal } | undefined;\n const signal = composeSignals(request?.signal, timer.controller.signal);\n const result = await next({\n ...args,\n // oxlint-disable-next-line typescript/no-unsafe-type-assertion -- spreading opaque Smithy request to add signal\n request: { ...(args.request as object), signal },\n });\n return result;\n }\n }\n };\n}\n"]}
1
+ {"mappings":"AAKA,cAAc,qBAAqB,0BAA0B,yBAAyB;AAGtF,cAIE,iCAEK;AAEP,OAAO,cAAM,kBAAmB,QAAQ,6BAA2B;AAqBnE,iBAAiB,cAAc;UACpB,YAAY;EACpB,OAAO;AACV;AAEA,OAAO,cAAM,sBACX,YAAY,mBACZ,QAAQ,6BACP;AAmBH,OAAO,cAAM,iBACX,UAAU,yBACV,UAAU,gBACT;AAKH,OAAO,cAAM;CACV;CAAsB;EACrB,QAAQ,6BACP,0BAA0B,OAAO","names":[],"sources":["src/middleware.ts"],"version":3,"sourcesContent":["// SPDX-FileCopyrightText: 2026 lambda-deadline-middleware contributors\n// SPDX-License-Identifier: MIT\n\nimport { getRemainingTimeInMillis } from \"./context-store.js\";\nimport { DeadlineExceededError } from \"./error.js\";\nimport type { DeadlineComputation, DeadlineMiddlewareConfig, RequestDeadlineMs } from \"./types.js\";\nimport { milliseconds } from \"./types.js\";\n\nimport type {\n FinalizeHandler,\n FinalizeHandlerArguments,\n FinalizeHandlerOutput,\n FinalizeRequestMiddleware,\n HandlerExecutionContext,\n} from \"@smithy/types\";\n\nexport const computeDeadline = (config: DeadlineMiddlewareConfig): DeadlineComputation => {\n const remaining = getRemainingTimeInMillis();\n\n if (remaining === undefined) {\n return { kind: \"no-context\" };\n }\n\n const deadline = remaining - config.flushBufferMs;\n\n if (deadline <= 0) {\n return {\n kind: \"insufficient-time\",\n remaining: milliseconds(remaining),\n buffer: config.flushBufferMs,\n };\n }\n\n // oxlint-disable-next-line typescript/no-unsafe-type-assertion -- branded narrowing: deadline is validated > 0 above\n return { kind: \"deadline\", value: deadline as RequestDeadlineMs };\n};\n\nexport interface DeadlineTimer {\n readonly controller: AbortController;\n [Symbol.dispose]: () => void;\n}\n\nexport const createDeadlineTimer = (\n deadlineMs: RequestDeadlineMs,\n config: DeadlineMiddlewareConfig,\n): DeadlineTimer => {\n const controller = new AbortController();\n const remaining = milliseconds(deadlineMs + config.flushBufferMs);\n const error = new DeadlineExceededError({\n deadlineMs: milliseconds(deadlineMs),\n flushBufferMs: config.flushBufferMs,\n remainingMs: remaining,\n });\n const timeoutId = setTimeout(() => {\n controller.abort(error);\n }, deadlineMs);\n return {\n controller,\n [Symbol.dispose]() {\n clearTimeout(timeoutId);\n },\n };\n};\n\nexport const composeSignals = (\n existing: AbortSignal | undefined,\n deadline: AbortSignal,\n): AbortSignal => {\n if (existing === undefined) return deadline;\n return AbortSignal.any([existing, deadline]);\n};\n\nexport const deadlineMiddlewareHandler =\n <Input extends object, Output extends object>(\n config: DeadlineMiddlewareConfig,\n ): FinalizeRequestMiddleware<Input, Output> =>\n (\n next: FinalizeHandler<Input, Output>,\n _context: HandlerExecutionContext,\n ): FinalizeHandler<Input, Output> =>\n // oxlint-disable-next-line typescript/consistent-return -- switch is exhaustive over DeadlineComputation discriminated union\n async (args: FinalizeHandlerArguments<Input>): Promise<FinalizeHandlerOutput<Output>> => {\n const computation = computeDeadline(config);\n\n switch (computation.kind) {\n case \"no-context\":\n return next(args);\n\n case \"insufficient-time\":\n throw new DeadlineExceededError({\n deadlineMs: milliseconds(0),\n flushBufferMs: computation.buffer,\n remainingMs: computation.remaining,\n });\n\n case \"deadline\": {\n // `using` guarantees cleanup (clearTimeout) even if next() throws, the promise rejects,\n // or an external abort signal fires — strictly more reliable than try/finally.\n using timer = createDeadlineTimer(computation.value, config);\n // oxlint-disable-next-line typescript/no-unsafe-type-assertion -- Smithy request is an opaque object; we access optional signal property\n const request = args.request as { signal?: AbortSignal } | undefined;\n const signal = composeSignals(request?.signal, timer.controller.signal);\n const result = await next({\n ...args,\n // oxlint-disable-next-line typescript/no-unsafe-type-assertion -- spreading opaque Smithy request to add signal\n request: { ...(args.request as object), signal },\n });\n return result;\n }\n }\n };\n"]}
@@ -1,9 +1,9 @@
1
- // SPDX-FileCopyrightText: 2024 lambda-deadline-middleware contributors
1
+ // SPDX-FileCopyrightText: 2026 lambda-deadline-middleware contributors
2
2
  // SPDX-License-Identifier: MIT
3
3
  import { getRemainingTimeInMillis } from "./context-store.js";
4
4
  import { DeadlineExceededError } from "./error.js";
5
5
  import { milliseconds } from "./types.js";
6
- export function computeDeadline(config) {
6
+ export const computeDeadline = (config) => {
7
7
  const remaining = getRemainingTimeInMillis();
8
8
  if (remaining === undefined) {
9
9
  return { kind: "no-context" };
@@ -21,8 +21,8 @@ export function computeDeadline(config) {
21
21
  kind: "deadline",
22
22
  value: deadline
23
23
  };
24
- }
25
- export function createDeadlineTimer(deadlineMs, config) {
24
+ };
25
+ export const createDeadlineTimer = (deadlineMs, config) => {
26
26
  const controller = new AbortController();
27
27
  const remaining = milliseconds(deadlineMs + config.flushBufferMs);
28
28
  const error = new DeadlineExceededError({
@@ -39,38 +39,38 @@ export function createDeadlineTimer(deadlineMs, config) {
39
39
  clearTimeout(timeoutId);
40
40
  }
41
41
  };
42
- }
43
- export function composeSignals(existing, deadline) {
42
+ };
43
+ export const composeSignals = (existing, deadline) => {
44
44
  if (existing === undefined) return deadline;
45
45
  return AbortSignal.any([existing, deadline]);
46
- }
47
- export function deadlineMiddlewareHandler(config) {
48
- return (next, _context) => async (args) => {
49
- const computation = computeDeadline(config);
50
- switch (computation.kind) {
51
- case "no-context": return next(args);
52
- case "insufficient-time": throw new DeadlineExceededError({
53
- deadlineMs: milliseconds(0),
54
- flushBufferMs: computation.buffer,
55
- remainingMs: computation.remaining
46
+ };
47
+ export const deadlineMiddlewareHandler = (config) => (next, _context) => async (args) => {
48
+ const computation = computeDeadline(config);
49
+ switch (computation.kind) {
50
+ case "no-context": return next(args);
51
+ case "insufficient-time": throw new DeadlineExceededError({
52
+ deadlineMs: milliseconds(0),
53
+ flushBufferMs: computation.buffer,
54
+ remainingMs: computation.remaining
55
+ });
56
+ case "deadline": {
57
+ // `using` guarantees cleanup (clearTimeout) even if next() throws, the promise rejects,
58
+ // or an external abort signal fires — strictly more reliable than try/finally.
59
+ using timer = createDeadlineTimer(computation.value, config);
60
+ // oxlint-disable-next-line typescript/no-unsafe-type-assertion -- Smithy request is an opaque object; we access optional signal property
61
+ const request = args.request;
62
+ const signal = composeSignals(request?.signal, timer.controller.signal);
63
+ const result = await next({
64
+ ...args,
65
+ // oxlint-disable-next-line typescript/no-unsafe-type-assertion -- spreading opaque Smithy request to add signal
66
+ request: {
67
+ ...args.request,
68
+ signal
69
+ }
56
70
  });
57
- case "deadline": {
58
- using timer = createDeadlineTimer(computation.value, config);
59
- // oxlint-disable-next-line typescript/no-unsafe-type-assertion -- Smithy request is an opaque object; we access optional signal property
60
- const request = args.request;
61
- const signal = composeSignals(request?.signal, timer.controller.signal);
62
- const result = await next({
63
- ...args,
64
- // oxlint-disable-next-line typescript/no-unsafe-type-assertion -- spreading opaque Smithy request to add signal
65
- request: {
66
- ...args.request,
67
- signal
68
- }
69
- });
70
- return result;
71
- }
71
+ return result;
72
72
  }
73
- };
74
- }
73
+ }
74
+ };
75
75
 
76
76
  //# sourceMappingURL=middleware.js.map
@@ -1 +1 @@
1
- {"mappings":";;AAGA,SAAS,gCAAgC;AACzC,SAAS,6BAA6B;AAEtC,SAAS,oBAAoB;AAU7B,OAAO,SAAS,gBAAgB,QAAuD;CACrF,MAAM,YAAY,yBAAyB;CAE3C,IAAI,cAAc,WAAW;EAC3B,OAAO,EAAE,MAAM,aAAa;CAC9B;CAEA,MAAM,WAAW,YAAY,OAAO;CAEpC,IAAI,YAAY,GAAG;EACjB,OAAO;GACL,MAAM;GACN,WAAW,aAAa,SAAS;GACjC,QAAQ,OAAO;EACjB;CACF;;CAGA,OAAO;EAAE,MAAM;EAAY,OAAO;CAA8B;AAClE;AAOA,OAAO,SAAS,oBACd,YACA,QACe;CACf,MAAM,aAAa,IAAI,gBAAgB;CACvC,MAAM,YAAY,aAAa,aAAa,OAAO,aAAa;CAChE,MAAM,QAAQ,IAAI,sBAAsB;EACtC,YAAY,aAAa,UAAU;EACnC,eAAe,OAAO;EACtB,aAAa;CACf,CAAC;CACD,MAAM,YAAY,iBAAiB;EACjC,WAAW,MAAM,KAAK;CACxB,GAAG,UAAU;CACb,OAAO;EACL;EACA,CAAC,OAAO,WAAW;GACjB,aAAa,SAAS;EACxB;CACF;AACF;AAEA,OAAO,SAAS,eACd,UACA,UACa;CACb,IAAI,aAAa,WAAW,OAAO;CACnC,OAAO,YAAY,IAAI,CAAC,UAAU,QAAQ,CAAC;AAC7C;AAEA,OAAO,SAAS,0BACd,QAC2C;CAC3C,QACE,MACA,aAGA,OAAO,SAAmF;EACxF,MAAM,cAAc,gBAAgB,MAAM;EAE1C,QAAQ,YAAY,MAApB;GACE,KAAK,cACH,OAAO,KAAK,IAAI;GAElB,KAAK,qBACH,MAAM,IAAI,sBAAsB;IAC9B,YAAY,aAAa,CAAC;IAC1B,eAAe,YAAY;IAC3B,aAAa,YAAY;GAC3B,CAAC;GAEH,KAAK,YAAY;IACf,MAAM,QAAQ,oBAAoB,YAAY,OAAO,MAAM;;IAE3D,MAAM,UAAU,KAAK;IACrB,MAAM,SAAS,eAAe,SAAS,QAAQ,MAAM,WAAW,MAAM;IACtE,MAAM,SAAS,MAAM,KAAK;KACxB,GAAG;;KAEH,SAAS;MAAE,GAAI,KAAK;MAAoB;KAAO;IACjD,CAAC;IACD,OAAO;GACT;EACF;CACF;AACJ","names":[],"sources":["src/middleware.ts"],"version":3,"sourcesContent":["// SPDX-FileCopyrightText: 2024 lambda-deadline-middleware contributors\n// SPDX-License-Identifier: MIT\n\nimport { getRemainingTimeInMillis } from \"./context-store.js\";\nimport { DeadlineExceededError } from \"./error.js\";\nimport type { DeadlineComputation, DeadlineMiddlewareConfig, RequestDeadlineMs } from \"./types.js\";\nimport { milliseconds } from \"./types.js\";\n\nimport type {\n FinalizeHandler,\n FinalizeHandlerArguments,\n FinalizeHandlerOutput,\n FinalizeRequestMiddleware,\n HandlerExecutionContext,\n} from \"@smithy/types\";\n\nexport function computeDeadline(config: DeadlineMiddlewareConfig): DeadlineComputation {\n const remaining = getRemainingTimeInMillis();\n\n if (remaining === undefined) {\n return { kind: \"no-context\" };\n }\n\n const deadline = remaining - config.flushBufferMs;\n\n if (deadline <= 0) {\n return {\n kind: \"insufficient-time\",\n remaining: milliseconds(remaining),\n buffer: config.flushBufferMs,\n };\n }\n\n // oxlint-disable-next-line typescript/no-unsafe-type-assertion -- branded narrowing: deadline is validated > 0 above\n return { kind: \"deadline\", value: deadline as RequestDeadlineMs };\n}\n\nexport interface DeadlineTimer {\n readonly controller: AbortController;\n [Symbol.dispose]: () => void;\n}\n\nexport function createDeadlineTimer(\n deadlineMs: RequestDeadlineMs,\n config: DeadlineMiddlewareConfig,\n): DeadlineTimer {\n const controller = new AbortController();\n const remaining = milliseconds(deadlineMs + config.flushBufferMs);\n const error = new DeadlineExceededError({\n deadlineMs: milliseconds(deadlineMs),\n flushBufferMs: config.flushBufferMs,\n remainingMs: remaining,\n });\n const timeoutId = setTimeout(() => {\n controller.abort(error);\n }, deadlineMs);\n return {\n controller,\n [Symbol.dispose]() {\n clearTimeout(timeoutId);\n },\n };\n}\n\nexport function composeSignals(\n existing: AbortSignal | undefined,\n deadline: AbortSignal,\n): AbortSignal {\n if (existing === undefined) return deadline;\n return AbortSignal.any([existing, deadline]);\n}\n\nexport function deadlineMiddlewareHandler(\n config: DeadlineMiddlewareConfig,\n): FinalizeRequestMiddleware<object, object> {\n return (\n next: FinalizeHandler<object, object>,\n _context: HandlerExecutionContext,\n ): FinalizeHandler<object, object> =>\n // oxlint-disable-next-line typescript/consistent-return -- switch is exhaustive over DeadlineComputation discriminated union\n async (args: FinalizeHandlerArguments<object>): Promise<FinalizeHandlerOutput<object>> => {\n const computation = computeDeadline(config);\n\n switch (computation.kind) {\n case \"no-context\":\n return next(args);\n\n case \"insufficient-time\":\n throw new DeadlineExceededError({\n deadlineMs: milliseconds(0),\n flushBufferMs: computation.buffer,\n remainingMs: computation.remaining,\n });\n\n case \"deadline\": {\n using timer = createDeadlineTimer(computation.value, config);\n // oxlint-disable-next-line typescript/no-unsafe-type-assertion -- Smithy request is an opaque object; we access optional signal property\n const request = args.request as { signal?: AbortSignal } | undefined;\n const signal = composeSignals(request?.signal, timer.controller.signal);\n const result = await next({\n ...args,\n // oxlint-disable-next-line typescript/no-unsafe-type-assertion -- spreading opaque Smithy request to add signal\n request: { ...(args.request as object), signal },\n });\n return result;\n }\n }\n };\n}\n"]}
1
+ {"mappings":";;AAGA,SAAS,gCAAgC;AACzC,SAAS,6BAA6B;AAEtC,SAAS,oBAAoB;AAU7B,OAAO,MAAM,mBAAmB,WAA0D;CACxF,MAAM,YAAY,yBAAyB;CAE3C,IAAI,cAAc,WAAW;EAC3B,OAAO,EAAE,MAAM,aAAa;CAC9B;CAEA,MAAM,WAAW,YAAY,OAAO;CAEpC,IAAI,YAAY,GAAG;EACjB,OAAO;GACL,MAAM;GACN,WAAW,aAAa,SAAS;GACjC,QAAQ,OAAO;EACjB;CACF;;CAGA,OAAO;EAAE,MAAM;EAAY,OAAO;CAA8B;AAClE;AAOA,OAAO,MAAM,uBACX,YACA,WACkB;CAClB,MAAM,aAAa,IAAI,gBAAgB;CACvC,MAAM,YAAY,aAAa,aAAa,OAAO,aAAa;CAChE,MAAM,QAAQ,IAAI,sBAAsB;EACtC,YAAY,aAAa,UAAU;EACnC,eAAe,OAAO;EACtB,aAAa;CACf,CAAC;CACD,MAAM,YAAY,iBAAiB;EACjC,WAAW,MAAM,KAAK;CACxB,GAAG,UAAU;CACb,OAAO;EACL;EACA,CAAC,OAAO,WAAW;GACjB,aAAa,SAAS;EACxB;CACF;AACF;AAEA,OAAO,MAAM,kBACX,UACA,aACgB;CAChB,IAAI,aAAa,WAAW,OAAO;CACnC,OAAO,YAAY,IAAI,CAAC,UAAU,QAAQ,CAAC;AAC7C;AAEA,OAAO,MAAM,6BAET,YAGA,MACA,aAGF,OAAO,SAAkF;CACvF,MAAM,cAAc,gBAAgB,MAAM;CAE1C,QAAQ,YAAY,MAApB;EACE,KAAK,cACH,OAAO,KAAK,IAAI;EAElB,KAAK,qBACH,MAAM,IAAI,sBAAsB;GAC9B,YAAY,aAAa,CAAC;GAC1B,eAAe,YAAY;GAC3B,aAAa,YAAY;EAC3B,CAAC;EAEH,KAAK,YAAY;;;GAGf,MAAM,QAAQ,oBAAoB,YAAY,OAAO,MAAM;;GAE3D,MAAM,UAAU,KAAK;GACrB,MAAM,SAAS,eAAe,SAAS,QAAQ,MAAM,WAAW,MAAM;GACtE,MAAM,SAAS,MAAM,KAAK;IACxB,GAAG;;IAEH,SAAS;KAAE,GAAI,KAAK;KAAoB;IAAO;GACjD,CAAC;GACD,OAAO;EACT;CACF;AACF","names":[],"sources":["src/middleware.ts"],"version":3,"sourcesContent":["// SPDX-FileCopyrightText: 2026 lambda-deadline-middleware contributors\n// SPDX-License-Identifier: MIT\n\nimport { getRemainingTimeInMillis } from \"./context-store.js\";\nimport { DeadlineExceededError } from \"./error.js\";\nimport type { DeadlineComputation, DeadlineMiddlewareConfig, RequestDeadlineMs } from \"./types.js\";\nimport { milliseconds } from \"./types.js\";\n\nimport type {\n FinalizeHandler,\n FinalizeHandlerArguments,\n FinalizeHandlerOutput,\n FinalizeRequestMiddleware,\n HandlerExecutionContext,\n} from \"@smithy/types\";\n\nexport const computeDeadline = (config: DeadlineMiddlewareConfig): DeadlineComputation => {\n const remaining = getRemainingTimeInMillis();\n\n if (remaining === undefined) {\n return { kind: \"no-context\" };\n }\n\n const deadline = remaining - config.flushBufferMs;\n\n if (deadline <= 0) {\n return {\n kind: \"insufficient-time\",\n remaining: milliseconds(remaining),\n buffer: config.flushBufferMs,\n };\n }\n\n // oxlint-disable-next-line typescript/no-unsafe-type-assertion -- branded narrowing: deadline is validated > 0 above\n return { kind: \"deadline\", value: deadline as RequestDeadlineMs };\n};\n\nexport interface DeadlineTimer {\n readonly controller: AbortController;\n [Symbol.dispose]: () => void;\n}\n\nexport const createDeadlineTimer = (\n deadlineMs: RequestDeadlineMs,\n config: DeadlineMiddlewareConfig,\n): DeadlineTimer => {\n const controller = new AbortController();\n const remaining = milliseconds(deadlineMs + config.flushBufferMs);\n const error = new DeadlineExceededError({\n deadlineMs: milliseconds(deadlineMs),\n flushBufferMs: config.flushBufferMs,\n remainingMs: remaining,\n });\n const timeoutId = setTimeout(() => {\n controller.abort(error);\n }, deadlineMs);\n return {\n controller,\n [Symbol.dispose]() {\n clearTimeout(timeoutId);\n },\n };\n};\n\nexport const composeSignals = (\n existing: AbortSignal | undefined,\n deadline: AbortSignal,\n): AbortSignal => {\n if (existing === undefined) return deadline;\n return AbortSignal.any([existing, deadline]);\n};\n\nexport const deadlineMiddlewareHandler =\n <Input extends object, Output extends object>(\n config: DeadlineMiddlewareConfig,\n ): FinalizeRequestMiddleware<Input, Output> =>\n (\n next: FinalizeHandler<Input, Output>,\n _context: HandlerExecutionContext,\n ): FinalizeHandler<Input, Output> =>\n // oxlint-disable-next-line typescript/consistent-return -- switch is exhaustive over DeadlineComputation discriminated union\n async (args: FinalizeHandlerArguments<Input>): Promise<FinalizeHandlerOutput<Output>> => {\n const computation = computeDeadline(config);\n\n switch (computation.kind) {\n case \"no-context\":\n return next(args);\n\n case \"insufficient-time\":\n throw new DeadlineExceededError({\n deadlineMs: milliseconds(0),\n flushBufferMs: computation.buffer,\n remainingMs: computation.remaining,\n });\n\n case \"deadline\": {\n // `using` guarantees cleanup (clearTimeout) even if next() throws, the promise rejects,\n // or an external abort signal fires — strictly more reliable than try/finally.\n using timer = createDeadlineTimer(computation.value, config);\n // oxlint-disable-next-line typescript/no-unsafe-type-assertion -- Smithy request is an opaque object; we access optional signal property\n const request = args.request as { signal?: AbortSignal } | undefined;\n const signal = composeSignals(request?.signal, timer.controller.signal);\n const result = await next({\n ...args,\n // oxlint-disable-next-line typescript/no-unsafe-type-assertion -- spreading opaque Smithy request to add signal\n request: { ...(args.request as object), signal },\n });\n return result;\n }\n }\n };\n"]}
@@ -1,10 +1,8 @@
1
1
  import type { Pluggable } from "@smithy/types";
2
2
  import type { DeadlineOptions } from "./types.js";
3
- export declare function deadlineMiddleware(options?: DeadlineOptions): Pluggable<object, object>;
4
- export declare function withDeadline<T extends {
5
- middlewareStack: {
6
- use: (pluggable: Pluggable<any, any>) => void;
7
- };
8
- }>(client: T, options?: DeadlineOptions): T;
3
+ export declare const deadlineMiddleware: <
4
+ Input extends object,
5
+ Output extends object
6
+ >(options?: DeadlineOptions) => Pluggable<Input, Output>;
9
7
 
10
8
  //# sourceMappingURL=registration.d.ts.map
@@ -1 +1 @@
1
- {"mappings":"AAGA,cAAc,iBAAiB;AAI/B,cAAc,uBAAuB;AAErC,OAAO,iBAAS,mBAAmB,UAAU,kBAAkB;AAkB/D,OAAO,iBAAS,aAEd,UAAU;CAAE,iBAAiB;EAAE,MAAM,WAAW;CAA6B;AAAE,GAC/E,QAAQ,GAAG,UAAU,kBAAkB","names":[],"sources":["src/registration.ts"],"version":3,"sourcesContent":["// SPDX-FileCopyrightText: 2024 lambda-deadline-middleware contributors\n// SPDX-License-Identifier: MIT\n\nimport type { Pluggable } from \"@smithy/types\";\n\nimport { parseConfig } from \"./config.js\";\nimport { deadlineMiddlewareHandler } from \"./middleware.js\";\nimport type { DeadlineOptions } from \"./types.js\";\n\nexport function deadlineMiddleware(options?: DeadlineOptions): Pluggable<object, object> {\n const config = parseConfig(options);\n\n return {\n applyToStack(stack) {\n stack.add(deadlineMiddlewareHandler(config), {\n step: \"finalizeRequest\",\n name: \"deadlineMiddleware\",\n override: true,\n });\n },\n };\n}\n\n// WeakSet allows GC of discarded clients in long-running processes\n// while still preventing duplicate middleware registration.\nconst registeredClients = new WeakSet<object>();\n\nexport function withDeadline<\n // oxlint-disable-next-line typescript/no-explicit-any -- AWS SDK clients use varying ServiceInput/OutputTypes generics, making `any` the only correct constraint here\n T extends { middlewareStack: { use: (pluggable: Pluggable<any, any>) => void } },\n>(client: T, options?: DeadlineOptions): T {\n if (registeredClients.has(client)) return client;\n registeredClients.add(client);\n client.middlewareStack.use(deadlineMiddleware(options));\n return client;\n}\n"]}
1
+ {"mappings":"AAGA,cAAc,iBAAiB;AAI/B,cAAc,uBAAuB;AAErC,OAAO,cAAM;CAAsB;CAAsB;EACvD,UAAU,oBACT,UAAU,OAAO","names":[],"sources":["src/registration.ts"],"version":3,"sourcesContent":["// SPDX-FileCopyrightText: 2026 lambda-deadline-middleware contributors\n// SPDX-License-Identifier: MIT\n\nimport type { Pluggable } from \"@smithy/types\";\n\nimport { parseConfig } from \"./config.js\";\nimport { deadlineMiddlewareHandler } from \"./middleware.js\";\nimport type { DeadlineOptions } from \"./types.js\";\n\nexport const deadlineMiddleware = <Input extends object, Output extends object>(\n options?: DeadlineOptions,\n): Pluggable<Input, Output> => {\n const config = parseConfig(options);\n\n return {\n applyToStack(stack) {\n // Registered at \"finalizeRequest\" (attempt level) rather than API-call level so each retry gets a deadline\n // computed from the actual remaining time at that moment. API-call level would cache a stale deadline\n // across retries, which grow more dangerous after backoff delays eat into remaining time.\n stack.add(deadlineMiddlewareHandler<Input, Output>(config), {\n step: \"finalizeRequest\",\n name: \"deadlineMiddleware\",\n override: true,\n });\n },\n };\n};\n"]}
@@ -1,23 +1,17 @@
1
1
  import { parseConfig } from "./config.js";
2
2
  import { deadlineMiddlewareHandler } from "./middleware.js";
3
- export function deadlineMiddleware(options) {
3
+ export const deadlineMiddleware = (options) => {
4
4
  const config = parseConfig(options);
5
5
  return { applyToStack(stack) {
6
+ // Registered at "finalizeRequest" (attempt level) rather than API-call level so each retry gets a deadline
7
+ // computed from the actual remaining time at that moment. API-call level would cache a stale deadline
8
+ // across retries, which grow more dangerous after backoff delays eat into remaining time.
6
9
  stack.add(deadlineMiddlewareHandler(config), {
7
10
  step: "finalizeRequest",
8
11
  name: "deadlineMiddleware",
9
12
  override: true
10
13
  });
11
14
  } };
12
- }
13
- // WeakSet allows GC of discarded clients in long-running processes
14
- // while still preventing duplicate middleware registration.
15
- const registeredClients = new WeakSet();
16
- export function withDeadline(client, options) {
17
- if (registeredClients.has(client)) return client;
18
- registeredClients.add(client);
19
- client.middlewareStack.use(deadlineMiddleware(options));
20
- return client;
21
- }
15
+ };
22
16
 
23
17
  //# sourceMappingURL=registration.js.map
@@ -1 +1 @@
1
- {"mappings":"AAKA,SAAS,mBAAmB;AAC5B,SAAS,iCAAiC;AAG1C,OAAO,SAAS,mBAAmB,SAAsD;CACvF,MAAM,SAAS,YAAY,OAAO;CAElC,OAAO,EACL,aAAa,OAAO;EAClB,MAAM,IAAI,0BAA0B,MAAM,GAAG;GAC3C,MAAM;GACN,MAAM;GACN,UAAU;EACZ,CAAC;CACH,EACF;AACF;;;AAIA,MAAM,oBAAoB,IAAI,QAAgB;AAE9C,OAAO,SAAS,aAGd,QAAW,SAA8B;CACzC,IAAI,kBAAkB,IAAI,MAAM,GAAG,OAAO;CAC1C,kBAAkB,IAAI,MAAM;CAC5B,OAAO,gBAAgB,IAAI,mBAAmB,OAAO,CAAC;CACtD,OAAO;AACT","names":[],"sources":["src/registration.ts"],"version":3,"sourcesContent":["// SPDX-FileCopyrightText: 2024 lambda-deadline-middleware contributors\n// SPDX-License-Identifier: MIT\n\nimport type { Pluggable } from \"@smithy/types\";\n\nimport { parseConfig } from \"./config.js\";\nimport { deadlineMiddlewareHandler } from \"./middleware.js\";\nimport type { DeadlineOptions } from \"./types.js\";\n\nexport function deadlineMiddleware(options?: DeadlineOptions): Pluggable<object, object> {\n const config = parseConfig(options);\n\n return {\n applyToStack(stack) {\n stack.add(deadlineMiddlewareHandler(config), {\n step: \"finalizeRequest\",\n name: \"deadlineMiddleware\",\n override: true,\n });\n },\n };\n}\n\n// WeakSet allows GC of discarded clients in long-running processes\n// while still preventing duplicate middleware registration.\nconst registeredClients = new WeakSet<object>();\n\nexport function withDeadline<\n // oxlint-disable-next-line typescript/no-explicit-any -- AWS SDK clients use varying ServiceInput/OutputTypes generics, making `any` the only correct constraint here\n T extends { middlewareStack: { use: (pluggable: Pluggable<any, any>) => void } },\n>(client: T, options?: DeadlineOptions): T {\n if (registeredClients.has(client)) return client;\n registeredClients.add(client);\n client.middlewareStack.use(deadlineMiddleware(options));\n return client;\n}\n"]}
1
+ {"mappings":"AAKA,SAAS,mBAAmB;AAC5B,SAAS,iCAAiC;AAG1C,OAAO,MAAM,sBACX,YAC6B;CAC7B,MAAM,SAAS,YAAY,OAAO;CAElC,OAAO,EACL,aAAa,OAAO;;;;EAIlB,MAAM,IAAI,0BAAyC,MAAM,GAAG;GAC1D,MAAM;GACN,MAAM;GACN,UAAU;EACZ,CAAC;CACH,EACF;AACF","names":[],"sources":["src/registration.ts"],"version":3,"sourcesContent":["// SPDX-FileCopyrightText: 2026 lambda-deadline-middleware contributors\n// SPDX-License-Identifier: MIT\n\nimport type { Pluggable } from \"@smithy/types\";\n\nimport { parseConfig } from \"./config.js\";\nimport { deadlineMiddlewareHandler } from \"./middleware.js\";\nimport type { DeadlineOptions } from \"./types.js\";\n\nexport const deadlineMiddleware = <Input extends object, Output extends object>(\n options?: DeadlineOptions,\n): Pluggable<Input, Output> => {\n const config = parseConfig(options);\n\n return {\n applyToStack(stack) {\n // Registered at \"finalizeRequest\" (attempt level) rather than API-call level so each retry gets a deadline\n // computed from the actual remaining time at that moment. API-call level would cache a stale deadline\n // across retries, which grow more dangerous after backoff delays eat into remaining time.\n stack.add(deadlineMiddlewareHandler<Input, Output>(config), {\n step: \"finalizeRequest\",\n name: \"deadlineMiddleware\",\n override: true,\n });\n },\n };\n};\n"]}
@@ -1,5 +1,5 @@
1
1
  import type { DeadlineExceededError } from "./error.js";
2
2
  import type { DeadlineMiddlewareConfig } from "./types.js";
3
- export declare function emitDeadlineAbort(error: DeadlineExceededError, config: DeadlineMiddlewareConfig): Promise<void>;
3
+ export declare const emitDeadlineAbort: (error: DeadlineExceededError, config: DeadlineMiddlewareConfig) => Promise<void>;
4
4
 
5
5
  //# sourceMappingURL=telemetry.d.ts.map
@@ -1 +1 @@
1
- {"mappings":"AAGA,cAAc,6BAA6B;AAC3C,cAAc,gCAAgC;AAwG9C,OAAO,iBAAe,kBACpB,OAAO,uBACP,QAAQ,2BACP","names":[],"sources":["src/telemetry.ts"],"version":3,"sourcesContent":["// SPDX-FileCopyrightText: 2024 lambda-deadline-middleware contributors\n// SPDX-License-Identifier: MIT\n\nimport type { DeadlineExceededError } from \"./error.js\";\nimport type { DeadlineMiddlewareConfig } from \"./types.js\";\n\ninterface AbortDetails {\n readonly deadlineMs: number;\n readonly flushBufferMs: number;\n readonly remainingMs: number;\n}\n\ninterface TelemetryEmitter {\n recordDeadlineAbort: (details: AbortDetails) => void;\n setDeadlineErrorStatus: (error: DeadlineExceededError) => void;\n}\n\nlet emitter: TelemetryEmitter | undefined;\nlet detected = false;\n\nasync function detectEmitter(): Promise<TelemetryEmitter | undefined> {\n if (detected) return emitter;\n detected = true;\n\n try {\n // Variable indirection prevents TypeScript from resolving the module\n // at compile time — keeps @opentelemetry/api as a purely optional runtime dep.\n const moduleName = \"@opentelemetry/api\";\n // oxlint-disable-next-line typescript/no-unsafe-assignment -- dynamic import of optional runtime dependency\n const otelApi: Record<string, unknown> = await import(/* webpackIgnore: true */ moduleName);\n // oxlint-disable-next-line typescript/no-unsafe-type-assertion -- duck-typing optional OTel API surface\n const trace = otelApi[\"trace\"] as { getActiveSpan: () => unknown } | undefined;\n\n // oxlint-disable-next-line typescript/no-unsafe-type-assertion -- duck-typing optional OTel API surface\n const SpanStatusCode = otelApi[\"SpanStatusCode\"] as\n | {\n ERROR: number;\n }\n | undefined;\n\n if (!trace || !SpanStatusCode) {\n emitter = undefined;\n return emitter;\n }\n\n emitter = {\n recordDeadlineAbort(details: AbortDetails): void {\n try {\n // oxlint-disable-next-line typescript/no-unsafe-type-assertion -- duck-typing OTel span from untyped getActiveSpan()\n const span = trace.getActiveSpan() as Record<string, unknown> | undefined;\n if (!span) return;\n\n // oxlint-disable-next-line typescript/no-unsafe-type-assertion -- duck-typing OTel span.addEvent method\n const addEvent = span[\"addEvent\"] as\n | ((name: string, attributes: Record<string, unknown>) => void)\n | undefined;\n if (typeof addEvent !== \"function\") return;\n\n addEvent.call(span, \"lambda-deadline-middleware.abort\", {\n \"deadline.duration_ms\": details.deadlineMs,\n \"deadline.flush_buffer_ms\": details.flushBufferMs,\n \"deadline.remaining_ms\": details.remainingMs,\n });\n } catch {\n // Telemetry must never disrupt request processing\n }\n },\n\n setDeadlineErrorStatus(error: DeadlineExceededError): void {\n try {\n // oxlint-disable-next-line typescript/no-unsafe-type-assertion -- duck-typing OTel span from untyped getActiveSpan()\n const span = trace.getActiveSpan() as Record<string, unknown> | undefined;\n if (!span) return;\n\n // oxlint-disable-next-line typescript/no-unsafe-type-assertion -- duck-typing OTel span.setStatus method\n const setStatus = span[\"setStatus\"] as\n | ((status: { code: number; message: string }) => void)\n | undefined;\n // oxlint-disable-next-line typescript/no-unsafe-type-assertion -- duck-typing OTel span.setAttribute method\n const setAttribute = span[\"setAttribute\"] as\n | ((key: string, value: unknown) => void)\n | undefined;\n\n if (typeof setStatus === \"function\") {\n setStatus.call(span, {\n code: SpanStatusCode.ERROR,\n message: error.message,\n });\n }\n\n if (typeof setAttribute === \"function\") {\n setAttribute.call(span, \"error.type\", \"DeadlineExceededError\");\n setAttribute.call(span, \"deadline.duration_ms\", error.deadlineMs);\n setAttribute.call(span, \"deadline.flush_buffer_ms\", error.flushBufferMs);\n setAttribute.call(span, \"deadline.remaining_ms\", error.remainingMs);\n }\n } catch {\n // Telemetry must never disrupt request processing\n }\n },\n };\n } catch {\n emitter = undefined;\n }\n\n return emitter;\n}\n\nexport async function emitDeadlineAbort(\n error: DeadlineExceededError,\n config: DeadlineMiddlewareConfig,\n): Promise<void> {\n try {\n if (!config.telemetryEnabled) return;\n\n const em = await detectEmitter();\n if (!em) return;\n\n em.recordDeadlineAbort({\n deadlineMs: error.deadlineMs,\n flushBufferMs: error.flushBufferMs,\n remainingMs: error.remainingMs,\n });\n\n em.setDeadlineErrorStatus(error);\n } catch {\n // Telemetry must never disrupt request processing\n }\n}\n"]}
1
+ {"mappings":"AAGA,cAAc,6BAA6B;AAC3C,cAAc,gCAAgC;AA2G9C,OAAO,cAAM,oBACX,OAAO,uBACP,QAAQ,6BACP","names":[],"sources":["src/telemetry.ts"],"version":3,"sourcesContent":["// SPDX-FileCopyrightText: 2026 lambda-deadline-middleware contributors\n// SPDX-License-Identifier: MIT\n\nimport type { DeadlineExceededError } from \"./error.js\";\nimport type { DeadlineMiddlewareConfig } from \"./types.js\";\n\n// OpenTelemetry is detected dynamically rather than declared as a peerDependency.\n// This avoids forcing all consumers to install @opentelemetry/api or suppress peer warnings.\n// Detection happens once at first use and the result is cached for the process lifetime.\ninterface AbortDetails {\n readonly deadlineMs: number;\n readonly flushBufferMs: number;\n readonly remainingMs: number;\n}\n\ninterface TelemetryEmitter {\n recordDeadlineAbort: (details: AbortDetails) => void;\n setDeadlineErrorStatus: (error: DeadlineExceededError) => void;\n}\n\nlet emitter: TelemetryEmitter | undefined;\nlet detected = false;\n\nconst detectEmitter = async (): Promise<TelemetryEmitter | undefined> => {\n if (detected) return emitter;\n detected = true;\n\n try {\n // Variable indirection prevents TypeScript from resolving the module\n // at compile time — keeps @opentelemetry/api as a purely optional runtime dep.\n const moduleName = \"@opentelemetry/api\";\n // oxlint-disable-next-line typescript/no-unsafe-assignment -- dynamic import of optional runtime dependency\n const otelApi: Record<string, unknown> = await import(/* webpackIgnore: true */ moduleName);\n // oxlint-disable-next-line typescript/no-unsafe-type-assertion -- duck-typing optional OTel API surface\n const trace = otelApi[\"trace\"] as { getActiveSpan: () => unknown } | undefined;\n\n // oxlint-disable-next-line typescript/no-unsafe-type-assertion -- duck-typing optional OTel API surface\n const SpanStatusCode = otelApi[\"SpanStatusCode\"] as\n | {\n ERROR: number;\n }\n | undefined;\n\n if (!trace || !SpanStatusCode) {\n emitter = undefined;\n return emitter;\n }\n\n emitter = {\n recordDeadlineAbort(details: AbortDetails): void {\n try {\n // oxlint-disable-next-line typescript/no-unsafe-type-assertion -- duck-typing OTel span from untyped getActiveSpan()\n const span = trace.getActiveSpan() as Record<string, unknown> | undefined;\n if (!span) return;\n\n // oxlint-disable-next-line typescript/no-unsafe-type-assertion -- duck-typing OTel span.addEvent method\n const addEvent = span[\"addEvent\"] as\n | ((name: string, attributes: Record<string, unknown>) => void)\n | undefined;\n if (typeof addEvent !== \"function\") return;\n\n addEvent.call(span, \"lambda-deadline-middleware.abort\", {\n \"deadline.duration_ms\": details.deadlineMs,\n \"deadline.flush_buffer_ms\": details.flushBufferMs,\n \"deadline.remaining_ms\": details.remainingMs,\n });\n } catch {\n // Telemetry must never disrupt request processing\n }\n },\n\n setDeadlineErrorStatus(error: DeadlineExceededError): void {\n try {\n // oxlint-disable-next-line typescript/no-unsafe-type-assertion -- duck-typing OTel span from untyped getActiveSpan()\n const span = trace.getActiveSpan() as Record<string, unknown> | undefined;\n if (!span) return;\n\n // oxlint-disable-next-line typescript/no-unsafe-type-assertion -- duck-typing OTel span.setStatus method\n const setStatus = span[\"setStatus\"] as\n | ((status: { code: number; message: string }) => void)\n | undefined;\n // oxlint-disable-next-line typescript/no-unsafe-type-assertion -- duck-typing OTel span.setAttribute method\n const setAttribute = span[\"setAttribute\"] as\n | ((key: string, value: unknown) => void)\n | undefined;\n\n if (typeof setStatus === \"function\") {\n setStatus.call(span, {\n code: SpanStatusCode.ERROR,\n message: error.message,\n });\n }\n\n if (typeof setAttribute === \"function\") {\n setAttribute.call(span, \"error.type\", \"DeadlineExceededError\");\n setAttribute.call(span, \"deadline.duration_ms\", error.deadlineMs);\n setAttribute.call(span, \"deadline.flush_buffer_ms\", error.flushBufferMs);\n setAttribute.call(span, \"deadline.remaining_ms\", error.remainingMs);\n }\n } catch {\n // Telemetry must never disrupt request processing\n }\n },\n };\n } catch {\n emitter = undefined;\n }\n\n return emitter;\n};\n\nexport const emitDeadlineAbort = async (\n error: DeadlineExceededError,\n config: DeadlineMiddlewareConfig,\n): Promise<void> => {\n try {\n if (!config.telemetryEnabled) return;\n\n const em = await detectEmitter();\n if (!em) return;\n\n em.recordDeadlineAbort({\n deadlineMs: error.deadlineMs,\n flushBufferMs: error.flushBufferMs,\n remainingMs: error.remainingMs,\n });\n\n em.setDeadlineErrorStatus(error);\n } catch {\n // Telemetry must never disrupt request processing\n }\n};\n"]}
package/dist/telemetry.js CHANGED
@@ -1,6 +1,6 @@
1
1
  let emitter;
2
2
  let detected = false;
3
- async function detectEmitter() {
3
+ const detectEmitter = async () => {
4
4
  if (detected) return emitter;
5
5
  detected = true;
6
6
  try {
@@ -64,8 +64,8 @@ async function detectEmitter() {
64
64
  emitter = undefined;
65
65
  }
66
66
  return emitter;
67
- }
68
- export async function emitDeadlineAbort(error, config) {
67
+ };
68
+ export const emitDeadlineAbort = async (error, config) => {
69
69
  try {
70
70
  if (!config.telemetryEnabled) return;
71
71
  const em = await detectEmitter();
@@ -77,6 +77,6 @@ export async function emitDeadlineAbort(error, config) {
77
77
  });
78
78
  em.setDeadlineErrorStatus(error);
79
79
  } catch {}
80
- }
80
+ };
81
81
 
82
82
  //# sourceMappingURL=telemetry.js.map
@@ -1 +1 @@
1
- {"mappings":"AAiBA,IAAI;AACJ,IAAI,WAAW;AAEf,eAAe,gBAAuD;CACpE,IAAI,UAAU,OAAO;CACrB,WAAW;CAEX,IAAI;;;EAGF,MAAM,aAAa;;EAEnB,MAAM,UAAmC,MAAM;;GAAiC;;;EAEhF,MAAM,QAAQ,QAAQ;;EAGtB,MAAM,iBAAiB,QAAQ;EAM/B,IAAI,CAAC,SAAS,CAAC,gBAAgB;GAC7B,UAAU;GACV,OAAO;EACT;EAEA,UAAU;GACR,oBAAoB,SAA6B;IAC/C,IAAI;;KAEF,MAAM,OAAO,MAAM,cAAc;KACjC,IAAI,CAAC,MAAM;;KAGX,MAAM,WAAW,KAAK;KAGtB,IAAI,OAAO,aAAa,YAAY;KAEpC,SAAS,KAAK,MAAM,oCAAoC;MACtD,wBAAwB,QAAQ;MAChC,4BAA4B,QAAQ;MACpC,yBAAyB,QAAQ;KACnC,CAAC;IACH,QAAQ,CAER;GACF;GAEA,uBAAuB,OAAoC;IACzD,IAAI;;KAEF,MAAM,OAAO,MAAM,cAAc;KACjC,IAAI,CAAC,MAAM;;KAGX,MAAM,YAAY,KAAK;;KAIvB,MAAM,eAAe,KAAK;KAI1B,IAAI,OAAO,cAAc,YAAY;MACnC,UAAU,KAAK,MAAM;OACnB,MAAM,eAAe;OACrB,SAAS,MAAM;MACjB,CAAC;KACH;KAEA,IAAI,OAAO,iBAAiB,YAAY;MACtC,aAAa,KAAK,MAAM,cAAc,uBAAuB;MAC7D,aAAa,KAAK,MAAM,wBAAwB,MAAM,UAAU;MAChE,aAAa,KAAK,MAAM,4BAA4B,MAAM,aAAa;MACvE,aAAa,KAAK,MAAM,yBAAyB,MAAM,WAAW;KACpE;IACF,QAAQ,CAER;GACF;EACF;CACF,QAAQ;EACN,UAAU;CACZ;CAEA,OAAO;AACT;AAEA,OAAO,eAAe,kBACpB,OACA,QACe;CACf,IAAI;EACF,IAAI,CAAC,OAAO,kBAAkB;EAE9B,MAAM,KAAK,MAAM,cAAc;EAC/B,IAAI,CAAC,IAAI;EAET,GAAG,oBAAoB;GACrB,YAAY,MAAM;GAClB,eAAe,MAAM;GACrB,aAAa,MAAM;EACrB,CAAC;EAED,GAAG,uBAAuB,KAAK;CACjC,QAAQ,CAER;AACF","names":[],"sources":["src/telemetry.ts"],"version":3,"sourcesContent":["// SPDX-FileCopyrightText: 2024 lambda-deadline-middleware contributors\n// SPDX-License-Identifier: MIT\n\nimport type { DeadlineExceededError } from \"./error.js\";\nimport type { DeadlineMiddlewareConfig } from \"./types.js\";\n\ninterface AbortDetails {\n readonly deadlineMs: number;\n readonly flushBufferMs: number;\n readonly remainingMs: number;\n}\n\ninterface TelemetryEmitter {\n recordDeadlineAbort: (details: AbortDetails) => void;\n setDeadlineErrorStatus: (error: DeadlineExceededError) => void;\n}\n\nlet emitter: TelemetryEmitter | undefined;\nlet detected = false;\n\nasync function detectEmitter(): Promise<TelemetryEmitter | undefined> {\n if (detected) return emitter;\n detected = true;\n\n try {\n // Variable indirection prevents TypeScript from resolving the module\n // at compile time — keeps @opentelemetry/api as a purely optional runtime dep.\n const moduleName = \"@opentelemetry/api\";\n // oxlint-disable-next-line typescript/no-unsafe-assignment -- dynamic import of optional runtime dependency\n const otelApi: Record<string, unknown> = await import(/* webpackIgnore: true */ moduleName);\n // oxlint-disable-next-line typescript/no-unsafe-type-assertion -- duck-typing optional OTel API surface\n const trace = otelApi[\"trace\"] as { getActiveSpan: () => unknown } | undefined;\n\n // oxlint-disable-next-line typescript/no-unsafe-type-assertion -- duck-typing optional OTel API surface\n const SpanStatusCode = otelApi[\"SpanStatusCode\"] as\n | {\n ERROR: number;\n }\n | undefined;\n\n if (!trace || !SpanStatusCode) {\n emitter = undefined;\n return emitter;\n }\n\n emitter = {\n recordDeadlineAbort(details: AbortDetails): void {\n try {\n // oxlint-disable-next-line typescript/no-unsafe-type-assertion -- duck-typing OTel span from untyped getActiveSpan()\n const span = trace.getActiveSpan() as Record<string, unknown> | undefined;\n if (!span) return;\n\n // oxlint-disable-next-line typescript/no-unsafe-type-assertion -- duck-typing OTel span.addEvent method\n const addEvent = span[\"addEvent\"] as\n | ((name: string, attributes: Record<string, unknown>) => void)\n | undefined;\n if (typeof addEvent !== \"function\") return;\n\n addEvent.call(span, \"lambda-deadline-middleware.abort\", {\n \"deadline.duration_ms\": details.deadlineMs,\n \"deadline.flush_buffer_ms\": details.flushBufferMs,\n \"deadline.remaining_ms\": details.remainingMs,\n });\n } catch {\n // Telemetry must never disrupt request processing\n }\n },\n\n setDeadlineErrorStatus(error: DeadlineExceededError): void {\n try {\n // oxlint-disable-next-line typescript/no-unsafe-type-assertion -- duck-typing OTel span from untyped getActiveSpan()\n const span = trace.getActiveSpan() as Record<string, unknown> | undefined;\n if (!span) return;\n\n // oxlint-disable-next-line typescript/no-unsafe-type-assertion -- duck-typing OTel span.setStatus method\n const setStatus = span[\"setStatus\"] as\n | ((status: { code: number; message: string }) => void)\n | undefined;\n // oxlint-disable-next-line typescript/no-unsafe-type-assertion -- duck-typing OTel span.setAttribute method\n const setAttribute = span[\"setAttribute\"] as\n | ((key: string, value: unknown) => void)\n | undefined;\n\n if (typeof setStatus === \"function\") {\n setStatus.call(span, {\n code: SpanStatusCode.ERROR,\n message: error.message,\n });\n }\n\n if (typeof setAttribute === \"function\") {\n setAttribute.call(span, \"error.type\", \"DeadlineExceededError\");\n setAttribute.call(span, \"deadline.duration_ms\", error.deadlineMs);\n setAttribute.call(span, \"deadline.flush_buffer_ms\", error.flushBufferMs);\n setAttribute.call(span, \"deadline.remaining_ms\", error.remainingMs);\n }\n } catch {\n // Telemetry must never disrupt request processing\n }\n },\n };\n } catch {\n emitter = undefined;\n }\n\n return emitter;\n}\n\nexport async function emitDeadlineAbort(\n error: DeadlineExceededError,\n config: DeadlineMiddlewareConfig,\n): Promise<void> {\n try {\n if (!config.telemetryEnabled) return;\n\n const em = await detectEmitter();\n if (!em) return;\n\n em.recordDeadlineAbort({\n deadlineMs: error.deadlineMs,\n flushBufferMs: error.flushBufferMs,\n remainingMs: error.remainingMs,\n });\n\n em.setDeadlineErrorStatus(error);\n } catch {\n // Telemetry must never disrupt request processing\n }\n}\n"]}
1
+ {"mappings":"AAoBA,IAAI;AACJ,IAAI,WAAW;AAEf,MAAM,gBAAgB,YAAmD;CACvE,IAAI,UAAU,OAAO;CACrB,WAAW;CAEX,IAAI;;;EAGF,MAAM,aAAa;;EAEnB,MAAM,UAAmC,MAAM;;GAAiC;;;EAEhF,MAAM,QAAQ,QAAQ;;EAGtB,MAAM,iBAAiB,QAAQ;EAM/B,IAAI,CAAC,SAAS,CAAC,gBAAgB;GAC7B,UAAU;GACV,OAAO;EACT;EAEA,UAAU;GACR,oBAAoB,SAA6B;IAC/C,IAAI;;KAEF,MAAM,OAAO,MAAM,cAAc;KACjC,IAAI,CAAC,MAAM;;KAGX,MAAM,WAAW,KAAK;KAGtB,IAAI,OAAO,aAAa,YAAY;KAEpC,SAAS,KAAK,MAAM,oCAAoC;MACtD,wBAAwB,QAAQ;MAChC,4BAA4B,QAAQ;MACpC,yBAAyB,QAAQ;KACnC,CAAC;IACH,QAAQ,CAER;GACF;GAEA,uBAAuB,OAAoC;IACzD,IAAI;;KAEF,MAAM,OAAO,MAAM,cAAc;KACjC,IAAI,CAAC,MAAM;;KAGX,MAAM,YAAY,KAAK;;KAIvB,MAAM,eAAe,KAAK;KAI1B,IAAI,OAAO,cAAc,YAAY;MACnC,UAAU,KAAK,MAAM;OACnB,MAAM,eAAe;OACrB,SAAS,MAAM;MACjB,CAAC;KACH;KAEA,IAAI,OAAO,iBAAiB,YAAY;MACtC,aAAa,KAAK,MAAM,cAAc,uBAAuB;MAC7D,aAAa,KAAK,MAAM,wBAAwB,MAAM,UAAU;MAChE,aAAa,KAAK,MAAM,4BAA4B,MAAM,aAAa;MACvE,aAAa,KAAK,MAAM,yBAAyB,MAAM,WAAW;KACpE;IACF,QAAQ,CAER;GACF;EACF;CACF,QAAQ;EACN,UAAU;CACZ;CAEA,OAAO;AACT;AAEA,OAAO,MAAM,oBAAoB,OAC/B,OACA,WACkB;CAClB,IAAI;EACF,IAAI,CAAC,OAAO,kBAAkB;EAE9B,MAAM,KAAK,MAAM,cAAc;EAC/B,IAAI,CAAC,IAAI;EAET,GAAG,oBAAoB;GACrB,YAAY,MAAM;GAClB,eAAe,MAAM;GACrB,aAAa,MAAM;EACrB,CAAC;EAED,GAAG,uBAAuB,KAAK;CACjC,QAAQ,CAER;AACF","names":[],"sources":["src/telemetry.ts"],"version":3,"sourcesContent":["// SPDX-FileCopyrightText: 2026 lambda-deadline-middleware contributors\n// SPDX-License-Identifier: MIT\n\nimport type { DeadlineExceededError } from \"./error.js\";\nimport type { DeadlineMiddlewareConfig } from \"./types.js\";\n\n// OpenTelemetry is detected dynamically rather than declared as a peerDependency.\n// This avoids forcing all consumers to install @opentelemetry/api or suppress peer warnings.\n// Detection happens once at first use and the result is cached for the process lifetime.\ninterface AbortDetails {\n readonly deadlineMs: number;\n readonly flushBufferMs: number;\n readonly remainingMs: number;\n}\n\ninterface TelemetryEmitter {\n recordDeadlineAbort: (details: AbortDetails) => void;\n setDeadlineErrorStatus: (error: DeadlineExceededError) => void;\n}\n\nlet emitter: TelemetryEmitter | undefined;\nlet detected = false;\n\nconst detectEmitter = async (): Promise<TelemetryEmitter | undefined> => {\n if (detected) return emitter;\n detected = true;\n\n try {\n // Variable indirection prevents TypeScript from resolving the module\n // at compile time — keeps @opentelemetry/api as a purely optional runtime dep.\n const moduleName = \"@opentelemetry/api\";\n // oxlint-disable-next-line typescript/no-unsafe-assignment -- dynamic import of optional runtime dependency\n const otelApi: Record<string, unknown> = await import(/* webpackIgnore: true */ moduleName);\n // oxlint-disable-next-line typescript/no-unsafe-type-assertion -- duck-typing optional OTel API surface\n const trace = otelApi[\"trace\"] as { getActiveSpan: () => unknown } | undefined;\n\n // oxlint-disable-next-line typescript/no-unsafe-type-assertion -- duck-typing optional OTel API surface\n const SpanStatusCode = otelApi[\"SpanStatusCode\"] as\n | {\n ERROR: number;\n }\n | undefined;\n\n if (!trace || !SpanStatusCode) {\n emitter = undefined;\n return emitter;\n }\n\n emitter = {\n recordDeadlineAbort(details: AbortDetails): void {\n try {\n // oxlint-disable-next-line typescript/no-unsafe-type-assertion -- duck-typing OTel span from untyped getActiveSpan()\n const span = trace.getActiveSpan() as Record<string, unknown> | undefined;\n if (!span) return;\n\n // oxlint-disable-next-line typescript/no-unsafe-type-assertion -- duck-typing OTel span.addEvent method\n const addEvent = span[\"addEvent\"] as\n | ((name: string, attributes: Record<string, unknown>) => void)\n | undefined;\n if (typeof addEvent !== \"function\") return;\n\n addEvent.call(span, \"lambda-deadline-middleware.abort\", {\n \"deadline.duration_ms\": details.deadlineMs,\n \"deadline.flush_buffer_ms\": details.flushBufferMs,\n \"deadline.remaining_ms\": details.remainingMs,\n });\n } catch {\n // Telemetry must never disrupt request processing\n }\n },\n\n setDeadlineErrorStatus(error: DeadlineExceededError): void {\n try {\n // oxlint-disable-next-line typescript/no-unsafe-type-assertion -- duck-typing OTel span from untyped getActiveSpan()\n const span = trace.getActiveSpan() as Record<string, unknown> | undefined;\n if (!span) return;\n\n // oxlint-disable-next-line typescript/no-unsafe-type-assertion -- duck-typing OTel span.setStatus method\n const setStatus = span[\"setStatus\"] as\n | ((status: { code: number; message: string }) => void)\n | undefined;\n // oxlint-disable-next-line typescript/no-unsafe-type-assertion -- duck-typing OTel span.setAttribute method\n const setAttribute = span[\"setAttribute\"] as\n | ((key: string, value: unknown) => void)\n | undefined;\n\n if (typeof setStatus === \"function\") {\n setStatus.call(span, {\n code: SpanStatusCode.ERROR,\n message: error.message,\n });\n }\n\n if (typeof setAttribute === \"function\") {\n setAttribute.call(span, \"error.type\", \"DeadlineExceededError\");\n setAttribute.call(span, \"deadline.duration_ms\", error.deadlineMs);\n setAttribute.call(span, \"deadline.flush_buffer_ms\", error.flushBufferMs);\n setAttribute.call(span, \"deadline.remaining_ms\", error.remainingMs);\n }\n } catch {\n // Telemetry must never disrupt request processing\n }\n },\n };\n } catch {\n emitter = undefined;\n }\n\n return emitter;\n};\n\nexport const emitDeadlineAbort = async (\n error: DeadlineExceededError,\n config: DeadlineMiddlewareConfig,\n): Promise<void> => {\n try {\n if (!config.telemetryEnabled) return;\n\n const em = await detectEmitter();\n if (!em) return;\n\n em.recordDeadlineAbort({\n deadlineMs: error.deadlineMs,\n flushBufferMs: error.flushBufferMs,\n remainingMs: error.remainingMs,\n });\n\n em.setDeadlineErrorStatus(error);\n } catch {\n // Telemetry must never disrupt request processing\n }\n};\n"]}
package/dist/types.d.ts CHANGED
@@ -8,8 +8,8 @@ type Brand<
8
8
  export type Milliseconds = Brand<number, "Milliseconds">;
9
9
  export type FlushBufferMs = Brand<number, "FlushBufferMs">;
10
10
  export type RequestDeadlineMs = Brand<number, "RequestDeadlineMs">;
11
- export declare function milliseconds(value: number): Milliseconds;
12
- export declare function flushBufferMs(value: number): FlushBufferMs;
11
+ export declare const milliseconds: (value: number) => Milliseconds;
12
+ export declare const flushBufferMs: (value: number) => FlushBufferMs;
13
13
  export type DeadlineComputation = {
14
14
  readonly kind: "deadline";
15
15
  readonly value: RequestDeadlineMs;
@@ -1 +1 @@
1
- {"mappings":"AAGA,cAAc;KAET;CAAM;CAAG;IAAoB,IAAI;WAAY,cAAc;AAAE;AAElE,YAAY,eAAe,cAAc;AAEzC,YAAY,gBAAgB,cAAc;AAE1C,YAAY,oBAAoB,cAAc;AAE9C,OAAO,iBAAS,aAAa,gBAAgB;AAQ7C,OAAO,iBAAS,cAAc,gBAAgB;AAW9C,YAAY,sBACR;UAAW,MAAM;UAAqB,OAAO;AAAkB,IAC/D;UACW,MAAM;UACN,WAAW;UACX,QAAQ;AACnB,IACA;UAAW,MAAM;AAAa;AAElC,iBAAiB,yBAAyB;UAC/B,eAAe;UACf;AACX;AAEA,iBAAiB,gBAAgB;UACtB;UACA;AACX","names":[],"sources":["src/types.ts"],"version":3,"sourcesContent":["// SPDX-FileCopyrightText: 2024 lambda-deadline-middleware contributors\n// SPDX-License-Identifier: MIT\n\ndeclare const BrandSymbol: unique symbol;\n\ntype Brand<T, B extends string> = T & { readonly [BrandSymbol]: B };\n\nexport type Milliseconds = Brand<number, \"Milliseconds\">;\n\nexport type FlushBufferMs = Brand<number, \"FlushBufferMs\">;\n\nexport type RequestDeadlineMs = Brand<number, \"RequestDeadlineMs\">;\n\nexport function milliseconds(value: number): Milliseconds {\n if (!Number.isFinite(value)) {\n throw new TypeError(`milliseconds value must be finite, received: ${value}`);\n }\n // oxlint-disable-next-line typescript/no-unsafe-type-assertion -- branded type constructor: value is validated above\n return value as Milliseconds;\n}\n\nexport function flushBufferMs(value: number): FlushBufferMs {\n if (!Number.isFinite(value)) {\n throw new TypeError(`flushBufferMs value must be finite, received: ${value}`);\n }\n if (value < 0) {\n throw new TypeError(`flushBufferMs must be non-negative, received: ${value}`);\n }\n // oxlint-disable-next-line typescript/no-unsafe-type-assertion -- branded type constructor: value is validated above\n return value as FlushBufferMs;\n}\n\nexport type DeadlineComputation =\n | { readonly kind: \"deadline\"; readonly value: RequestDeadlineMs }\n | {\n readonly kind: \"insufficient-time\";\n readonly remaining: Milliseconds;\n readonly buffer: FlushBufferMs;\n }\n | { readonly kind: \"no-context\" };\n\nexport interface DeadlineMiddlewareConfig {\n readonly flushBufferMs: FlushBufferMs;\n readonly telemetryEnabled: boolean;\n}\n\nexport interface DeadlineOptions {\n readonly flushBufferMs?: number;\n readonly telemetryEnabled?: boolean;\n}\n"]}
1
+ {"mappings":"AAKA,cAAc;KAET;CAAM;CAAG;IAAoB,IAAI;WAAY,cAAc;AAAE;AAElE,YAAY,eAAe,cAAc;AAEzC,YAAY,gBAAgB,cAAc;AAE1C,YAAY,oBAAoB,cAAc;AAE9C,OAAO,cAAM,eAAgB,kBAAgB;AAQ7C,OAAO,cAAM,gBAAiB,kBAAgB;AAW9C,YAAY,sBACR;UAAW,MAAM;UAAqB,OAAO;AAAkB,IAC/D;UACW,MAAM;UACN,WAAW;UACX,QAAQ;AACnB,IACA;UAAW,MAAM;AAAa;AAElC,iBAAiB,yBAAyB;UAC/B,eAAe;UACf;AACX;AAEA,iBAAiB,gBAAgB;UACtB;UACA;AACX","names":[],"sources":["src/types.ts"],"version":3,"sourcesContent":["// SPDX-FileCopyrightText: 2026 lambda-deadline-middleware contributors\n// SPDX-License-Identifier: MIT\n\n// Branded types prevent interchange errors at compile time (e.g. passing seconds where milliseconds are expected).\n// Zero runtime cost. Smart constructors below validate at the boundary and brand the value.\ndeclare const BrandSymbol: unique symbol;\n\ntype Brand<T, B extends string> = T & { readonly [BrandSymbol]: B };\n\nexport type Milliseconds = Brand<number, \"Milliseconds\">;\n\nexport type FlushBufferMs = Brand<number, \"FlushBufferMs\">;\n\nexport type RequestDeadlineMs = Brand<number, \"RequestDeadlineMs\">;\n\nexport const milliseconds = (value: number): Milliseconds => {\n if (!Number.isFinite(value)) {\n throw new TypeError(`milliseconds value must be finite, received: ${value}`);\n }\n // oxlint-disable-next-line typescript/no-unsafe-type-assertion -- branded type constructor: value is validated above\n return value as Milliseconds;\n};\n\nexport const flushBufferMs = (value: number): FlushBufferMs => {\n if (!Number.isFinite(value)) {\n throw new TypeError(`flushBufferMs value must be finite, received: ${value}`);\n }\n if (value < 0) {\n throw new TypeError(`flushBufferMs must be non-negative, received: ${value}`);\n }\n // oxlint-disable-next-line typescript/no-unsafe-type-assertion -- branded type constructor: value is validated above\n return value as FlushBufferMs;\n};\n\nexport type DeadlineComputation =\n | { readonly kind: \"deadline\"; readonly value: RequestDeadlineMs }\n | {\n readonly kind: \"insufficient-time\";\n readonly remaining: Milliseconds;\n readonly buffer: FlushBufferMs;\n }\n | { readonly kind: \"no-context\" };\n\nexport interface DeadlineMiddlewareConfig {\n readonly flushBufferMs: FlushBufferMs;\n readonly telemetryEnabled: boolean;\n}\n\nexport interface DeadlineOptions {\n readonly flushBufferMs?: number;\n readonly telemetryEnabled?: boolean;\n}\n"]}
package/dist/types.js CHANGED
@@ -1,11 +1,11 @@
1
- export function milliseconds(value) {
1
+ export const milliseconds = (value) => {
2
2
  if (!Number.isFinite(value)) {
3
3
  throw new TypeError(`milliseconds value must be finite, received: ${value}`);
4
4
  }
5
5
  // oxlint-disable-next-line typescript/no-unsafe-type-assertion -- branded type constructor: value is validated above
6
6
  return value;
7
- }
8
- export function flushBufferMs(value) {
7
+ };
8
+ export const flushBufferMs = (value) => {
9
9
  if (!Number.isFinite(value)) {
10
10
  throw new TypeError(`flushBufferMs value must be finite, received: ${value}`);
11
11
  }
@@ -14,6 +14,6 @@ export function flushBufferMs(value) {
14
14
  }
15
15
  // oxlint-disable-next-line typescript/no-unsafe-type-assertion -- branded type constructor: value is validated above
16
16
  return value;
17
- }
17
+ };
18
18
 
19
19
  //# sourceMappingURL=types.js.map
package/dist/types.js.map CHANGED
@@ -1 +1 @@
1
- {"mappings":"AAaA,OAAO,SAAS,aAAa,OAA6B;CACxD,IAAI,CAAC,OAAO,SAAS,KAAK,GAAG;EAC3B,MAAM,IAAI,UAAU,gDAAgD,OAAO;CAC7E;;CAEA,OAAO;AACT;AAEA,OAAO,SAAS,cAAc,OAA8B;CAC1D,IAAI,CAAC,OAAO,SAAS,KAAK,GAAG;EAC3B,MAAM,IAAI,UAAU,iDAAiD,OAAO;CAC9E;CACA,IAAI,QAAQ,GAAG;EACb,MAAM,IAAI,UAAU,iDAAiD,OAAO;CAC9E;;CAEA,OAAO;AACT","names":[],"sources":["src/types.ts"],"version":3,"sourcesContent":["// SPDX-FileCopyrightText: 2024 lambda-deadline-middleware contributors\n// SPDX-License-Identifier: MIT\n\ndeclare const BrandSymbol: unique symbol;\n\ntype Brand<T, B extends string> = T & { readonly [BrandSymbol]: B };\n\nexport type Milliseconds = Brand<number, \"Milliseconds\">;\n\nexport type FlushBufferMs = Brand<number, \"FlushBufferMs\">;\n\nexport type RequestDeadlineMs = Brand<number, \"RequestDeadlineMs\">;\n\nexport function milliseconds(value: number): Milliseconds {\n if (!Number.isFinite(value)) {\n throw new TypeError(`milliseconds value must be finite, received: ${value}`);\n }\n // oxlint-disable-next-line typescript/no-unsafe-type-assertion -- branded type constructor: value is validated above\n return value as Milliseconds;\n}\n\nexport function flushBufferMs(value: number): FlushBufferMs {\n if (!Number.isFinite(value)) {\n throw new TypeError(`flushBufferMs value must be finite, received: ${value}`);\n }\n if (value < 0) {\n throw new TypeError(`flushBufferMs must be non-negative, received: ${value}`);\n }\n // oxlint-disable-next-line typescript/no-unsafe-type-assertion -- branded type constructor: value is validated above\n return value as FlushBufferMs;\n}\n\nexport type DeadlineComputation =\n | { readonly kind: \"deadline\"; readonly value: RequestDeadlineMs }\n | {\n readonly kind: \"insufficient-time\";\n readonly remaining: Milliseconds;\n readonly buffer: FlushBufferMs;\n }\n | { readonly kind: \"no-context\" };\n\nexport interface DeadlineMiddlewareConfig {\n readonly flushBufferMs: FlushBufferMs;\n readonly telemetryEnabled: boolean;\n}\n\nexport interface DeadlineOptions {\n readonly flushBufferMs?: number;\n readonly telemetryEnabled?: boolean;\n}\n"]}
1
+ {"mappings":"AAeA,OAAO,MAAM,gBAAgB,UAAgC;CAC3D,IAAI,CAAC,OAAO,SAAS,KAAK,GAAG;EAC3B,MAAM,IAAI,UAAU,gDAAgD,OAAO;CAC7E;;CAEA,OAAO;AACT;AAEA,OAAO,MAAM,iBAAiB,UAAiC;CAC7D,IAAI,CAAC,OAAO,SAAS,KAAK,GAAG;EAC3B,MAAM,IAAI,UAAU,iDAAiD,OAAO;CAC9E;CACA,IAAI,QAAQ,GAAG;EACb,MAAM,IAAI,UAAU,iDAAiD,OAAO;CAC9E;;CAEA,OAAO;AACT","names":[],"sources":["src/types.ts"],"version":3,"sourcesContent":["// SPDX-FileCopyrightText: 2026 lambda-deadline-middleware contributors\n// SPDX-License-Identifier: MIT\n\n// Branded types prevent interchange errors at compile time (e.g. passing seconds where milliseconds are expected).\n// Zero runtime cost. Smart constructors below validate at the boundary and brand the value.\ndeclare const BrandSymbol: unique symbol;\n\ntype Brand<T, B extends string> = T & { readonly [BrandSymbol]: B };\n\nexport type Milliseconds = Brand<number, \"Milliseconds\">;\n\nexport type FlushBufferMs = Brand<number, \"FlushBufferMs\">;\n\nexport type RequestDeadlineMs = Brand<number, \"RequestDeadlineMs\">;\n\nexport const milliseconds = (value: number): Milliseconds => {\n if (!Number.isFinite(value)) {\n throw new TypeError(`milliseconds value must be finite, received: ${value}`);\n }\n // oxlint-disable-next-line typescript/no-unsafe-type-assertion -- branded type constructor: value is validated above\n return value as Milliseconds;\n};\n\nexport const flushBufferMs = (value: number): FlushBufferMs => {\n if (!Number.isFinite(value)) {\n throw new TypeError(`flushBufferMs value must be finite, received: ${value}`);\n }\n if (value < 0) {\n throw new TypeError(`flushBufferMs must be non-negative, received: ${value}`);\n }\n // oxlint-disable-next-line typescript/no-unsafe-type-assertion -- branded type constructor: value is validated above\n return value as FlushBufferMs;\n};\n\nexport type DeadlineComputation =\n | { readonly kind: \"deadline\"; readonly value: RequestDeadlineMs }\n | {\n readonly kind: \"insufficient-time\";\n readonly remaining: Milliseconds;\n readonly buffer: FlushBufferMs;\n }\n | { readonly kind: \"no-context\" };\n\nexport interface DeadlineMiddlewareConfig {\n readonly flushBufferMs: FlushBufferMs;\n readonly telemetryEnabled: boolean;\n}\n\nexport interface DeadlineOptions {\n readonly flushBufferMs?: number;\n readonly telemetryEnabled?: boolean;\n}\n"]}