{"_id":"@aws/durable-execution-sdk-js-otel","_rev":"5-7a89e0ea02fa4bd60f940b7cdea99702","name":"@aws/durable-execution-sdk-js-otel","dist-tags":{"beta":"0.0.1","latest":"1.1.0"},"versions":{"0.0.1":{"name":"@aws/durable-execution-sdk-js-otel","version":"0.0.1","license":"Apache-2.0","_id":"@aws/durable-execution-sdk-js-otel@0.0.1","maintainers":[{"name":"durable-execution-dev","email":"durable-execution-dev@amazon.com"}],"homepage":"https://github.com/aws/aws-durable-execution-sdk-js/tree/main/packages/aws-durable-execution-sdk-js-otel","bugs":{"url":"https://github.com/aws/aws-durable-execution-sdk-js/issues"},"dist":{"shasum":"2e735395beca8898541437c2c11cecd3b771d7f7","tarball":"https://registry.npmjs.org/@aws/durable-execution-sdk-js-otel/-/durable-execution-sdk-js-otel-0.0.1.tgz","fileCount":4,"integrity":"sha512-g+p8ch5tmB3zchHyjno62MbxcZ28yLYwnpJBFYgG5AMMX0gqrgbd618sUoCjY/5/NvMX6UeOLsYmPTlmoS/Ufw==","signatures":[{"sig":"MEQCIEQxqrpyvlMKbq2wb3AmENie8O4+ivFCoLYbh4D+CW5iAiAJAMzluBiiHlU24KRNdswFz/2v0hoxw8bhai8bFxIBaA==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":10595},"main":"./index.js","types":"./index.d.ts","exports":{".":{"types":"./index.d.ts","import":"./index.js","require":"./index.js"}},"gitHead":"1264fc841d5d73ff0b5d60593514a3e4e2ee3ad6","scripts":{"prepublishOnly":"echo 'dummy publish'"},"_npmUser":{"name":"durable-execution-dev","email":"durable-execution-dev@amazon.com"},"repository":{"url":"git+ssh://git@github.com/aws/aws-durable-execution-sdk-js.git","type":"git","directory":"packages/aws-durable-execution-sdk-js-otel"},"_npmVersion":"11.11.0","description":"OpenTelemetry instrumentation plugin for AWS Durable Execution SDK (placeholder)","directories":{},"_nodeVersion":"24.14.1","_hasShrinkwrap":false,"_npmOperationalInternal":{"tmp":"tmp/durable-execution-sdk-js-otel_0.0.1_1781907301553_0.04576491818973727","host":"s3://npm-registry-packages-npm-production"}},"0.1.0":{"name":"@aws/durable-execution-sdk-js-otel","version":"0.1.0","license":"Apache-2.0","_id":"@aws/durable-execution-sdk-js-otel@0.1.0","maintainers":[{"name":"durable-execution-dev","email":"durable-execution-dev@amazon.com"}],"homepage":"https://github.com/aws/aws-durable-execution-sdk-js/tree/main/packages/aws-durable-execution-sdk-js-otel","bugs":{"url":"https://github.com/aws/aws-durable-execution-sdk-js/issues"},"dist":{"shasum":"4b7e486c469761b4e32a69c757028e0c79b06751","tarball":"https://registry.npmjs.org/@aws/durable-execution-sdk-js-otel/-/durable-execution-sdk-js-otel-0.1.0.tgz","fileCount":15,"integrity":"sha512-ZynpaiUrb9Txe6c5IAsDzO+BObgFQNyPpSxxBmpUZM7xNOYFO80AslUPMJ9KGZBoTajPg7qHEe6HXYZ+IXriZA==","signatures":[{"sig":"MEUCIQCNi2bzdWKRfIhjuuZ2PxGuYp6r8eLVwBXbUBibSE9b1gIgW0q8VDo/C4PC0T3ZtSBTDMJ0+lKKo/hXRDYhzTpSM8E=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/@aws%2fdurable-execution-sdk-js-otel@0.1.0","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"unpackedSize":299937},"main":"./dist-cjs/index.js","types":"./dist-types/index.d.ts","module":"./dist/index.mjs","engines":{"node":">=22"},"exports":{".":{"types":"./dist-types/index.d.ts","import":"./dist/index.mjs","require":"./dist-cjs/index.js"}},"gitHead":"3e5f74c008480ad800e49bcf8b1baa276c2cef44","private":false,"scripts":{"lint":"eslint --fix","test":"tsc --noEmit && jest --config jest.config.mjs --collectCoverage --collectCoverageFrom=src/**/*.{ts,js}","build":"concurrently npm:build:esm npm:build:cjs npm:build:types","clean":"rm -rf dist dist-cjs dist-types node_modules coverage .tsbuildinfo .rollup.cache","prebuild":"npm run lint","build:cjs":"rollup --config rollup.config.mjs --environment MODE:cjs","build:esm":"rollup --config rollup.config.mjs --environment MODE:esm","build:types":"tsc --project tsconfig.build.json --outDir dist-types","prepublishOnly":"npm run build && npm run test"},"_npmUser":{"name":"GitHub Actions","email":"npm-oidc-no-reply@github.com","trustedPublisher":{"id":"github","oidcConfigId":"oidc:89a6564c-6896-4206-b64c-a96eeee5ad54"}},"repository":{"url":"git+ssh://git@github.com/aws/aws-durable-execution-sdk-js.git","type":"git","directory":"packages/aws-durable-execution-sdk-js-otel"},"_npmVersion":"11.13.0","description":"OpenTelemetry instrumentation plugin for AWS Durable Execution SDK","directories":{},"_nodeVersion":"24.16.0","_hasShrinkwrap":false,"devDependencies":{"jest":"^30.0.3","eslint":"^9.29.0","@eslint/js":"^9.29.0","fast-check":"^3.23.2","typescript":"^5.8.3","@eslint/compat":"^1.4.1","typescript-eslint":"^8.34.1","eslint-plugin-jest":"^29.0.1","eslint-config-prettier":"^10.1.5"},"peerDependencies":{"@opentelemetry/api":"^1.0.0","@aws/durable-execution-sdk-js":"*","@opentelemetry/sdk-trace-node":"^2.6.1","@opentelemetry/instrumentation":"^0.219.0","@opentelemetry/instrumentation-aws-sdk":"^0.74.0"},"_npmOperationalInternal":{"tmp":"tmp/durable-execution-sdk-js-otel_0.1.0_1782238084030_0.5615660462891046","host":"s3://npm-registry-packages-npm-production"}},"0.1.1":{"name":"@aws/durable-execution-sdk-js-otel","version":"0.1.1","license":"Apache-2.0","_id":"@aws/durable-execution-sdk-js-otel@0.1.1","maintainers":[{"name":"durable-execution-dev","email":"durable-execution-dev@amazon.com"}],"homepage":"https://github.com/aws/aws-durable-execution-sdk-js/tree/main/packages/aws-durable-execution-sdk-js-otel","bugs":{"url":"https://github.com/aws/aws-durable-execution-sdk-js/issues"},"dist":{"shasum":"62e5acbd70522831f32a9ab22c60d0615c280403","tarball":"https://registry.npmjs.org/@aws/durable-execution-sdk-js-otel/-/durable-execution-sdk-js-otel-0.1.1.tgz","fileCount":15,"integrity":"sha512-mnwFKTSGN9Nw6zySSFkHSXU2VpC7t98fhOY3mpU16FRZ+4fvbZvT8CJ9UzLqNC3ijOM/EXCY1kTa/CsGIfSfyA==","signatures":[{"sig":"MEUCIQCKESYbBcL/2opQudxtd6/GrGNtNWPxbXi3LzgWTbEYJwIgfqJTK8tUTT83csDu2INBTmNUPye9XOEDJEu/EIYZq0A=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/@aws%2fdurable-execution-sdk-js-otel@0.1.1","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"unpackedSize":349362},"main":"./dist-cjs/index.js","types":"./dist-types/index.d.ts","module":"./dist/index.mjs","engines":{"node":">=22"},"exports":{".":{"types":"./dist-types/index.d.ts","import":"./dist/index.mjs","require":"./dist-cjs/index.js"}},"gitHead":"78bf9c713bd4ad7334e0d8826326cb540d85914f","private":false,"scripts":{"lint":"eslint --fix","test":"tsc --noEmit && jest --config jest.config.mjs --collectCoverage --collectCoverageFrom=src/**/*.{ts,js}","build":"concurrently npm:build:esm npm:build:cjs npm:build:types","clean":"rm -rf dist dist-cjs dist-types node_modules coverage .tsbuildinfo .rollup.cache","prebuild":"npm run lint","build:cjs":"rollup --config rollup.config.mjs --environment MODE:cjs","build:esm":"rollup --config rollup.config.mjs --environment MODE:esm","build:types":"tsc --project tsconfig.build.json --outDir dist-types","prepublishOnly":"npm run build && npm run test"},"_npmUser":{"name":"GitHub Actions","email":"npm-oidc-no-reply@github.com","trustedPublisher":{"id":"github","oidcConfigId":"oidc:89a6564c-6896-4206-b64c-a96eeee5ad54"}},"repository":{"url":"git+ssh://git@github.com/aws/aws-durable-execution-sdk-js.git","type":"git","directory":"packages/aws-durable-execution-sdk-js-otel"},"_npmVersion":"11.16.0","description":"OpenTelemetry instrumentation plugin for AWS Durable Execution SDK","directories":{},"_nodeVersion":"24.18.0","_hasShrinkwrap":false,"devDependencies":{"jest":"^30.0.3","eslint":"^9.29.0","@eslint/js":"^9.29.0","fast-check":"^3.23.2","typescript":"^5.8.3","@eslint/compat":"^1.4.1","typescript-eslint":"^8.34.1","eslint-plugin-jest":"^29.0.1","eslint-config-prettier":"^10.1.5"},"peerDependencies":{"@opentelemetry/api":"^1.0.0","@aws/durable-execution-sdk-js":">=2.1.0","@opentelemetry/sdk-trace-node":"^2.6.1","@opentelemetry/instrumentation":"^0.219.0","@opentelemetry/instrumentation-aws-sdk":"^0.74.0"},"_npmOperationalInternal":{"tmp":"tmp/durable-execution-sdk-js-otel_0.1.1_1783372154462_0.4087689504241656","host":"s3://npm-registry-packages-npm-production"}},"1.0.0":{"name":"@aws/durable-execution-sdk-js-otel","version":"1.0.0","license":"Apache-2.0","_id":"@aws/durable-execution-sdk-js-otel@1.0.0","maintainers":[{"name":"durable-execution-dev","email":"durable-execution-dev@amazon.com"}],"homepage":"https://github.com/aws/aws-durable-execution-sdk-js/tree/main/packages/aws-durable-execution-sdk-js-otel","bugs":{"url":"https://github.com/aws/aws-durable-execution-sdk-js/issues"},"dist":{"shasum":"6099de883afd31c07a9596d9fdcc763b24b4567d","tarball":"https://registry.npmjs.org/@aws/durable-execution-sdk-js-otel/-/durable-execution-sdk-js-otel-1.0.0.tgz","fileCount":26,"integrity":"sha512-KclL94qJ+oms5lXe6ieTY9w0fMjrq7fTCk4NJmEgJrwXdGY22xu6dzP42kZqz5Dwdx/UWmO6K74/IKtoNgZdkQ==","signatures":[{"sig":"MEUCIBBMKgXZjQONEbrBYqxMA7pN8UvtAGG2UuWApAtNlxCtAiEA+G2tFAY0M4pXCOx9UEYfNyLfoRHUidSw8oI3rNJL33g=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"},{"sig":"MEQCIC+fzs2pORmxVAWgVm4ib7aKZB7JXVysqo8g3gjSA7A5AiBIMk45EDwXZAOAs1gm5oN3FmU0Ne9ctJh2sq9DKeV6MA==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/@aws%2fdurable-execution-sdk-js-otel@1.0.0","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"unpackedSize":280618},"main":"./dist-cjs/index.js","types":"./dist-types/index.d.ts","module":"./dist/index.mjs","engines":{"node":">=22"},"exports":{".":{"types":"./dist-types/index.d.ts","import":"./dist/index.mjs","require":"./dist-cjs/index.js"},"./otel-execution":{"types":"./dist-types/execution-plugin-provider.d.ts","import":"./dist/otel-execution.mjs","require":"./dist-cjs/otel-execution.js"},"./otel-invocation":{"types":"./dist-types/invocation-plugin-provider.d.ts","import":"./dist/otel-invocation.mjs","require":"./dist-cjs/otel-invocation.js"}},"gitHead":"974f9d4c73a96a613448fce86a213b854e006442","private":false,"scripts":{"lint":"biome check src --diagnostic-level=error","test":"jest --config jest.config.mjs --collectCoverage --collectCoverageFrom=src/**/*.{ts,js}","build":"concurrently npm:build:esm npm:build:cjs npm:build:types","clean":"rm -rf dist dist-cjs dist-types node_modules coverage .tsbuildinfo .rollup.cache","lint:fix":"biome check --write src","prebuild":"rm -rf dist dist-cjs dist-types","build:cjs":"rollup --config rollup.config.mjs --environment MODE:cjs","build:esm":"rollup --config rollup.config.mjs --environment MODE:esm","build:types":"tsc --project tsconfig.build.json --outDir dist-types","prepublishOnly":"npm run build && npm run test"},"_npmUser":{"name":"GitHub Actions","email":"npm-oidc-no-reply@github.com","trustedPublisher":{"id":"github","oidcConfigId":"oidc:89a6564c-6896-4206-b64c-a96eeee5ad54"}},"repository":{"url":"git+ssh://git@github.com/aws/aws-durable-execution-sdk-js.git","type":"git","directory":"packages/aws-durable-execution-sdk-js-otel"},"_npmVersion":"11.19.0","description":"OpenTelemetry instrumentation plugin for AWS Durable Execution SDK","directories":{},"_nodeVersion":"24.20.0","_hasShrinkwrap":false,"devDependencies":{"jest":"^30.5.1","fast-check":"^3.23.2","typescript":"^6.0.3","@biomejs/biome":"2.5.11","@opentelemetry/core":"^2.0.0"},"peerDependencies":{"@opentelemetry/api":"^1.0.0","@opentelemetry/core":"^2.0.0","@aws/durable-execution-sdk-js":">=2.4.0","@opentelemetry/sdk-trace-node":"^2.6.1"},"peerDependenciesMeta":{"@aws/durable-execution-sdk-js":{"optional":true}},"_npmOperationalInternal":{"tmp":"tmp/durable-execution-sdk-js-otel_1.0.0_1788889399879_0.30700187995902484","host":"s3://npm-registry-packages-npm-production"}},"1.1.0":{"_id":"@aws/durable-execution-sdk-js-otel@1.1.0","bugs":{"url":"https://github.com/aws/aws-durable-execution-sdk-js/issues"},"dist":{"shasum":"205c0b2a19dd39e64983ad460da7dc8b4d97c44e","tarball":"https://registry.npmjs.org/@aws/durable-execution-sdk-js-otel/-/durable-execution-sdk-js-otel-1.1.0.tgz","fileCount":50,"integrity":"sha512-1DrulHO66S8tStX+Ofh0WwW3zgeHHekNh6Y39z0LTdbDlqTG9A8UO0Kte7sBiJiTp1pXUNIs/qGVFw7XSrjc1Q==","signatures":[{"sig":"MEUCIQCYF4/JLUG4iKAc9JMdIqsGAffo702n3cRFWe4ZaTSZKwIgU4P40U7NqMu0UP8kjuY08jCYgmY2UjfdAYq6pHrI9Vc=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"},{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEUCIAHWN6O9f+FC4fUbUOfFyyOnTv2OjwO0GxIKiMdylSviAiEAuvLYcIu2i5KNbEbQXU5kYNnHBpAdIqpbRmRIoMQaWyM="}],"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/@aws%2fdurable-execution-sdk-js-otel@1.1.0","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"unpackedSize":327823},"main":"./dist-cjs/index.js","name":"@aws/durable-execution-sdk-js-otel","types":"./dist-types/index.d.ts","module":"./dist/index.mjs","engines":{"node":">=22"},"exports":{".":{"types":"./dist-types/index.d.ts","import":"./dist/index.mjs","require":"./dist-cjs/index.js"},"./otel-execution":{"types":"./dist-types/execution-plugin-provider.d.ts","import":"./dist/otel-execution.mjs","require":"./dist-cjs/otel-execution.js"},"./otel-invocation":{"types":"./dist-types/invocation-plugin-provider.d.ts","import":"./dist/otel-invocation.mjs","require":"./dist-cjs/otel-invocation.js"}},"gitHead":"b16eafb20db51ee13404882e4aa90976bd22230e","license":"Apache-2.0","private":false,"scripts":{"lint":"biome check src --diagnostic-level=error","test":"jest --config jest.config.mjs --collectCoverage --collectCoverageFrom=src/**/*.{ts,js}","build":"concurrently npm:build:esm npm:build:cjs npm:build:types","clean":"rm -rf dist dist-cjs dist-types node_modules coverage .tsbuildinfo .rollup.cache","lint:fix":"biome check --write src","prebuild":"rm -rf dist dist-cjs dist-types","build:cjs":"rollup --config rollup.config.mjs --environment MODE:cjs","build:esm":"rollup --config rollup.config.mjs --environment MODE:esm","build:types":"tsc --project tsconfig.build.json --outDir dist-types","prepublishOnly":"npm run build && npm run test"},"version":"1.1.0","_npmUser":{"name":"GitHub Actions","email":"npm-oidc-no-reply@github.com","trustedPublisher":{"id":"github","oidcConfigId":"oidc:89a6564c-6896-4206-b64c-a96eeee5ad54"}},"homepage":"https://github.com/aws/aws-durable-execution-sdk-js/tree/main/packages/aws-durable-execution-sdk-js-otel","repository":{"url":"git+ssh://git@github.com/aws/aws-durable-execution-sdk-js.git","type":"git","directory":"packages/aws-durable-execution-sdk-js-otel"},"_npmVersion":"11.19.0","description":"OpenTelemetry instrumentation plugin for AWS Durable Execution SDK","directories":{},"maintainers":[{"name":"durable-execution-dev","email":"durable-execution-dev@amazon.com"}],"_nodeVersion":"24.20.0","_hasShrinkwrap":false,"devDependencies":{"jest":"^30.5.1","fast-check":"^3.23.2","typescript":"^6.0.3","@biomejs/biome":"2.5.11","@opentelemetry/core":"^2.0.0"},"peerDependencies":{"@opentelemetry/api":"^1.0.0","@opentelemetry/core":"^2.0.0","@aws/durable-execution-sdk-js":">=2.4.0","@opentelemetry/sdk-trace-node":"^2.6.1"},"peerDependenciesMeta":{"@aws/durable-execution-sdk-js":{"optional":true}},"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/durable-execution-sdk-js-otel_1.1.0_1789169600426_0.4536628743289497"}}},"time":{"created":"2026-06-19T22:15:01.398Z","modified":"2026-09-11T23:33:21.054Z","0.0.1":"2026-06-19T22:15:01.687Z","0.1.0":"2026-06-23T18:08:04.174Z","0.1.1":"2026-07-06T21:09:14.644Z","1.0.0":"2026-09-08T17:43:19.991Z","1.1.0":"2026-09-11T23:33:20.666Z"},"bugs":{"url":"https://github.com/aws/aws-durable-execution-sdk-js/issues"},"license":"Apache-2.0","homepage":"https://github.com/aws/aws-durable-execution-sdk-js/tree/main/packages/aws-durable-execution-sdk-js-otel","repository":{"url":"git+ssh://git@github.com/aws/aws-durable-execution-sdk-js.git","type":"git","directory":"packages/aws-durable-execution-sdk-js-otel"},"description":"OpenTelemetry instrumentation plugin for AWS Durable Execution SDK","maintainers":[{"name":"durable-execution-dev","email":"durable-execution-dev@amazon.com"}],"readme":"# AWS Durable Execution SDK - OpenTelemetry Plugin\n\nOpenTelemetry instrumentation for the AWS Durable Execution SDK. The package\nprovides two plugins that emit Workflow, Invocation, durable operation, and\noperation-attempt spans.\n\nThe whole durable execution shares **one trace**, anchored at the execution\nancestor resolved at invocation start. The `Workflow` span and every per-invocation\n`Invocation` span join that trace, so a single trace ID spans all invocations of\nthe execution.\n\nThey differ in where durable operation spans are parented:\n\n| Plugin                 | Operation hierarchy                  | Cross-link                              |\n| ---------------------- | ------------------------------------ | --------------------------------------- |\n| `ExecutionOtelPlugin`  | `Workflow -> operation -> attempt`   | Operations and attempts link Invocation |\n| `InvocationOtelPlugin` | `Invocation -> operation -> attempt` | Operations and attempts link Workflow   |\n\nThe plugins do not create or register an OpenTelemetry provider, exporter,\nsampler, resource, propagator, context manager, or library instrumentation.\nThey use the global provider by default, or an application-owned provider\ncreated through `tracerProviderFactory`.\n\n## Installation\n\n```bash\nnpm install @aws/durable-execution-sdk-js-otel \\\n            @aws/durable-execution-sdk-js \\\n            @opentelemetry/api \\\n            @opentelemetry/core \\\n            @opentelemetry/sdk-trace-node\n```\n\nThe package requires Node.js 22 or later. Exporters, span processors,\npropagators, resources, and library instrumentation are application or ADOT\nresponsibilities.\n\n## Quick Start\n\nWhen an SDK provider is registered globally, no plugin configuration is\nrequired:\n\n```typescript\nimport { withDurableExecution } from \"@aws/durable-execution-sdk-js\";\nimport { ExecutionOtelPlugin } from \"@aws/durable-execution-sdk-js-otel\";\n\nconst plugin = new ExecutionOtelPlugin();\n\nexport const handler = withDurableExecution(\n  async (event, context) => {\n    return context.step(\"process\", async () => process(event));\n  },\n  { plugins: [plugin] },\n);\n```\n\nUse `InvocationOtelPlugin` instead when operations should appear under each\nLambda invocation rather than under the durable Workflow.\n\n## Provider Setup\n\n### Global Provider\n\nOmitting `tracerProviderFactory` uses `trace.getTracerProvider()`. This is the\nnormal setup for the ADOT Lambda layer, OpenTelemetry zero-code\ninstrumentation, or an application that registers its own provider globally.\n\nWhen using ADOT, activate its instrumentation wrapper:\n\n```text\nAWS_LAMBDA_EXEC_WRAPPER=/opt/otel-instrument\n```\n\nThe OpenTelemetry JavaScript API does not provide a public way to retrieve or\nreplace a provider's configured ID generator. For a compatible SDK tracer, the\nplugin therefore:\n\n1. reads the tracer's runtime `_idGenerator` field;\n2. replaces it with a guarded deterministic wrapper;\n3. delegates all ID generation outside plugin span creation to the original\n   generator.\n\nThis private-field integration is isolated behind runtime shape and assignment\nchecks. It does not change IDs for unrelated spans, including spans created\nconcurrently or with the same instrumentation scope.\n\nIf the plugin is constructed before the SDK provider is globally registered,\nits initial tracer may be a proxy without `_idGenerator`. At each invocation\nstart, the plugin re-resolves the global provider until a compatible SDK tracer\nis available. When installation still fails:\n\n- plugin telemetry and log enrichment are disabled for that invocation;\n- a warning is emitted;\n- provider resolution is retried on the next invocation.\n\nProviders or future SDK tracers that do not expose the compatible runtime field\ncannot use this global-provider path. Use `tracerProviderFactory` to install the\ngenerator through the supported provider constructor API.\n\n### Application-Owned Provider\n\n`tracerProviderFactory` receives a function that creates the plugin's\ndeterministic ID wrapper. The factory is called during plugin construction.\n\n```typescript\nimport { InvocationOtelPlugin } from \"@aws/durable-execution-sdk-js-otel\";\nimport { OTLPTraceExporter } from \"@opentelemetry/exporter-trace-otlp-http\";\nimport {\n  NodeTracerProvider,\n  SimpleSpanProcessor,\n} from \"@opentelemetry/sdk-trace-node\";\n\nconst plugin = new InvocationOtelPlugin({\n  tracerProviderFactory: (createIdGenerator) => {\n    const provider = new NodeTracerProvider({\n      idGenerator: createIdGenerator(),\n      spanProcessors: [\n        new SimpleSpanProcessor(\n          new OTLPTraceExporter({\n            url: \"http://localhost:4318/v1/traces\",\n          }),\n        ),\n      ],\n    });\n\n    provider.register();\n    return provider;\n  },\n});\n```\n\n`createIdGenerator()` delegates non-durable IDs to OpenTelemetry's standard\nrandom generator. To preserve another generator, pass it as the fallback:\n\n```typescript\nidGenerator: createIdGenerator(applicationIdGenerator);\n```\n\nThe deterministic override is active only for the synchronous `startSpan()`\ncall made by the plugin. All unrelated IDs use the fallback generator.\n\nThe application owns the returned provider and all associated configuration:\n\n- exporters and span processors;\n- sampling and resources;\n- context management and propagation;\n- HTTP, AWS SDK, Lambda, and other library instrumentation;\n- global registration;\n- shutdown.\n\nThe provider does not have to be the global provider for the plugin to obtain a\ntracer from it. Register it globally when the application also needs its\ncontext manager, propagator, or library instrumentation.\n\nAt the end of each enabled invocation, both plugins call `forceFlush()` when\nthe provider exposes it. They never call `shutdown()`.\n\n## Dynamic Loading from a Lambda Layer\n\nThe SDK can load either plugin without importing it in function code. Package\nthis module and its OpenTelemetry peer dependencies in a Lambda layer under\n`nodejs/node_modules`, then configure one entry point:\n\n```text\nDURABLE_EXECUTION_PLUGINS=@aws/durable-execution-sdk-js-otel/otel-execution\n```\n\nor:\n\n```text\nDURABLE_EXECUTION_PLUGINS=@aws/durable-execution-sdk-js-otel/otel-invocation\n```\n\nDo not package `@aws/durable-execution-sdk-js` in the layer. The provider entry\npoints use SDK types only, and the SDK peer dependency is optional so package\ninstallation does not add a second copy. At runtime, the plugin is loaded and\ndriven by the SDK instance bundled with the function.\n\nDynamic providers construct plugins with default configuration, so they\nrequire a compatible globally registered SDK provider. Use code-based\nregistration when `tracerProviderFactory` or other custom configuration is\nneeded.\n\n## Choosing a Plugin\n\n### `ExecutionOtelPlugin`\n\nUse this plugin for a workflow-centered view. Operations and attempts are\nchildren of the `Workflow` span. Each also links to the `Invocation` span that\nobserved it. The whole execution shares one trace.\n\n```text\nExecution trace\n\nExecution ancestor\n├── Workflow\n│   └── Operation: fetch-data\n│       └── Attempt 1\n└── Invocation\n\nLinks:\nOperation -> Invocation\nAttempt   -> Invocation\n```\n\nThe plugin makes Workflow the active span while durable handler code runs.\nCompleted operation spans use durable operation start/end timestamps and\ndeterministic span IDs. While an operation spans multiple invocations its\nidentity is carried as a non-recording context; nothing is exported until it\ncompletes. The single recording operation span is then created and ended once,\nin the invocation where the operation terminates, under a **deterministic span\nID on the execution trace**. Because there is one span per logical operation,\nno cross-invocation link is needed to stitch it together — unlike\n`InvocationOtelPlugin` below.\n\n### `InvocationOtelPlugin`\n\nUse this plugin for an invocation-centered view. Operations and attempts are\nchildren of the current `Invocation` span. Each links to the `Workflow` span.\nThe whole execution shares one trace.\n\n```text\nExecution trace\n\nExecution ancestor\n├── Workflow\n└── Invocation\n    └── Operation: fetch-data\n        └── Attempt 1\n\nLinks:\nOperation -> Workflow\nAttempt   -> Workflow\n```\n\nThe plugin makes Invocation the active span while durable handler code runs.\nOpen operation spans are ended at the invocation boundary and retain\n`durable.operation.status=STARTED`. When an operation completes in a later\ninvocation, the plugin emits a continuation span in that invocation.\n\nBecause the original span context is not checkpointed, replayed `STEP` and\n`CONTEXT` spans and cross-invocation continuation spans use new provider IDs.\nThey correlate through two links: the real exported `Workflow` span, and the\n**initial logical operation span** — whose ID is deterministic on\n`(operationId, execution ARN)` and lives on the execution trace, so the segments\nof one logical operation stay stitched together across invocations. Replay-only\n`WAIT`, `INVOKE`, `CHAINED_INVOKE`, and `CALLBACK` operations are not emitted\nagain.\n\n## Execution Trace and the Execution Ancestor\n\nBoth plugins resolve one **execution ancestor** at invocation start — the common\nparent the `Workflow` and `Invocation` spans join — so the whole execution\nshares a single trace. The ancestor is chosen by precedence:\n\n1. a **complete propagated remote parent** (a valid `Root` trace ID and a valid\n   `Parent` span ID): used directly, whether or not `Sampled` is present;\n2. otherwise a **synthetic execution root** with a deterministic span ID derived\n   from the execution ARN.\n\nThe canonical trace ID follows the same precedence: the propagated remote trace\nID when valid, else one derived from the ARN and start time.\n\nA live ambient span (a `context.active()` span created by an auto-instrumentation\nlayer) is deliberately **never** used as the execution ancestor. Its trace ID is\nnot guaranteed stable across Lambda reinvocations, so anchoring the\nmulti-invocation execution on it could change the execution trace ID on replay\nand break the cross-invocation continuation and replay links (which target a\ndeterministic operation span ID on the canonical trace). Both anchors used above\nare stable: the durable backend keeps the propagated `Root` identical for every\ninvocation, and the ARN-derived synthetic root is a pure hash of the ARN.\n\n### Valid Workflow parent shapes\n\n`ADOT` and community Node.js auto-instrumentation layers can create the ambient\nhandler span before the durable plugin runs, on the trace the durable backend\npropagated. OpenTelemetry `SpanContext` has no ancestor pointer, so the plugin\ncannot walk from that local span to the durable backend span. The `Workflow`\nspan therefore joins the canonical trace and parents onto whichever ancestor the\nprecedence above resolves. When a complete remote parent is propagated, that is\nthe ancestor:\n\n```text\nPropagated remote parent\n├── Workflow\n└── Invocation\n```\n\nWhen no complete remote parent can be constructed, the synthetic execution root\nanchors the trace and the `Workflow` span parents onto it:\n\n```text\nSynthetic execution root\n└── Workflow\n```\n\nThe `Invocation` span may still nest under a same-trace ambient handler span —\nsee [Invocation parent](#invocation-parent) — without changing the execution\nancestor the `Workflow` span joins.\n\n### Workflow identity and lifecycle\n\n`Workflow` is an `INTERNAL` span that **joins the execution trace** by parenting\nonto the execution ancestor (its span ID is forced; the trace ID comes from the\nparent). Its span ID is reproducible across replays:\n\n- span ID: the first 16 hexadecimal characters of SHA-256 over\n  `workflow:<execution ARN>`.\n\nThe synthetic execution root, when used, gets a distinct deterministic span ID\nfrom SHA-256 over `execution-root:<execution ARN>`, and the ARN-derived trace ID\nis the first 32 hexadecimal characters of SHA-256 over\n`<execution ARN>:<execution start timestamp in ISO 8601 format>` (falling back\nto the ARN alone when the timestamp is unavailable).\n\nThe plugins carry the same `Workflow` span identity on each invocation as a\nnon-recording span context, and create the single recording `Workflow` span only\nwhen the execution reaches `SUCCEEDED` or `FAILED`, backdated to the execution\nstart. `PENDING` and `RETRYING` invocations create no recording `Workflow` span,\nso none is ever left unended, and exactly one `Workflow` root is exported for the\ndurable execution while intermediate invocation spans export normally. The\nnon-recording context carries the execution's sampling decision, so operations\nunder it are sampled consistently with the eventual root. In-flight attempt spans\nare ended at invocation cleanup, so a non-terminal invocation leaves no recording\nspan unended. Suspended operations differ by plugin: `InvocationOtelPlugin` ends\nthe open operation span at the boundary and continues it later, while\n`ExecutionOtelPlugin` holds the operation identity as a non-recording context and\nexports one recording span only when the operation completes.\n\nWhen a chained parent and target execution share a propagated remote parent,\nboth join that one trace, each keeping its own deterministic `Workflow` span ID.\n\n### Invocation parent\n\nThe `Invocation` span parents onto the **same-trace ambient span** when one is\nactive on the canonical trace (preserving the Lambda/X-Ray linkage), otherwise\nonto the execution ancestor so it stays on the execution trace. Provider\nownership does not change this topology.\n\n### Sampling\n\nSampling follows this precedence, highest first:\n\n1. **Explicit upstream decision** — an explicit `Sampled=1` / `Sampled=0` in a\n   valid propagated header is authoritative and preserved. It is applied only\n   when the extracted trace ID is itself valid, so an unusable trace never\n   carries its sampling bit into the derived execution trace.\n2. **Configured sampler** — when the header carries no usable decision, the\n   provider sampler decides. It is evaluated at its **root policy**\n   (`ROOT_CONTEXT`, no parent) with the real trace ID, span name, and attributes,\n   so a `ParentBasedSampler` applies its `root` sampler rather than inheriting an\n   unrelated ambient span's decision.\n3. **Default to sampled** — used only when no sampler decision can be obtained.\n\nThe resolved execution decision is enforced for all SDK-created spans through a\ndurable sampler wrapper around the provider sampler. This makes explicit backend\nsampling authoritative even for direct/custom samplers that ignore parent\n`traceFlags`. Unrelated application spans still use the original configured\nsampler. If the resolved tracer does not expose a compatible writable sampler,\nthe plugin preserves normal tracing through the configured provider; in that\ncase direct samplers may make their normal span-level decisions.\n\n### Context extractors\n\nThe default `xRayContextExtractor` parses `Root`, `Parent`, and `Sampled`\nindependently from `_X_AMZN_TRACE_ID`, rejecting an all-zero (invalid) `Root` or\n`Parent`. The durable backend keeps the X-Ray `Root` stable for every invocation\nof one execution, so its trace ID anchors the whole execution. The package also\nexports `w3cClientContextExtractor`, which reads W3C `traceparent` data from\n`context.clientContext.custom.traceparent`.\n\nA custom extractor can return:\n\n```typescript\ntype Sampling = \"SAMPLED\" | \"NOT_SAMPLED\" | \"UNDECIDED\";\n\ntype ContextExtractor = (info: InvocationInfo) =>\n  | {\n      traceId: string;\n      parentSpanId?: string;\n      traceFlags?: number;\n      sampling?: Sampling;\n    }\n  | undefined;\n```\n\nA complete remote parent needs a valid `traceId` and a valid `parentSpanId`.\n`sampling` is the tri-state upstream decision; when omitted it is derived from\n`traceFlags` (sampled bit), and when neither is present the decision is\n`UNDECIDED` and the sampling rules above decide. A custom extractor must return\nthe durable execution's own trace context: a valid trace ID anchors the\nexecution across replays, so returning stale or per-invocation context (for\nexample an ambient span that changes each invocation) would split one durable\nexecution across traces.\n\n## Shared Configuration\n\nBoth plugins accept `OtelPluginConfig`:\n\n```typescript\ninterface OtelPluginConfig {\n  /** Creates an application-owned provider with a deterministic ID wrapper. */\n  tracerProviderFactory?: (\n    createIdGenerator: (fallbackIdGenerator?: IdGenerator) => IdGenerator,\n  ) => TracerProvider;\n\n  /** Extracts upstream trace context. Defaults to xRayContextExtractor. */\n  contextExtractor?: ContextExtractor;\n\n  /** Instrumentation scope name. */\n  instrumentationName?: string;\n\n  /** Custom Workflow span name. Defaults to \"Workflow\". */\n  workflowSpanName?: string;\n\n  /** Add active OTel IDs to durable log records. Defaults to true. */\n  enrichLogger?: boolean;\n}\n```\n\nProvider selection is implicit:\n\n- omit `tracerProviderFactory` to use the global provider;\n- provide `tracerProviderFactory` to use the returned application-owned\n  provider.\n\nThe default instrumentation scope name is\n`aws-durable-execution-sdk-js`.\n\n## Spans, Attributes, and Status\n\nAll plugin-created spans use `SpanKind.INTERNAL`.\n\n- **Workflow:** Named by `workflowSpanName`, which defaults to `Workflow`.\n  Carries `durable.execution.arn` and, when terminal,\n  `durable.execution.status`.\n- **Invocation:** Named `Invocation`. Carries `durable.execution.arn`,\n  `durable.invocation.first`, and `durable.invocation.status`.\n- **Operation:** Named from the configured operation name, or the operation\n  type when unnamed. Carries `durable.execution.arn`,\n  `durable.operation.id`, `durable.operation.type`, optional\n  `durable.operation.name`, and optional `durable.operation.subtype`.\n  `InvocationOtelPlugin` sets `durable.operation.status=STARTED` at span\n  creation; both plugins apply a supplied terminal operation status at\n  completion. `durable.attempt.number` is added to `STEP` and\n  `WAIT_FOR_CONDITION` operation spans when supplied.\n- **Attempt:** Named `<operation name or type> attempt <number>`. Carries the\n  operation identity attributes, `durable.attempt.number`, and terminal\n  `durable.attempt.outcome`. Attempt spans do not carry\n  `durable.operation.status`.\n\nFor `ExecutionOtelPlugin` with an application-owned provider, Invocation also\nadds `cloud.resource_id` and `faas.max_memory` when the corresponding Lambda\nenvironment values are available.\n\nOpenTelemetry status mapping is:\n\n| Span       | Durable result                                                     | OTel status              |\n| ---------- | ------------------------------------------------------------------ | ------------------------ |\n| Workflow   | `SUCCEEDED` / `FAILED`                                             | `OK` / `ERROR`           |\n| Invocation | `SUCCEEDED` or `PENDING` / `FAILED` / `RETRYING`                   | `OK` / `ERROR` / `UNSET` |\n| Operation  | `SUCCEEDED` / error object / other failure without an error object | `OK` / `ERROR` / `UNSET` |\n| Attempt    | `FAILED` / any other outcome                                       | `ERROR` / `OK`           |\n\nOperation and attempt errors are recorded as exception events when an error\nobject is available. Workflow and Invocation failures set an `ERROR` status and\nstatus message without recording an exception event.\n\n## Log Correlation\n\nWhen `enrichLogger` is enabled, durable log records receive the currently\nactive OpenTelemetry `traceId`, `spanId`, and `otelTraceSampled` values.\nOutside an active span, no fields are added.\n\nDisable enrichment when another logging integration already injects equivalent\nfields:\n\n```typescript\nconst plugin = new ExecutionOtelPlugin({\n  enrichLogger: false,\n});\n```\n\nFor `ExecutionOtelPlugin`, handler-level logs correlate with Workflow. For\n`InvocationOtelPlugin`, handler-level logs correlate with Invocation. Logs\ninside child contexts and attempts correlate with their active operation or\nattempt span.\n\n## Public API\n\n### Plugins\n\n```typescript\nnew ExecutionOtelPlugin(config?: OtelPluginConfig);\nnew InvocationOtelPlugin(config?: OtelPluginConfig);\n```\n\n### Provider Types\n\n```typescript\ntype IdGeneratorFactory = (fallbackIdGenerator?: IdGenerator) => IdGenerator;\n\ntype TracerProviderFactory = (\n  createIdGenerator: IdGeneratorFactory,\n) => TracerProvider;\n```\n\n### `DeterministicIdGenerator`\n\nAn OpenTelemetry `IdGenerator` with `AsyncLocalStorage`-scoped deterministic\noverrides. `withIds()` applies optional trace and span IDs only while its\nsynchronous callback starts a span. The span ID override is consumed after its\nfirst use. All other ID generation delegates to the fallback generator.\n\n```typescript\nconst generator = new DeterministicIdGenerator(fallbackIdGenerator);\n\nconst span = generator.withIds(\n  { traceId: executionTraceId, spanId: deterministicSpanId },\n  () => tracer.startSpan(\"operation\"),\n);\n```\n\n### ID Helpers\n\n```typescript\nderiveTraceIdFromArn(\n  executionArn: string,\n  executionStartTimestamp?: Date,\n): string;\n\nderiveTraceIdFromXRayRoot(xRayRoot: string): string | undefined;\n\nderiveExecutionTraceId(\n  environment: ExecutionTraceEnvironment,\n  executionArn: string,\n  executionStartTimestamp?: Date,\n): string;\n\nderiveWorkflowSpanId(executionArn: string): string;\n\nderiveExecutionRootSpanId(executionArn: string): string;\n\nderiveSpanIdFromOperationId(\n  operationId: string,\n  executionArn: string,\n): string;\n```\n\n`deriveTraceIdFromArn` returns a 32-character hexadecimal trace ID.\n`deriveTraceIdFromXRayRoot` converts a valid X-Ray `Root` value to an\nOpenTelemetry trace ID and returns `undefined` for invalid input.\n`deriveExecutionTraceId` applies the default plugin precedence to an explicit\nenvironment: a valid `_X_AMZN_TRACE_ID` `Root` wins, otherwise it uses the same\nARN-and-start-time fallback as the plugins. Pass `process.env` in Lambda or a\nplain object in tests. When no valid X-Ray Root is available, pass the same\nexecution start timestamp supplied to the plugin; omit it only when it is\nunavailable to both callers.\n`deriveWorkflowSpanId` hashes `workflow:<execution ARN>`,\n`deriveExecutionRootSpanId` hashes `execution-root:<execution ARN>` (a distinct\nnamespace so the synthetic root never collides with the Workflow or operation\nspans on the shared trace), and `deriveSpanIdFromOperationId` hashes\n`<execution ARN>:<operation ID>`. All three span helpers return 16-character\nhexadecimal IDs.\n\nWrapper-style instrumentation can create spans on the same execution trace and\nrefer to the same Workflow span without copying the plugin's derivations:\n\n```typescript\nimport {\n  deriveExecutionTraceId,\n  deriveWorkflowSpanId,\n} from \"@aws/durable-execution-sdk-js-otel\";\n\nconst executionTraceId = deriveExecutionTraceId(\n  process.env,\n  executionArn,\n  executionStartTimestamp,\n);\nconst workflowSpanId = deriveWorkflowSpanId(executionArn);\n```\n\n### Context Extractors\n\n```typescript\nxRayContextExtractor(info: InvocationInfo): ContextExtractorResult;\nw3cClientContextExtractor(info: InvocationInfo): ContextExtractorResult;\n```\n\nThe package also exports the `ContextExtractor`, `ContextExtractorResult`,\n`ExecutionTraceEnvironment`, `IdGeneratorFactory`, `TracerProviderFactory`, and\n`OtelPluginConfig` types.\n\n## Verification and Troubleshooting\n\nAfter deployment:\n\n1. Invoke a durable function with multiple steps or a wait/resume cycle.\n2. Verify Invocation spans and completed operation spans appear after enabled\n   invocations.\n3. Verify one Workflow span appears after the execution becomes terminal.\n4. Expect the Workflow span, every Invocation span, and the operation/attempt\n   spans to share one execution trace ID.\n5. Confirm the documented cross-links connect the workflow and invocation views.\n6. Confirm unrelated root spans retain provider-generated trace IDs.\n7. Verify durable log records contain correlation fields when\n   `enrichLogger` is enabled.\n\nIf no plugin spans appear:\n\n- confirm a compatible SDK provider is registered before invocation start, or\n  return one through `tracerProviderFactory`;\n- confirm the provider has a span processor and exporter;\n- check for the plugin warning that says telemetry was disabled because the\n  global tracer was incompatible;\n- remember that dynamic loading supports only the global-provider path;\n- remember that Workflow is not exported until `SUCCEEDED` or `FAILED`.\n\nOne execution trace is expected. The Workflow span and every per-invocation\nInvocation span share it, anchored at the execution ancestor (the propagated\nremote parent, or a synthetic execution root).\n\n## License\n\nApache-2.0\n","readmeFilename":"README.md"}