autotel 6.1.0 → 6.2.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.
- package/dist/analysis.cjs +1 -2
- package/dist/analysis.d.cts +1 -2
- package/dist/analysis.d.ts +1 -2
- package/dist/analysis.js +1 -2
- package/dist/attribute-redacting-processor-Pk7lAzWd.d.cts +1 -2
- package/dist/attribute-redacting-processor-Pk7lAzWd.d.ts +1 -2
- package/dist/attribute-redacting-processor.cjs +1 -2
- package/dist/attribute-redacting-processor.js +1 -2
- package/dist/attributes-B7wix2VG.js +1 -2
- package/dist/attributes-aDmJYral.cjs +1 -2
- package/dist/auto.cjs +2 -3
- package/dist/auto.js +2 -3
- package/dist/business-baggage.cjs +1 -2
- package/dist/business-baggage.d.cts +1 -2
- package/dist/business-baggage.d.ts +1 -2
- package/dist/business-baggage.js +1 -2
- package/dist/canonical-log-line-processor-B4WgG-VS.d.cts +1 -2
- package/dist/canonical-log-line-processor-CL_J7gb5.d.ts +1 -2
- package/dist/canonical-log-line-processor-DOjb6Kxy.cjs +1 -2
- package/dist/canonical-log-line-processor-mKABvGP0.js +1 -2
- package/dist/config.cjs +9 -3
- package/dist/config.d.cts +1 -2
- package/dist/config.d.ts +1 -2
- package/dist/config.js +9 -3
- package/dist/correlated-events-Bzh5y-UB.js +1 -2
- package/dist/correlated-events-kSwLo3mi.cjs +1 -2
- package/dist/correlation-id.cjs +1 -1
- package/dist/correlation-id.d.cts +1 -2
- package/dist/correlation-id.d.ts +1 -2
- package/dist/correlation-id.js +1 -1
- package/dist/db.cjs +1 -2
- package/dist/db.d.cts +1 -2
- package/dist/db.d.ts +1 -2
- package/dist/db.js +1 -2
- package/dist/decorators.cjs +2 -3
- package/dist/decorators.d.cts +1 -2
- package/dist/decorators.d.ts +1 -2
- package/dist/decorators.js +2 -3
- package/dist/define-event-B2z1SBe7.d.ts +1 -2
- package/dist/define-event-CGG048HE.d.cts +1 -2
- package/dist/diagnostics.cjs +1 -2
- package/dist/diagnostics.d.cts +1 -2
- package/dist/diagnostics.d.ts +1 -2
- package/dist/diagnostics.js +1 -2
- package/dist/drain-pipeline.cjs +1 -2
- package/dist/drain-pipeline.d.cts +1 -2
- package/dist/drain-pipeline.d.ts +1 -2
- package/dist/drain-pipeline.js +1 -2
- package/dist/enrichers.cjs +1 -2
- package/dist/enrichers.d.cts +1 -2
- package/dist/enrichers.d.ts +1 -2
- package/dist/enrichers.js +1 -2
- package/dist/event-subscriber-CWh8sTGh.d.cts +1 -2
- package/dist/event-subscriber-CWh8sTGh.d.ts +1 -2
- package/dist/event-testing-CA2mIx1E.d.ts +1 -2
- package/dist/event-testing-D0qWfqAy.d.cts +1 -2
- package/dist/event-testing.cjs +1 -2
- package/dist/event-testing.js +1 -2
- package/dist/event.cjs +1 -1
- package/dist/event.d.cts +1 -2
- package/dist/event.d.ts +1 -2
- package/dist/event.js +1 -1
- package/dist/exporters.d.cts +1 -2
- package/dist/exporters.d.ts +1 -2
- package/dist/filtering-span-processor-BpDagWNa.d.cts +1 -2
- package/dist/filtering-span-processor-BpDagWNa.d.ts +1 -2
- package/dist/filtering-span-processor.cjs +1 -2
- package/dist/filtering-span-processor.js +1 -2
- package/dist/{functional-BnDUxnSl.js → functional-2AZsH_gQ.js} +2 -3
- package/dist/{functional-DcLBuCPz.cjs → functional-CogDARqC.cjs} +2 -3
- package/dist/functional.cjs +1 -1
- package/dist/functional.d.cts +1 -2
- package/dist/functional.d.ts +1 -2
- package/dist/functional.js +1 -1
- package/dist/http.cjs +2 -3
- package/dist/http.d.cts +1 -2
- package/dist/http.d.ts +1 -2
- package/dist/http.js +2 -3
- package/dist/index-BPcxVucm.d.cts +1 -2
- package/dist/index-DolOVX6F.d.ts +1 -2
- package/dist/index.cjs +3 -4
- package/dist/index.d.cts +2 -3
- package/dist/index.d.ts +2 -3
- package/dist/index.js +3 -4
- package/dist/{init-D6n2diBy.d.ts → init-BHp-kqLJ.d.ts} +12 -4
- package/dist/{init-XzXzrarP.d.cts → init-BoIYyB6Q.d.cts} +12 -4
- package/dist/{init-R-gSEXkJ.js → init-Bu6wR-k_.js} +56 -6
- package/dist/{init-C3RApHKJ.cjs → init-BzVuFs5a.cjs} +56 -6
- package/dist/instrumentation.cjs +2 -3
- package/dist/instrumentation.d.cts +1 -2
- package/dist/instrumentation.d.ts +1 -2
- package/dist/instrumentation.js +2 -3
- package/dist/logger-CN4xpzMd.d.cts +1 -2
- package/dist/logger-CN4xpzMd.d.ts +1 -2
- package/dist/logger-D3Ej3DII.js +1 -2
- package/dist/logger-thMPLpOG.cjs +1 -2
- package/dist/messaging-adapters.cjs +1 -2
- package/dist/messaging-adapters.d.cts +1 -2
- package/dist/messaging-adapters.d.ts +1 -2
- package/dist/messaging-adapters.js +1 -2
- package/dist/messaging-testing.cjs +1 -2
- package/dist/messaging-testing.d.cts +1 -2
- package/dist/messaging-testing.d.ts +1 -2
- package/dist/messaging-testing.js +1 -2
- package/dist/messaging.cjs +2 -3
- package/dist/messaging.d.cts +1 -2
- package/dist/messaging.d.ts +1 -2
- package/dist/messaging.js +2 -3
- package/dist/metric-helpers.cjs +1 -2
- package/dist/metric-helpers.d.cts +1 -2
- package/dist/metric-helpers.d.ts +1 -2
- package/dist/metric-helpers.js +1 -2
- package/dist/metric-testing-CWm6UhaR.d.ts +1 -2
- package/dist/metric-testing-CpvP3ZIa.d.cts +1 -2
- package/dist/metric-testing.cjs +1 -2
- package/dist/metric-testing.js +1 -2
- package/dist/metric.cjs +1 -2
- package/dist/metric.d.cts +1 -2
- package/dist/metric.d.ts +1 -2
- package/dist/metric.js +1 -2
- package/dist/node-require-PFqDihze.cjs +1 -2
- package/dist/node-require-vROmTeJ8.js +1 -2
- package/dist/parse-error.cjs +1 -2
- package/dist/parse-error.d.cts +1 -2
- package/dist/parse-error.d.ts +1 -2
- package/dist/parse-error.js +1 -2
- package/dist/pretty-console-exporter-CMzlrRNg.cjs +1 -2
- package/dist/pretty-console-exporter-DqKl_q9z.js +1 -2
- package/dist/register.cjs +1 -2
- package/dist/register.js +1 -2
- package/dist/registry-DVSmWg6Y.js +1 -2
- package/dist/registry-DYgvb62e.cjs +1 -2
- package/dist/sampling-BR9fkSwx.d.cts +1 -2
- package/dist/sampling-CP3e7-Yr.d.ts +1 -2
- package/dist/sampling.cjs +1 -2
- package/dist/sampling.js +1 -2
- package/dist/security-schema.cjs +1 -2
- package/dist/security-schema.d.cts +1 -2
- package/dist/security-schema.d.ts +1 -2
- package/dist/security-schema.js +1 -2
- package/dist/semantic-conventions-FhSxv-bK.d.cts +1 -2
- package/dist/semantic-conventions-FhSxv-bK.d.ts +1 -2
- package/dist/semantic-conventions.cjs +1 -2
- package/dist/semantic-conventions.js +1 -2
- package/dist/semantic-helpers.cjs +2 -3
- package/dist/semantic-helpers.d.cts +1 -2
- package/dist/semantic-helpers.d.ts +1 -2
- package/dist/semantic-helpers.js +2 -3
- package/dist/slo.cjs +1 -2
- package/dist/slo.d.cts +1 -2
- package/dist/slo.d.ts +1 -2
- package/dist/slo.js +1 -2
- package/dist/span-name-normalizer-CN1-8C76.d.cts +1 -2
- package/dist/span-name-normalizer-CN1-8C76.d.ts +1 -2
- package/dist/span-name-normalizer.cjs +1 -2
- package/dist/span-name-normalizer.js +1 -2
- package/dist/stable-hash-CS9BxvVQ.cjs +1 -2
- package/dist/stable-hash-ChFBIhNt.js +1 -2
- package/dist/structured-error-9--cxBay.js +1 -2
- package/dist/structured-error-CHg7DoIQ.cjs +1 -2
- package/dist/tail-sampling-processor.cjs +1 -2
- package/dist/tail-sampling-processor.d.cts +1 -2
- package/dist/tail-sampling-processor.d.ts +1 -2
- package/dist/tail-sampling-processor.js +1 -2
- package/dist/test-span-collector.cjs +1 -2
- package/dist/test-span-collector.d.cts +1 -2
- package/dist/test-span-collector.d.ts +1 -2
- package/dist/test-span-collector.js +1 -2
- package/dist/testing.cjs +1 -2
- package/dist/testing.d.cts +1 -2
- package/dist/testing.d.ts +1 -2
- package/dist/testing.js +1 -2
- package/dist/trace-context-IuyoPyNq.d.cts +1 -2
- package/dist/trace-context-IuyoPyNq.d.ts +1 -2
- package/dist/trace-factory-validation-BjVAinz6.js +1 -2
- package/dist/trace-factory-validation-Dc8epn87.cjs +1 -2
- package/dist/trace-helpers.cjs +1 -2
- package/dist/trace-helpers.d.cts +1 -2
- package/dist/trace-helpers.d.ts +1 -2
- package/dist/trace-helpers.js +1 -2
- package/dist/tracer-provider.cjs +1 -2
- package/dist/tracer-provider.d.cts +1 -2
- package/dist/tracer-provider.d.ts +1 -2
- package/dist/tracer-provider.js +1 -2
- package/dist/validate.cjs +1 -2
- package/dist/validate.d.cts +1 -2
- package/dist/validate.d.ts +1 -2
- package/dist/validate.js +1 -2
- package/dist/validation-attributes.cjs +1 -2
- package/dist/validation-attributes.d.cts +1 -2
- package/dist/validation-attributes.d.ts +1 -2
- package/dist/validation-attributes.js +1 -2
- package/dist/webhook.cjs +2 -3
- package/dist/webhook.d.cts +1 -2
- package/dist/webhook.d.ts +1 -2
- package/dist/webhook.js +2 -3
- package/dist/workflow-distributed.cjs +2 -3
- package/dist/workflow-distributed.d.cts +1 -2
- package/dist/workflow-distributed.d.ts +1 -2
- package/dist/workflow-distributed.js +2 -3
- package/dist/workflow.cjs +2 -3
- package/dist/workflow.d.cts +1 -2
- package/dist/workflow.d.ts +1 -2
- package/dist/workflow.js +2 -3
- package/dist/yaml-config.cjs +1 -2
- package/dist/yaml-config.d.cts +4 -5
- package/dist/yaml-config.d.ts +4 -5
- package/dist/yaml-config.js +1 -2
- package/package.json +47 -32
- package/dist/analysis.cjs.map +0 -1
- package/dist/analysis.d.cts.map +0 -1
- package/dist/analysis.d.ts.map +0 -1
- package/dist/analysis.js.map +0 -1
- package/dist/attribute-redacting-processor-Pk7lAzWd.d.cts.map +0 -1
- package/dist/attribute-redacting-processor-Pk7lAzWd.d.ts.map +0 -1
- package/dist/attribute-redacting-processor.cjs.map +0 -1
- package/dist/attribute-redacting-processor.js.map +0 -1
- package/dist/attributes-B7wix2VG.js.map +0 -1
- package/dist/attributes-aDmJYral.cjs.map +0 -1
- package/dist/auto.cjs.map +0 -1
- package/dist/auto.js.map +0 -1
- package/dist/business-baggage.cjs.map +0 -1
- package/dist/business-baggage.d.cts.map +0 -1
- package/dist/business-baggage.d.ts.map +0 -1
- package/dist/business-baggage.js.map +0 -1
- package/dist/canonical-log-line-processor-B4WgG-VS.d.cts.map +0 -1
- package/dist/canonical-log-line-processor-CL_J7gb5.d.ts.map +0 -1
- package/dist/canonical-log-line-processor-DOjb6Kxy.cjs.map +0 -1
- package/dist/canonical-log-line-processor-mKABvGP0.js.map +0 -1
- package/dist/config.cjs.map +0 -1
- package/dist/config.d.cts.map +0 -1
- package/dist/config.d.ts.map +0 -1
- package/dist/config.js.map +0 -1
- package/dist/correlated-events-Bzh5y-UB.js.map +0 -1
- package/dist/correlated-events-kSwLo3mi.cjs.map +0 -1
- package/dist/correlation-id.d.cts.map +0 -1
- package/dist/correlation-id.d.ts.map +0 -1
- package/dist/db.cjs.map +0 -1
- package/dist/db.d.cts.map +0 -1
- package/dist/db.d.ts.map +0 -1
- package/dist/db.js.map +0 -1
- package/dist/decorators.cjs.map +0 -1
- package/dist/decorators.d.cts.map +0 -1
- package/dist/decorators.d.ts.map +0 -1
- package/dist/decorators.js.map +0 -1
- package/dist/define-event-B2z1SBe7.d.ts.map +0 -1
- package/dist/define-event-CGG048HE.d.cts.map +0 -1
- package/dist/diagnostics.cjs.map +0 -1
- package/dist/diagnostics.d.cts.map +0 -1
- package/dist/diagnostics.d.ts.map +0 -1
- package/dist/diagnostics.js.map +0 -1
- package/dist/drain-pipeline.cjs.map +0 -1
- package/dist/drain-pipeline.d.cts.map +0 -1
- package/dist/drain-pipeline.d.ts.map +0 -1
- package/dist/drain-pipeline.js.map +0 -1
- package/dist/enrichers.cjs.map +0 -1
- package/dist/enrichers.d.cts.map +0 -1
- package/dist/enrichers.d.ts.map +0 -1
- package/dist/enrichers.js.map +0 -1
- package/dist/event-subscriber-CWh8sTGh.d.cts.map +0 -1
- package/dist/event-subscriber-CWh8sTGh.d.ts.map +0 -1
- package/dist/event-testing-CA2mIx1E.d.ts.map +0 -1
- package/dist/event-testing-D0qWfqAy.d.cts.map +0 -1
- package/dist/event-testing.cjs.map +0 -1
- package/dist/event-testing.js.map +0 -1
- package/dist/event.d.cts.map +0 -1
- package/dist/event.d.ts.map +0 -1
- package/dist/exporters.d.cts.map +0 -1
- package/dist/exporters.d.ts.map +0 -1
- package/dist/filtering-span-processor-BpDagWNa.d.cts.map +0 -1
- package/dist/filtering-span-processor-BpDagWNa.d.ts.map +0 -1
- package/dist/filtering-span-processor.cjs.map +0 -1
- package/dist/filtering-span-processor.js.map +0 -1
- package/dist/functional-BnDUxnSl.js.map +0 -1
- package/dist/functional-DcLBuCPz.cjs.map +0 -1
- package/dist/functional.d.cts.map +0 -1
- package/dist/functional.d.ts.map +0 -1
- package/dist/http.cjs.map +0 -1
- package/dist/http.d.cts.map +0 -1
- package/dist/http.d.ts.map +0 -1
- package/dist/http.js.map +0 -1
- package/dist/index-BPcxVucm.d.cts.map +0 -1
- package/dist/index-DolOVX6F.d.ts.map +0 -1
- package/dist/index.cjs.map +0 -1
- package/dist/index.d.cts.map +0 -1
- package/dist/index.d.ts.map +0 -1
- package/dist/index.js.map +0 -1
- package/dist/init-C3RApHKJ.cjs.map +0 -1
- package/dist/init-D6n2diBy.d.ts.map +0 -1
- package/dist/init-R-gSEXkJ.js.map +0 -1
- package/dist/init-XzXzrarP.d.cts.map +0 -1
- package/dist/instrumentation.cjs.map +0 -1
- package/dist/instrumentation.d.cts.map +0 -1
- package/dist/instrumentation.d.ts.map +0 -1
- package/dist/instrumentation.js.map +0 -1
- package/dist/logger-CN4xpzMd.d.cts.map +0 -1
- package/dist/logger-CN4xpzMd.d.ts.map +0 -1
- package/dist/logger-D3Ej3DII.js.map +0 -1
- package/dist/logger-thMPLpOG.cjs.map +0 -1
- package/dist/messaging-adapters.cjs.map +0 -1
- package/dist/messaging-adapters.d.cts.map +0 -1
- package/dist/messaging-adapters.d.ts.map +0 -1
- package/dist/messaging-adapters.js.map +0 -1
- package/dist/messaging-testing.cjs.map +0 -1
- package/dist/messaging-testing.d.cts.map +0 -1
- package/dist/messaging-testing.d.ts.map +0 -1
- package/dist/messaging-testing.js.map +0 -1
- package/dist/messaging.cjs.map +0 -1
- package/dist/messaging.d.cts.map +0 -1
- package/dist/messaging.d.ts.map +0 -1
- package/dist/messaging.js.map +0 -1
- package/dist/metric-helpers.cjs.map +0 -1
- package/dist/metric-helpers.d.cts.map +0 -1
- package/dist/metric-helpers.d.ts.map +0 -1
- package/dist/metric-helpers.js.map +0 -1
- package/dist/metric-testing-CWm6UhaR.d.ts.map +0 -1
- package/dist/metric-testing-CpvP3ZIa.d.cts.map +0 -1
- package/dist/metric-testing.cjs.map +0 -1
- package/dist/metric-testing.js.map +0 -1
- package/dist/metric.cjs.map +0 -1
- package/dist/metric.d.cts.map +0 -1
- package/dist/metric.d.ts.map +0 -1
- package/dist/metric.js.map +0 -1
- package/dist/node-require-PFqDihze.cjs.map +0 -1
- package/dist/node-require-vROmTeJ8.js.map +0 -1
- package/dist/parse-error.cjs.map +0 -1
- package/dist/parse-error.d.cts.map +0 -1
- package/dist/parse-error.d.ts.map +0 -1
- package/dist/parse-error.js.map +0 -1
- package/dist/pretty-console-exporter-CMzlrRNg.cjs.map +0 -1
- package/dist/pretty-console-exporter-DqKl_q9z.js.map +0 -1
- package/dist/register.cjs.map +0 -1
- package/dist/register.js.map +0 -1
- package/dist/registry-DVSmWg6Y.js.map +0 -1
- package/dist/registry-DYgvb62e.cjs.map +0 -1
- package/dist/sampling-BR9fkSwx.d.cts.map +0 -1
- package/dist/sampling-CP3e7-Yr.d.ts.map +0 -1
- package/dist/sampling.cjs.map +0 -1
- package/dist/sampling.js.map +0 -1
- package/dist/security-schema.cjs.map +0 -1
- package/dist/security-schema.d.cts.map +0 -1
- package/dist/security-schema.d.ts.map +0 -1
- package/dist/security-schema.js.map +0 -1
- package/dist/semantic-conventions-FhSxv-bK.d.cts.map +0 -1
- package/dist/semantic-conventions-FhSxv-bK.d.ts.map +0 -1
- package/dist/semantic-conventions.cjs.map +0 -1
- package/dist/semantic-conventions.js.map +0 -1
- package/dist/semantic-helpers.cjs.map +0 -1
- package/dist/semantic-helpers.d.cts.map +0 -1
- package/dist/semantic-helpers.d.ts.map +0 -1
- package/dist/semantic-helpers.js.map +0 -1
- package/dist/slo.cjs.map +0 -1
- package/dist/slo.d.cts.map +0 -1
- package/dist/slo.d.ts.map +0 -1
- package/dist/slo.js.map +0 -1
- package/dist/span-name-normalizer-CN1-8C76.d.cts.map +0 -1
- package/dist/span-name-normalizer-CN1-8C76.d.ts.map +0 -1
- package/dist/span-name-normalizer.cjs.map +0 -1
- package/dist/span-name-normalizer.js.map +0 -1
- package/dist/stable-hash-CS9BxvVQ.cjs.map +0 -1
- package/dist/stable-hash-ChFBIhNt.js.map +0 -1
- package/dist/structured-error-9--cxBay.js.map +0 -1
- package/dist/structured-error-CHg7DoIQ.cjs.map +0 -1
- package/dist/tail-sampling-processor.cjs.map +0 -1
- package/dist/tail-sampling-processor.d.cts.map +0 -1
- package/dist/tail-sampling-processor.d.ts.map +0 -1
- package/dist/tail-sampling-processor.js.map +0 -1
- package/dist/test-span-collector.cjs.map +0 -1
- package/dist/test-span-collector.d.cts.map +0 -1
- package/dist/test-span-collector.d.ts.map +0 -1
- package/dist/test-span-collector.js.map +0 -1
- package/dist/testing.cjs.map +0 -1
- package/dist/testing.d.cts.map +0 -1
- package/dist/testing.d.ts.map +0 -1
- package/dist/testing.js.map +0 -1
- package/dist/trace-context-IuyoPyNq.d.cts.map +0 -1
- package/dist/trace-context-IuyoPyNq.d.ts.map +0 -1
- package/dist/trace-factory-validation-BjVAinz6.js.map +0 -1
- package/dist/trace-factory-validation-Dc8epn87.cjs.map +0 -1
- package/dist/trace-helpers.cjs.map +0 -1
- package/dist/trace-helpers.d.cts.map +0 -1
- package/dist/trace-helpers.d.ts.map +0 -1
- package/dist/trace-helpers.js.map +0 -1
- package/dist/tracer-provider.cjs.map +0 -1
- package/dist/tracer-provider.d.cts.map +0 -1
- package/dist/tracer-provider.d.ts.map +0 -1
- package/dist/tracer-provider.js.map +0 -1
- package/dist/validate.cjs.map +0 -1
- package/dist/validate.d.cts.map +0 -1
- package/dist/validate.d.ts.map +0 -1
- package/dist/validate.js.map +0 -1
- package/dist/validation-attributes.cjs.map +0 -1
- package/dist/validation-attributes.d.cts.map +0 -1
- package/dist/validation-attributes.d.ts.map +0 -1
- package/dist/validation-attributes.js.map +0 -1
- package/dist/webhook.cjs.map +0 -1
- package/dist/webhook.d.cts.map +0 -1
- package/dist/webhook.d.ts.map +0 -1
- package/dist/webhook.js.map +0 -1
- package/dist/workflow-distributed.cjs.map +0 -1
- package/dist/workflow-distributed.d.cts.map +0 -1
- package/dist/workflow-distributed.d.ts.map +0 -1
- package/dist/workflow-distributed.js.map +0 -1
- package/dist/workflow.cjs.map +0 -1
- package/dist/workflow.d.cts.map +0 -1
- package/dist/workflow.d.ts.map +0 -1
- package/dist/workflow.js.map +0 -1
- package/dist/yaml-config.cjs.map +0 -1
- package/dist/yaml-config.d.cts.map +0 -1
- package/dist/yaml-config.d.ts.map +0 -1
- package/dist/yaml-config.js.map +0 -1
package/dist/db.js.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"db.js","names":[],"sources":["../src/db.ts"],"sourcesContent":["/**\n * Database Instrumentation Helpers\n *\n * Optional import: Not included in main bundle\n * Import from: 'autotel/db'\n *\n * Provides functional utilities for database query instrumentation.\n * Works with Prisma, Drizzle, TypeORM, raw SQL, and more.\n *\n * @example\n * ```typescript\n * import { instrumentDatabase } from 'autotel/db'\n *\n * const db = drizzle(pool)\n * instrumentDatabase(db, { dbSystem: 'postgresql', dbName: 'myapp' })\n *\n * // Now all queries are automatically trace\n * await db.select().from(users)\n * ```\n */\n\nimport { SpanStatusCode } from '@opentelemetry/api';\nimport { getConfig } from './config';\n\n/**\n * Helper: Trace a single database query\n *\n * @example\n * ```typescript\n * import { tracebQuery } from 'autotel/db'\n *\n * const users = await tracebQuery(\n * 'postgresql',\n * 'SELECT',\n * () => db.query('SELECT * FROM users WHERE active = true')\n * )\n * ```\n */\nexport async function tracebQuery<T>(\n dbSystem: string,\n operation: string,\n fn: () => Promise<T>,\n attributes?: Record<string, string | number>,\n): Promise<T> {\n const config = getConfig();\n const tracer = config.tracer;\n\n const spanName = `${dbSystem}.${operation}`;\n\n return tracer.startActiveSpan(spanName, async (span) => {\n const startTime = performance.now();\n\n try {\n span.setAttributes({\n 'db.system': dbSystem,\n 'db.operation': operation,\n ...attributes,\n });\n\n const result = await fn();\n\n const duration = performance.now() - startTime;\n span.setStatus({ code: SpanStatusCode.OK });\n span.setAttribute('db.duration_ms', duration);\n\n if (Array.isArray(result)) {\n span.setAttribute('db.result_count', result.length);\n }\n\n return result;\n } catch (error) {\n const duration = performance.now() - startTime;\n\n span.setStatus({\n code: SpanStatusCode.ERROR,\n message: error instanceof Error ? error.message : 'Unknown error',\n });\n\n span.setAttributes({\n 'db.duration_ms': duration,\n 'error.type':\n error instanceof Error ? error.constructor.name : 'Unknown',\n 'error.message':\n error instanceof Error ? error.message : 'Unknown error',\n });\n\n throw error;\n } finally {\n span.end();\n }\n });\n}\n\n// Helper functions\n\nfunction inferDbOperation(methodName: string): string {\n const lower = methodName.toLowerCase();\n if (lower.includes('find') || lower.includes('get') || lower.includes('list'))\n return 'SELECT';\n if (lower.includes('create') || lower.includes('insert')) return 'INSERT';\n if (lower.includes('update') || lower.includes('modify')) return 'UPDATE';\n if (lower.includes('delete') || lower.includes('remove')) return 'DELETE';\n if (lower.includes('count')) return 'COUNT';\n return 'QUERY';\n}\n\nfunction inferTableName(methodName: string): string | undefined {\n // Extract table name from method patterns like:\n // findUser -> user\n // listUsers -> users\n // createOrder -> order\n\n const patterns = [\n /find([A-Z][a-zA-Z]+)/,\n /get([A-Z][a-zA-Z]+)/,\n /list([A-Z][a-zA-Z]+)/,\n /create([A-Z][a-zA-Z]+)/,\n /update([A-Z][a-zA-Z]+)/,\n /delete([A-Z][a-zA-Z]+)/,\n /remove([A-Z][a-zA-Z]+)/,\n ];\n\n for (const pattern of patterns) {\n const match = methodName.match(pattern);\n if (match && match[1]) {\n return match[1].toLowerCase();\n }\n }\n\n return undefined;\n}\n\nfunction sanitizeSqlQuery(query: string): string {\n // Remove string literals and sensitive values (PII, credentials, etc.)\n // Preserves query structure for debugging while protecting data\n return query\n .replaceAll(/'[^']*'/g, \"'?'\")\n .replaceAll(/\"[^\"]*\"/g, '\"?\"')\n .replaceAll(/\\b\\d+\\b/g, '?') // Replace literal numbers\n .trim();\n}\n\n/**\n * Common database operation metrics\n */\nexport const DB_OPERATIONS = {\n SELECT: 'SELECT',\n INSERT: 'INSERT',\n UPDATE: 'UPDATE',\n DELETE: 'DELETE',\n COUNT: 'COUNT',\n AGGREGATE: 'AGGREGATE',\n} as const;\n\n/**\n * Common database systems\n */\nexport const DB_SYSTEMS = {\n POSTGRESQL: 'postgresql',\n MYSQL: 'mysql',\n MONGODB: 'mongodb',\n REDIS: 'redis',\n SQLITE: 'sqlite',\n MSSQL: 'mssql',\n} as const;\n\n// Symbol for idempotency - prevents double-instrumentation\nconst INSTRUMENTED_SYMBOL = Symbol.for('autotel.db.instrumented');\n\n/**\n * Options for instrumentDatabase\n */\nexport interface InstrumentDatabaseOptions {\n /** Database system (e.g., 'postgresql', 'mysql') */\n dbSystem: string;\n /** Database name (optional) */\n dbName?: string;\n /** Method names to instrument (if not provided, instruments common patterns) */\n methods?: string[];\n /** Method names to skip */\n skipMethods?: string[];\n /** Sanitize queries (remove sensitive data) - default: true */\n sanitizeQuery?: boolean;\n /** Slow query threshold in milliseconds - default: 1000ms */\n slowQueryThresholdMs?: number;\n}\n\n/**\n * Instrument a database client instance with OpenTelemetry tracing\n *\n * This is a function-based alternative to @DbInstrumented decorator.\n * Modifies the client in-place and returns it (idempotent - safe to call multiple times).\n *\n * Inspired by otel-drizzle and other otel instrumentation packages.\n *\n * @example Drizzle ORM\n * ```typescript\n * import { drizzle } from 'drizzle-orm/node-postgres'\n * import { instrumentDatabase } from 'autotel/db'\n *\n * const db = drizzle(pool)\n * instrumentDatabase(db, { dbSystem: 'postgresql', dbName: 'myapp' })\n *\n * // Now all db queries are automatically trace\n * await db.select().from(users)\n * ```\n *\n * @example Prisma\n * ```typescript\n * import { PrismaClient } from '@prisma/client'\n * import { instrumentDatabase } from 'autotel/db'\n *\n * const prisma = new PrismaClient()\n * instrumentDatabase(prisma, {\n * dbSystem: 'postgresql',\n * methods: ['findMany', 'findUnique', 'create', 'update', 'delete']\n * })\n *\n * // All specified methods are trace\n * await prisma.user.findMany()\n * ```\n *\n * @example Generic database client\n * ```typescript\n * import { instrumentDatabase } from 'autotel/db'\n *\n * const db = createDatabaseClient()\n * instrumentDatabase(db, {\n * dbSystem: 'mongodb',\n * methods: ['find', 'findOne', 'insertOne', 'updateOne', 'deleteOne']\n * })\n * ```\n */\nexport function instrumentDatabase<T extends object>(\n client: T,\n options: InstrumentDatabaseOptions,\n): T {\n // Idempotency check - if already instrumented, return as-is\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n if ((client as any)[INSTRUMENTED_SYMBOL]) {\n return client;\n }\n\n const {\n dbSystem,\n dbName,\n methods,\n skipMethods = [],\n sanitizeQuery = true,\n slowQueryThresholdMs = 1000,\n } = options;\n\n const config = getConfig();\n const tracer = config.tracer;\n\n // Determine which methods to instrument\n const methodsToInstrument = methods || extractDatabaseMethods(client);\n const skipSet = new Set(skipMethods);\n\n for (const methodName of methodsToInstrument) {\n if (skipSet.has(methodName)) continue;\n if (methodName.startsWith('_')) continue; // Skip private methods\n\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const method = (client as any)[methodName];\n if (typeof method !== 'function') continue;\n\n // Preserve the original method\n const originalMethod = method;\n\n // Wrap the method\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n (client as any)[methodName] = async function (this: T, ...args: any[]) {\n const operation = inferDbOperation(methodName);\n const table = inferTableName(methodName);\n\n const spanName = table\n ? `${dbSystem}.${operation} ${table}`\n : `${dbSystem}.${operation}`;\n\n return tracer.startActiveSpan(spanName, async (span) => {\n const startTime = performance.now();\n\n try {\n span.setAttributes({\n 'db.system': dbSystem,\n 'db.operation': operation,\n });\n\n if (dbName) {\n span.setAttribute('db.name', dbName);\n }\n\n if (table) {\n span.setAttribute('db.sql.table', table);\n }\n\n // Try to extract query from arguments (common patterns)\n const query = extractQueryFromArgs(args);\n if (query) {\n span.setAttribute(\n 'db.statement',\n sanitizeQuery ? sanitizeSqlQuery(query) : query,\n );\n }\n\n // Execute original method\n const result = await originalMethod.apply(this, args);\n\n const duration = performance.now() - startTime;\n\n span.setStatus({ code: SpanStatusCode.OK });\n span.setAttributes({\n 'db.duration_ms': duration,\n });\n\n // Mark slow queries\n if (duration > slowQueryThresholdMs) {\n span.setAttribute('db.slow_query', true);\n span.setAttribute(\n 'db.slow_query_threshold_ms',\n slowQueryThresholdMs,\n );\n }\n\n // Track result count if it's an array\n if (Array.isArray(result)) {\n span.setAttribute('db.result_count', result.length);\n }\n\n return result;\n } catch (error) {\n const duration = performance.now() - startTime;\n\n span.setStatus({\n code: SpanStatusCode.ERROR,\n message: error instanceof Error ? error.message : 'Unknown error',\n });\n\n span.setAttributes({\n 'db.duration_ms': duration,\n 'error.type':\n error instanceof Error ? error.constructor.name : 'Unknown',\n 'error.message':\n error instanceof Error ? error.message : 'Unknown error',\n });\n\n span.recordException(\n error instanceof Error ? error : new Error(String(error)),\n );\n\n throw error;\n } finally {\n span.end();\n }\n });\n };\n\n // Preserve function name\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n Object.defineProperty((client as any)[methodName], 'name', {\n value: methodName,\n configurable: true,\n });\n }\n\n // Mark as instrumented\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n (client as any)[INSTRUMENTED_SYMBOL] = true;\n\n return client;\n}\n\n/**\n * Extract method names from a database client that should be instrumented\n */\nfunction extractDatabaseMethods(client: object): string[] {\n const methods: string[] = [];\n const proto = Object.getPrototypeOf(client);\n\n // Get own methods\n for (const key of Object.getOwnPropertyNames(client)) {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n if (typeof (client as any)[key] === 'function' && !key.startsWith('_')) {\n methods.push(key);\n }\n }\n\n // Get prototype methods\n if (proto) {\n for (const key of Object.getOwnPropertyNames(proto)) {\n if (\n typeof proto[key] === 'function' &&\n !key.startsWith('_') &&\n key !== 'constructor'\n ) {\n methods.push(key);\n }\n }\n }\n\n return [...new Set(methods)]; // Deduplicate\n}\n\n/**\n * Try to extract SQL query from common argument patterns\n */\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nfunction extractQueryFromArgs(args: any[]): string | undefined {\n if (args.length === 0) return undefined;\n\n const firstArg = args[0];\n\n // String query (raw SQL)\n if (typeof firstArg === 'string') {\n return firstArg;\n }\n\n // Object with sql property\n if (firstArg && typeof firstArg === 'object') {\n if ('sql' in firstArg && typeof firstArg.sql === 'string') {\n return firstArg.sql;\n }\n // PostgreSQL-style query object\n if ('text' in firstArg && typeof firstArg.text === 'string') {\n return firstArg.text;\n }\n // Query builder pattern\n if ('toQuery' in firstArg && typeof firstArg.toQuery === 'function') {\n try {\n const queryResult = firstArg.toQuery();\n if (typeof queryResult === 'string') return queryResult;\n if (\n queryResult &&\n typeof queryResult === 'object' &&\n 'sql' in queryResult\n ) {\n return queryResult.sql as string;\n }\n } catch {\n // Ignore errors from toQuery()\n }\n }\n }\n\n return undefined;\n}\n"],"mappings":"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"}
|
package/dist/decorators.cjs.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"decorators.cjs","names":["getConfig","createTraceContext","SpanStatusCode"],"sources":["../src/decorators.ts"],"sourcesContent":["/**\n * TypeScript 5+ Decorators for autotel\n *\n * Provides @Trace decorator for class-based code.\n *\n * **Requires TypeScript 5.0+**\n *\n * @example Method decorator\n * ```typescript\n * import { Trace } from 'autotel/decorators'\n *\n * class OrderService {\n * @Trace('order.create', { withMetrics: true })\n * async createOrder(data: OrderData) {\n * return await db.orders.create(data)\n * }\n *\n * @Trace() // Uses method name as span name\n * async processPayment(orderId: string) {\n * return await stripe.charge(orderId)\n * }\n * }\n * ```\n */\n\nimport type { TracingOptions, TraceContext } from './functional';\nimport { getConfig } from './config';\nimport { SpanStatusCode } from '@opentelemetry/api';\nimport { createTraceContext } from './trace-context';\n\n/**\n * Options for @Trace method decorator\n */\nexport interface TraceDecoratorOptions extends Omit<TracingOptions, 'name'> {\n /**\n * Custom span name. If not provided, uses the method name.\n */\n name?: string;\n}\n\n/**\n * @Trace - Method decorator for fine-grained tracing\n *\n * Wraps a class method with automatic tracing. Supports both patterns:\n * - Simple: method doesn't use ctx\n * - Advanced: method accesses ctx via this.ctx\n *\n * @example Simple usage (no ctx)\n * ```typescript\n * class OrderService {\n * @Trace()\n * async createOrder(data: OrderData) {\n * return await db.orders.create(data)\n * }\n * }\n * ```\n *\n * @example With custom name and options\n * ```typescript\n * class PaymentService {\n * @Trace('payment.charge', { withMetrics: true })\n * async chargeCard(amount: number) {\n * return await stripe.charges.create({ amount })\n * }\n * }\n * ```\n *\n * @example Accessing ctx\n * ```typescript\n * interface WithTraceContext {\n * ctx?: TraceContext\n * }\n *\n * class UserService {\n * @Trace()\n * async createUser(data: UserData) {\n * // Access ctx via this.ctx (available during execution)\n * const ctx = (this as unknown as WithTraceContext).ctx\n * if (ctx) {\n * ctx.setAttribute('user.id', data.id)\n * }\n * return await db.users.create(data)\n * }\n * }\n * ```\n */\nexport function Trace(\n options?: TraceDecoratorOptions,\n): <T extends (...args: unknown[]) => Promise<unknown>>(\n originalMethod: T,\n context: ClassMethodDecoratorContext,\n) => T;\nexport function Trace(\n name?: string,\n options?: TraceDecoratorOptions,\n): <T extends (...args: unknown[]) => Promise<unknown>>(\n originalMethod: T,\n context: ClassMethodDecoratorContext,\n) => T;\nexport function Trace(\n nameOrOptions?: string | TraceDecoratorOptions,\n maybeOptions?: TraceDecoratorOptions,\n): <T extends (...args: unknown[]) => Promise<unknown>>(\n originalMethod: T,\n context: ClassMethodDecoratorContext,\n) => T {\n // Parse arguments\n const name =\n typeof nameOrOptions === 'string' ? nameOrOptions : nameOrOptions?.name;\n // Options are used in the returned decorator function, not here\n const _options: TraceDecoratorOptions =\n typeof nameOrOptions === 'string'\n ? maybeOptions || {}\n : nameOrOptions || {};\n\n // TypeScript 5+ decorator signature\n return function <T extends (...args: unknown[]) => Promise<unknown>>(\n originalMethod: T,\n context: ClassMethodDecoratorContext,\n ): T {\n const methodName = String(context.name);\n\n // Skip if not an async function\n // Check multiple ways to detect async functions (for different transpilation environments)\n // TypeScript decorators run at class definition time, so we need robust detection\n const methodStr = originalMethod?.toString() || '';\n const isAsync =\n originalMethod &&\n (originalMethod.constructor?.name === 'AsyncFunction' ||\n methodStr.trim().startsWith('async ') ||\n (methodStr.includes('[native code]') && methodStr.includes('async')) ||\n // Fallback: if function has async in its string representation\n /async\\s+/.test(methodStr));\n\n if (!isAsync) {\n // Not an async function, return as-is\n return originalMethod;\n }\n\n const spanName = name || methodName;\n\n return async function <This>(\n this: This,\n ...args: unknown[]\n ): Promise<unknown> {\n const config = getConfig();\n const tracer = config.tracer;\n\n return tracer.startActiveSpan(spanName, async (span) => {\n try {\n // Make ctx available via this.ctx for methods that need it\n const ctx: TraceContext = createTraceContext(span);\n\n const originalCtx = (this as { ctx?: TraceContext }).ctx;\n try {\n (this as { ctx?: TraceContext }).ctx = ctx;\n const result = await originalMethod.apply(this, args as []);\n span.setStatus({ code: SpanStatusCode.OK });\n return result;\n } finally {\n // Restore original ctx\n if (originalCtx === undefined) {\n delete (this as { ctx?: TraceContext }).ctx;\n } else {\n (this as { ctx?: TraceContext }).ctx = originalCtx;\n }\n }\n } catch (error) {\n span.setStatus({\n code: SpanStatusCode.ERROR,\n message: error instanceof Error ? error.message : 'Unknown error',\n });\n span.recordException(\n error instanceof Error ? error : new Error(String(error)),\n );\n throw error;\n } finally {\n span.end();\n }\n });\n } as T;\n };\n}\n\n// Re-export types for convenience\n\nexport { type TraceContext, type TracingOptions } from './functional';\n"],"mappings":";;;;;;AAmGA,SAAgB,MACd,eACA,cAIK;CAEL,MAAM,OACJ,OAAO,kBAAkB,WAAW,gBAAgB,eAAe;CAQrE,OAAO,SACL,gBACA,SACG;EACH,MAAM,aAAa,OAAO,QAAQ,IAAI;EAKtC,MAAM,YAAY,gBAAgB,SAAS,KAAK;EAShD,IAAI,EAPF,mBACC,eAAe,aAAa,SAAS,mBACpC,UAAU,KAAK,CAAC,CAAC,WAAW,QAAQ,KACnC,UAAU,SAAS,eAAe,KAAK,UAAU,SAAS,OAAO,KAElE,WAAW,KAAK,SAAS,KAI3B,OAAO;EAGT,MAAM,WAAW,QAAQ;EAEzB,OAAO,eAEL,GAAG,MACe;GAIlB,OAHeA,yBACK,CAAC,CAAC,OAER,gBAAgB,UAAU,OAAO,SAAS;IACtD,IAAI;KAEF,MAAM,MAAoBC,gCAAmB,IAAI;KAEjD,MAAM,cAAe,KAAgC;KACrD,IAAI;MACF,AAAC,KAAgC,MAAM;MACvC,MAAM,SAAS,MAAM,eAAe,MAAM,MAAM,IAAU;MAC1D,KAAK,UAAU,EAAE,MAAMC,kCAAe,GAAG,CAAC;MAC1C,OAAO;KACT,UAAU;MAER,IAAI,gBAAgB,QAClB,OAAQ,KAAgC;WAExC,AAAC,KAAgC,MAAM;KAE3C;IACF,SAAS,OAAO;KACd,KAAK,UAAU;MACb,MAAMA,kCAAe;MACrB,SAAS,iBAAiB,QAAQ,MAAM,UAAU;KACpD,CAAC;KACD,KAAK,gBACH,iBAAiB,QAAQ,QAAQ,IAAI,MAAM,OAAO,KAAK,CAAC,CAC1D;KACA,MAAM;IACR,UAAU;KACR,KAAK,IAAI;IACX;GACF,CAAC;EACH;CACF;AACF"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"decorators.d.cts","names":[],"sources":["../src/decorators.ts"],"mappings":";;;;;;UAiCiB,8BAA8B,KAAK;;;;EAIlD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBAiDc,MACd,UAAU,yBACR,cAAc,oBAAoB,kBACpC,gBAAgB,GAChB,SAAS,gCACN;iBACW,MACd,eACA,UAAU,yBACR,cAAc,oBAAoB,kBACpC,gBAAgB,GAChB,SAAS,gCACN"}
|
package/dist/decorators.d.ts.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"decorators.d.ts","names":[],"sources":["../src/decorators.ts"],"mappings":";;;;;;UAiCiB,8BAA8B,KAAK;;;;EAIlD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBAiDc,MACd,UAAU,yBACR,cAAc,oBAAoB,kBACpC,gBAAgB,GAChB,SAAS,gCACN;iBACW,MACd,eACA,UAAU,yBACR,cAAc,oBAAoB,kBACpC,gBAAgB,GAChB,SAAS,gCACN"}
|
package/dist/decorators.js.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"decorators.js","names":[],"sources":["../src/decorators.ts"],"sourcesContent":["/**\n * TypeScript 5+ Decorators for autotel\n *\n * Provides @Trace decorator for class-based code.\n *\n * **Requires TypeScript 5.0+**\n *\n * @example Method decorator\n * ```typescript\n * import { Trace } from 'autotel/decorators'\n *\n * class OrderService {\n * @Trace('order.create', { withMetrics: true })\n * async createOrder(data: OrderData) {\n * return await db.orders.create(data)\n * }\n *\n * @Trace() // Uses method name as span name\n * async processPayment(orderId: string) {\n * return await stripe.charge(orderId)\n * }\n * }\n * ```\n */\n\nimport type { TracingOptions, TraceContext } from './functional';\nimport { getConfig } from './config';\nimport { SpanStatusCode } from '@opentelemetry/api';\nimport { createTraceContext } from './trace-context';\n\n/**\n * Options for @Trace method decorator\n */\nexport interface TraceDecoratorOptions extends Omit<TracingOptions, 'name'> {\n /**\n * Custom span name. If not provided, uses the method name.\n */\n name?: string;\n}\n\n/**\n * @Trace - Method decorator for fine-grained tracing\n *\n * Wraps a class method with automatic tracing. Supports both patterns:\n * - Simple: method doesn't use ctx\n * - Advanced: method accesses ctx via this.ctx\n *\n * @example Simple usage (no ctx)\n * ```typescript\n * class OrderService {\n * @Trace()\n * async createOrder(data: OrderData) {\n * return await db.orders.create(data)\n * }\n * }\n * ```\n *\n * @example With custom name and options\n * ```typescript\n * class PaymentService {\n * @Trace('payment.charge', { withMetrics: true })\n * async chargeCard(amount: number) {\n * return await stripe.charges.create({ amount })\n * }\n * }\n * ```\n *\n * @example Accessing ctx\n * ```typescript\n * interface WithTraceContext {\n * ctx?: TraceContext\n * }\n *\n * class UserService {\n * @Trace()\n * async createUser(data: UserData) {\n * // Access ctx via this.ctx (available during execution)\n * const ctx = (this as unknown as WithTraceContext).ctx\n * if (ctx) {\n * ctx.setAttribute('user.id', data.id)\n * }\n * return await db.users.create(data)\n * }\n * }\n * ```\n */\nexport function Trace(\n options?: TraceDecoratorOptions,\n): <T extends (...args: unknown[]) => Promise<unknown>>(\n originalMethod: T,\n context: ClassMethodDecoratorContext,\n) => T;\nexport function Trace(\n name?: string,\n options?: TraceDecoratorOptions,\n): <T extends (...args: unknown[]) => Promise<unknown>>(\n originalMethod: T,\n context: ClassMethodDecoratorContext,\n) => T;\nexport function Trace(\n nameOrOptions?: string | TraceDecoratorOptions,\n maybeOptions?: TraceDecoratorOptions,\n): <T extends (...args: unknown[]) => Promise<unknown>>(\n originalMethod: T,\n context: ClassMethodDecoratorContext,\n) => T {\n // Parse arguments\n const name =\n typeof nameOrOptions === 'string' ? nameOrOptions : nameOrOptions?.name;\n // Options are used in the returned decorator function, not here\n const _options: TraceDecoratorOptions =\n typeof nameOrOptions === 'string'\n ? maybeOptions || {}\n : nameOrOptions || {};\n\n // TypeScript 5+ decorator signature\n return function <T extends (...args: unknown[]) => Promise<unknown>>(\n originalMethod: T,\n context: ClassMethodDecoratorContext,\n ): T {\n const methodName = String(context.name);\n\n // Skip if not an async function\n // Check multiple ways to detect async functions (for different transpilation environments)\n // TypeScript decorators run at class definition time, so we need robust detection\n const methodStr = originalMethod?.toString() || '';\n const isAsync =\n originalMethod &&\n (originalMethod.constructor?.name === 'AsyncFunction' ||\n methodStr.trim().startsWith('async ') ||\n (methodStr.includes('[native code]') && methodStr.includes('async')) ||\n // Fallback: if function has async in its string representation\n /async\\s+/.test(methodStr));\n\n if (!isAsync) {\n // Not an async function, return as-is\n return originalMethod;\n }\n\n const spanName = name || methodName;\n\n return async function <This>(\n this: This,\n ...args: unknown[]\n ): Promise<unknown> {\n const config = getConfig();\n const tracer = config.tracer;\n\n return tracer.startActiveSpan(spanName, async (span) => {\n try {\n // Make ctx available via this.ctx for methods that need it\n const ctx: TraceContext = createTraceContext(span);\n\n const originalCtx = (this as { ctx?: TraceContext }).ctx;\n try {\n (this as { ctx?: TraceContext }).ctx = ctx;\n const result = await originalMethod.apply(this, args as []);\n span.setStatus({ code: SpanStatusCode.OK });\n return result;\n } finally {\n // Restore original ctx\n if (originalCtx === undefined) {\n delete (this as { ctx?: TraceContext }).ctx;\n } else {\n (this as { ctx?: TraceContext }).ctx = originalCtx;\n }\n }\n } catch (error) {\n span.setStatus({\n code: SpanStatusCode.ERROR,\n message: error instanceof Error ? error.message : 'Unknown error',\n });\n span.recordException(\n error instanceof Error ? error : new Error(String(error)),\n );\n throw error;\n } finally {\n span.end();\n }\n });\n } as T;\n };\n}\n\n// Re-export types for convenience\n\nexport { type TraceContext, type TracingOptions } from './functional';\n"],"mappings":";;;;;AAmGA,SAAgB,MACd,eACA,cAIK;CAEL,MAAM,OACJ,OAAO,kBAAkB,WAAW,gBAAgB,eAAe;CAQrE,OAAO,SACL,gBACA,SACG;EACH,MAAM,aAAa,OAAO,QAAQ,IAAI;EAKtC,MAAM,YAAY,gBAAgB,SAAS,KAAK;EAShD,IAAI,EAPF,mBACC,eAAe,aAAa,SAAS,mBACpC,UAAU,KAAK,CAAC,CAAC,WAAW,QAAQ,KACnC,UAAU,SAAS,eAAe,KAAK,UAAU,SAAS,OAAO,KAElE,WAAW,KAAK,SAAS,KAI3B,OAAO;EAGT,MAAM,WAAW,QAAQ;EAEzB,OAAO,eAEL,GAAG,MACe;GAIlB,OAHe,UACK,CAAC,CAAC,OAER,gBAAgB,UAAU,OAAO,SAAS;IACtD,IAAI;KAEF,MAAM,MAAoB,mBAAmB,IAAI;KAEjD,MAAM,cAAe,KAAgC;KACrD,IAAI;MACF,AAAC,KAAgC,MAAM;MACvC,MAAM,SAAS,MAAM,eAAe,MAAM,MAAM,IAAU;MAC1D,KAAK,UAAU,EAAE,MAAM,eAAe,GAAG,CAAC;MAC1C,OAAO;KACT,UAAU;MAER,IAAI,gBAAgB,QAClB,OAAQ,KAAgC;WAExC,AAAC,KAAgC,MAAM;KAE3C;IACF,SAAS,OAAO;KACd,KAAK,UAAU;MACb,MAAM,eAAe;MACrB,SAAS,iBAAiB,QAAQ,MAAM,UAAU;KACpD,CAAC;KACD,KAAK,gBACH,iBAAiB,QAAQ,QAAQ,IAAI,MAAM,OAAO,KAAK,CAAC,CAC1D;KACA,MAAM;IACR,UAAU;KACR,KAAK,IAAI;IACX;GACF,CAAC;EACH;CACF;AACF"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"define-event-B2z1SBe7.d.ts","names":[],"sources":["../src/define-event.ts"],"mappings":";;KAIK,gBAAgB;EACjB;EAAe,MAAM;;EAAQ;EAAgB;;UAEhC,WAAW;EAC1B,UAAU,iBAAiB,gBAAgB;;UAG5B,mBAAmB;EAClC,gBAAgB,QAAQ;;UAGT,aAAa,qBAAqB;WACxC,MAAM;WACN,iBAAiB;EAC1B,MAAM,SAAS;;iBAGD,YACd,qBACA,SACA,UAAU,WAAW,UAErB,MAAM,MACN,QAAQ,GACR,UAAS,mBAAmB,KAC3B,aAAa,MAAM"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"define-event-CGG048HE.d.cts","names":[],"sources":["../src/define-event.ts"],"mappings":";;KAIK,gBAAgB;EACjB;EAAe,MAAM;;EAAQ;EAAgB;;UAEhC,WAAW;EAC1B,UAAU,iBAAiB,gBAAgB;;UAG5B,mBAAmB;EAClC,gBAAgB,QAAQ;;UAGT,aAAa,qBAAqB;WACxC,MAAM;WACN,iBAAiB;EAC1B,MAAM,SAAS;;iBAGD,YACd,qBACA,SACA,UAAU,WAAW,UAErB,MAAM,MACN,QAAQ,GACR,UAAS,mBAAmB,KAC3B,aAAa,MAAM"}
|
package/dist/diagnostics.cjs.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"diagnostics.cjs","names":["safeRequire","SeverityNumber","safeRequire","logs","trace","ATTR_HTTP_REQUEST_METHOD","ATTR_URL_PATH","ATTR_URL_SCHEME","ATTR_NETWORK_PROTOCOL_VERSION","ATTR_USER_AGENT_ORIGINAL","ATTR_SERVER_ADDRESS","ATTR_SERVER_PORT","propagation","otelContext","defaultTextMapGetter","SpanKind","ATTR_URL_FULL","defaultTextMapSetter","SpanStatusCode","ATTR_HTTP_RESPONSE_STATUS_CODE"],"sources":["../src/diagnostics/channel.ts","../src/diagnostics/console.ts","../src/diagnostics/http.ts"],"sourcesContent":["/**\n * Edge-safe wrappers over Node's `diagnostics_channel`.\n *\n * The module is loaded lazily through {@link safeRequire} — never a static\n * `node:` import — so merely importing this file is side-effect-free and bundles\n * cleanly for browser/edge targets, where every subscribe call degrades to a\n * no-op (returning an unsubscribe that does nothing). This is the shared\n * primitive behind autotel's diagnostics-channel integrations (console capture,\n * HTTP spans) and any app- or library-specific channel you want to bridge into\n * a span/event.\n *\n * `diagnostics_channel.subscribe` (Node 18.7+) and `tracingChannel` (Node 19+)\n * are used; autotel targets Node 22+, but on any runtime that lacks them the\n * loader returns `undefined` and the helpers no-op.\n */\n\nimport { safeRequire } from '../node-require.js';\n\ntype DiagnosticsChannelModule = typeof import('node:diagnostics_channel');\n\nlet cached: DiagnosticsChannelModule | null | undefined;\n\nfunction loadDiagnosticsChannel(): DiagnosticsChannelModule | undefined {\n if (cached !== undefined) return cached ?? undefined;\n cached =\n safeRequire<DiagnosticsChannelModule>('node:diagnostics_channel') ?? null;\n return cached ?? undefined;\n}\n\n/** Whether Node's `diagnostics_channel` is available in this runtime. */\nexport function diagnosticsChannelAvailable(): boolean {\n return loadDiagnosticsChannel() !== undefined;\n}\n\n/** Handler for a plain named channel. */\nexport type ChannelMessageHandler = (\n message: unknown,\n name: string | symbol,\n) => void;\n\n/**\n * Subscribe to a named diagnostics channel. Returns an idempotent unsubscribe\n * function; a no-op (that still returns a disposer) on unsupported runtimes.\n */\nexport function subscribeChannel(\n name: string,\n handler: ChannelMessageHandler,\n): () => void {\n const dc = loadDiagnosticsChannel();\n if (!dc?.subscribe) return () => {};\n dc.subscribe(name, handler);\n let active = true;\n return () => {\n if (!active) return;\n active = false;\n dc.unsubscribe?.(name, handler);\n };\n}\n\n/** Subscriber set for a {@link https://nodejs.org/api/diagnostics_channel.html#class-tracingchannel TracingChannel}. */\nexport interface TracingChannelHandlers {\n start?(message: unknown): void;\n end?(message: unknown): void;\n asyncStart?(message: unknown): void;\n asyncEnd?(message: unknown): void;\n error?(message: unknown): void;\n}\n\n/**\n * Subscribe to a `tracingChannel` (the `tracing:${name}:{start,end,…}` set).\n * Returns an idempotent unsubscribe; a no-op on runtimes without\n * `tracingChannel` support.\n */\nexport function subscribeTracingChannel(\n name: string,\n handlers: TracingChannelHandlers,\n): () => void {\n const dc = loadDiagnosticsChannel();\n const channel = dc?.tracingChannel?.(name);\n if (!channel) return () => {};\n // Node's typings want all five handlers; we pass the subset provided.\n channel.subscribe(handlers as Parameters<typeof channel.subscribe>[0]);\n let active = true;\n return () => {\n if (!active) return;\n active = false;\n channel.unsubscribe(handlers as Parameters<typeof channel.unsubscribe>[0]);\n };\n}\n","/**\n * Capture `console.*` calls as wide events — without monkey-patching `console`.\n *\n * Node publishes every `console.log` / `info` / `debug` / `warn` / `error` call\n * on a built-in diagnostics channel. {@link captureConsole} subscribes to those\n * channels and turns each call into an OpenTelemetry **log record** (correlated\n * to the active span via trace context by the logs SDK) and/or a **span event**\n * on the active span. Nothing patches the global `console`, so there is no\n * load-order fragility and no interference with other tooling.\n *\n * Opt-in. Call once after `init()` and keep the returned disposer to stop:\n *\n * ```ts\n * import { captureConsole } from 'autotel/diagnostics';\n *\n * const stop = captureConsole(); // every console.* → correlated log record\n * // …later: stop();\n * ```\n *\n * The built-in `console.*` channels are a Stability-1 (experimental) Node API;\n * this module degrades to a no-op where they are unavailable.\n */\n\nimport { trace, type Attributes } from '@opentelemetry/api';\nimport { logs, SeverityNumber, type Logger } from '@opentelemetry/api-logs';\nimport { safeRequire } from '../node-require.js';\nimport { subscribeChannel } from './channel.js';\n\n/** Console methods that publish a diagnostics channel. */\nexport type ConsoleLevel = 'log' | 'info' | 'debug' | 'warn' | 'error';\n\nconst ALL_LEVELS: readonly ConsoleLevel[] = [\n 'log',\n 'info',\n 'debug',\n 'warn',\n 'error',\n];\n\nconst SEVERITY: Record<ConsoleLevel, SeverityNumber> = {\n debug: SeverityNumber.DEBUG,\n log: SeverityNumber.INFO,\n info: SeverityNumber.INFO,\n warn: SeverityNumber.WARN,\n error: SeverityNumber.ERROR,\n};\n\nexport interface CaptureConsoleOptions {\n /** Which console methods to capture. Defaults to all five. */\n levels?: readonly ConsoleLevel[];\n /**\n * Where to record captured output:\n * - `'log'` (default): emit an OpenTelemetry log record;\n * - `'span-event'`: add an event to the active span (nothing if no active span);\n * - `'both'`.\n */\n target?: 'log' | 'span-event' | 'both';\n /** Logger name for emitted records. Defaults to `'autotel.console'`. */\n loggerName?: string;\n /** Static attributes merged onto every captured record/event. */\n attributes?: Attributes;\n}\n\ntype ConsoleMessage = { args?: unknown[] };\n\n/**\n * Node publishes `console.*` channel messages as the raw argument array\n * (e.g. `console.warn('a', 1)` → `['a', 1]`); some publishers use the\n * `{ args: [...] }` object shape instead. Accept both.\n */\nfunction messageArgs(message: unknown): unknown[] {\n if (Array.isArray(message)) return message;\n return (message as ConsoleMessage)?.args ?? [];\n}\n\nconst nodeUtil = safeRequire<typeof import('node:util')>('node:util');\n\n/** Format console arguments the way `console` itself would (printf + inspect). */\nfunction formatArgs(args: unknown[]): string {\n if (nodeUtil?.format) return nodeUtil.format(...args);\n return args\n .map((a) => (typeof a === 'string' ? a : safeStringify(a)))\n .join(' ');\n}\n\nfunction safeStringify(value: unknown): string {\n try {\n return JSON.stringify(value) ?? String(value);\n } catch {\n return String(value);\n }\n}\n\n/**\n * Start capturing `console.*` calls as wide events. Returns a disposer that\n * stops capture. Safe to call on runtimes without the console channels (no-op).\n */\nexport function captureConsole(\n options: CaptureConsoleOptions = {},\n): () => void {\n const levels = options.levels ?? ALL_LEVELS;\n const target = options.target ?? 'log';\n const toLog = target === 'log' || target === 'both';\n const toSpan = target === 'span-event' || target === 'both';\n const logger: Logger = logs.getLogger(\n options.loggerName ?? 'autotel.console',\n );\n\n // Guard against re-entrancy: if recording a captured call itself triggers a\n // `console.*` (e.g. an exporter logging a warning), don't capture that.\n let recording = false;\n\n const disposers = levels.map((level) =>\n subscribeChannel(`console.${level}`, (message) => {\n if (recording) return;\n const args = messageArgs(message);\n const body = formatArgs(args);\n recording = true;\n try {\n const attributes: Attributes = {\n 'log.source': 'console',\n 'log.method': level,\n ...options.attributes,\n };\n if (toLog) {\n logger.emit({\n severityNumber: SEVERITY[level],\n severityText: level.toUpperCase(),\n body,\n attributes,\n });\n }\n if (toSpan) {\n trace\n .getActiveSpan()\n ?.addEvent('log', { 'log.message': body, ...attributes });\n }\n } finally {\n recording = false;\n }\n }),\n );\n\n let active = true;\n return () => {\n if (!active) return;\n active = false;\n for (const dispose of disposers) dispose();\n };\n}\n","/**\n * Lightweight HTTP spans via Node's built-in `diagnostics_channel` — no\n * monkey-patching, no `import-in-the-middle`.\n *\n * Node publishes `http.server.request.start` / `http.server.response.finish`\n * and `http.client.request.start` / `http.client.response.finish` /\n * `http.client.request.error`. {@link instrumentHttp} subscribes to those and\n * emits a `SERVER` span per inbound request (parented to an incoming W3C\n * `traceparent`) and a `CLIENT` span per outbound request (whose context it\n * injects into the outgoing headers for downstream propagation).\n *\n * ```ts\n * import { instrumentHttp } from 'autotel/diagnostics';\n *\n * const stop = instrumentHttp();\n * ```\n *\n * Scope & limitation. This is an opt-in, low-overhead alternative to\n * `@opentelemetry/instrumentation-http` for HTTP span coverage + W3C\n * propagation. Client-side propagation works (the `traceparent` is injected on\n * the `ClientRequest` object directly). What it does **not** do is establish an\n * *ambient* OpenTelemetry context for the duration of a server request handler,\n * so application spans created inside a handler will not become children of the\n * `SERVER` span.\n *\n * This is structural, not a \"wait for a newer Node\" gap. Node publishes the\n * `http.*` channels with a plain `channel.publish()` — not `runStores` /\n * `tracingChannel` — so a subscriber has no scope to bind a store to. The only\n * ways to get handler nesting both defeat the purpose of using a channel:\n * 1. `AsyncLocalStorage.enterWith()` in the start handler — no scoped exit, so\n * context leaks across requests sharing an event-loop tick / keep-alive\n * connection and misattributes spans. Strictly worse than no nesting.\n * 2. Patching `http.Server.prototype.emit` to wrap the `'request'` listener in\n * `context.with()` — monkey-patching, i.e. reimplementing\n * `@opentelemetry/instrumentation-http`.\n * If you need handler nesting, use `@opentelemetry/instrumentation-http`.\n *\n * The `http.*` channels are a Stability-1 (experimental) Node API; this module\n * degrades to a no-op where they are unavailable.\n */\n\nimport type { ClientRequest, IncomingMessage, ServerResponse } from 'node:http';\nimport {\n context as otelContext,\n defaultTextMapGetter,\n defaultTextMapSetter,\n propagation,\n SpanKind,\n SpanStatusCode,\n trace,\n type Attributes,\n type Span,\n type Tracer,\n} from '@opentelemetry/api';\nimport {\n ATTR_HTTP_REQUEST_METHOD,\n ATTR_HTTP_RESPONSE_STATUS_CODE,\n ATTR_NETWORK_PROTOCOL_VERSION,\n ATTR_SERVER_ADDRESS,\n ATTR_SERVER_PORT,\n ATTR_URL_FULL,\n ATTR_URL_PATH,\n ATTR_URL_SCHEME,\n ATTR_USER_AGENT_ORIGINAL,\n} from '@opentelemetry/semantic-conventions';\nimport { subscribeChannel } from './channel.js';\n\nexport interface InstrumentHttpOptions {\n /** Instrument inbound (server) requests. Default `true`. */\n server?: boolean;\n /** Instrument outbound (client) requests. Default `true`. */\n client?: boolean;\n /** Tracer to use. Defaults to `trace.getTracer('autotel.http-diagnostics')`. */\n tracer?: Tracer;\n}\n\ninterface ServerStartMessage {\n request?: IncomingMessage;\n response?: ServerResponse;\n}\ninterface ServerFinishMessage {\n request?: IncomingMessage;\n response?: ServerResponse;\n}\ninterface ClientStartMessage {\n request?: ClientRequest;\n}\ninterface ClientFinishMessage {\n request?: ClientRequest;\n response?: IncomingMessage;\n}\ninterface ClientErrorMessage {\n request?: ClientRequest;\n error?: unknown;\n}\n\nconst SERVER_SPANS = new WeakMap<object, Span>();\nconst CLIENT_SPANS = new WeakMap<object, Span>();\n\nfunction firstHeader(value: string | string[] | undefined): string | undefined {\n return Array.isArray(value) ? value[0] : value;\n}\n\nfunction splitHostPort(host: string | undefined): {\n address?: string;\n port?: number;\n} {\n if (!host) return {};\n const idx = host.lastIndexOf(':');\n if (idx === -1) return { address: host };\n const port = Number(host.slice(idx + 1));\n return {\n address: host.slice(0, idx),\n port: Number.isFinite(port) ? port : undefined,\n };\n}\n\n/**\n * Start emitting HTTP server/client spans from Node's HTTP diagnostics\n * channels. Returns a disposer; a no-op on runtimes without the channels.\n */\nexport function instrumentHttp(\n options: InstrumentHttpOptions = {},\n): () => void {\n const tracer = options.tracer ?? trace.getTracer('autotel.http-diagnostics');\n const disposers: Array<() => void> = [];\n\n if (options.server !== false) {\n disposers.push(\n subscribeChannel('http.server.request.start', (message) => {\n const request = (message as ServerStartMessage)?.request;\n if (!request) return;\n const method = request.method ?? 'HTTP';\n const host = firstHeader(request.headers.host);\n const { address, port } = splitHostPort(host);\n const path = (request.url ?? '/').split('?', 1)[0];\n const attributes: Attributes = {\n [ATTR_HTTP_REQUEST_METHOD]: method,\n [ATTR_URL_PATH]: path,\n [ATTR_URL_SCHEME]: 'http',\n [ATTR_NETWORK_PROTOCOL_VERSION]: request.httpVersion,\n [ATTR_USER_AGENT_ORIGINAL]: firstHeader(\n request.headers['user-agent'],\n ),\n [ATTR_SERVER_ADDRESS]: address,\n [ATTR_SERVER_PORT]: port,\n };\n const parent = propagation.extract(\n otelContext.active(),\n request.headers,\n defaultTextMapGetter,\n );\n const span = tracer.startSpan(\n method,\n { kind: SpanKind.SERVER, attributes },\n parent,\n );\n SERVER_SPANS.set(request, span);\n }),\n subscribeChannel('http.server.response.finish', (message) => {\n const { request, response } = (message as ServerFinishMessage) ?? {};\n if (!request) return;\n const span = SERVER_SPANS.get(request);\n if (!span) return;\n SERVER_SPANS.delete(request);\n finishHttpSpan(span, response?.statusCode, 500);\n }),\n );\n }\n\n if (options.client !== false) {\n disposers.push(\n subscribeChannel('http.client.request.start', (message) => {\n const request = (message as ClientStartMessage)?.request;\n if (!request) return;\n const method = request.method ?? 'HTTP';\n // `ClientRequest` exposes host/protocol/path on the public surface.\n const req = request as ClientRequest & {\n host?: string;\n protocol?: string;\n path?: string;\n };\n const { address, port } = splitHostPort(req.host);\n const scheme = (req.protocol ?? 'http:').replace(':', '');\n const attributes: Attributes = {\n [ATTR_HTTP_REQUEST_METHOD]: method,\n [ATTR_SERVER_ADDRESS]: address,\n [ATTR_SERVER_PORT]: port,\n [ATTR_URL_FULL]:\n address && req.path\n ? `${scheme}://${req.host}${req.path}`\n : undefined,\n };\n const span = tracer.startSpan(method, {\n kind: SpanKind.CLIENT,\n attributes,\n });\n CLIENT_SPANS.set(request, span);\n\n // Inject this span's context into the outbound headers so the\n // downstream service continues the trace.\n if (!request.headersSent) {\n const carrier: Record<string, string> = {};\n propagation.inject(\n trace.setSpan(otelContext.active(), span),\n carrier,\n defaultTextMapSetter,\n );\n for (const [key, value] of Object.entries(carrier)) {\n try {\n request.setHeader(key, value);\n } catch {\n // Headers already sent / immutable — propagation best-effort.\n }\n }\n }\n }),\n subscribeChannel('http.client.response.finish', (message) => {\n const { request, response } = (message as ClientFinishMessage) ?? {};\n if (!request) return;\n const span = CLIENT_SPANS.get(request);\n if (!span) return;\n CLIENT_SPANS.delete(request);\n finishHttpSpan(span, response?.statusCode, 400);\n }),\n subscribeChannel('http.client.request.error', (message) => {\n const { request, error } = (message as ClientErrorMessage) ?? {};\n if (!request) return;\n const span = CLIENT_SPANS.get(request);\n if (!span) return;\n CLIENT_SPANS.delete(request);\n if (error instanceof Error) span.recordException(error);\n span.setStatus({\n code: SpanStatusCode.ERROR,\n message: error instanceof Error ? error.message : undefined,\n });\n span.end();\n }),\n );\n }\n\n let active = true;\n return () => {\n if (!active) return;\n active = false;\n for (const dispose of disposers) dispose();\n };\n}\n\n/** Set status code + error status (when `>= errorAt`) and end the span. */\nfunction finishHttpSpan(\n span: Span,\n statusCode: number | undefined,\n errorAt: number,\n): void {\n if (statusCode !== undefined) {\n span.setAttribute(ATTR_HTTP_RESPONSE_STATUS_CODE, statusCode);\n if (statusCode >= errorAt) {\n span.setStatus({ code: SpanStatusCode.ERROR });\n }\n }\n span.end();\n}\n"],"mappings":"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"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"diagnostics.d.cts","names":[],"sources":["../src/diagnostics/channel.ts","../src/diagnostics/console.ts","../src/diagnostics/http.ts"],"mappings":";;;;;;;;;;;;;;;;;;iBA8BgB;;KAKJ,yBACV,kBACA;;;;;iBAOc,iBACd,cACA,SAAS;;UAcM;EACf,OAAO;EACP,KAAK;EACL,YAAY;EACZ,UAAU;EACV,OAAO;;;;;;;iBAQO,wBACd,cACA,UAAU;;;;KC9CA;UAkBK;;EAEf,kBAAkB;;;;;;;EAOlB;;EAEA;;EAEA,aAAa;;;;;;iBAqCC,eACd,UAAS;;;UC/BM;;EAEf;;EAEA;;EAEA,SAAS;;;;;;iBAgDK,eACd,UAAS"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"diagnostics.d.ts","names":[],"sources":["../src/diagnostics/channel.ts","../src/diagnostics/console.ts","../src/diagnostics/http.ts"],"mappings":";;;;;;;;;;;;;;;;;;iBA8BgB;;KAKJ,yBACV,kBACA;;;;;iBAOc,iBACd,cACA,SAAS;;UAcM;EACf,OAAO;EACP,KAAK;EACL,YAAY;EACZ,UAAU;EACV,OAAO;;;;;;;iBAQO,wBACd,cACA,UAAU;;;;KC9CA;UAkBK;;EAEf,kBAAkB;;;;;;;EAOlB;;EAEA;;EAEA,aAAa;;;;;;iBAqCC,eACd,UAAS;;;UC/BM;;EAEf;;EAEA;;EAEA,SAAS;;;;;;iBAgDK,eACd,UAAS"}
|
package/dist/diagnostics.js.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"diagnostics.js","names":["otelContext"],"sources":["../src/diagnostics/channel.ts","../src/diagnostics/console.ts","../src/diagnostics/http.ts"],"sourcesContent":["/**\n * Edge-safe wrappers over Node's `diagnostics_channel`.\n *\n * The module is loaded lazily through {@link safeRequire} — never a static\n * `node:` import — so merely importing this file is side-effect-free and bundles\n * cleanly for browser/edge targets, where every subscribe call degrades to a\n * no-op (returning an unsubscribe that does nothing). This is the shared\n * primitive behind autotel's diagnostics-channel integrations (console capture,\n * HTTP spans) and any app- or library-specific channel you want to bridge into\n * a span/event.\n *\n * `diagnostics_channel.subscribe` (Node 18.7+) and `tracingChannel` (Node 19+)\n * are used; autotel targets Node 22+, but on any runtime that lacks them the\n * loader returns `undefined` and the helpers no-op.\n */\n\nimport { safeRequire } from '../node-require.js';\n\ntype DiagnosticsChannelModule = typeof import('node:diagnostics_channel');\n\nlet cached: DiagnosticsChannelModule | null | undefined;\n\nfunction loadDiagnosticsChannel(): DiagnosticsChannelModule | undefined {\n if (cached !== undefined) return cached ?? undefined;\n cached =\n safeRequire<DiagnosticsChannelModule>('node:diagnostics_channel') ?? null;\n return cached ?? undefined;\n}\n\n/** Whether Node's `diagnostics_channel` is available in this runtime. */\nexport function diagnosticsChannelAvailable(): boolean {\n return loadDiagnosticsChannel() !== undefined;\n}\n\n/** Handler for a plain named channel. */\nexport type ChannelMessageHandler = (\n message: unknown,\n name: string | symbol,\n) => void;\n\n/**\n * Subscribe to a named diagnostics channel. Returns an idempotent unsubscribe\n * function; a no-op (that still returns a disposer) on unsupported runtimes.\n */\nexport function subscribeChannel(\n name: string,\n handler: ChannelMessageHandler,\n): () => void {\n const dc = loadDiagnosticsChannel();\n if (!dc?.subscribe) return () => {};\n dc.subscribe(name, handler);\n let active = true;\n return () => {\n if (!active) return;\n active = false;\n dc.unsubscribe?.(name, handler);\n };\n}\n\n/** Subscriber set for a {@link https://nodejs.org/api/diagnostics_channel.html#class-tracingchannel TracingChannel}. */\nexport interface TracingChannelHandlers {\n start?(message: unknown): void;\n end?(message: unknown): void;\n asyncStart?(message: unknown): void;\n asyncEnd?(message: unknown): void;\n error?(message: unknown): void;\n}\n\n/**\n * Subscribe to a `tracingChannel` (the `tracing:${name}:{start,end,…}` set).\n * Returns an idempotent unsubscribe; a no-op on runtimes without\n * `tracingChannel` support.\n */\nexport function subscribeTracingChannel(\n name: string,\n handlers: TracingChannelHandlers,\n): () => void {\n const dc = loadDiagnosticsChannel();\n const channel = dc?.tracingChannel?.(name);\n if (!channel) return () => {};\n // Node's typings want all five handlers; we pass the subset provided.\n channel.subscribe(handlers as Parameters<typeof channel.subscribe>[0]);\n let active = true;\n return () => {\n if (!active) return;\n active = false;\n channel.unsubscribe(handlers as Parameters<typeof channel.unsubscribe>[0]);\n };\n}\n","/**\n * Capture `console.*` calls as wide events — without monkey-patching `console`.\n *\n * Node publishes every `console.log` / `info` / `debug` / `warn` / `error` call\n * on a built-in diagnostics channel. {@link captureConsole} subscribes to those\n * channels and turns each call into an OpenTelemetry **log record** (correlated\n * to the active span via trace context by the logs SDK) and/or a **span event**\n * on the active span. Nothing patches the global `console`, so there is no\n * load-order fragility and no interference with other tooling.\n *\n * Opt-in. Call once after `init()` and keep the returned disposer to stop:\n *\n * ```ts\n * import { captureConsole } from 'autotel/diagnostics';\n *\n * const stop = captureConsole(); // every console.* → correlated log record\n * // …later: stop();\n * ```\n *\n * The built-in `console.*` channels are a Stability-1 (experimental) Node API;\n * this module degrades to a no-op where they are unavailable.\n */\n\nimport { trace, type Attributes } from '@opentelemetry/api';\nimport { logs, SeverityNumber, type Logger } from '@opentelemetry/api-logs';\nimport { safeRequire } from '../node-require.js';\nimport { subscribeChannel } from './channel.js';\n\n/** Console methods that publish a diagnostics channel. */\nexport type ConsoleLevel = 'log' | 'info' | 'debug' | 'warn' | 'error';\n\nconst ALL_LEVELS: readonly ConsoleLevel[] = [\n 'log',\n 'info',\n 'debug',\n 'warn',\n 'error',\n];\n\nconst SEVERITY: Record<ConsoleLevel, SeverityNumber> = {\n debug: SeverityNumber.DEBUG,\n log: SeverityNumber.INFO,\n info: SeverityNumber.INFO,\n warn: SeverityNumber.WARN,\n error: SeverityNumber.ERROR,\n};\n\nexport interface CaptureConsoleOptions {\n /** Which console methods to capture. Defaults to all five. */\n levels?: readonly ConsoleLevel[];\n /**\n * Where to record captured output:\n * - `'log'` (default): emit an OpenTelemetry log record;\n * - `'span-event'`: add an event to the active span (nothing if no active span);\n * - `'both'`.\n */\n target?: 'log' | 'span-event' | 'both';\n /** Logger name for emitted records. Defaults to `'autotel.console'`. */\n loggerName?: string;\n /** Static attributes merged onto every captured record/event. */\n attributes?: Attributes;\n}\n\ntype ConsoleMessage = { args?: unknown[] };\n\n/**\n * Node publishes `console.*` channel messages as the raw argument array\n * (e.g. `console.warn('a', 1)` → `['a', 1]`); some publishers use the\n * `{ args: [...] }` object shape instead. Accept both.\n */\nfunction messageArgs(message: unknown): unknown[] {\n if (Array.isArray(message)) return message;\n return (message as ConsoleMessage)?.args ?? [];\n}\n\nconst nodeUtil = safeRequire<typeof import('node:util')>('node:util');\n\n/** Format console arguments the way `console` itself would (printf + inspect). */\nfunction formatArgs(args: unknown[]): string {\n if (nodeUtil?.format) return nodeUtil.format(...args);\n return args\n .map((a) => (typeof a === 'string' ? a : safeStringify(a)))\n .join(' ');\n}\n\nfunction safeStringify(value: unknown): string {\n try {\n return JSON.stringify(value) ?? String(value);\n } catch {\n return String(value);\n }\n}\n\n/**\n * Start capturing `console.*` calls as wide events. Returns a disposer that\n * stops capture. Safe to call on runtimes without the console channels (no-op).\n */\nexport function captureConsole(\n options: CaptureConsoleOptions = {},\n): () => void {\n const levels = options.levels ?? ALL_LEVELS;\n const target = options.target ?? 'log';\n const toLog = target === 'log' || target === 'both';\n const toSpan = target === 'span-event' || target === 'both';\n const logger: Logger = logs.getLogger(\n options.loggerName ?? 'autotel.console',\n );\n\n // Guard against re-entrancy: if recording a captured call itself triggers a\n // `console.*` (e.g. an exporter logging a warning), don't capture that.\n let recording = false;\n\n const disposers = levels.map((level) =>\n subscribeChannel(`console.${level}`, (message) => {\n if (recording) return;\n const args = messageArgs(message);\n const body = formatArgs(args);\n recording = true;\n try {\n const attributes: Attributes = {\n 'log.source': 'console',\n 'log.method': level,\n ...options.attributes,\n };\n if (toLog) {\n logger.emit({\n severityNumber: SEVERITY[level],\n severityText: level.toUpperCase(),\n body,\n attributes,\n });\n }\n if (toSpan) {\n trace\n .getActiveSpan()\n ?.addEvent('log', { 'log.message': body, ...attributes });\n }\n } finally {\n recording = false;\n }\n }),\n );\n\n let active = true;\n return () => {\n if (!active) return;\n active = false;\n for (const dispose of disposers) dispose();\n };\n}\n","/**\n * Lightweight HTTP spans via Node's built-in `diagnostics_channel` — no\n * monkey-patching, no `import-in-the-middle`.\n *\n * Node publishes `http.server.request.start` / `http.server.response.finish`\n * and `http.client.request.start` / `http.client.response.finish` /\n * `http.client.request.error`. {@link instrumentHttp} subscribes to those and\n * emits a `SERVER` span per inbound request (parented to an incoming W3C\n * `traceparent`) and a `CLIENT` span per outbound request (whose context it\n * injects into the outgoing headers for downstream propagation).\n *\n * ```ts\n * import { instrumentHttp } from 'autotel/diagnostics';\n *\n * const stop = instrumentHttp();\n * ```\n *\n * Scope & limitation. This is an opt-in, low-overhead alternative to\n * `@opentelemetry/instrumentation-http` for HTTP span coverage + W3C\n * propagation. Client-side propagation works (the `traceparent` is injected on\n * the `ClientRequest` object directly). What it does **not** do is establish an\n * *ambient* OpenTelemetry context for the duration of a server request handler,\n * so application spans created inside a handler will not become children of the\n * `SERVER` span.\n *\n * This is structural, not a \"wait for a newer Node\" gap. Node publishes the\n * `http.*` channels with a plain `channel.publish()` — not `runStores` /\n * `tracingChannel` — so a subscriber has no scope to bind a store to. The only\n * ways to get handler nesting both defeat the purpose of using a channel:\n * 1. `AsyncLocalStorage.enterWith()` in the start handler — no scoped exit, so\n * context leaks across requests sharing an event-loop tick / keep-alive\n * connection and misattributes spans. Strictly worse than no nesting.\n * 2. Patching `http.Server.prototype.emit` to wrap the `'request'` listener in\n * `context.with()` — monkey-patching, i.e. reimplementing\n * `@opentelemetry/instrumentation-http`.\n * If you need handler nesting, use `@opentelemetry/instrumentation-http`.\n *\n * The `http.*` channels are a Stability-1 (experimental) Node API; this module\n * degrades to a no-op where they are unavailable.\n */\n\nimport type { ClientRequest, IncomingMessage, ServerResponse } from 'node:http';\nimport {\n context as otelContext,\n defaultTextMapGetter,\n defaultTextMapSetter,\n propagation,\n SpanKind,\n SpanStatusCode,\n trace,\n type Attributes,\n type Span,\n type Tracer,\n} from '@opentelemetry/api';\nimport {\n ATTR_HTTP_REQUEST_METHOD,\n ATTR_HTTP_RESPONSE_STATUS_CODE,\n ATTR_NETWORK_PROTOCOL_VERSION,\n ATTR_SERVER_ADDRESS,\n ATTR_SERVER_PORT,\n ATTR_URL_FULL,\n ATTR_URL_PATH,\n ATTR_URL_SCHEME,\n ATTR_USER_AGENT_ORIGINAL,\n} from '@opentelemetry/semantic-conventions';\nimport { subscribeChannel } from './channel.js';\n\nexport interface InstrumentHttpOptions {\n /** Instrument inbound (server) requests. Default `true`. */\n server?: boolean;\n /** Instrument outbound (client) requests. Default `true`. */\n client?: boolean;\n /** Tracer to use. Defaults to `trace.getTracer('autotel.http-diagnostics')`. */\n tracer?: Tracer;\n}\n\ninterface ServerStartMessage {\n request?: IncomingMessage;\n response?: ServerResponse;\n}\ninterface ServerFinishMessage {\n request?: IncomingMessage;\n response?: ServerResponse;\n}\ninterface ClientStartMessage {\n request?: ClientRequest;\n}\ninterface ClientFinishMessage {\n request?: ClientRequest;\n response?: IncomingMessage;\n}\ninterface ClientErrorMessage {\n request?: ClientRequest;\n error?: unknown;\n}\n\nconst SERVER_SPANS = new WeakMap<object, Span>();\nconst CLIENT_SPANS = new WeakMap<object, Span>();\n\nfunction firstHeader(value: string | string[] | undefined): string | undefined {\n return Array.isArray(value) ? value[0] : value;\n}\n\nfunction splitHostPort(host: string | undefined): {\n address?: string;\n port?: number;\n} {\n if (!host) return {};\n const idx = host.lastIndexOf(':');\n if (idx === -1) return { address: host };\n const port = Number(host.slice(idx + 1));\n return {\n address: host.slice(0, idx),\n port: Number.isFinite(port) ? port : undefined,\n };\n}\n\n/**\n * Start emitting HTTP server/client spans from Node's HTTP diagnostics\n * channels. Returns a disposer; a no-op on runtimes without the channels.\n */\nexport function instrumentHttp(\n options: InstrumentHttpOptions = {},\n): () => void {\n const tracer = options.tracer ?? trace.getTracer('autotel.http-diagnostics');\n const disposers: Array<() => void> = [];\n\n if (options.server !== false) {\n disposers.push(\n subscribeChannel('http.server.request.start', (message) => {\n const request = (message as ServerStartMessage)?.request;\n if (!request) return;\n const method = request.method ?? 'HTTP';\n const host = firstHeader(request.headers.host);\n const { address, port } = splitHostPort(host);\n const path = (request.url ?? '/').split('?', 1)[0];\n const attributes: Attributes = {\n [ATTR_HTTP_REQUEST_METHOD]: method,\n [ATTR_URL_PATH]: path,\n [ATTR_URL_SCHEME]: 'http',\n [ATTR_NETWORK_PROTOCOL_VERSION]: request.httpVersion,\n [ATTR_USER_AGENT_ORIGINAL]: firstHeader(\n request.headers['user-agent'],\n ),\n [ATTR_SERVER_ADDRESS]: address,\n [ATTR_SERVER_PORT]: port,\n };\n const parent = propagation.extract(\n otelContext.active(),\n request.headers,\n defaultTextMapGetter,\n );\n const span = tracer.startSpan(\n method,\n { kind: SpanKind.SERVER, attributes },\n parent,\n );\n SERVER_SPANS.set(request, span);\n }),\n subscribeChannel('http.server.response.finish', (message) => {\n const { request, response } = (message as ServerFinishMessage) ?? {};\n if (!request) return;\n const span = SERVER_SPANS.get(request);\n if (!span) return;\n SERVER_SPANS.delete(request);\n finishHttpSpan(span, response?.statusCode, 500);\n }),\n );\n }\n\n if (options.client !== false) {\n disposers.push(\n subscribeChannel('http.client.request.start', (message) => {\n const request = (message as ClientStartMessage)?.request;\n if (!request) return;\n const method = request.method ?? 'HTTP';\n // `ClientRequest` exposes host/protocol/path on the public surface.\n const req = request as ClientRequest & {\n host?: string;\n protocol?: string;\n path?: string;\n };\n const { address, port } = splitHostPort(req.host);\n const scheme = (req.protocol ?? 'http:').replace(':', '');\n const attributes: Attributes = {\n [ATTR_HTTP_REQUEST_METHOD]: method,\n [ATTR_SERVER_ADDRESS]: address,\n [ATTR_SERVER_PORT]: port,\n [ATTR_URL_FULL]:\n address && req.path\n ? `${scheme}://${req.host}${req.path}`\n : undefined,\n };\n const span = tracer.startSpan(method, {\n kind: SpanKind.CLIENT,\n attributes,\n });\n CLIENT_SPANS.set(request, span);\n\n // Inject this span's context into the outbound headers so the\n // downstream service continues the trace.\n if (!request.headersSent) {\n const carrier: Record<string, string> = {};\n propagation.inject(\n trace.setSpan(otelContext.active(), span),\n carrier,\n defaultTextMapSetter,\n );\n for (const [key, value] of Object.entries(carrier)) {\n try {\n request.setHeader(key, value);\n } catch {\n // Headers already sent / immutable — propagation best-effort.\n }\n }\n }\n }),\n subscribeChannel('http.client.response.finish', (message) => {\n const { request, response } = (message as ClientFinishMessage) ?? {};\n if (!request) return;\n const span = CLIENT_SPANS.get(request);\n if (!span) return;\n CLIENT_SPANS.delete(request);\n finishHttpSpan(span, response?.statusCode, 400);\n }),\n subscribeChannel('http.client.request.error', (message) => {\n const { request, error } = (message as ClientErrorMessage) ?? {};\n if (!request) return;\n const span = CLIENT_SPANS.get(request);\n if (!span) return;\n CLIENT_SPANS.delete(request);\n if (error instanceof Error) span.recordException(error);\n span.setStatus({\n code: SpanStatusCode.ERROR,\n message: error instanceof Error ? error.message : undefined,\n });\n span.end();\n }),\n );\n }\n\n let active = true;\n return () => {\n if (!active) return;\n active = false;\n for (const dispose of disposers) dispose();\n };\n}\n\n/** Set status code + error status (when `>= errorAt`) and end the span. */\nfunction finishHttpSpan(\n span: Span,\n statusCode: number | undefined,\n errorAt: number,\n): void {\n if (statusCode !== undefined) {\n span.setAttribute(ATTR_HTTP_RESPONSE_STATUS_CODE, statusCode);\n if (statusCode >= errorAt) {\n span.setStatus({ code: SpanStatusCode.ERROR });\n }\n }\n span.end();\n}\n"],"mappings":"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"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"drain-pipeline.cjs","names":[],"sources":["../src/drain-pipeline.ts"],"sourcesContent":["export interface DrainPipelineOptions<T = unknown> {\n batch?: {\n /** Maximum events per batch. @default 50 */\n size?: number;\n /** Max time an event can stay buffered before flush. @default 5000 */\n intervalMs?: number;\n };\n retry?: {\n /** Total attempts including first try. @default 3 */\n maxAttempts?: number;\n /** Delay strategy between attempts. @default 'exponential' */\n backoff?: 'exponential' | 'linear' | 'fixed';\n /** Base delay for first retry. @default 1000 */\n initialDelayMs?: number;\n /** Max delay cap. @default 30000 */\n maxDelayMs?: number;\n /** Add random jitter to delays. @default true */\n jitter?: boolean;\n /**\n * Decide whether a failed attempt is safe to repeat. Return false for\n * permanent failures such as an HTTP 4xx response. @default always retry\n */\n shouldRetry?: (\n error: Error,\n attempt: number,\n batch: readonly T[],\n ) => boolean;\n };\n /** Max buffered events before dropping. @default 1000 */\n maxBufferSize?: number;\n /** Overflow policy. @default 'oldest' */\n dropPolicy?: 'oldest' | 'newest';\n /** Called when events are dropped from overflow or exhausted retries. */\n onDropped?: (events: T[], error?: Error) => void;\n}\n\nexport interface PipelineDrainFn<T> {\n (ctx: T): void;\n /** Flush all buffered events. */\n flush: () => Promise<void>;\n /** Flush and stop scheduling future timer work. */\n shutdown: () => Promise<void>;\n readonly pending: number;\n}\n\nfunction wait(ms: number): Promise<void> {\n return new Promise((resolve) => {\n const timer = setTimeout(resolve, ms);\n timer.unref?.();\n });\n}\n\nexport function createDrainPipeline<T = unknown>(\n options?: DrainPipelineOptions<T>,\n): (drain: (batch: T[]) => void | Promise<void>) => PipelineDrainFn<T> {\n const batchSize = options?.batch?.size ?? 50;\n const intervalMs = options?.batch?.intervalMs ?? 5000;\n const maxBufferSize = options?.maxBufferSize ?? 1000;\n const maxAttempts = options?.retry?.maxAttempts ?? 3;\n const backoff = options?.retry?.backoff ?? 'exponential';\n const initialDelayMs = options?.retry?.initialDelayMs ?? 1000;\n const maxDelayMs = options?.retry?.maxDelayMs ?? 30_000;\n const jitter = options?.retry?.jitter ?? true;\n const shouldRetry = options?.retry?.shouldRetry;\n const dropPolicy = options?.dropPolicy ?? 'oldest';\n const onDropped = options?.onDropped;\n\n if (!Number.isFinite(batchSize) || batchSize <= 0) {\n throw new Error(\n `[autotel/drain-pipeline] batch.size must be a positive finite number, got: ${batchSize}`,\n );\n }\n if (!Number.isFinite(intervalMs) || intervalMs <= 0) {\n throw new Error(\n `[autotel/drain-pipeline] batch.intervalMs must be a positive finite number, got: ${intervalMs}`,\n );\n }\n if (!Number.isFinite(maxBufferSize) || maxBufferSize <= 0) {\n throw new Error(\n `[autotel/drain-pipeline] maxBufferSize must be a positive finite number, got: ${maxBufferSize}`,\n );\n }\n if (!Number.isFinite(maxAttempts) || maxAttempts <= 0) {\n throw new Error(\n `[autotel/drain-pipeline] retry.maxAttempts must be a positive finite number, got: ${maxAttempts}`,\n );\n }\n\n return (drain: (batch: T[]) => void | Promise<void>): PipelineDrainFn<T> => {\n const buffer: T[] = [];\n let timer: ReturnType<typeof setTimeout> | null = null;\n let activeFlush: Promise<void> | null = null;\n let isShutdown = false;\n\n const clearTimer = () => {\n if (timer) {\n clearTimeout(timer);\n timer = null;\n }\n };\n\n const computeDelay = (attempt: number): number => {\n const base =\n backoff === 'fixed'\n ? initialDelayMs\n : backoff === 'linear'\n ? initialDelayMs * attempt\n : initialDelayMs * 2 ** (attempt - 1);\n\n const bounded = Math.min(base, maxDelayMs);\n if (!jitter || bounded <= 0) return bounded;\n const factor = 0.5 + Math.random(); // [0.5, 1.5)\n return Math.max(0, Math.round(bounded * factor));\n };\n\n const sendWithRetry = async (batch: T[]): Promise<void> => {\n let lastError: Error | undefined;\n for (let attempt = 1; attempt <= maxAttempts; attempt++) {\n try {\n await drain(batch);\n return;\n } catch (error) {\n lastError = error instanceof Error ? error : new Error(String(error));\n let retry = attempt < maxAttempts;\n if (retry && shouldRetry) {\n try {\n retry = shouldRetry(lastError, attempt, batch);\n } catch (classifierError) {\n lastError =\n classifierError instanceof Error\n ? classifierError\n : new Error(String(classifierError));\n retry = false;\n }\n }\n if (retry) {\n await wait(computeDelay(attempt));\n } else {\n break;\n }\n }\n }\n onDropped?.(batch, lastError);\n };\n\n const drainBuffer = async (): Promise<void> => {\n while (buffer.length > 0) {\n const batch = buffer.splice(0, batchSize);\n await sendWithRetry(batch);\n }\n };\n\n const scheduleFlush = () => {\n if (isShutdown || timer || activeFlush) return;\n timer = setTimeout(() => {\n timer = null;\n startFlush();\n }, intervalMs);\n timer.unref?.();\n };\n\n const startFlush = () => {\n if (activeFlush || isShutdown) return;\n activeFlush = drainBuffer().finally(() => {\n activeFlush = null;\n if (isShutdown) return;\n if (buffer.length >= batchSize) {\n startFlush();\n } else if (buffer.length > 0) {\n scheduleFlush();\n }\n });\n };\n\n const push = (ctx: T) => {\n if (isShutdown) return;\n\n if (buffer.length >= maxBufferSize) {\n if (dropPolicy === 'newest') {\n onDropped?.([ctx]);\n return;\n }\n const dropped = buffer.splice(0, 1);\n onDropped?.(dropped);\n }\n\n buffer.push(ctx);\n if (buffer.length >= batchSize) {\n clearTimer();\n startFlush();\n } else {\n scheduleFlush();\n }\n };\n\n const flush = async (): Promise<void> => {\n clearTimer();\n if (activeFlush) await activeFlush;\n\n const snapshot = buffer.length;\n if (snapshot <= 0) return;\n const toFlush = buffer.splice(0, snapshot);\n while (toFlush.length > 0) {\n const batch = toFlush.splice(0, batchSize);\n await sendWithRetry(batch);\n }\n };\n\n const shutdown = async (): Promise<void> => {\n isShutdown = true;\n await flush();\n };\n\n const fn = push as PipelineDrainFn<T>;\n fn.flush = flush;\n fn.shutdown = shutdown;\n Object.defineProperty(fn, 'pending', {\n enumerable: true,\n get: () => buffer.length,\n });\n return fn;\n };\n}\n"],"mappings":"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"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"drain-pipeline.d.cts","names":[],"sources":["../src/drain-pipeline.ts"],"mappings":";UAAiB,qBAAqB;EACpC;;IAEE;;IAEA;;EAEF;;IAEE;;IAEA;;IAEA;;IAEA;;IAEA;;;;;IAKA,eACE,OAAO,OACP,iBACA,gBAAgB;;;EAIpB;;EAEA;;EAEA,aAAa,QAAQ,KAAK,QAAQ;;UAGnB,gBAAgB;GAC9B,KAAK;;EAEN,aAAa;;EAEb,gBAAgB;WACP;;iBAUK,oBAAoB,aAClC,UAAU,qBAAqB,MAC7B,QAAQ,OAAO,eAAe,kBAAkB,gBAAgB"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"drain-pipeline.d.ts","names":[],"sources":["../src/drain-pipeline.ts"],"mappings":";UAAiB,qBAAqB;EACpC;;IAEE;;IAEA;;EAEF;;IAEE;;IAEA;;IAEA;;IAEA;;IAEA;;;;;IAKA,eACE,OAAO,OACP,iBACA,gBAAgB;;;EAIpB;;EAEA;;EAEA,aAAa,QAAQ,KAAK,QAAQ;;UAGnB,gBAAgB;GAC9B,KAAK;;EAEN,aAAa;;EAEb,gBAAgB;WACP;;iBAUK,oBAAoB,aAClC,UAAU,qBAAqB,MAC7B,QAAQ,OAAO,eAAe,kBAAkB,gBAAgB"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"drain-pipeline.js","names":[],"sources":["../src/drain-pipeline.ts"],"sourcesContent":["export interface DrainPipelineOptions<T = unknown> {\n batch?: {\n /** Maximum events per batch. @default 50 */\n size?: number;\n /** Max time an event can stay buffered before flush. @default 5000 */\n intervalMs?: number;\n };\n retry?: {\n /** Total attempts including first try. @default 3 */\n maxAttempts?: number;\n /** Delay strategy between attempts. @default 'exponential' */\n backoff?: 'exponential' | 'linear' | 'fixed';\n /** Base delay for first retry. @default 1000 */\n initialDelayMs?: number;\n /** Max delay cap. @default 30000 */\n maxDelayMs?: number;\n /** Add random jitter to delays. @default true */\n jitter?: boolean;\n /**\n * Decide whether a failed attempt is safe to repeat. Return false for\n * permanent failures such as an HTTP 4xx response. @default always retry\n */\n shouldRetry?: (\n error: Error,\n attempt: number,\n batch: readonly T[],\n ) => boolean;\n };\n /** Max buffered events before dropping. @default 1000 */\n maxBufferSize?: number;\n /** Overflow policy. @default 'oldest' */\n dropPolicy?: 'oldest' | 'newest';\n /** Called when events are dropped from overflow or exhausted retries. */\n onDropped?: (events: T[], error?: Error) => void;\n}\n\nexport interface PipelineDrainFn<T> {\n (ctx: T): void;\n /** Flush all buffered events. */\n flush: () => Promise<void>;\n /** Flush and stop scheduling future timer work. */\n shutdown: () => Promise<void>;\n readonly pending: number;\n}\n\nfunction wait(ms: number): Promise<void> {\n return new Promise((resolve) => {\n const timer = setTimeout(resolve, ms);\n timer.unref?.();\n });\n}\n\nexport function createDrainPipeline<T = unknown>(\n options?: DrainPipelineOptions<T>,\n): (drain: (batch: T[]) => void | Promise<void>) => PipelineDrainFn<T> {\n const batchSize = options?.batch?.size ?? 50;\n const intervalMs = options?.batch?.intervalMs ?? 5000;\n const maxBufferSize = options?.maxBufferSize ?? 1000;\n const maxAttempts = options?.retry?.maxAttempts ?? 3;\n const backoff = options?.retry?.backoff ?? 'exponential';\n const initialDelayMs = options?.retry?.initialDelayMs ?? 1000;\n const maxDelayMs = options?.retry?.maxDelayMs ?? 30_000;\n const jitter = options?.retry?.jitter ?? true;\n const shouldRetry = options?.retry?.shouldRetry;\n const dropPolicy = options?.dropPolicy ?? 'oldest';\n const onDropped = options?.onDropped;\n\n if (!Number.isFinite(batchSize) || batchSize <= 0) {\n throw new Error(\n `[autotel/drain-pipeline] batch.size must be a positive finite number, got: ${batchSize}`,\n );\n }\n if (!Number.isFinite(intervalMs) || intervalMs <= 0) {\n throw new Error(\n `[autotel/drain-pipeline] batch.intervalMs must be a positive finite number, got: ${intervalMs}`,\n );\n }\n if (!Number.isFinite(maxBufferSize) || maxBufferSize <= 0) {\n throw new Error(\n `[autotel/drain-pipeline] maxBufferSize must be a positive finite number, got: ${maxBufferSize}`,\n );\n }\n if (!Number.isFinite(maxAttempts) || maxAttempts <= 0) {\n throw new Error(\n `[autotel/drain-pipeline] retry.maxAttempts must be a positive finite number, got: ${maxAttempts}`,\n );\n }\n\n return (drain: (batch: T[]) => void | Promise<void>): PipelineDrainFn<T> => {\n const buffer: T[] = [];\n let timer: ReturnType<typeof setTimeout> | null = null;\n let activeFlush: Promise<void> | null = null;\n let isShutdown = false;\n\n const clearTimer = () => {\n if (timer) {\n clearTimeout(timer);\n timer = null;\n }\n };\n\n const computeDelay = (attempt: number): number => {\n const base =\n backoff === 'fixed'\n ? initialDelayMs\n : backoff === 'linear'\n ? initialDelayMs * attempt\n : initialDelayMs * 2 ** (attempt - 1);\n\n const bounded = Math.min(base, maxDelayMs);\n if (!jitter || bounded <= 0) return bounded;\n const factor = 0.5 + Math.random(); // [0.5, 1.5)\n return Math.max(0, Math.round(bounded * factor));\n };\n\n const sendWithRetry = async (batch: T[]): Promise<void> => {\n let lastError: Error | undefined;\n for (let attempt = 1; attempt <= maxAttempts; attempt++) {\n try {\n await drain(batch);\n return;\n } catch (error) {\n lastError = error instanceof Error ? error : new Error(String(error));\n let retry = attempt < maxAttempts;\n if (retry && shouldRetry) {\n try {\n retry = shouldRetry(lastError, attempt, batch);\n } catch (classifierError) {\n lastError =\n classifierError instanceof Error\n ? classifierError\n : new Error(String(classifierError));\n retry = false;\n }\n }\n if (retry) {\n await wait(computeDelay(attempt));\n } else {\n break;\n }\n }\n }\n onDropped?.(batch, lastError);\n };\n\n const drainBuffer = async (): Promise<void> => {\n while (buffer.length > 0) {\n const batch = buffer.splice(0, batchSize);\n await sendWithRetry(batch);\n }\n };\n\n const scheduleFlush = () => {\n if (isShutdown || timer || activeFlush) return;\n timer = setTimeout(() => {\n timer = null;\n startFlush();\n }, intervalMs);\n timer.unref?.();\n };\n\n const startFlush = () => {\n if (activeFlush || isShutdown) return;\n activeFlush = drainBuffer().finally(() => {\n activeFlush = null;\n if (isShutdown) return;\n if (buffer.length >= batchSize) {\n startFlush();\n } else if (buffer.length > 0) {\n scheduleFlush();\n }\n });\n };\n\n const push = (ctx: T) => {\n if (isShutdown) return;\n\n if (buffer.length >= maxBufferSize) {\n if (dropPolicy === 'newest') {\n onDropped?.([ctx]);\n return;\n }\n const dropped = buffer.splice(0, 1);\n onDropped?.(dropped);\n }\n\n buffer.push(ctx);\n if (buffer.length >= batchSize) {\n clearTimer();\n startFlush();\n } else {\n scheduleFlush();\n }\n };\n\n const flush = async (): Promise<void> => {\n clearTimer();\n if (activeFlush) await activeFlush;\n\n const snapshot = buffer.length;\n if (snapshot <= 0) return;\n const toFlush = buffer.splice(0, snapshot);\n while (toFlush.length > 0) {\n const batch = toFlush.splice(0, batchSize);\n await sendWithRetry(batch);\n }\n };\n\n const shutdown = async (): Promise<void> => {\n isShutdown = true;\n await flush();\n };\n\n const fn = push as PipelineDrainFn<T>;\n fn.flush = flush;\n fn.shutdown = shutdown;\n Object.defineProperty(fn, 'pending', {\n enumerable: true,\n get: () => buffer.length,\n });\n return fn;\n };\n}\n"],"mappings":"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"}
|
package/dist/enrichers.cjs.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"enrichers.cjs","names":[],"sources":["../src/enrichers.ts"],"sourcesContent":["type Headers = Record<string, string | string[] | undefined>;\n\nfunction get(headers: Headers, key: string): string | undefined {\n const lower = key.toLowerCase();\n for (const [k, v] of Object.entries(headers)) {\n if (k.toLowerCase() === lower) {\n return Array.isArray(v) ? v[0] : v;\n }\n }\n return undefined;\n}\n\n// --- User Agent ---\n\nexport interface UserAgentAttributes {\n 'user_agent.raw': string;\n 'user_agent.browser'?: string;\n 'user_agent.os'?: string;\n 'user_agent.device'?: string;\n}\n\nconst BROWSER_RE = /(Firefox|OPR|Edg|Chrome|Safari|MSIE|Trident)[\\s/]?([\\d.]*)/;\nconst OS_RE =\n /(Windows NT|Mac OS X|Linux|Android|iPhone OS|iPad|CrOS)[\\s]?([\\d._]*)/;\n\nfunction parseBrowser(ua: string): string | undefined {\n const m = BROWSER_RE.exec(ua);\n if (!m) return undefined;\n const name =\n m[1] === 'OPR'\n ? 'Opera'\n : m[1] === 'Edg'\n ? 'Edge'\n : m[1] === 'Trident'\n ? 'IE'\n : m[1];\n return m[2] ? `${name} ${m[2]}` : name;\n}\n\nfunction parseOS(ua: string): string | undefined {\n const m = OS_RE.exec(ua);\n if (!m) return undefined;\n const name =\n m[1] === 'iPhone OS'\n ? 'iOS'\n : m[1] === 'Windows NT'\n ? 'Windows'\n : m[1] === 'Mac OS X'\n ? 'macOS'\n : m[1];\n const ver = m[2]?.replaceAll('_', '.') || undefined;\n return ver ? `${name} ${ver}` : name;\n}\n\nfunction parseDevice(ua: string): string | undefined {\n if (/Mobi|Android.*Mobile|iPhone/.test(ua)) return 'mobile';\n if (/iPad|Android(?!.*Mobile)|Tablet/.test(ua)) return 'tablet';\n if (/Bot|Crawler|Spider|Lighthouse/i.test(ua)) return 'bot';\n return 'desktop';\n}\n\nexport function userAgent(headers: Headers): UserAgentAttributes | undefined {\n const raw = get(headers, 'user-agent');\n if (!raw) return undefined;\n\n const attrs: UserAgentAttributes = { 'user_agent.raw': raw };\n const browser = parseBrowser(raw);\n if (browser) attrs['user_agent.browser'] = browser;\n const os = parseOS(raw);\n if (os) attrs['user_agent.os'] = os;\n const device = parseDevice(raw);\n if (device) attrs['user_agent.device'] = device;\n\n return attrs;\n}\n\n// --- Geo ---\n\nexport interface GeoAttributes {\n 'geo.country'?: string;\n 'geo.region'?: string;\n 'geo.city'?: string;\n 'geo.latitude'?: string;\n 'geo.longitude'?: string;\n}\n\nexport function geo(headers: Headers): GeoAttributes | undefined {\n const country =\n get(headers, 'x-vercel-ip-country') ?? get(headers, 'cf-ipcountry');\n const region = get(headers, 'x-vercel-ip-country-region');\n const city = get(headers, 'x-vercel-ip-city');\n const latitude = get(headers, 'x-vercel-ip-latitude');\n const longitude = get(headers, 'x-vercel-ip-longitude');\n\n if (!country && !region && !city && !latitude && !longitude) return undefined;\n\n const attrs: GeoAttributes = {};\n if (country) attrs['geo.country'] = country;\n if (region) attrs['geo.region'] = region;\n if (city) {\n try {\n attrs['geo.city'] = decodeURIComponent(city);\n } catch {\n attrs['geo.city'] = city;\n }\n }\n if (latitude) attrs['geo.latitude'] = latitude;\n if (longitude) attrs['geo.longitude'] = longitude;\n\n return attrs;\n}\n\n// --- Request Size ---\n\nexport interface RequestSizeAttributes {\n 'http.request.body.size'?: number;\n 'http.response.body.size'?: number;\n}\n\nconst DIGITS_RE = /^\\d+$/;\n\nfunction parseContentLength(value: string | undefined): number | undefined {\n if (!value || !DIGITS_RE.test(value)) return undefined;\n return Number(value);\n}\n\nexport function requestSize(\n requestHeaders: Headers,\n responseHeaders?: Headers,\n): RequestSizeAttributes | undefined {\n const reqLen = get(requestHeaders, 'content-length');\n const resLen = responseHeaders\n ? get(responseHeaders, 'content-length')\n : undefined;\n\n if (!reqLen && !resLen) return undefined;\n\n const attrs: RequestSizeAttributes = {};\n const reqBytes = parseContentLength(reqLen);\n if (reqBytes !== undefined) attrs['http.request.body.size'] = reqBytes;\n const resBytes = parseContentLength(resLen);\n if (resBytes !== undefined) attrs['http.response.body.size'] = resBytes;\n\n return Object.keys(attrs).length > 0 ? attrs : undefined;\n}\n"],"mappings":"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"}
|
package/dist/enrichers.d.cts.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"enrichers.d.cts","names":[],"sources":["../src/enrichers.ts"],"mappings":";KAAK,UAAU;UAcE;EACf;EACA;EACA;EACA;;iBA2Cc,UAAU,SAAS,UAAU;UAiB5B;EACf;EACA;EACA;EACA;EACA;;iBAGc,IAAI,SAAS,UAAU;UA4BtB;EACf;EACA;;iBAUc,YACd,gBAAgB,SAChB,kBAAkB,UACjB"}
|
package/dist/enrichers.d.ts.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"enrichers.d.ts","names":[],"sources":["../src/enrichers.ts"],"mappings":";KAAK,UAAU;UAcE;EACf;EACA;EACA;EACA;;iBA2Cc,UAAU,SAAS,UAAU;UAiB5B;EACf;EACA;EACA;EACA;EACA;;iBAGc,IAAI,SAAS,UAAU;UA4BtB;EACf;EACA;;iBAUc,YACd,gBAAgB,SAChB,kBAAkB,UACjB"}
|
package/dist/enrichers.js.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"enrichers.js","names":[],"sources":["../src/enrichers.ts"],"sourcesContent":["type Headers = Record<string, string | string[] | undefined>;\n\nfunction get(headers: Headers, key: string): string | undefined {\n const lower = key.toLowerCase();\n for (const [k, v] of Object.entries(headers)) {\n if (k.toLowerCase() === lower) {\n return Array.isArray(v) ? v[0] : v;\n }\n }\n return undefined;\n}\n\n// --- User Agent ---\n\nexport interface UserAgentAttributes {\n 'user_agent.raw': string;\n 'user_agent.browser'?: string;\n 'user_agent.os'?: string;\n 'user_agent.device'?: string;\n}\n\nconst BROWSER_RE = /(Firefox|OPR|Edg|Chrome|Safari|MSIE|Trident)[\\s/]?([\\d.]*)/;\nconst OS_RE =\n /(Windows NT|Mac OS X|Linux|Android|iPhone OS|iPad|CrOS)[\\s]?([\\d._]*)/;\n\nfunction parseBrowser(ua: string): string | undefined {\n const m = BROWSER_RE.exec(ua);\n if (!m) return undefined;\n const name =\n m[1] === 'OPR'\n ? 'Opera'\n : m[1] === 'Edg'\n ? 'Edge'\n : m[1] === 'Trident'\n ? 'IE'\n : m[1];\n return m[2] ? `${name} ${m[2]}` : name;\n}\n\nfunction parseOS(ua: string): string | undefined {\n const m = OS_RE.exec(ua);\n if (!m) return undefined;\n const name =\n m[1] === 'iPhone OS'\n ? 'iOS'\n : m[1] === 'Windows NT'\n ? 'Windows'\n : m[1] === 'Mac OS X'\n ? 'macOS'\n : m[1];\n const ver = m[2]?.replaceAll('_', '.') || undefined;\n return ver ? `${name} ${ver}` : name;\n}\n\nfunction parseDevice(ua: string): string | undefined {\n if (/Mobi|Android.*Mobile|iPhone/.test(ua)) return 'mobile';\n if (/iPad|Android(?!.*Mobile)|Tablet/.test(ua)) return 'tablet';\n if (/Bot|Crawler|Spider|Lighthouse/i.test(ua)) return 'bot';\n return 'desktop';\n}\n\nexport function userAgent(headers: Headers): UserAgentAttributes | undefined {\n const raw = get(headers, 'user-agent');\n if (!raw) return undefined;\n\n const attrs: UserAgentAttributes = { 'user_agent.raw': raw };\n const browser = parseBrowser(raw);\n if (browser) attrs['user_agent.browser'] = browser;\n const os = parseOS(raw);\n if (os) attrs['user_agent.os'] = os;\n const device = parseDevice(raw);\n if (device) attrs['user_agent.device'] = device;\n\n return attrs;\n}\n\n// --- Geo ---\n\nexport interface GeoAttributes {\n 'geo.country'?: string;\n 'geo.region'?: string;\n 'geo.city'?: string;\n 'geo.latitude'?: string;\n 'geo.longitude'?: string;\n}\n\nexport function geo(headers: Headers): GeoAttributes | undefined {\n const country =\n get(headers, 'x-vercel-ip-country') ?? get(headers, 'cf-ipcountry');\n const region = get(headers, 'x-vercel-ip-country-region');\n const city = get(headers, 'x-vercel-ip-city');\n const latitude = get(headers, 'x-vercel-ip-latitude');\n const longitude = get(headers, 'x-vercel-ip-longitude');\n\n if (!country && !region && !city && !latitude && !longitude) return undefined;\n\n const attrs: GeoAttributes = {};\n if (country) attrs['geo.country'] = country;\n if (region) attrs['geo.region'] = region;\n if (city) {\n try {\n attrs['geo.city'] = decodeURIComponent(city);\n } catch {\n attrs['geo.city'] = city;\n }\n }\n if (latitude) attrs['geo.latitude'] = latitude;\n if (longitude) attrs['geo.longitude'] = longitude;\n\n return attrs;\n}\n\n// --- Request Size ---\n\nexport interface RequestSizeAttributes {\n 'http.request.body.size'?: number;\n 'http.response.body.size'?: number;\n}\n\nconst DIGITS_RE = /^\\d+$/;\n\nfunction parseContentLength(value: string | undefined): number | undefined {\n if (!value || !DIGITS_RE.test(value)) return undefined;\n return Number(value);\n}\n\nexport function requestSize(\n requestHeaders: Headers,\n responseHeaders?: Headers,\n): RequestSizeAttributes | undefined {\n const reqLen = get(requestHeaders, 'content-length');\n const resLen = responseHeaders\n ? get(responseHeaders, 'content-length')\n : undefined;\n\n if (!reqLen && !resLen) return undefined;\n\n const attrs: RequestSizeAttributes = {};\n const reqBytes = parseContentLength(reqLen);\n if (reqBytes !== undefined) attrs['http.request.body.size'] = reqBytes;\n const resBytes = parseContentLength(resLen);\n if (resBytes !== undefined) attrs['http.response.body.size'] = resBytes;\n\n return Object.keys(attrs).length > 0 ? attrs : undefined;\n}\n"],"mappings":";AAEA,SAAS,IAAI,SAAkB,KAAiC;CAC9D,MAAM,QAAQ,IAAI,YAAY;CAC9B,KAAK,MAAM,CAAC,GAAG,MAAM,OAAO,QAAQ,OAAO,GACzC,IAAI,EAAE,YAAY,MAAM,OACtB,OAAO,MAAM,QAAQ,CAAC,IAAI,EAAE,KAAK;AAIvC;AAWA,MAAM,aAAa;AACnB,MAAM,QACJ;AAEF,SAAS,aAAa,IAAgC;CACpD,MAAM,IAAI,WAAW,KAAK,EAAE;CAC5B,IAAI,CAAC,GAAG,OAAO;CACf,MAAM,OACJ,EAAE,OAAO,QACL,UACA,EAAE,OAAO,QACP,SACA,EAAE,OAAO,YACP,OACA,EAAE;CACZ,OAAO,EAAE,KAAK,GAAG,KAAK,GAAG,EAAE,OAAO;AACpC;AAEA,SAAS,QAAQ,IAAgC;CAC/C,MAAM,IAAI,MAAM,KAAK,EAAE;CACvB,IAAI,CAAC,GAAG,OAAO;CACf,MAAM,OACJ,EAAE,OAAO,cACL,QACA,EAAE,OAAO,eACP,YACA,EAAE,OAAO,aACP,UACA,EAAE;CACZ,MAAM,MAAM,EAAE,EAAE,EAAE,WAAW,KAAK,GAAG,KAAK;CAC1C,OAAO,MAAM,GAAG,KAAK,GAAG,QAAQ;AAClC;AAEA,SAAS,YAAY,IAAgC;CACnD,IAAI,8BAA8B,KAAK,EAAE,GAAG,OAAO;CACnD,IAAI,kCAAkC,KAAK,EAAE,GAAG,OAAO;CACvD,IAAI,iCAAiC,KAAK,EAAE,GAAG,OAAO;CACtD,OAAO;AACT;AAEA,SAAgB,UAAU,SAAmD;CAC3E,MAAM,MAAM,IAAI,SAAS,YAAY;CACrC,IAAI,CAAC,KAAK,OAAO;CAEjB,MAAM,QAA6B,EAAE,kBAAkB,IAAI;CAC3D,MAAM,UAAU,aAAa,GAAG;CAChC,IAAI,SAAS,MAAM,wBAAwB;CAC3C,MAAM,KAAK,QAAQ,GAAG;CACtB,IAAI,IAAI,MAAM,mBAAmB;CACjC,MAAM,SAAS,YAAY,GAAG;CAC9B,IAAI,QAAQ,MAAM,uBAAuB;CAEzC,OAAO;AACT;AAYA,SAAgB,IAAI,SAA6C;CAC/D,MAAM,UACJ,IAAI,SAAS,qBAAqB,KAAK,IAAI,SAAS,cAAc;CACpE,MAAM,SAAS,IAAI,SAAS,4BAA4B;CACxD,MAAM,OAAO,IAAI,SAAS,kBAAkB;CAC5C,MAAM,WAAW,IAAI,SAAS,sBAAsB;CACpD,MAAM,YAAY,IAAI,SAAS,uBAAuB;CAEtD,IAAI,CAAC,WAAW,CAAC,UAAU,CAAC,QAAQ,CAAC,YAAY,CAAC,WAAW,OAAO;CAEpE,MAAM,QAAuB,CAAC;CAC9B,IAAI,SAAS,MAAM,iBAAiB;CACpC,IAAI,QAAQ,MAAM,gBAAgB;CAClC,IAAI,MACF,IAAI;EACF,MAAM,cAAc,mBAAmB,IAAI;CAC7C,QAAQ;EACN,MAAM,cAAc;CACtB;CAEF,IAAI,UAAU,MAAM,kBAAkB;CACtC,IAAI,WAAW,MAAM,mBAAmB;CAExC,OAAO;AACT;AASA,MAAM,YAAY;AAElB,SAAS,mBAAmB,OAA+C;CACzE,IAAI,CAAC,SAAS,CAAC,UAAU,KAAK,KAAK,GAAG,OAAO;CAC7C,OAAO,OAAO,KAAK;AACrB;AAEA,SAAgB,YACd,gBACA,iBACmC;CACnC,MAAM,SAAS,IAAI,gBAAgB,gBAAgB;CACnD,MAAM,SAAS,kBACX,IAAI,iBAAiB,gBAAgB,IACrC;CAEJ,IAAI,CAAC,UAAU,CAAC,QAAQ,OAAO;CAE/B,MAAM,QAA+B,CAAC;CACtC,MAAM,WAAW,mBAAmB,MAAM;CAC1C,IAAI,aAAa,QAAW,MAAM,4BAA4B;CAC9D,MAAM,WAAW,mBAAmB,MAAM;CAC1C,IAAI,aAAa,QAAW,MAAM,6BAA6B;CAE/D,OAAO,OAAO,KAAK,KAAK,CAAC,CAAC,SAAS,IAAI,QAAQ;AACjD"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"event-subscriber-CWh8sTGh.d.cts","names":[],"sources":["../src/event-subscriber.ts"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;KA2CY,kBAAkB;;;;;;;;;;;;;;;;;KAkBlB,uBAAuB;;;;KAQvB;;;;KAKA;;;;;;;UAQK;;EAEf;;EAEA;;EAEA;;EAEA;;EAEA;;EAEA;;EAEA;;EAEA;;EAEA;;;;;;UAOe;;EAEf;;EAEA;;EAEA;;;;;UAMe;;EAEf,UAAU;;EAEV,SAAS;;;;;;;;;;;;;;UAeM;;;;;;;;;EASf,WACE,cACA,aAAa,iBACb,UAAU,uBACT;;;;;;;;;;EAWH,gBACE,oBACA,MAAM,cACN,aAAa,iBACb,UAAU,uBACT;;;;;;;;;;EAWH,aACE,uBACA,SAAS,eACT,aAAa,iBACb,UAAU,uBACT;;;;;;;;;;EAWH,WACE,cACA,eACA,aAAa,iBACb,UAAU,uBACT;;;;;;;;;;;;;;;;;;;;;;EAuBH,wBACE,oBACA,kBACA,qBACA,aAAa,iBACb,UAAU,uBACT;;;;;;;;;;;;;;;;;EAkBH,aAAa;;;;;;WAOJ;;;;;;WAOA"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"event-subscriber-CWh8sTGh.d.ts","names":[],"sources":["../src/event-subscriber.ts"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;KA2CY,kBAAkB;;;;;;;;;;;;;;;;;KAkBlB,uBAAuB;;;;KAQvB;;;;KAKA;;;;;;;UAQK;;EAEf;;EAEA;;EAEA;;EAEA;;EAEA;;EAEA;;EAEA;;EAEA;;EAEA;;;;;;UAOe;;EAEf;;EAEA;;EAEA;;;;;UAMe;;EAEf,UAAU;;EAEV,SAAS;;;;;;;;;;;;;;UAeM;;;;;;;;;EASf,WACE,cACA,aAAa,iBACb,UAAU,uBACT;;;;;;;;;;EAWH,gBACE,oBACA,MAAM,cACN,aAAa,iBACb,UAAU,uBACT;;;;;;;;;;EAWH,aACE,uBACA,SAAS,eACT,aAAa,iBACb,UAAU,uBACT;;;;;;;;;;EAWH,WACE,cACA,eACA,aAAa,iBACb,UAAU,uBACT;;;;;;;;;;;;;;;;;;;;;;EAuBH,wBACE,oBACA,kBACA,qBACA,aAAa,iBACb,UAAU,uBACT;;;;;;;;;;;;;;;;;EAkBH,aAAa;;;;;;WAOJ;;;;;;WAOA"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"event-testing-CA2mIx1E.d.ts","names":[],"sources":["../src/event-testing.ts"],"mappings":";;UAYiB;EACf;EACA,aAAa;EACb;EACA;;UAGe;EACf;EACA,QAAQ;EACR,aAAa;EACb;EACA;;UAGe;EACf;EACA,QAAQ;EACR,aAAa;EACb;EACA;;UAGe;EACf;EACA;EACA,aAAa;EACb;EACA;;;;;UAMe;;EAEf,aAAa;;EAEb,kBAAkB;;EAElB,eAAe;;EAEf,aAAa;;EAEb;;EAEA,YAAY,OAAO;;EAEnB,iBAAiB,MAAM;;EAEvB,cAAc,SAAS;;EAEvB,YAAY,OAAO;;;;;;;;;;;;;;;;;iBAkBL,wBAAwB;;;;;;;;;;;;;iBA4DxB,mBAAmB;EACjC,WAAW;EACX;EACA,aAAa;;;;;;;;;;;;;;iBAoCC,qBAAqB;EACnC,WAAW;EACX;EACA"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"event-testing-D0qWfqAy.d.cts","names":[],"sources":["../src/event-testing.ts"],"mappings":";;UAYiB;EACf;EACA,aAAa;EACb;EACA;;UAGe;EACf;EACA,QAAQ;EACR,aAAa;EACb;EACA;;UAGe;EACf;EACA,QAAQ;EACR,aAAa;EACb;EACA;;UAGe;EACf;EACA;EACA,aAAa;EACb;EACA;;;;;UAMe;;EAEf,aAAa;;EAEb,kBAAkB;;EAElB,eAAe;;EAEf,aAAa;;EAEb;;EAEA,YAAY,OAAO;;EAEnB,iBAAiB,MAAM;;EAEvB,cAAc,SAAS;;EAEvB,YAAY,OAAO;;;;;;;;;;;;;;;;;iBAkBL,wBAAwB;;;;;;;;;;;;;iBA4DxB,mBAAmB;EACjC,WAAW;EACX;EACA,aAAa;;;;;;;;;;;;;;iBAoCC,qBAAqB;EACnC,WAAW;EACX;EACA"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"event-testing.cjs","names":[],"sources":["../src/event-testing.ts"],"sourcesContent":["/**\n * Testing utilities for Events\n *\n * Provides in-memory collection of events for testing purposes.\n */\n\nimport type {\n EventAttributes,\n FunnelStatus,\n OutcomeStatus,\n} from './event-subscriber';\n\nexport interface EventData {\n event: string;\n attributes?: EventAttributes;\n service: string;\n timestamp: number;\n}\n\nexport interface EventsFunnelStep {\n funnel: string;\n status: FunnelStatus;\n attributes?: EventAttributes;\n service: string;\n timestamp: number;\n}\n\nexport interface EventsOutcome {\n operation: string;\n status: OutcomeStatus;\n attributes?: EventAttributes;\n service: string;\n timestamp: number;\n}\n\nexport interface EventsValue {\n metric: string;\n value: number;\n attributes?: EventAttributes;\n service: string;\n timestamp: number;\n}\n\n/**\n * In-memory events collector for testing\n */\nexport interface EventCollector {\n /** Get all collected events */\n getEvents(): EventData[];\n /** Get all collected funnel steps */\n getFunnelSteps(): EventsFunnelStep[];\n /** Get all collected outcomes */\n getOutcomes(): EventsOutcome[];\n /** Get all collected values */\n getValues(): EventsValue[];\n /** Clear all collected events */\n clear(): void;\n /** Record an event (internal use) */\n recordEvent(event: EventData): void;\n /** Record a funnel step (internal use) */\n recordFunnelStep(step: EventsFunnelStep): void;\n /** Record an outcome (internal use) */\n recordOutcome(outcome: EventsOutcome): void;\n /** Record a value (internal use) */\n recordValue(value: EventsValue): void;\n}\n\n/**\n * Create an in-memory events collector for testing\n *\n * @example\n * ```typescript\n * const collector = createEventCollector()\n *\n * const events = new Event('test-service', { collector })\n * events.trackEvent('application.submitted', { jobId: '123' })\n *\n * const event =collector.getEvents()\n * expect(events).toHaveLength(1)\n * expect(events[0].event).toBe('application.submitted')\n * ```\n */\nexport function createEventCollector(): EventCollector {\n const events: EventData[] = [];\n const funnelSteps: EventsFunnelStep[] = [];\n const outcomes: EventsOutcome[] = [];\n const values: EventsValue[] = [];\n\n return {\n getEvents(): EventData[] {\n return [...events];\n },\n\n getFunnelSteps(): EventsFunnelStep[] {\n return [...funnelSteps];\n },\n\n getOutcomes(): EventsOutcome[] {\n return [...outcomes];\n },\n\n getValues(): EventsValue[] {\n return [...values];\n },\n\n clear(): void {\n events.length = 0;\n funnelSteps.length = 0;\n outcomes.length = 0;\n values.length = 0;\n },\n\n recordEvent(event: EventData): void {\n events.push(event);\n },\n\n recordFunnelStep(step: EventsFunnelStep): void {\n funnelSteps.push(step);\n },\n\n recordOutcome(outcome: EventsOutcome): void {\n outcomes.push(outcome);\n },\n\n recordValue(value: EventsValue): void {\n values.push(value);\n },\n };\n}\n\n/**\n * Assert that an events event was tracked\n *\n * @example\n * ```typescript\n * assertEventTracked({\n * collector,\n * eventName: 'application.submitted',\n * attributes: { jobId: '123' }\n * })\n * ```\n */\nexport function assertEventTracked(options: {\n collector: EventCollector;\n eventName: string;\n attributes?: Record<string, unknown>;\n}): void {\n const events = options.collector.getEvents();\n const matching = events.filter((e) => e.event === options.eventName);\n\n if (matching.length === 0) {\n throw new Error(`No events found with name: ${options.eventName}`);\n }\n\n if (options.attributes) {\n const matchingWithAttrs = matching.filter((e) =>\n Object.entries(options.attributes!).every(\n ([key, value]) => e.attributes && e.attributes[key] === value,\n ),\n );\n\n if (matchingWithAttrs.length === 0) {\n throw new Error(\n `Event ${options.eventName} found but attributes don't match: ${JSON.stringify(options.attributes)}`,\n );\n }\n }\n}\n\n/**\n * Assert that an outcome was tracked\n *\n * @example\n * ```typescript\n * assertOutcomeTracked({\n * collector,\n * operation: 'email.delivery',\n * status: 'success'\n * })\n * ```\n */\nexport function assertOutcomeTracked(options: {\n collector: EventCollector;\n operation: string;\n status: 'success' | 'failure' | 'partial';\n}): void {\n const outcomes = options.collector.getOutcomes();\n const matching = outcomes.filter(\n (o) => o.operation === options.operation && o.status === options.status,\n );\n\n if (matching.length === 0) {\n throw new Error(\n `No outcomes found with operation: ${options.operation} and status: ${options.status}`,\n );\n }\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;AAkFA,SAAgB,uBAAuC;CACrD,MAAM,SAAsB,CAAC;CAC7B,MAAM,cAAkC,CAAC;CACzC,MAAM,WAA4B,CAAC;CACnC,MAAM,SAAwB,CAAC;CAE/B,OAAO;EACL,YAAyB;GACvB,OAAO,CAAC,GAAG,MAAM;EACnB;EAEA,iBAAqC;GACnC,OAAO,CAAC,GAAG,WAAW;EACxB;EAEA,cAA+B;GAC7B,OAAO,CAAC,GAAG,QAAQ;EACrB;EAEA,YAA2B;GACzB,OAAO,CAAC,GAAG,MAAM;EACnB;EAEA,QAAc;GACZ,OAAO,SAAS;GAChB,YAAY,SAAS;GACrB,SAAS,SAAS;GAClB,OAAO,SAAS;EAClB;EAEA,YAAY,OAAwB;GAClC,OAAO,KAAK,KAAK;EACnB;EAEA,iBAAiB,MAA8B;GAC7C,YAAY,KAAK,IAAI;EACvB;EAEA,cAAc,SAA8B;GAC1C,SAAS,KAAK,OAAO;EACvB;EAEA,YAAY,OAA0B;GACpC,OAAO,KAAK,KAAK;EACnB;CACF;AACF;;;;;;;;;;;;;AAcA,SAAgB,mBAAmB,SAI1B;CAEP,MAAM,WADS,QAAQ,UAAU,UACX,CAAC,CAAC,QAAQ,MAAM,EAAE,UAAU,QAAQ,SAAS;CAEnE,IAAI,SAAS,WAAW,GACtB,MAAM,IAAI,MAAM,8BAA8B,QAAQ,WAAW;CAGnE,IAAI,QAAQ,YAOV;MAN0B,SAAS,QAAQ,MACzC,OAAO,QAAQ,QAAQ,UAAW,CAAC,CAAC,OACjC,CAAC,KAAK,WAAW,EAAE,cAAc,EAAE,WAAW,SAAS,KAC1D,CAGkB,CAAC,CAAC,WAAW,GAC/B,MAAM,IAAI,MACR,SAAS,QAAQ,UAAU,qCAAqC,KAAK,UAAU,QAAQ,UAAU,GACnG;CACF;AAEJ;;;;;;;;;;;;;AAcA,SAAgB,qBAAqB,SAI5B;CAMP,IALiB,QAAQ,UAAU,YACX,CAAC,CAAC,QACvB,MAAM,EAAE,cAAc,QAAQ,aAAa,EAAE,WAAW,QAAQ,MAGxD,CAAC,CAAC,WAAW,GACtB,MAAM,IAAI,MACR,qCAAqC,QAAQ,UAAU,eAAe,QAAQ,QAChF;AAEJ"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"event-testing.js","names":[],"sources":["../src/event-testing.ts"],"sourcesContent":["/**\n * Testing utilities for Events\n *\n * Provides in-memory collection of events for testing purposes.\n */\n\nimport type {\n EventAttributes,\n FunnelStatus,\n OutcomeStatus,\n} from './event-subscriber';\n\nexport interface EventData {\n event: string;\n attributes?: EventAttributes;\n service: string;\n timestamp: number;\n}\n\nexport interface EventsFunnelStep {\n funnel: string;\n status: FunnelStatus;\n attributes?: EventAttributes;\n service: string;\n timestamp: number;\n}\n\nexport interface EventsOutcome {\n operation: string;\n status: OutcomeStatus;\n attributes?: EventAttributes;\n service: string;\n timestamp: number;\n}\n\nexport interface EventsValue {\n metric: string;\n value: number;\n attributes?: EventAttributes;\n service: string;\n timestamp: number;\n}\n\n/**\n * In-memory events collector for testing\n */\nexport interface EventCollector {\n /** Get all collected events */\n getEvents(): EventData[];\n /** Get all collected funnel steps */\n getFunnelSteps(): EventsFunnelStep[];\n /** Get all collected outcomes */\n getOutcomes(): EventsOutcome[];\n /** Get all collected values */\n getValues(): EventsValue[];\n /** Clear all collected events */\n clear(): void;\n /** Record an event (internal use) */\n recordEvent(event: EventData): void;\n /** Record a funnel step (internal use) */\n recordFunnelStep(step: EventsFunnelStep): void;\n /** Record an outcome (internal use) */\n recordOutcome(outcome: EventsOutcome): void;\n /** Record a value (internal use) */\n recordValue(value: EventsValue): void;\n}\n\n/**\n * Create an in-memory events collector for testing\n *\n * @example\n * ```typescript\n * const collector = createEventCollector()\n *\n * const events = new Event('test-service', { collector })\n * events.trackEvent('application.submitted', { jobId: '123' })\n *\n * const event =collector.getEvents()\n * expect(events).toHaveLength(1)\n * expect(events[0].event).toBe('application.submitted')\n * ```\n */\nexport function createEventCollector(): EventCollector {\n const events: EventData[] = [];\n const funnelSteps: EventsFunnelStep[] = [];\n const outcomes: EventsOutcome[] = [];\n const values: EventsValue[] = [];\n\n return {\n getEvents(): EventData[] {\n return [...events];\n },\n\n getFunnelSteps(): EventsFunnelStep[] {\n return [...funnelSteps];\n },\n\n getOutcomes(): EventsOutcome[] {\n return [...outcomes];\n },\n\n getValues(): EventsValue[] {\n return [...values];\n },\n\n clear(): void {\n events.length = 0;\n funnelSteps.length = 0;\n outcomes.length = 0;\n values.length = 0;\n },\n\n recordEvent(event: EventData): void {\n events.push(event);\n },\n\n recordFunnelStep(step: EventsFunnelStep): void {\n funnelSteps.push(step);\n },\n\n recordOutcome(outcome: EventsOutcome): void {\n outcomes.push(outcome);\n },\n\n recordValue(value: EventsValue): void {\n values.push(value);\n },\n };\n}\n\n/**\n * Assert that an events event was tracked\n *\n * @example\n * ```typescript\n * assertEventTracked({\n * collector,\n * eventName: 'application.submitted',\n * attributes: { jobId: '123' }\n * })\n * ```\n */\nexport function assertEventTracked(options: {\n collector: EventCollector;\n eventName: string;\n attributes?: Record<string, unknown>;\n}): void {\n const events = options.collector.getEvents();\n const matching = events.filter((e) => e.event === options.eventName);\n\n if (matching.length === 0) {\n throw new Error(`No events found with name: ${options.eventName}`);\n }\n\n if (options.attributes) {\n const matchingWithAttrs = matching.filter((e) =>\n Object.entries(options.attributes!).every(\n ([key, value]) => e.attributes && e.attributes[key] === value,\n ),\n );\n\n if (matchingWithAttrs.length === 0) {\n throw new Error(\n `Event ${options.eventName} found but attributes don't match: ${JSON.stringify(options.attributes)}`,\n );\n }\n }\n}\n\n/**\n * Assert that an outcome was tracked\n *\n * @example\n * ```typescript\n * assertOutcomeTracked({\n * collector,\n * operation: 'email.delivery',\n * status: 'success'\n * })\n * ```\n */\nexport function assertOutcomeTracked(options: {\n collector: EventCollector;\n operation: string;\n status: 'success' | 'failure' | 'partial';\n}): void {\n const outcomes = options.collector.getOutcomes();\n const matching = outcomes.filter(\n (o) => o.operation === options.operation && o.status === options.status,\n );\n\n if (matching.length === 0) {\n throw new Error(\n `No outcomes found with operation: ${options.operation} and status: ${options.status}`,\n );\n }\n}\n"],"mappings":";;;;;;;;;;;;;;;;AAkFA,SAAgB,uBAAuC;CACrD,MAAM,SAAsB,CAAC;CAC7B,MAAM,cAAkC,CAAC;CACzC,MAAM,WAA4B,CAAC;CACnC,MAAM,SAAwB,CAAC;CAE/B,OAAO;EACL,YAAyB;GACvB,OAAO,CAAC,GAAG,MAAM;EACnB;EAEA,iBAAqC;GACnC,OAAO,CAAC,GAAG,WAAW;EACxB;EAEA,cAA+B;GAC7B,OAAO,CAAC,GAAG,QAAQ;EACrB;EAEA,YAA2B;GACzB,OAAO,CAAC,GAAG,MAAM;EACnB;EAEA,QAAc;GACZ,OAAO,SAAS;GAChB,YAAY,SAAS;GACrB,SAAS,SAAS;GAClB,OAAO,SAAS;EAClB;EAEA,YAAY,OAAwB;GAClC,OAAO,KAAK,KAAK;EACnB;EAEA,iBAAiB,MAA8B;GAC7C,YAAY,KAAK,IAAI;EACvB;EAEA,cAAc,SAA8B;GAC1C,SAAS,KAAK,OAAO;EACvB;EAEA,YAAY,OAA0B;GACpC,OAAO,KAAK,KAAK;EACnB;CACF;AACF;;;;;;;;;;;;;AAcA,SAAgB,mBAAmB,SAI1B;CAEP,MAAM,WADS,QAAQ,UAAU,UACX,CAAC,CAAC,QAAQ,MAAM,EAAE,UAAU,QAAQ,SAAS;CAEnE,IAAI,SAAS,WAAW,GACtB,MAAM,IAAI,MAAM,8BAA8B,QAAQ,WAAW;CAGnE,IAAI,QAAQ,YAOV;MAN0B,SAAS,QAAQ,MACzC,OAAO,QAAQ,QAAQ,UAAW,CAAC,CAAC,OACjC,CAAC,KAAK,WAAW,EAAE,cAAc,EAAE,WAAW,SAAS,KAC1D,CAGkB,CAAC,CAAC,WAAW,GAC/B,MAAM,IAAI,MACR,SAAS,QAAQ,UAAU,qCAAqC,KAAK,UAAU,QAAQ,UAAU,GACnG;CACF;AAEJ;;;;;;;;;;;;;AAcA,SAAgB,qBAAqB,SAI5B;CAMP,IALiB,QAAQ,UAAU,YACX,CAAC,CAAC,QACvB,MAAM,EAAE,cAAc,QAAQ,aAAa,EAAE,WAAW,QAAQ,MAGxD,CAAC,CAAC,WAAW,GACtB,MAAM,IAAI,MACR,qCAAqC,QAAQ,UAAU,eAAe,QAAQ,QAChF;AAEJ"}
|
package/dist/event.d.cts.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"event.d.cts","names":[],"sources":["../src/event.ts"],"mappings":";;;;;;;;;;;;;;;;;;;UA4FiB;;EAEf,SAAS;;EAET,YAAY;;;;;;;;;;;;EAYZ,cAAc;;cAGH;UACH;UACA;UACA;UACA;UACA;UACA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EA8CI,YAAA,qBAAqB,UAAS;;;;;;;;;UAsClC;;;;;;;;;;;;UAiDA;;;;;;;UA4FA;;;;UAsEA;;;;;UA2BA;;;;;;;;;;;;;;;;;;;;;;;;;;EAiCR,WAAW,mBAAmB,aAAa;;;;;;UAoD7B;;;;;;;;;;;;;;;;;;;EAwDd,gBACE,oBACA,QAAQ,cACR,aAAa;;;;;;;;;;;;;;;;;;;;;;;;EA2Df,aACE,uBACA,QAAQ,eACR,aAAa;;;;;;;;;;;;;;;;;;;;;;;;;;;EA8Df,WACE,oBACA,eACA,aAAa;;;;;;;;;;;;;;EAoDT,SAAS;;;;;;;;;;;;;;;;;;;;;;;;;;EA+CT,YAAY;;;;;;;;;;;;;;;;;;;;;EA6ClB,uBACE,oBACA,kBACA,qBACA,aAAa;;;;;;;;;;;;;;;;;;EA4Ef,WACE,QAAQ;IAAQ;IAAc,aAAa;;;;;;;;;;;;;;;;iBAoC/B,UAAU,qBAAqB,SAAS,SAAS;;;;iBAUjD"}
|
package/dist/event.d.ts.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"event.d.ts","names":[],"sources":["../src/event.ts"],"mappings":";;;;;;;;;;;;;;;;;;;UA4FiB;;EAEf,SAAS;;EAET,YAAY;;;;;;;;;;;;EAYZ,cAAc;;cAGH;UACH;UACA;UACA;UACA;UACA;UACA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EA8CI,YAAA,qBAAqB,UAAS;;;;;;;;;UAsClC;;;;;;;;;;;;UAiDA;;;;;;;UA4FA;;;;UAsEA;;;;;UA2BA;;;;;;;;;;;;;;;;;;;;;;;;;;EAiCR,WAAW,mBAAmB,aAAa;;;;;;UAoD7B;;;;;;;;;;;;;;;;;;;EAwDd,gBACE,oBACA,QAAQ,cACR,aAAa;;;;;;;;;;;;;;;;;;;;;;;;EA2Df,aACE,uBACA,QAAQ,eACR,aAAa;;;;;;;;;;;;;;;;;;;;;;;;;;;EA8Df,WACE,oBACA,eACA,aAAa;;;;;;;;;;;;;;EAoDT,SAAS;;;;;;;;;;;;;;;;;;;;;;;;;;EA+CT,YAAY;;;;;;;;;;;;;;;;;;;;;EA6ClB,uBACE,oBACA,kBACA,qBACA,aAAa;;;;;;;;;;;;;;;;;;EA4Ef,WACE,QAAQ;IAAQ;IAAc,aAAa;;;;;;;;;;;;;;;;iBAoC/B,UAAU,qBAAqB,SAAS,SAAS;;;;iBAUjD"}
|
package/dist/exporters.d.cts.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"exporters.d.cts","names":[],"sources":["../src/pretty-console-exporter.ts"],"mappings":";;;;;UA2CU;EACR;EACA,QAAQ;;;;;UAuBO;;;;;EAKf;;;;;EAMA;;;;;EAMA;;;;;EAMA;;;;;EAMA;;;;;EAMA;;;;;;;;;;;;cAqBW,iCAAiC;mBAC3B;EAEL,YAAA,UAAS;;;;EAcrB,OACE,OAAO,gBACP,iBAAiB,QAAQ;;;;UA0BnB;;;;UAgBA;;;;UA4BA;;;;UA+BA;;;;UA+DA;;;;UAaA;;;;UA4BA;;;;UAQA;;;;EAQR,YAAY;;;;EAOZ,cAAc"}
|
package/dist/exporters.d.ts.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"exporters.d.ts","names":[],"sources":["../src/pretty-console-exporter.ts"],"mappings":";;;;;UA2CU;EACR;EACA,QAAQ;;;;;UAuBO;;;;;EAKf;;;;;EAMA;;;;;EAMA;;;;;EAMA;;;;;EAMA;;;;;EAMA;;;;;;;;;;;;cAqBW,iCAAiC;mBAC3B;EAEL,YAAA,UAAS;;;;EAcrB,OACE,OAAO,gBACP,iBAAiB,QAAQ;;;;UA0BnB;;;;UAgBA;;;;UA4BA;;;;UA+BA;;;;UA+DA;;;;UAaA;;;;UA4BA;;;;UAQA;;;;EAQR,YAAY;;;;EAOZ,cAAc"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"filtering-span-processor-BpDagWNa.d.cts","names":[],"sources":["../src/filtering-span-processor.ts"],"mappings":";;;;;;;;;;;;;;;;;KA4CY,uBAAuB,MAAM;UAExB;;;;;EAKf,QAAQ;;;;;;;;;;;;;;;;cAiBG,kCAAkC;mBAC5B;mBACA;EAGf,YAAA,kBAAkB,eAClB,SAAS;;;;EASX,QAAQ,MAAM,MAAM,eAAe;;;;;EAQnC,MAAM,MAAM;EAYZ,cAAc;EAId,YAAY"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"filtering-span-processor-BpDagWNa.d.ts","names":[],"sources":["../src/filtering-span-processor.ts"],"mappings":";;;;;;;;;;;;;;;;;KA4CY,uBAAuB,MAAM;UAExB;;;;;EAKf,QAAQ;;;;;;;;;;;;;;;;cAiBG,kCAAkC;mBAC5B;mBACA;EAGf,YAAA,kBAAkB,eAClB,SAAS;;;;EASX,QAAQ,MAAM,MAAM,eAAe;;;;;EAQnC,MAAM,MAAM;EAYZ,cAAc;EAId,YAAY"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"filtering-span-processor.cjs","names":[],"sources":["../src/filtering-span-processor.ts"],"sourcesContent":["/**\n * Filtering Span Processor\n *\n * Filters spans based on a user-provided predicate function.\n * Runs filtering on onEnd() to have access to complete span data.\n *\n * @example Filter out Next.js instrumentation spans\n * ```typescript\n * init({\n * service: 'my-app',\n * spanFilter: (span) => span.instrumentationScope.name !== 'next.js'\n * })\n * ```\n *\n * @example Filter out health check endpoints\n * ```typescript\n * init({\n * service: 'my-app',\n * spanFilter: (span) => !span.name.includes('/health')\n * })\n * ```\n */\n\nimport type {\n SpanProcessor,\n ReadableSpan,\n} from '@opentelemetry/sdk-trace-base';\nimport type { Context } from '@opentelemetry/api';\nimport type { Span } from '@opentelemetry/sdk-trace-base';\n\n/**\n * Predicate function for filtering spans\n *\n * @param span - The completed span (ReadableSpan) with all attributes and metadata\n * @returns true to keep the span, false to drop it\n *\n * Available span properties for filtering:\n * - `span.name` - Span name\n * - `span.attributes` - All span attributes\n * - `span.instrumentationScope` - `{ name, version }` of the instrumentation\n * - `span.status` - Span status code and message\n * - `span.duration` - Span duration as `[seconds, nanoseconds]`\n * - `span.kind` - SpanKind (INTERNAL, SERVER, CLIENT, etc.)\n */\nexport type SpanFilterPredicate = (span: ReadableSpan) => boolean;\n\nexport interface FilteringSpanProcessorOptions {\n /**\n * Predicate function to determine if a span should be kept\n * Return true to keep the span, false to drop it\n */\n filter: SpanFilterPredicate;\n}\n\n/**\n * Span processor that filters spans based on a predicate function.\n *\n * The filter is applied on onEnd() when the span has complete data including:\n * - All attributes\n * - Status code and message\n * - Duration\n * - Events and links\n * - Instrumentation scope (useful for filtering by library)\n *\n * onStart() passes through unchanged to ensure child spans can still be created.\n *\n * Error handling: If the filter predicate throws, the span is forwarded (fail-open).\n */\nexport class FilteringSpanProcessor implements SpanProcessor {\n private readonly wrappedProcessor: SpanProcessor;\n private readonly filter: SpanFilterPredicate;\n\n constructor(\n wrappedProcessor: SpanProcessor,\n options: FilteringSpanProcessorOptions,\n ) {\n this.wrappedProcessor = wrappedProcessor;\n this.filter = options.filter;\n }\n\n /**\n * Pass through onStart - we need spans to start so child spans work\n */\n onStart(span: Span, parentContext: Context): void {\n this.wrappedProcessor.onStart(span, parentContext);\n }\n\n /**\n * Apply filter predicate on span end\n * If filter returns false, span is dropped (not forwarded)\n */\n onEnd(span: ReadableSpan): void {\n try {\n if (this.filter(span)) {\n this.wrappedProcessor.onEnd(span);\n }\n // If filter returns false, span is silently dropped\n } catch {\n // If filter throws, forward the span (fail-open behavior)\n this.wrappedProcessor.onEnd(span);\n }\n }\n\n forceFlush(): Promise<void> {\n return this.wrappedProcessor.forceFlush();\n }\n\n shutdown(): Promise<void> {\n return this.wrappedProcessor.shutdown();\n }\n}\n"],"mappings":";;;;;;;;;;;;;;;;;AAoEA,IAAa,yBAAb,MAA6D;CAC3D,AAAiB;CACjB,AAAiB;CAEjB,YACE,kBACA,SACA;EACA,KAAK,mBAAmB;EACxB,KAAK,SAAS,QAAQ;CACxB;;;;CAKA,QAAQ,MAAY,eAA8B;EAChD,KAAK,iBAAiB,QAAQ,MAAM,aAAa;CACnD;;;;;CAMA,MAAM,MAA0B;EAC9B,IAAI;GACF,IAAI,KAAK,OAAO,IAAI,GAClB,KAAK,iBAAiB,MAAM,IAAI;EAGpC,QAAQ;GAEN,KAAK,iBAAiB,MAAM,IAAI;EAClC;CACF;CAEA,aAA4B;EAC1B,OAAO,KAAK,iBAAiB,WAAW;CAC1C;CAEA,WAA0B;EACxB,OAAO,KAAK,iBAAiB,SAAS;CACxC;AACF"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"filtering-span-processor.js","names":[],"sources":["../src/filtering-span-processor.ts"],"sourcesContent":["/**\n * Filtering Span Processor\n *\n * Filters spans based on a user-provided predicate function.\n * Runs filtering on onEnd() to have access to complete span data.\n *\n * @example Filter out Next.js instrumentation spans\n * ```typescript\n * init({\n * service: 'my-app',\n * spanFilter: (span) => span.instrumentationScope.name !== 'next.js'\n * })\n * ```\n *\n * @example Filter out health check endpoints\n * ```typescript\n * init({\n * service: 'my-app',\n * spanFilter: (span) => !span.name.includes('/health')\n * })\n * ```\n */\n\nimport type {\n SpanProcessor,\n ReadableSpan,\n} from '@opentelemetry/sdk-trace-base';\nimport type { Context } from '@opentelemetry/api';\nimport type { Span } from '@opentelemetry/sdk-trace-base';\n\n/**\n * Predicate function for filtering spans\n *\n * @param span - The completed span (ReadableSpan) with all attributes and metadata\n * @returns true to keep the span, false to drop it\n *\n * Available span properties for filtering:\n * - `span.name` - Span name\n * - `span.attributes` - All span attributes\n * - `span.instrumentationScope` - `{ name, version }` of the instrumentation\n * - `span.status` - Span status code and message\n * - `span.duration` - Span duration as `[seconds, nanoseconds]`\n * - `span.kind` - SpanKind (INTERNAL, SERVER, CLIENT, etc.)\n */\nexport type SpanFilterPredicate = (span: ReadableSpan) => boolean;\n\nexport interface FilteringSpanProcessorOptions {\n /**\n * Predicate function to determine if a span should be kept\n * Return true to keep the span, false to drop it\n */\n filter: SpanFilterPredicate;\n}\n\n/**\n * Span processor that filters spans based on a predicate function.\n *\n * The filter is applied on onEnd() when the span has complete data including:\n * - All attributes\n * - Status code and message\n * - Duration\n * - Events and links\n * - Instrumentation scope (useful for filtering by library)\n *\n * onStart() passes through unchanged to ensure child spans can still be created.\n *\n * Error handling: If the filter predicate throws, the span is forwarded (fail-open).\n */\nexport class FilteringSpanProcessor implements SpanProcessor {\n private readonly wrappedProcessor: SpanProcessor;\n private readonly filter: SpanFilterPredicate;\n\n constructor(\n wrappedProcessor: SpanProcessor,\n options: FilteringSpanProcessorOptions,\n ) {\n this.wrappedProcessor = wrappedProcessor;\n this.filter = options.filter;\n }\n\n /**\n * Pass through onStart - we need spans to start so child spans work\n */\n onStart(span: Span, parentContext: Context): void {\n this.wrappedProcessor.onStart(span, parentContext);\n }\n\n /**\n * Apply filter predicate on span end\n * If filter returns false, span is dropped (not forwarded)\n */\n onEnd(span: ReadableSpan): void {\n try {\n if (this.filter(span)) {\n this.wrappedProcessor.onEnd(span);\n }\n // If filter returns false, span is silently dropped\n } catch {\n // If filter throws, forward the span (fail-open behavior)\n this.wrappedProcessor.onEnd(span);\n }\n }\n\n forceFlush(): Promise<void> {\n return this.wrappedProcessor.forceFlush();\n }\n\n shutdown(): Promise<void> {\n return this.wrappedProcessor.shutdown();\n }\n}\n"],"mappings":";;;;;;;;;;;;;;;AAoEA,IAAa,yBAAb,MAA6D;CAC3D,AAAiB;CACjB,AAAiB;CAEjB,YACE,kBACA,SACA;EACA,KAAK,mBAAmB;EACxB,KAAK,SAAS,QAAQ;CACxB;;;;CAKA,QAAQ,MAAY,eAA8B;EAChD,KAAK,iBAAiB,QAAQ,MAAM,aAAa;CACnD;;;;;CAMA,MAAM,MAA0B;EAC9B,IAAI;GACF,IAAI,KAAK,OAAO,IAAI,GAClB,KAAK,iBAAiB,MAAM,IAAI;EAGpC,QAAQ;GAEN,KAAK,iBAAiB,MAAM,IAAI;EAClC;CACF;CAEA,aAA4B;EAC1B,OAAO,KAAK,iBAAiB,WAAW;CAC1C;CAEA,WAA0B;EACxB,OAAO,KAAK,iBAAiB,SAAS;CACxC;AACF"}
|