@scope-analytics/node 0.1.0 → 0.1.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/README.md +9 -9
- package/dist/index.cjs +47 -19
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +46 -19
- package/dist/index.js.map +1 -1
- package/dist/register.cjs +47 -19
- package/dist/register.cjs.map +1 -1
- package/dist/register.js +46 -19
- package/dist/register.js.map +1 -1
- package/package.json +1 -1
package/dist/register.cjs
CHANGED
|
@@ -85,10 +85,10 @@ function registerEsmManualInstrument(entries) {
|
|
|
85
85
|
}
|
|
86
86
|
|
|
87
87
|
// src/index.ts
|
|
88
|
+
var import_node_module = require("module");
|
|
89
|
+
var import_node_url = require("url");
|
|
88
90
|
var import_instrumentation3 = require("@opentelemetry/instrumentation");
|
|
89
91
|
var import_sdk_trace_node = require("@opentelemetry/sdk-trace-node");
|
|
90
|
-
var import_openinference_instrumentation_openai = require("@arizeai/openinference-instrumentation-openai");
|
|
91
|
-
var import_openinference_instrumentation_anthropic = require("@arizeai/openinference-instrumentation-anthropic");
|
|
92
92
|
var import_openinference_vercel = require("@arizeai/openinference-vercel");
|
|
93
93
|
|
|
94
94
|
// src/google-genai-instrumentation.ts
|
|
@@ -98,7 +98,7 @@ var import_instrumentation = require("@opentelemetry/instrumentation");
|
|
|
98
98
|
var import_openinference_semantic_conventions = require("@arizeai/openinference-semantic-conventions");
|
|
99
99
|
|
|
100
100
|
// src/version.ts
|
|
101
|
-
var SDK_VERSION = "0.1.
|
|
101
|
+
var SDK_VERSION = "0.1.1";
|
|
102
102
|
var SDK_SOURCE = "backend_sdk";
|
|
103
103
|
var SDK_USER_AGENT = `scope-tracer-node/${SDK_VERSION}`;
|
|
104
104
|
|
|
@@ -797,6 +797,32 @@ var ScopeContextSpanProcessor = class {
|
|
|
797
797
|
};
|
|
798
798
|
|
|
799
799
|
// src/index.ts
|
|
800
|
+
var import_meta2 = {};
|
|
801
|
+
function _makeRequire() {
|
|
802
|
+
try {
|
|
803
|
+
if (typeof import_meta2 !== "undefined" && import_meta2.url) return (0, import_node_module.createRequire)(import_meta2.url);
|
|
804
|
+
} catch {
|
|
805
|
+
}
|
|
806
|
+
try {
|
|
807
|
+
if (typeof __filename === "string") return (0, import_node_module.createRequire)((0, import_node_url.pathToFileURL)(__filename).href);
|
|
808
|
+
} catch {
|
|
809
|
+
}
|
|
810
|
+
return null;
|
|
811
|
+
}
|
|
812
|
+
var _require = _makeRequire();
|
|
813
|
+
function loadInstrumentationIfPresent(providerPackage, load) {
|
|
814
|
+
if (!_require) return null;
|
|
815
|
+
try {
|
|
816
|
+
_require.resolve(providerPackage);
|
|
817
|
+
} catch {
|
|
818
|
+
return null;
|
|
819
|
+
}
|
|
820
|
+
try {
|
|
821
|
+
return load(_require);
|
|
822
|
+
} catch {
|
|
823
|
+
return null;
|
|
824
|
+
}
|
|
825
|
+
}
|
|
800
826
|
var STARTED_AT = /* @__PURE__ */ new Date();
|
|
801
827
|
var active = null;
|
|
802
828
|
function init(options = {}) {
|
|
@@ -826,24 +852,26 @@ function init(options = {}) {
|
|
|
826
852
|
]
|
|
827
853
|
});
|
|
828
854
|
provider.register();
|
|
829
|
-
const openaiInstrumentation =
|
|
830
|
-
|
|
855
|
+
const openaiInstrumentation = loadInstrumentationIfPresent(
|
|
856
|
+
"openai",
|
|
857
|
+
(req) => new (req("@arizeai/openinference-instrumentation-openai")).OpenAIInstrumentation()
|
|
858
|
+
);
|
|
859
|
+
const anthropicInstrumentation = loadInstrumentationIfPresent(
|
|
860
|
+
"@anthropic-ai/sdk",
|
|
861
|
+
(req) => new (req("@arizeai/openinference-instrumentation-anthropic")).AnthropicInstrumentation()
|
|
862
|
+
);
|
|
831
863
|
const googleGenAIInstrumentation = new GoogleGenAIInstrumentation();
|
|
832
864
|
const vercelAIInstrumentation = new VercelAIInstrumentation();
|
|
833
|
-
|
|
834
|
-
|
|
835
|
-
|
|
836
|
-
|
|
837
|
-
|
|
838
|
-
|
|
839
|
-
|
|
840
|
-
]
|
|
841
|
-
});
|
|
842
|
-
registerEsmManualInstrument(
|
|
843
|
-
{ modules: ["openai"], instrumentation: openaiInstrumentation },
|
|
844
|
-
{ modules: ["@anthropic-ai/sdk"], instrumentation: anthropicInstrumentation },
|
|
845
|
-
{ modules: ["@google/genai"], instrumentation: googleGenAIInstrumentation }
|
|
846
|
-
]);
|
|
865
|
+
const instrumentations = [googleGenAIInstrumentation, vercelAIInstrumentation];
|
|
866
|
+
if (openaiInstrumentation) instrumentations.push(openaiInstrumentation);
|
|
867
|
+
if (anthropicInstrumentation) instrumentations.push(anthropicInstrumentation);
|
|
868
|
+
(0, import_instrumentation3.registerInstrumentations)({ tracerProvider: provider, instrumentations });
|
|
869
|
+
const esmManual = [];
|
|
870
|
+
if (openaiInstrumentation) esmManual.push({ modules: ["openai"], instrumentation: openaiInstrumentation });
|
|
871
|
+
if (anthropicInstrumentation)
|
|
872
|
+
esmManual.push({ modules: ["@anthropic-ai/sdk"], instrumentation: anthropicInstrumentation });
|
|
873
|
+
esmManual.push({ modules: ["@google/genai"], instrumentation: googleGenAIInstrumentation });
|
|
874
|
+
registerEsmManualInstrument(esmManual);
|
|
847
875
|
active = {
|
|
848
876
|
config,
|
|
849
877
|
deployment,
|
package/dist/register.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/esm-hook.ts","../src/index.ts","../src/google-genai-instrumentation.ts","../src/version.ts","../src/vercel-ai-instrumentation.ts","../src/config.ts","../src/deployment.ts","../src/exporter.ts","../src/event.ts","../src/attributes.ts","../src/session.ts","../src/transport.ts","../src/processor.ts","../src/register.ts"],"sourcesContent":["import * as nodeModule from 'node:module';\nimport { diag } from '@opentelemetry/api';\n// LOAD-BEARING DEDUP INVARIANT: this `Hook` MUST come from the SAME import-in-the-middle instance as the\n// loader we register (`@opentelemetry/instrumentation/hook.mjs`, which imports its own iitm) — otherwise\n// our hook registers in a different registry and its callback never fires (silent big-3 ESM no-capture,\n// while CJS keeps working). We pin `import-in-the-middle` to the same `^3` range @opentelemetry/\n// instrumentation uses so npm dedupes them to one instance. version-pin.test.ts guards this invariant\n// directly (asserts both resolve to one physical package); the esm-bootstrap subprocess test is the\n// functional backstop. If you bump @opentelemetry/instrumentation, re-verify the dedup.\nimport { Hook } from 'import-in-the-middle';\n\n// Turn on ESM auto-instrumentation. Node's module hooks come in two halves: a require-hook\n// (require-in-the-middle) that fires for CJS `require(...)`, and an import-hook (import-in-the-middle)\n// that fires for ESM `import ...`. @opentelemetry/instrumentation sets the require-hook up on its own,\n// but the IMPORT-hook only fires if the import-in-the-middle loader is registered at startup — which\n// nothing does by default. So without this, ESM apps (the majority of modern AI apps — Next.js et al.)\n// get NO auto-capture for ANY provider, because every provider resolves its `import` condition to true\n// ESM. This registers the loader hook @opentelemetry/instrumentation ships, so ESM imports are\n// instrumented too.\n//\n// Constraints (all load-bearing):\n// - Only meaningful on the `--import @scope-analytics/node/register` bootstrap: an ESM loader must be\n// registered BEFORE the app's modules load, which `--import` guarantees and a late init() cannot.\n// In the CJS (`--require`) build, import.meta.url is unavailable, so we no-op there (CJS apps are\n// captured via the require-hook regardless).\n// - module.register() needs Node >= 18.19 / >= 20.6; we feature-detect and no-op on older runtimes.\n// - NEVER throws (rule b): any failure degrades to CJS-only capture, never a crashed host startup.\n// - Opt-out via SCOPE_DISABLE_ESM_HOOK=1 for hosts that don't want a loader processing their imports.\n\nconst HOOK_SPECIFIER = '@opentelemetry/instrumentation/hook.mjs';\n\n// True once we've actually registered the IITM loader (only on the `--import` ESM bootstrap). Gates\n// registerEsmManualInstrument so we never create IITM hooks when the loader isn't active (e.g. the CJS\n// build or the explicit init() path). register.ts is bundled standalone, so enableEsmInstrumentation()\n// and registerEsmManualInstrument() share this module instance within the bootstrap bundle.\nlet _loaderRegistered = false;\n\nfunction esmHookDisabled(): boolean {\n const v = process.env.SCOPE_DISABLE_ESM_HOOK;\n return v === '1' || v === 'true' || v === 'TRUE';\n}\n\n/** Resolve the parent URL used to resolve the loader specifier. Only available when running as ESM\n * (the `--import` build); returns undefined in the CJS build, where the ESM hook does not apply. */\nfunction moduleUrl(): string | undefined {\n try {\n // In the ESM build this is the register.js module URL; in the CJS build import.meta is absent.\n return import.meta.url;\n } catch {\n return undefined;\n }\n}\n\n/** Register the import-in-the-middle ESM loader hook (best-effort). Idempotent enough for our use —\n * called once at bootstrap. */\nexport function enableEsmInstrumentation(): void {\n if (esmHookDisabled()) return;\n const parentURL = moduleUrl();\n if (!parentURL) return; // CJS build / no ESM context — require-hook still covers CJS apps.\n const register = (nodeModule as { register?: (s: string, p: string) => unknown }).register;\n if (typeof register !== 'function') return; // Node < 18.19 / < 20.6\n try {\n register(HOOK_SPECIFIER, parentURL);\n _loaderRegistered = true;\n diag.debug('[scope] ESM auto-instrumentation enabled (import-in-the-middle loader registered).');\n } catch (err) {\n diag.debug(\n `[scope] ESM auto-instrumentation not enabled (${err instanceof Error ? err.message : String(err)}); ` +\n 'CJS apps are still captured via the require-hook.',\n );\n }\n}\n\n/** A provider instrumentation that can be applied to an already-loaded module namespace. */\nexport interface ManualInstrumentable {\n manuallyInstrument(moduleExports: unknown): unknown;\n}\n\n/**\n * Force the require-hook instrumentations to also apply under ESM. OpenTelemetry's own IITM hook does\n * NOT auto-invoke these instrumentations' patch under ESM (their entry modules are re-export shims — the\n * auto-hook doesn't fire), yet their patch logic works fine on the ESM namespace (verified). So when the\n * ESM loader is active (the `--import` bootstrap), we register our OWN import-in-the-middle hook that\n * calls each instrumentation's `manuallyInstrument(moduleExports)` as the module is imported.\n *\n * Only the openai/anthropic/google-genai instrumentations need this. The Vercel AI SDK is excluded — its\n * OTel auto-patch DOES fire under ESM (its `ai` entry points are top-level functions IITM intercepts).\n *\n * No-ops unless we registered the loader (CJS build / explicit init() path → ESM capture isn't in play;\n * those are covered by the require-hook). NEVER throws (rule b: a telemetry failure can't break startup).\n */\nexport function registerEsmManualInstrument(\n entries: Array<{ modules: string[]; instrumentation: ManualInstrumentable }>,\n): void {\n if (!_loaderRegistered) return;\n // Map every module specifier → its instrumentation, then one hook routes by the imported name.\n const byModule = new Map<string, ManualInstrumentable>();\n for (const { modules, instrumentation } of entries) {\n for (const m of modules) byModule.set(m, instrumentation);\n }\n if (byModule.size === 0) return;\n try {\n // eslint-disable-next-line no-new -- the Hook self-registers with the active IITM loader.\n new Hook([...byModule.keys()], (exported: unknown, name: string) => {\n const instrumentation = byModule.get(name);\n if (!instrumentation) return exported;\n try {\n instrumentation.manuallyInstrument(exported);\n } catch (err) {\n diag.debug(\n `[scope] ESM manual instrument of '${name}' failed (${err instanceof Error ? err.message : String(err)}).`,\n );\n }\n return exported;\n });\n diag.debug(`[scope] ESM manual instrumentation registered for: ${[...byModule.keys()].join(', ')}.`);\n } catch (err) {\n diag.debug(\n `[scope] ESM manual instrumentation not registered (${err instanceof Error ? err.message : String(err)}).`,\n );\n }\n}\n","import { registerInstrumentations } from '@opentelemetry/instrumentation';\nimport { NodeTracerProvider } from '@opentelemetry/sdk-trace-node';\nimport { OpenAIInstrumentation } from '@arizeai/openinference-instrumentation-openai';\nimport { AnthropicInstrumentation } from '@arizeai/openinference-instrumentation-anthropic';\nimport { OpenInferenceBatchSpanProcessor } from '@arizeai/openinference-vercel';\nimport { GoogleGenAIInstrumentation } from './google-genai-instrumentation';\nimport { VercelAIInstrumentation } from './vercel-ai-instrumentation';\nimport { registerEsmManualInstrument } from './esm-hook';\nimport { resolveConfig, type ScopeConfig, type ScopeOptions } from './config';\nimport { resolveDeployment, type Deployment } from './deployment';\nimport { ScopeSpanExporter } from './exporter';\nimport { ScopeContextSpanProcessor } from './processor';\nimport { shipEvents } from './transport';\nimport { SDK_SOURCE } from './version';\n\n// Process start time, captured once at module load — used for a stable deployment_id.\nconst STARTED_AT = new Date();\n\nexport interface ScopeHandle {\n config: ScopeConfig;\n deployment: Deployment;\n /** Flush + stop the tracer (best-effort). Safe to call multiple times. */\n shutdown: () => Promise<void>;\n}\n\nlet active: ScopeHandle | null = null;\n\n/**\n * Start the Scope tracer: wire an OpenTelemetry NodeTracerProvider whose LLM spans — from the\n * OpenInference OpenAI/Anthropic instrumentations, our hand-built Google Gen AI instrumentation,\n * and (translated) the Vercel AI SDK — are mapped to Scope events and shipped to the Scope backend.\n * Idempotent — a second call returns the existing handle.\n *\n * Zero-code path: `NODE_OPTIONS=\"--import @scope-analytics/node/register\" node server.js`.\n * Explicit path: `import { init } from '@scope-analytics/node'; init();` (before importing your LLM SDK).\n *\n * NOTE (Vercel AI SDK): the `ai` package emits NOTHING unless its telemetry is enabled per call. The\n * VercelAIInstrumentation registered below makes capture zero-code by injecting\n * `experimental_telemetry: { isEnabled: true }` into generateText/streamText/generateObject/streamObject\n * (deep-merged with any telemetry config you already pass; an explicit `isEnabled: false` is respected).\n *\n * NOTE (ESM): auto-instrumentation of ESM `import`s requires the import-in-the-middle loader, which the\n * `--import @scope-analytics/node/register` bootstrap registers (see src/esm-hook.ts). On that path, all four\n * providers are captured under both CommonJS and ESM. The explicit init() path covers CommonJS via the\n * require-hook (an ESM loader can't retroactively hook already-imported modules).\n */\nexport function init(options: ScopeOptions = {}): ScopeHandle {\n if (active) {\n if (active.config.debug) console.warn('[scope] init() called again; reusing the running tracer.');\n return active;\n }\n\n const config = resolveConfig(options);\n const deployment = resolveDeployment(STARTED_AT);\n\n const provider = new NodeTracerProvider({\n spanProcessors: [\n // Stamp session/user from AsyncLocalStorage onto each span before it's read at export.\n new ScopeContextSpanProcessor(),\n // Batch spans, then translate + ship them to Scope. We route through the OpenInference Vercel\n // span processor (rather than a plain BatchSpanProcessor) so the Vercel AI SDK's own\n // `ai.*`/`gen_ai.*` spans are translated to OpenInference `llm.*` attributes before our exporter\n // reads them — the only way to capture the Vercel AI SDK, which emits its own spans instead of\n // calling a provider SDK we instrument. On spans that are ALREADY OpenInference\n // (OpenAI/Anthropic/Gemini) the translation is additive-only (it just re-affirms their span\n // kind), so those keep flowing through unchanged. NB: the adapter tags EVERY span the process\n // ends (a non-LLM span just gets an OpenInference span-kind attribute), but ScopeSpanExporter\n // stays the single gate for which spans become events (LLM only) — so no spanFilter is needed,\n // and any non-LLM span (Vercel's AGENT/TOOL spans, or a host's own HTTP/DB spans) is dropped\n // there. Vercel emits a parent (AGENT) + child (LLM) span per call; the AGENT span is dropped,\n // leaving exactly one llm_call per call.\n new OpenInferenceBatchSpanProcessor({ exporter: new ScopeSpanExporter(config, deployment) }),\n ],\n });\n provider.register();\n\n const openaiInstrumentation = new OpenAIInstrumentation();\n const anthropicInstrumentation = new AnthropicInstrumentation();\n // Scope-authored OTel instrumentation: no Arize drop-in exists for @google/genai. Emits the same\n // OpenInference llm.* attributes, so it flows through the identical pipeline.\n const googleGenAIInstrumentation = new GoogleGenAIInstrumentation();\n // Scope-authored instrumentation for the Vercel AI SDK. Unlike the others it emits no spans — it only\n // injects `experimental_telemetry: { isEnabled: true }` into the `ai` entry points so the SDK's own\n // spans are emitted; the OpenInferenceBatchSpanProcessor above then captures them.\n const vercelAIInstrumentation = new VercelAIInstrumentation();\n registerInstrumentations({\n tracerProvider: provider,\n instrumentations: [\n openaiInstrumentation,\n anthropicInstrumentation,\n googleGenAIInstrumentation,\n vercelAIInstrumentation,\n ],\n });\n\n // ESM coverage (only on the `--import` bootstrap, which registered the IITM loader): OpenTelemetry's\n // own IITM hook does NOT auto-invoke the openai/anthropic/google-genai instrumentations under ESM\n // (their entry modules are re-export shims, so the hook doesn't fire), even though their patch works\n // on the ESM namespace. So apply them explicitly as those modules are imported. Vercel is excluded —\n // its auto-patch DOES fire under ESM. No-op off the bootstrap (CJS is covered by the require-hook).\n registerEsmManualInstrument([\n { modules: ['openai'], instrumentation: openaiInstrumentation },\n { modules: ['@anthropic-ai/sdk'], instrumentation: anthropicInstrumentation },\n { modules: ['@google/genai'], instrumentation: googleGenAIInstrumentation },\n ]);\n\n active = {\n config,\n deployment,\n shutdown: async () => {\n try {\n await provider.shutdown();\n } finally {\n active = null;\n }\n },\n };\n\n // Announce this deploy once per process (PRODUCT.md §4.2). The backend dedups by\n // (tenant, git_sha), so emit-once-per-process is safe across workers/cold starts.\n if (deployment.gitSha) void emitDeploymentDetected(config, deployment);\n\n if (config.debug) {\n console.log(\n `[scope] tracer started (endpoint=${config.endpoint}, env=${config.environment}` +\n (deployment.gitSha ? `, git_sha=${deployment.gitSha.slice(0, 7)}` : '') +\n ').',\n );\n }\n return active;\n}\n\nasync function emitDeploymentDetected(config: ScopeConfig, deployment: Deployment): Promise<void> {\n const nowIso = new Date().toISOString();\n await shipEvents(\n [\n {\n event_type: 'deployment_detected',\n source: SDK_SOURCE,\n timestamp: nowIso,\n server_timestamp: nowIso,\n session_id: `deploy_${deployment.deploymentId}`,\n git_sha: deployment.gitSha,\n deployment_id: deployment.deploymentId,\n is_user_facing: false,\n success: true,\n environment: config.environment,\n sdk_version: config.sdkVersion,\n },\n ],\n config,\n );\n}\n\nexport { resolveConfig, ScopeConfigError } from './config';\nexport type { ScopeConfig, ScopeOptions } from './config';\nexport { runWithContext, getContext, setUser } from './session';\nexport type { ScopeContextData } from './session';\nexport { spanToScopeEvent, isLlmSpan, CREDENTIAL_REDACT_PATTERNS } from './event';\nexport type { ScopeEvent, SpanLike } from './event';\nexport { GoogleGenAIInstrumentation, isGoogleGenAIPatched } from './google-genai-instrumentation';\nexport { VercelAIInstrumentation, isVercelAIPatched } from './vercel-ai-instrumentation';\nexport { ScopeSpanExporter } from './exporter';\nexport { detectGitSha, resolveDeployment } from './deployment';\nexport type { Deployment } from './deployment';\n","import {\n context,\n diag,\n SpanKind,\n SpanStatusCode,\n trace,\n type Attributes,\n type Span,\n} from '@opentelemetry/api';\nimport { isTracingSuppressed } from '@opentelemetry/core';\nimport {\n InstrumentationBase,\n InstrumentationNodeModuleDefinition,\n isWrapped,\n type InstrumentationConfig,\n} from '@opentelemetry/instrumentation';\nimport {\n LLMProvider,\n MimeType,\n OpenInferenceSpanKind,\n SemanticConventions as SC,\n} from '@arizeai/openinference-semantic-conventions';\nimport { SDK_VERSION } from './version';\n\n// Scope-authored OpenTelemetry instrumentation for the unified Google Gen AI SDK (@google/genai).\n//\n// WHY HAND-BUILT: there is no Arize OpenInference instrumentation for @google/genai on npm (unlike\n// openai/anthropic, which we get as drop-ins). So we author a minimal OTel instrumentation that emits\n// the SAME OpenInference `llm.*` span attributes our event.ts mapper already reads — the span then\n// flows through the exact same pipeline (ScopeContextSpanProcessor → ScopeSpanExporter →\n// spanToScopeEvent) as every other provider. This is the reusable pattern for any provider without a\n// drop-in (Mistral next).\n//\n// PATCH POINT (load-bearing, see the @google/genai probe): the PUBLIC `models.generateContent` /\n// `generateContentStream` are INSTANCE arrow-function properties (own props on each Models instance) —\n// NOT prototype methods — so they cannot be wrapped on the prototype. The public methods delegate to\n// `Models.prototype.generateContentInternal` / `generateContentStreamInternal`, which ARE real\n// prototype methods. Wrapping those covers every client/instance with one wrap. (Internal-method names\n// are version-sensitive → @google/genai is pinned and the version-pin drift guard forces re-verification\n// on every bump.)\n//\n// EXTRACTION PARITY: extraction mirrors backend-sdk/.../patches/google_genai_patch.py (provider\n// \"google\", model stripped of \"models/\", `.text` read under a guard with a candidates[] fallback,\n// `contents` normalized to {role,content}, usage → prompt/completion/total) so the Python and Node SDKs\n// emit a wire-identical EVENT SHAPE (CLAUDE.md §1.6). Like the Python SDK, `config.systemInstruction`\n// is intentionally NOT captured (a shared, tracked gap — keeping the two SDKs identical beats adding it\n// to one). Two known behavioral divergences from the Python patcher, both because we wrap the INTERNAL\n// method (Python wraps the public one):\n// - Automatic Function Calling (a CallableTool in config.tools): the public method loops, calling the\n// internal method once per remote round → Node emits one llm_call PER ROUND (each a real model\n// round-trip with its own tokens), whereas the Python patcher emits a single event for the final\n// result. Tracked for cross-SDK alignment; the common (no-AFC) path is 1:1.\n// - chats.sendMessage routes through the same internal method, so it IS captured on Node (with the\n// conversation history as `contents`); the Python patcher defers the Chat surface. A Node bonus,\n// noted here for honesty about the prompt shape on that path.\n\nconst MODULE_NAME = '@google/genai';\nconst INSTRUMENTATION_NAME = '@scope-analytics/node/instrumentation-google-genai';\n\nlet _isPatched = false;\n/** True once @google/genai's Models prototype has been patched (mirrors the Arize isPatched()). */\nexport function isGoogleGenAIPatched(): boolean {\n return _isPatched;\n}\n\n// --- minimal structural types we read at runtime. @google/genai is a peer/devDependency, NEVER a\n// runtime dependency of @scope-analytics/node (the host app brings its own), so we read its shapes\n// structurally rather than importing its types. ---\ntype GenerateFn = (this: unknown, ...args: unknown[]) => unknown;\ninterface GenAIPart {\n text?: unknown;\n}\ninterface GenAIContent {\n role?: unknown;\n parts?: GenAIPart[];\n}\ninterface GenAICandidate {\n content?: GenAIContent;\n}\ninterface GenAIUsage {\n promptTokenCount?: unknown;\n candidatesTokenCount?: unknown;\n totalTokenCount?: unknown;\n}\ninterface GenAIResponse {\n // `text` is a convenience GETTER: on the pinned 2.8.0 it console.warns + returns the concatenation\n // of text parts (or undefined) on multi-part/function-call responses; on other versions in the\n // supported range it can THROW. We read it under a guard and fall back to candidates[] either way.\n readonly text?: unknown;\n candidates?: GenAICandidate[];\n usageMetadata?: GenAIUsage;\n}\ninterface GenerateParams {\n model?: unknown;\n contents?: unknown;\n}\ninterface ModelsProto {\n generateContentInternal?: GenerateFn;\n generateContentStreamInternal?: GenerateFn;\n}\ninterface WrappableProto {\n generateContentInternal: GenerateFn;\n generateContentStreamInternal: GenerateFn;\n}\ninterface GenAIModuleExports {\n Models?: { prototype?: ModelsProto };\n default?: GenAIModuleExports;\n scopePatched?: boolean;\n}\ninterface NormalizedMessage {\n role?: string;\n content?: string;\n}\n\n// --- pure helpers (mirror the Python patcher) --------------------------------\nfunction asFiniteNumber(v: unknown): number | undefined {\n if (typeof v === 'number' && Number.isFinite(v)) return v;\n if (typeof v === 'string' && v.trim() !== '' && Number.isFinite(Number(v))) return Number(v);\n return undefined;\n}\n\nfunction safeJsonStringify(v: unknown): string {\n try {\n return JSON.stringify(v) ?? String(v);\n } catch {\n return '[unserializable]';\n }\n}\n\nfunction errMessage(err: unknown): string {\n const m = (err as { message?: unknown } | null)?.message;\n return m != null ? String(m) : 'error';\n}\n\nfunction isPromiseLike(v: unknown): v is Promise<unknown> {\n return v != null && typeof (v as { then?: unknown }).then === 'function';\n}\n\n/** Model name from request params, stripping the \"models/\" prefix (Python `_model_name`). */\nfunction modelName(params: GenerateParams): string {\n const m = typeof params.model === 'string' ? params.model : 'gemini';\n return m.startsWith('models/') ? m.slice('models/'.length) : m;\n}\n\n/**\n * Normalize @google/genai `contents` (string | Content[] | Part[] | {role,content}[]) into the\n * universal {role,content} messages — the same normalization as the Python SDK's\n * GoogleGenaiPatcher._messages, so both SDKs emit a wire-identical event.\n */\nfunction normalizeContents(contents: unknown): NormalizedMessage[] {\n if (typeof contents === 'string') return [{ role: 'user', content: contents }];\n if (Array.isArray(contents)) {\n const msgs: NormalizedMessage[] = [];\n for (const item of contents) {\n if (typeof item === 'string') {\n msgs.push({ role: 'user', content: item });\n } else if (item && typeof item === 'object') {\n const obj = item as Record<string, unknown>;\n if ('content' in obj) {\n // already a {role, content} message — pass through (stringify non-string content for OTel)\n msgs.push({\n role: typeof obj.role === 'string' ? obj.role : 'user',\n content: typeof obj.content === 'string' ? obj.content : safeJsonStringify(obj.content),\n });\n } else if ('parts' in obj) {\n // the idiomatic unified-SDK turn: {role, parts:[{text}]} — flatten the parts' text\n const parts = Array.isArray(obj.parts) ? (obj.parts as GenAIPart[]) : [];\n const content = parts\n .filter((p) => p && typeof p.text === 'string')\n .map((p) => p.text as string)\n .join('');\n msgs.push({ role: typeof obj.role === 'string' ? obj.role : 'user', content });\n } else if (typeof obj.text === 'string') {\n // a bare Part with .text\n msgs.push({ role: 'user', content: obj.text });\n }\n }\n }\n return msgs.length ? msgs : [{ role: 'user', content: safeJsonStringify(contents) }];\n }\n if (contents == null) return [];\n return [{ role: 'user', content: safeJsonStringify(contents) }];\n}\n\n/** Response text, reading the `.text` getter under a broad guard (it can throw or warn), then falling\n * back to candidates[].content.parts[].text — exactly the Python `_response_text`. */\nfunction responseText(resp: GenAIResponse | undefined): string {\n let text: unknown;\n try {\n text = resp?.text;\n } catch {\n text = undefined;\n }\n if (typeof text === 'string' && text) return text;\n let out = '';\n // Array.isArray (not just `?? []`) so a truthy non-array candidates/parts can't throw \"not iterable\"\n // — keeps the helper safe in isolation (the template the next hand-built instrumentation copies).\n const candidates = Array.isArray(resp?.candidates) ? (resp?.candidates as GenAICandidate[]) : [];\n for (const cand of candidates) {\n const parts = Array.isArray(cand?.content?.parts) ? (cand?.content?.parts as GenAIPart[]) : [];\n for (const part of parts) {\n if (typeof part?.text === 'string') out += part.text;\n }\n }\n return out;\n}\n\nfunction inputAttributes(params: GenerateParams): Attributes {\n const attrs: Attributes = {\n [SC.OPENINFERENCE_SPAN_KIND]: OpenInferenceSpanKind.LLM,\n [SC.LLM_PROVIDER]: LLMProvider.GOOGLE,\n [SC.LLM_MODEL_NAME]: modelName(params),\n [SC.INPUT_VALUE]: safeJsonStringify(params),\n [SC.INPUT_MIME_TYPE]: MimeType.JSON,\n };\n normalizeContents(params.contents).forEach((msg, i) => {\n const prefix = `${SC.LLM_INPUT_MESSAGES}.${i}.`;\n if (msg.role !== undefined) attrs[`${prefix}${SC.MESSAGE_ROLE}`] = msg.role;\n if (msg.content !== undefined) attrs[`${prefix}${SC.MESSAGE_CONTENT}`] = msg.content;\n });\n return attrs;\n}\n\nfunction setOutputAttributes(span: Span, text: string, usage: GenAIUsage | undefined): void {\n const attrs: Attributes = {\n [SC.OUTPUT_VALUE]: text,\n [SC.OUTPUT_MIME_TYPE]: MimeType.TEXT,\n [`${SC.LLM_OUTPUT_MESSAGES}.0.${SC.MESSAGE_ROLE}`]: 'model',\n [`${SC.LLM_OUTPUT_MESSAGES}.0.${SC.MESSAGE_CONTENT}`]: text,\n };\n if (usage) {\n // Match the Python SDK: when usage is present, always emit all three counts (0-filled), so the\n // event's `tokens` object is {prompt_tokens, completion_tokens, total_tokens} for both SDKs.\n attrs[SC.LLM_TOKEN_COUNT_PROMPT] = asFiniteNumber(usage.promptTokenCount) ?? 0;\n attrs[SC.LLM_TOKEN_COUNT_COMPLETION] = asFiniteNumber(usage.candidatesTokenCount) ?? 0;\n attrs[SC.LLM_TOKEN_COUNT_TOTAL] = asFiniteNumber(usage.totalTokenCount) ?? 0;\n }\n span.setAttributes(attrs);\n}\n\n// endOk / endWithError must NEVER throw: they run in the user's promise continuations, so a capture-side\n// error here would otherwise reject a successful call (or mask the real error). The whole body is\n// guarded, and the span is always ended (rule b: a telemetry failure must never break the host app).\nfunction endOk(span: Span, resp: GenAIResponse | undefined): void {\n try {\n setOutputAttributes(span, responseText(resp), resp?.usageMetadata);\n span.setStatus({ code: SpanStatusCode.OK });\n } catch {\n /* capture-side error swallowed — must not surface to the caller */\n }\n try {\n span.end();\n } catch {\n /* ignore */\n }\n}\n\nfunction endWithError(span: Span, err: unknown): void {\n try {\n span.recordException(err as Error);\n span.setStatus({ code: SpanStatusCode.ERROR, message: errMessage(err) });\n } catch {\n /* ignore */\n }\n try {\n span.end();\n } catch {\n /* ignore */\n }\n}\n\nexport class GoogleGenAIInstrumentation extends InstrumentationBase {\n constructor(config: InstrumentationConfig = {}) {\n super(INSTRUMENTATION_NAME, SDK_VERSION, config);\n }\n\n protected init(): InstrumentationNodeModuleDefinition {\n return new InstrumentationNodeModuleDefinition(\n MODULE_NAME,\n ['*'],\n (moduleExports: GenAIModuleExports) => this.patch(moduleExports),\n (moduleExports: GenAIModuleExports) => this.unpatch(moduleExports),\n );\n }\n\n /** ESM escape hatch — the require-hook doesn't fire for `import` (mirrors the Arize instrumentations). */\n manuallyInstrument(moduleExports: GenAIModuleExports): void {\n diag.debug(`Manually instrumenting ${MODULE_NAME}`);\n this.patch(moduleExports);\n }\n\n private patch(moduleExports: GenAIModuleExports): GenAIModuleExports {\n if (!moduleExports || moduleExports.scopePatched || _isPatched) return moduleExports;\n const m = moduleExports.default || moduleExports;\n const proto = m?.Models?.prototype;\n if (!proto || typeof proto.generateContentInternal !== 'function') {\n diag.warn(`[scope] cannot find Models.prototype.generateContentInternal in ${MODULE_NAME}`);\n return moduleExports;\n }\n const wrappable = proto as unknown as WrappableProto;\n this._wrap(wrappable, 'generateContentInternal', this._wrapGenerate(false));\n if (typeof proto.generateContentStreamInternal === 'function') {\n this._wrap(wrappable, 'generateContentStreamInternal', this._wrapGenerate(true));\n }\n _isPatched = true;\n try {\n moduleExports.scopePatched = true;\n } catch {\n /* module frozen (bundler/Deno) — the _isPatched flag still guards double-patching */\n }\n return moduleExports;\n }\n\n private unpatch(moduleExports: GenAIModuleExports): void {\n const m = moduleExports?.default || moduleExports;\n const proto = m?.Models?.prototype;\n if (proto) {\n // Only unwrap what we actually wrapped — `_unwrap` on a never-wrapped method logs a spurious error.\n if (isWrapped(proto.generateContentInternal)) {\n this._unwrap(proto as unknown as WrappableProto, 'generateContentInternal');\n }\n if (isWrapped(proto.generateContentStreamInternal)) {\n this._unwrap(proto as unknown as WrappableProto, 'generateContentStreamInternal');\n }\n }\n _isPatched = false;\n try {\n if (moduleExports) moduleExports.scopePatched = false;\n } catch {\n /* ignore */\n }\n }\n\n private _wrapGenerate(streaming: boolean): (original: GenerateFn) => GenerateFn {\n const instrumentation = this;\n return (original: GenerateFn): GenerateFn =>\n function patched(this: unknown, ...args: unknown[]): unknown {\n // Respect OTel tracing suppression (e.g. a re-entrant internal call).\n if (isTracingSuppressed(context.active())) {\n return original.apply(this, args);\n }\n // Build the span + input attributes DEFENSIVELY: if anything here throws, fall back to the\n // untouched call so capture never breaks the user's request (rule b).\n let span: Span | undefined;\n try {\n const params = (args[0] ?? {}) as GenerateParams;\n span = instrumentation.tracer.startSpan('GoogleGenAI.generateContent', {\n kind: SpanKind.INTERNAL,\n attributes: inputAttributes(params),\n });\n } catch {\n span = undefined;\n }\n if (!span) return original.apply(this, args);\n const activeSpan = span;\n\n const activeContext = trace.setSpan(context.active(), activeSpan);\n let result: unknown;\n try {\n result = context.with(activeContext, () => original.apply(this, args));\n } catch (err) {\n // a synchronous throw from the SDK call itself — record + rethrow to the caller\n endWithError(activeSpan, err);\n throw err;\n }\n\n if (!isPromiseLike(result)) {\n // Defensive: these methods always return a promise, but never break the caller otherwise.\n endOk(activeSpan, undefined);\n return result;\n }\n\n if (streaming) {\n return (result as Promise<AsyncIterable<GenAIResponse>>).then(\n (gen) => instrumentation._wrapStream(gen, activeSpan),\n (err) => {\n endWithError(activeSpan, err);\n throw err;\n },\n );\n }\n return (result as Promise<GenAIResponse>).then(\n (resp) => {\n endOk(activeSpan, resp); // never throws — a successful call stays successful\n return resp;\n },\n (err) => {\n endWithError(activeSpan, err);\n throw err;\n },\n );\n };\n }\n\n /**\n * Wrap the streaming async-generator: yield every chunk through to the caller while accumulating the\n * full text + final usage, then end the span. Capture is fully isolated from the caller's stream:\n * - per-chunk extraction is swallowed, so a malformed chunk never aborts the user's iteration;\n * - the catch handles ONLY a real error thrown by the underlying stream (records it, rethrows);\n * - the finally ends the span exactly once, even on early abandonment (the generator's .return()\n * runs `finally`) — capturing whatever text/usage arrived so far.\n * Mirrors the Python _wrap_stream_iter + _capture_streaming_response (chunks carry text; the final\n * chunk carries usage).\n */\n private async *_wrapStream(\n gen: AsyncIterable<GenAIResponse>,\n span: Span,\n ): AsyncGenerator<GenAIResponse> {\n const texts: string[] = [];\n let usage: GenAIUsage | undefined;\n let errored = false;\n try {\n for await (const chunk of gen) {\n try {\n texts.push(responseText(chunk));\n if (chunk?.usageMetadata) usage = chunk.usageMetadata; // last non-null wins (final chunk)\n } catch {\n /* a capture/extraction error must never abort the caller's stream */\n }\n yield chunk;\n }\n } catch (err) {\n errored = true;\n try {\n span.recordException(err as Error);\n span.setStatus({ code: SpanStatusCode.ERROR, message: errMessage(err) });\n } catch {\n /* ignore */\n }\n throw err; // a real error from the underlying stream — surface it to the caller\n } finally {\n if (!errored) {\n try {\n setOutputAttributes(span, texts.join(''), usage);\n span.setStatus({ code: SpanStatusCode.OK });\n } catch {\n /* ignore */\n }\n }\n try {\n span.end();\n } catch {\n /* ignore */\n }\n }\n }\n}\n","// SDK identity constants. `SDK_SOURCE` MUST be \"backend_sdk\" — the Scope backend keys off\n// it (belt-and-suspenders with the secret-key type) to skip browser-origin/domain validation\n// and mark events active (see backend main.py is_backend_sdk).\nexport const SDK_VERSION = '0.1.0';\nexport const SDK_SOURCE = 'backend_sdk';\nexport const SDK_USER_AGENT = `scope-tracer-node/${SDK_VERSION}`;\n","import { diag } from '@opentelemetry/api';\nimport {\n InstrumentationBase,\n InstrumentationNodeModuleDefinition,\n isWrapped,\n type InstrumentationConfig,\n} from '@opentelemetry/instrumentation';\nimport { SDK_VERSION } from './version';\n\n// Scope-authored OpenTelemetry instrumentation for the Vercel AI SDK (`ai`) — the \"make Vercel\n// zero-code\" piece. Unlike the openai/anthropic Arize drop-ins and our hand-built Google Gen AI\n// instrumentation, this one DOES NOT emit spans. The `ai` package emits its OWN OTel spans, captured\n// downstream by `@arizeai/openinference-vercel`'s OpenInferenceBatchSpanProcessor (wired in index.ts).\n// The single problem this instrumentation solves: the AI SDK emits NOTHING unless telemetry is enabled\n// PER CALL (`experimental_telemetry: { isEnabled: true }`) — verified against ai@6.0.197: getTracer()\n// returns a noopTracer unless isEnabled, and there is NO global on-switch. So to make capture truly\n// zero-code, we wrap the `ai` package's public entry points and INJECT `isEnabled: true` into the call\n// options (deep-merged with any telemetry config the user already passed). Once enabled — and as long\n// as the user does not pass their OWN tracer — the AI SDK calls the GLOBAL tracer `trace.getTracer(\"ai\")`,\n// which is the provider init() registers, so the spans flow into our pipeline with no further setup.\n//\n// TWO PATCH STRATEGIES (decided per call, because the `ai` exports differ by module system — both\n// verified empirically against ai@6.0.197):\n// - CJS (`require('ai')`): the exports are esbuild's NON-CONFIGURABLE GETTER-ONLY properties, so they\n// cannot be wrapped in place (shimmer's `_wrap`/`Object.defineProperty` both fail). Instead we\n// RETURN a Proxy that injects telemetry on the target functions and passes everything else through;\n// require-in-the-middle hands consumers our returned object.\n// - ESM (`import { generateText } from 'ai'`, via the import-in-the-middle loader registered by\n// src/esm-hook.ts on the `--import` bootstrap): named imports bind to the live export, so a\n// returned Proxy is NOT seen — but IITM makes the exports settable, so we `_wrap` them IN PLACE and\n// return the same (mutated) namespace.\n// NB: this is the ONE provider whose ESM capture currently works (its entry points are top-level\n// functions in the module IITM intercepts). openai/anthropic/gemini patch a class prototype reached\n// through an ESM re-export that IITM does not connect, so they remain CJS-only under ESM (tracked\n// follow-up). The require-hook (CJS) path covers all four.\n//\n// LOAD-ORDER INVARIANT (load-bearing — do NOT `import` from 'ai' here, or anywhere index.ts pulls in):\n// the ESM loader (src/esm-hook.ts, registered by register.ts) only instruments `ai` if `ai` is loaded\n// AFTER the loader is registered. `import`s are hoisted, and a bundler lifts external imports to the\n// top of the bootstrap, so any `import … from 'ai'` in @scope-analytics/node's own graph would materialize the\n// `ai` module before the loader exists → the app's later `import { generateText } from 'ai'` resolves\n// to the un-instrumented cached module → ESM capture silently dies. We therefore read `ai`'s shapes\n// STRUCTURALLY at patch time (the module object the hook hands us) and never import it — same as the\n// Gemini instrumentation. instrumentation.vercel-ai-bootstrap.test.ts is the regression guard: it\n// would fail (0 events) if `ai` ever loaded early.\n\nconst MODULE_NAME = 'ai';\nconst INSTRUMENTATION_NAME = '@scope-analytics/node/instrumentation-vercel-ai';\n\n// The Vercel AI SDK top-level entry points whose telemetry we auto-enable. Each emits a child\n// `ai.<fn>.doGenerate`/`.doStream` span (OpenInference LLM kind) that our pipeline maps to exactly\n// one llm_call (the parent AGENT span is dropped by the LLM-only export gate). `embed`/`embedMany`\n// are intentionally excluded — they map to EMBEDDING spans Scope does not ship as llm_call events.\nconst TARGET_FUNCTIONS = ['generateText', 'streamText', 'generateObject', 'streamObject'] as const;\n\nlet _isPatched = false;\n/** True once the `ai` package's entry points have been wrapped (CJS or ESM). Mirrors isGoogleGenAIPatched(). */\nexport function isVercelAIPatched(): boolean {\n return _isPatched;\n}\n\ntype AnyFn = (this: unknown, ...args: unknown[]) => unknown;\ninterface TelemetrySettings {\n isEnabled?: unknown;\n [k: string]: unknown;\n}\n\n/**\n * Return a NEW args array with `experimental_telemetry.isEnabled` forced `true` on the call options\n * (args[0]), DEEP-MERGED so every other telemetry field the user set is preserved\n * (tracer/functionId/metadata/recordInputs/recordOutputs/integrations). Pure and NEVER throws — on any\n * unexpected argument shape it returns the original args untouched (rule b: capture must never break the\n * call). An explicit `isEnabled: false` is RESPECTED — a deliberate per-call opt-out, so that call is\n * not captured (and, by the AI SDK's own gate, emits no spans). Exported for unit testing.\n */\nexport function injectTelemetryArgs(args: unknown[]): unknown[] {\n try {\n const opts = args[0];\n if (!opts || typeof opts !== 'object' || Array.isArray(opts)) return args;\n const o = opts as Record<string, unknown>;\n const existing = o.experimental_telemetry as TelemetrySettings | undefined;\n const hasExisting = !!existing && typeof existing === 'object' && !Array.isArray(existing);\n // Respect an explicit opt-out: never override a user's deliberate `isEnabled: false`.\n if (hasExisting && existing!.isEnabled === false) return args;\n // No-op fast path: telemetry already explicitly enabled — nothing to inject (avoids a clone).\n if (hasExisting && existing!.isEnabled === true) return args;\n const mergedTelemetry: TelemetrySettings = {\n ...(hasExisting ? existing! : {}),\n isEnabled: true,\n };\n return [{ ...o, experimental_telemetry: mergedTelemetry }, ...args.slice(1)];\n } catch {\n return args;\n }\n}\n\n/** A telemetry-injecting wrapper around an `ai` entry point — transparent passthrough of `this` and\n * the return value; only args[0].experimental_telemetry is (deep-)merged. */\nfunction makeTelemetryWrapper(original: AnyFn): AnyFn {\n return function scopeVercelTelemetryWrapper(this: unknown, ...args: unknown[]): unknown {\n return original.apply(this, injectTelemetryArgs(args));\n };\n}\n\n/**\n * Can `obj[name]` be replaced in place? True for an accessor with a setter (the IITM ESM namespace), a\n * writable data property, or a configurable property (redefinable). False for esbuild's CJS output —\n * non-configurable getter-only — which must instead be handled by returning a Proxy.\n */\nfunction settableInPlace(obj: object, name: string): boolean {\n const d = Object.getOwnPropertyDescriptor(obj, name);\n if (!d) return false;\n if (typeof d.set === 'function') return true;\n if (d.writable === true) return true;\n if (d.configurable === true) return true;\n return false;\n}\n\nexport class VercelAIInstrumentation extends InstrumentationBase {\n // Same original-exports → Proxy, so repeated patch() calls (re-entrancy) return one stable Proxy.\n private readonly _proxyCache = new WeakMap<object, object>();\n\n constructor(config: InstrumentationConfig = {}) {\n super(INSTRUMENTATION_NAME, SDK_VERSION, config);\n }\n\n protected init(): InstrumentationNodeModuleDefinition {\n return new InstrumentationNodeModuleDefinition(\n MODULE_NAME,\n ['*'],\n (moduleExports: Record<string, unknown>) => this.patch(moduleExports),\n (moduleExports: Record<string, unknown>) => this.unpatch(moduleExports),\n );\n }\n\n /** ESM escape hatch — the require-hook doesn't fire for `import` (mirrors the Arize instrumentations). */\n manuallyInstrument(moduleExports: Record<string, unknown>): Record<string, unknown> {\n diag.debug(`Manually instrumenting ${MODULE_NAME}`);\n return this.patch(moduleExports);\n }\n\n private patch(moduleExports: Record<string, unknown>): Record<string, unknown> {\n if (!moduleExports) return moduleExports;\n const present = TARGET_FUNCTIONS.filter((n) => typeof moduleExports[n] === 'function');\n if (present.length === 0) {\n diag.warn(`[scope] no target functions found in '${MODULE_NAME}'; AI SDK telemetry not auto-enabled`);\n return moduleExports;\n }\n\n // ESM (IITM namespace) or a plain CJS object: wrap each export in place; the require/import hook\n // hands consumers the same (mutated) module object.\n if (present.every((n) => settableInPlace(moduleExports, n))) {\n for (const n of present) {\n if (!isWrapped(moduleExports[n])) {\n this._wrap(moduleExports, n, (original: unknown) => makeTelemetryWrapper(original as AnyFn));\n }\n }\n _isPatched = true;\n return moduleExports;\n }\n\n // CJS esbuild output: non-configurable getter-only exports — return a Proxy.\n const cached = this._proxyCache.get(moduleExports);\n if (cached) {\n _isPatched = true;\n return cached as Record<string, unknown>;\n }\n const targets = new Set<string>(present);\n const fnCache = new Map<string, AnyFn>();\n const proxy = new Proxy(moduleExports, {\n get(target, prop, receiver) {\n const value = Reflect.get(target, prop, receiver);\n if (typeof prop === 'string' && targets.has(prop) && typeof value === 'function') {\n let wrapped = fnCache.get(prop);\n if (!wrapped) {\n wrapped = makeTelemetryWrapper(value as AnyFn);\n fnCache.set(prop, wrapped);\n }\n return wrapped;\n }\n return value;\n },\n });\n this._proxyCache.set(moduleExports, proxy);\n _isPatched = true;\n return proxy as Record<string, unknown>;\n }\n\n private unpatch(moduleExports: Record<string, unknown>): Record<string, unknown> {\n if (moduleExports) {\n // Only the in-place (ESM/IITM) path leaves wrapped functions to unwrap; the CJS Proxy is simply\n // discarded by the require-hook on unpatch (consumers that already captured it keep it — telemetry\n // injection is harmless either way).\n for (const n of TARGET_FUNCTIONS) {\n if (typeof moduleExports[n] === 'function' && isWrapped(moduleExports[n])) {\n this._unwrap(moduleExports, n);\n }\n }\n this._proxyCache.delete(moduleExports);\n }\n _isPatched = false;\n return moduleExports;\n }\n}\n","import { SDK_VERSION } from './version';\n\n/** User-supplied options to {@link init}. Anything omitted falls back to an env var. */\nexport interface ScopeOptions {\n /** Project SECRET key (sk_live_… / sk_test_…). Env: SCOPE_API_KEY. */\n apiKey?: string;\n /** Scope ingest base URL. Env: SCOPE_ENDPOINT. Default https://api.scopeai.dev. */\n endpoint?: string;\n /** Logical environment tag on every event. Env: SCOPE_ENVIRONMENT. Default \"production\". */\n environment?: string;\n /** Verbose logging. Env: SCOPE_DEBUG=true. */\n debug?: boolean;\n /** OTel service.name for the tracer resource. Env: SCOPE_SERVICE_NAME / OTEL_SERVICE_NAME. */\n serviceName?: string;\n /**\n * OPT-IN regex patterns to scrub from captured prompt/response/message text. Default: none\n * (RAW — full fidelity, so the analyst sees the real interaction). Pass\n * {@link CREDENTIAL_REDACT_PATTERNS} (from this package) for a credential scrub, or your own —\n * each pattern must capture the key as group 1; the value is replaced with ***REDACTED***.\n * Best-effort over free text (applied to prompt + response + message contents), NOT a structural\n * guarantee — it won't catch secrets in non-`key=value` shapes (e.g. JSON `\"api_key\":\"…\"`).\n */\n redactPatterns?: readonly RegExp[];\n}\n\n/** Fully-resolved, validated configuration. */\nexport interface ScopeConfig {\n apiKey: string;\n /** Normalized base URL (no trailing slash). */\n endpoint: string;\n /** Fully-qualified ingest URL: `${endpoint}/api/events`. */\n eventsUrl: string;\n environment: string;\n debug: boolean;\n serviceName: string;\n sdkVersion: string;\n /** Opt-in redaction patterns (empty/undefined = raw, the default). Always set by resolveConfig;\n * optional here so hand-built config literals (tests, custom wiring) can omit it. */\n redactPatterns?: readonly RegExp[];\n}\n\n/** Thrown when configuration is missing or malformed (e.g. no/invalid API key). */\nexport class ScopeConfigError extends Error {\n constructor(message: string) {\n super(message);\n this.name = 'ScopeConfigError';\n }\n}\n\nconst DEFAULT_ENDPOINT = 'https://api.scopeai.dev';\n\n/**\n * Resolve options + environment into a validated {@link ScopeConfig}.\n *\n * Mirrors the Python SDK's contract exactly: the key MUST be a project SECRET key\n * (sk_live_… / sk_test_…) — a public pk_… key is rejected so a misconfigured backend\n * install fails loudly rather than silently dropping data (rule b: honest non-coverage).\n */\nexport function resolveConfig(\n options: ScopeOptions = {},\n env: NodeJS.ProcessEnv = process.env,\n): ScopeConfig {\n const apiKey = (options.apiKey ?? env.SCOPE_API_KEY ?? '').trim();\n if (!apiKey) {\n throw new ScopeConfigError(\n 'Scope: missing API key. Set SCOPE_API_KEY (your project secret key, sk_live_… or ' +\n 'sk_test_…) or pass { apiKey } to init().',\n );\n }\n if (!(apiKey.startsWith('sk_live_') || apiKey.startsWith('sk_test_'))) {\n throw new ScopeConfigError(\n 'Scope: invalid API key. The backend SDK needs a project SECRET key starting with ' +\n '\"sk_live_\" or \"sk_test_\" (a public \"pk_…\" key will not work for server-side ingest).',\n );\n }\n\n const rawEndpoint = (options.endpoint ?? env.SCOPE_ENDPOINT ?? DEFAULT_ENDPOINT).trim();\n const endpoint = (rawEndpoint || DEFAULT_ENDPOINT).replace(/\\/+$/, '');\n const environment =\n (options.environment ?? env.SCOPE_ENVIRONMENT ?? 'production').trim() || 'production';\n const debug = options.debug ?? (env.SCOPE_DEBUG ?? '').toLowerCase() === 'true';\n const serviceName =\n (options.serviceName ?? env.SCOPE_SERVICE_NAME ?? env.OTEL_SERVICE_NAME ?? 'scope-app').trim() ||\n 'scope-app';\n\n return {\n apiKey,\n endpoint,\n eventsUrl: `${endpoint}/api/events`,\n environment,\n debug,\n serviceName,\n sdkVersion: SDK_VERSION,\n redactPatterns: options.redactPatterns ?? [],\n };\n}\n","// Deploy-aware identity (PRODUCT.md §4.2). Read the deployed commit SHA from whatever\n// platform env var the host exposes, once at startup, and stamp every event with\n// git_sha + deployment_id so the analyst can reason about \"what changed before the drop?\".\n// Mirrors the Python SDK's deployment.py exactly (same env vars, same precedence, same id format).\n\n/** Platform commit-SHA env vars, in priority order. First non-empty wins. */\nconst GIT_SHA_ENV_VARS = [\n 'RAILWAY_GIT_COMMIT_SHA', // Railway\n 'VERCEL_GIT_COMMIT_SHA', // Vercel\n 'RENDER_GIT_COMMIT', // Render\n 'HEROKU_RELEASE_VERSION', // Heroku\n 'K_REVISION', // Cloud Run / Cloud Functions / Firebase\n 'AWS_LAMBDA_FUNCTION_VERSION', // AWS Lambda\n 'GIT_COMMIT_SHA', // Generic fallback\n] as const;\n\nexport interface Deployment {\n /** The deployed commit SHA, or undefined when no platform env var is set. */\n gitSha?: string;\n /** `${ISO_START}-${gitSha.slice(0,7)}`, or undefined when no SHA is known. */\n deploymentId?: string;\n}\n\n/** Return the deployed commit SHA from platform env vars, or undefined. Never invents one. */\nexport function detectGitSha(env: NodeJS.ProcessEnv = process.env): string | undefined {\n for (const name of GIT_SHA_ENV_VARS) {\n const value = env[name];\n if (value && value.trim()) return value.trim();\n }\n return undefined;\n}\n\n/**\n * Resolve the deployment identity for this process.\n * @param startedAt process start time (UTC), used to build a stable deployment_id.\n */\nexport function resolveDeployment(\n startedAt: Date,\n env: NodeJS.ProcessEnv = process.env,\n): Deployment {\n const gitSha = detectGitSha(env);\n if (!gitSha) return {};\n // Match the Python SDK's id format: \"2024-01-15T10:30:00Z-abc1234\" (no millis).\n const startIso = startedAt.toISOString().replace(/\\.\\d{3}Z$/, 'Z');\n return { gitSha, deploymentId: `${startIso}-${gitSha.slice(0, 7)}` };\n}\n\n/**\n * Add git_sha + deployment_id to an event when known. Never overwrites a value the caller\n * already set (parity with the Python enricher's setdefault semantics).\n */\nexport function stampDeployment<T extends Record<string, unknown>>(\n event: T,\n deployment: Deployment,\n): T {\n if (deployment.gitSha && event.git_sha === undefined) {\n (event as Record<string, unknown>).git_sha = deployment.gitSha;\n if (deployment.deploymentId && event.deployment_id === undefined) {\n (event as Record<string, unknown>).deployment_id = deployment.deploymentId;\n }\n }\n return event;\n}\n","import { ExportResultCode, type ExportResult } from '@opentelemetry/core';\nimport type { ReadableSpan, SpanExporter } from '@opentelemetry/sdk-trace-base';\nimport type { ScopeConfig } from './config';\nimport type { Deployment } from './deployment';\nimport { spanToScopeEvent, type ScopeEvent } from './event';\nimport { shipEvents } from './transport';\n\n/**\n * An OTel SpanExporter that translates OpenInference GenAI spans into Scope events and ships\n * them. Batching/timeout/flush are handled by the OTel BatchSpanProcessor that wraps this — we\n * just map the batch and POST it (the \"wrap OpenTelemetry, don't reinvent\" philosophy, PLAN\n * Track B). Non-LLM spans are dropped (this slice maps LLM spans only).\n */\nexport class ScopeSpanExporter implements SpanExporter {\n constructor(\n private readonly config: ScopeConfig,\n private readonly deployment: Deployment,\n ) {}\n\n export(spans: ReadableSpan[], resultCallback: (result: ExportResult) => void): void {\n const events: ScopeEvent[] = [];\n for (const span of spans) {\n const event = spanToScopeEvent(span, { config: this.config, deployment: this.deployment });\n if (event) events.push(event);\n }\n if (events.length === 0) {\n resultCallback({ code: ExportResultCode.SUCCESS });\n return;\n }\n shipEvents(events, this.config)\n .then((ok) => resultCallback({ code: ok ? ExportResultCode.SUCCESS : ExportResultCode.FAILED }))\n .catch(() => resultCallback({ code: ExportResultCode.FAILED }));\n }\n\n shutdown(): Promise<void> {\n return Promise.resolve();\n }\n\n forceFlush(): Promise<void> {\n return Promise.resolve();\n }\n}\n","import {\n SemanticConventions as SC,\n OpenInferenceSpanKind,\n} from '@arizeai/openinference-semantic-conventions';\nimport { SpanStatusCode } from '@opentelemetry/api';\nimport { SCOPE_THREAD_ID_ATTR, SCOPE_URL_ATTR } from './attributes';\nimport { stampDeployment, type Deployment } from './deployment';\nimport { generateTempSessionId } from './session';\nimport { SDK_SOURCE } from './version';\nimport type { ScopeConfig } from './config';\n\n// The load-bearing translation: an OpenInference GenAI span -> a wire-compatible Scope event.\n// We deliberately read OpenInference's published semantic-convention constants (SC.*) rather\n// than hardcoding attribute strings, so a convention rename surfaces at build time, not as a\n// silently malformed event. The output is the SAME universal event shape the Python SDK emits\n// (CLAUDE.md §1.6 universal storage) so both SDKs are wire-identical to the backend.\n\n/** A Scope universal event. The three required fields plus arbitrary extras (backend allows them). */\nexport interface ScopeEvent {\n event_type: string;\n source: string;\n timestamp: string;\n session_id: string;\n user_id?: string | null;\n [key: string]: unknown;\n}\n\n/** The structural subset of an OTel ReadableSpan we read. ReadableSpan satisfies this. */\nexport interface SpanLike {\n attributes: Record<string, unknown>;\n startTime: [number, number]; // HrTime [seconds, nanoseconds]\n endTime: [number, number];\n status?: { code: number; message?: string };\n}\n\ninterface ChatMessage {\n role?: string;\n content?: string;\n}\n\nfunction asString(v: unknown): string | undefined {\n if (typeof v === 'string') return v;\n if (v === undefined || v === null) return undefined;\n return String(v);\n}\n\nfunction asNumber(v: unknown): number | undefined {\n if (typeof v === 'number' && Number.isFinite(v)) return v;\n if (typeof v === 'string' && v.trim() !== '' && Number.isFinite(Number(v))) return Number(v);\n return undefined;\n}\n\n// Provider-name fallbacks for spans translated from the Vercel AI SDK by @arizeai/openinference-vercel.\n// That adapter does NOT emit llm.provider/llm.system, but the span retains the OpenTelemetry GenAI\n// `gen_ai.system` and the Vercel `ai.model.provider` attributes. Reading them (in order) lets\n// Vercel-captured events carry a provider label, consistent with the OpenAI/Anthropic/Gemini SDKs —\n// which DO set llm.provider/llm.system, so these fallbacks never change their value. These are\n// standard upstream attribute names (OTel GenAI / Vercel AI), captured as-is — not Scope keyword logic.\nconst GEN_AI_SYSTEM_ATTR = 'gen_ai.system';\nconst VERCEL_MODEL_PROVIDER_ATTR = 'ai.model.provider';\n\n/**\n * Opt-in credential-scrub patterns. Pass to `init({ redactPatterns: CREDENTIAL_REDACT_PATTERNS })`.\n * Each captures the KEY as group 1 and matches the secret VALUE OUTSIDE the group, so the\n * substitution keeps the key and DROPS the value: \"password=hunter2\" -> \"password=***REDACTED***\".\n * Wire-identical to the Python SDK's DEFAULT_REDACT_PATTERNS. NOT applied unless opted in (raw default).\n * Best-effort free-text scrub over `key=value` forms — NOT a structural guarantee: it won't catch a\n * secret written as JSON (`\"api_key\":\"…\"`) or in other non-`=` shapes.\n */\nexport const CREDENTIAL_REDACT_PATTERNS: readonly RegExp[] = [\n /(password\\s*=\\s*['\"]?)[^'\"\\s]+/gi,\n /(api[_-]?key\\s*=\\s*['\"]?)[^'\"\\s]+/gi,\n /(token\\s*=\\s*['\"]?)[^'\"\\s]+/gi,\n /(secret\\s*=\\s*['\"]?)[^'\"\\s]+/gi,\n];\n\n/** Apply opt-in redaction patterns to text. No-op when none are configured (the default) — raw text\n * for full fidelity. Patterns capture the key as group 1; the matched value is replaced. */\nfunction redactText(text: string | undefined, patterns: readonly RegExp[]): string | undefined {\n if (text === undefined || patterns.length === 0) return text;\n let out = text;\n for (const re of patterns) out = out.replace(re, '$1***REDACTED***');\n return out;\n}\n\nfunction hrTimeToMs(t: [number, number]): number {\n return t[0] * 1000 + t[1] / 1e6;\n}\n\nfunction escapeRe(s: string): string {\n return s.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\$&');\n}\n\n/**\n * Collect the flattened, indexed message attributes under a prefix (e.g. \"llm.input_messages\")\n * into an ordered array of {role, content}.\n *\n * Handles BOTH content shapes OpenInference emits:\n * - scalar: {prefix}.{i}.message.content (chat-completions, string content)\n * - array: {prefix}.{i}.message.contents.{j}.message_content.text (Responses API + multimodal/vision)\n * For the array shape we join the text parts in order. Missing this second shape would drop the\n * prompt/response text for the modern OpenAI Responses API and leave a raw JSON blob behind.\n */\nfunction collectMessages(attrs: Record<string, unknown>, prefix: string): ChatMessage[] {\n const p = escapeRe(prefix);\n const roleRe = new RegExp(`^${p}\\\\.(\\\\d+)\\\\.${escapeRe(SC.MESSAGE_ROLE)}$`);\n const contentRe = new RegExp(`^${p}\\\\.(\\\\d+)\\\\.${escapeRe(SC.MESSAGE_CONTENT)}$`);\n const partRe = new RegExp(\n `^${p}\\\\.(\\\\d+)\\\\.${escapeRe(SC.MESSAGE_CONTENTS)}\\\\.(\\\\d+)\\\\.${escapeRe(SC.MESSAGE_CONTENT_TEXT)}$`,\n );\n\n const roles = new Map<number, string | undefined>();\n const scalarContent = new Map<number, string | undefined>();\n const parts = new Map<number, Map<number, string>>(); // messageIndex -> partIndex -> text\n\n for (const [key, value] of Object.entries(attrs)) {\n let m: RegExpExecArray | null;\n if ((m = roleRe.exec(key))) {\n roles.set(Number(m[1]), asString(value));\n } else if ((m = contentRe.exec(key))) {\n scalarContent.set(Number(m[1]), asString(value));\n } else if ((m = partRe.exec(key))) {\n const i = Number(m[1]);\n const text = asString(value);\n if (text !== undefined) {\n const byPart = parts.get(i) ?? new Map<number, string>();\n byPart.set(Number(m[2]), text);\n parts.set(i, byPart);\n }\n }\n }\n\n const indices = [...new Set([...roles.keys(), ...scalarContent.keys(), ...parts.keys()])].sort(\n (a, b) => a - b,\n );\n return indices.map((i) => {\n const message: ChatMessage = {};\n const role = roles.get(i);\n if (role !== undefined) message.role = role;\n let content = scalarContent.get(i);\n if (content === undefined && parts.has(i)) {\n const byPart = parts.get(i)!;\n content = [...byPart.keys()]\n .sort((a, b) => a - b)\n .map((j) => byPart.get(j))\n .join('');\n }\n if (content !== undefined) message.content = content;\n return message;\n });\n}\n\n/** True if the span is an OpenInference LLM span (the only kind this slice maps). */\nexport function isLlmSpan(span: SpanLike): boolean {\n return span.attributes[SC.OPENINFERENCE_SPAN_KIND] === OpenInferenceSpanKind.LLM;\n}\n\n/**\n * Map an OpenInference LLM span to a Scope `llm_call` event, or null if the span isn't an LLM\n * span. `now` is injectable for deterministic tests.\n */\nexport function spanToScopeEvent(\n span: SpanLike,\n ctx: { config: ScopeConfig; deployment: Deployment; now?: Date },\n): ScopeEvent | null {\n if (!isLlmSpan(span)) return null;\n\n const a = span.attributes;\n const inputMessages = collectMessages(a, SC.LLM_INPUT_MESSAGES);\n const outputMessages = collectMessages(a, SC.LLM_OUTPUT_MESSAGES);\n\n // Prompt = the last user turn (fall back to the last input turn, then the raw input value).\n const lastUser = [...inputMessages].reverse().find((m) => (m.role ?? '').toLowerCase() === 'user');\n const patterns = ctx.config.redactPatterns ?? [];\n const prompt = redactText(\n lastUser?.content ?? inputMessages.at(-1)?.content ?? asString(a[SC.INPUT_VALUE]),\n patterns,\n );\n const response = redactText(outputMessages[0]?.content ?? asString(a[SC.OUTPUT_VALUE]), patterns);\n\n const tokens: Record<string, number> = {};\n const promptTokens = asNumber(a[SC.LLM_TOKEN_COUNT_PROMPT]);\n if (promptTokens !== undefined) tokens.prompt_tokens = promptTokens;\n const completionTokens = asNumber(a[SC.LLM_TOKEN_COUNT_COMPLETION]);\n if (completionTokens !== undefined) tokens.completion_tokens = completionTokens;\n const totalTokens = asNumber(a[SC.LLM_TOKEN_COUNT_TOTAL]);\n if (totalTokens !== undefined) tokens.total_tokens = totalTokens;\n\n const sessionId = asString(a[SC.SESSION_ID]) ?? generateTempSessionId();\n const userId = asString(a[SC.USER_ID]) ?? null;\n const isError = span.status?.code === SpanStatusCode.ERROR;\n const now = ctx.now ?? new Date();\n const nowIso = now.toISOString();\n\n const event: ScopeEvent = {\n event_type: 'llm_call',\n source: SDK_SOURCE,\n timestamp: nowIso,\n session_id: sessionId,\n user_id: userId,\n is_user_facing: !sessionId.startsWith('temp_'),\n provider:\n asString(a[SC.LLM_PROVIDER]) ??\n asString(a[SC.LLM_SYSTEM]) ??\n asString(a[GEN_AI_SYSTEM_ATTR]) ??\n asString(a[VERCEL_MODEL_PROVIDER_ATTR]),\n model: asString(a[SC.LLM_MODEL_NAME]),\n prompt,\n response,\n messages: patterns.length\n ? inputMessages.map((m) =>\n m.content !== undefined ? { ...m, content: redactText(m.content, patterns) } : m,\n )\n : inputMessages,\n tokens,\n latency_ms: Math.max(0, hrTimeToMs(span.endTime) - hrTimeToMs(span.startTime)),\n error: isError ? (span.status?.message ?? 'error') : null,\n success: !isError,\n environment: ctx.config.environment,\n sdk_version: ctx.config.sdkVersion,\n server_timestamp: nowIso,\n };\n\n // Conversation-continuity hints (§1.8). Emitted only when present so the backend's fallback\n // chain (thread_id -> session_id+url -> session_id) behaves like it does for the Python SDK.\n const threadId = asString(a[SCOPE_THREAD_ID_ATTR]);\n if (threadId !== undefined) event.thread_id = threadId;\n const url = asString(a[SCOPE_URL_ATTR]);\n if (url !== undefined) event.url = url;\n\n return stampDeployment(event, ctx.deployment);\n}\n","// Custom span attributes Scope stamps from AsyncLocalStorage context — these have no\n// OpenInference equivalent (OpenInference covers session.id/user.id but not the host app's\n// thread/url). The ScopeContextSpanProcessor writes them at span start; the exporter reads\n// them back at export time and emits them as top-level event fields, so the backend's\n// conversation-continuity fallback chain (thread_id -> session_id+url -> session_id, §1.8)\n// works for Node services exactly as it does for the Python SDK.\nexport const SCOPE_THREAD_ID_ATTR = 'scope.thread_id';\nexport const SCOPE_URL_ATTR = 'scope.url';\n","import { AsyncLocalStorage } from 'node:async_hooks';\nimport { randomBytes } from 'node:crypto';\n\n// Session/user context propagation via AsyncLocalStorage (PLAN.md Track B). The host app\n// wraps a request in runWithContext({ sessionId, userId }) so that any LLM span created\n// during that request inherits the session — letting Scope stitch a user's activity across\n// frontend + backend + LLM (CLAUDE.md §1.8). The ScopeContextSpanProcessor reads this at\n// span start; the exporter falls back to a temp_ session when none is set.\n\nexport interface ScopeContextData {\n sessionId?: string;\n userId?: string;\n threadId?: string;\n url?: string;\n}\n\nconst storage = new AsyncLocalStorage<ScopeContextData>();\n\n/** Run `fn` with the given Scope context bound for its whole async subtree. */\nexport function runWithContext<T>(ctx: ScopeContextData, fn: () => T): T {\n return storage.run({ ...ctx }, fn);\n}\n\n/** The context bound to the current async execution, if any. */\nexport function getContext(): ScopeContextData | undefined {\n return storage.getStore();\n}\n\n/** Attach/replace the identified user on the current context (e.g. after auth resolves). */\nexport function setUser(userId: string): void {\n const store = storage.getStore();\n if (store) store.userId = userId;\n}\n\n/**\n * A temporary, non-user-facing session id used when no session context is present.\n * Matches the Python SDK's `temp_{16 hex}` shape; the backend treats `temp_`-prefixed\n * sessions as not user-facing.\n */\nexport function generateTempSessionId(): string {\n return `temp_${randomBytes(8).toString('hex')}`;\n}\n","import type { ScopeConfig } from './config';\nimport type { ScopeEvent } from './event';\nimport { SDK_SOURCE, SDK_USER_AGENT } from './version';\n\n// The HTTP shipper. POSTs the batch envelope the Scope backend expects:\n// POST {endpoint}/api/events { \"events\": [...], \"source\": \"backend_sdk\" }\n// Authorization: Bearer sk_...\n// Best-effort and NEVER throws — a telemetry failure must not crash or slow the host app\n// (rule b). Uses the global fetch (Node >= 18).\n\nexport async function shipEvents(events: ScopeEvent[], config: ScopeConfig): Promise<boolean> {\n if (events.length === 0) return true;\n try {\n const response = await fetch(config.eventsUrl, {\n method: 'POST',\n headers: {\n Authorization: `Bearer ${config.apiKey}`,\n 'Content-Type': 'application/json',\n 'User-Agent': SDK_USER_AGENT,\n },\n body: JSON.stringify({ events, source: SDK_SOURCE }),\n });\n if (response.ok) {\n if (config.debug) console.log(`[scope] shipped ${events.length} event(s)`);\n return true;\n }\n if (config.debug) console.warn(`[scope] ship failed: HTTP ${response.status}`);\n return false;\n } catch (err) {\n if (config.debug) {\n console.warn(`[scope] ship error: ${err instanceof Error ? err.message : String(err)}`);\n }\n return false;\n }\n}\n","import type { Context } from '@opentelemetry/api';\nimport type { ReadableSpan, Span, SpanProcessor } from '@opentelemetry/sdk-trace-base';\nimport { SemanticConventions as SC } from '@arizeai/openinference-semantic-conventions';\nimport { SCOPE_THREAD_ID_ATTR, SCOPE_URL_ATTR } from './attributes';\nimport { getContext } from './session';\n\n/**\n * Stamps the current AsyncLocalStorage Scope context (session/user/thread/url) onto each span\n * as it starts — so the exporter can read it back at export time (when the request's async\n * context is already gone). Session/user use OpenInference's own attributes; thread/url use\n * Scope's custom attributes. Never overwrites an attribute the instrumentation already set.\n */\nexport class ScopeContextSpanProcessor implements SpanProcessor {\n onStart(span: Span, _parentContext: Context): void {\n const ctx = getContext();\n if (!ctx) return;\n if (ctx.sessionId && span.attributes[SC.SESSION_ID] === undefined) {\n span.setAttribute(SC.SESSION_ID, ctx.sessionId);\n }\n if (ctx.userId && span.attributes[SC.USER_ID] === undefined) {\n span.setAttribute(SC.USER_ID, ctx.userId);\n }\n if (ctx.threadId && span.attributes[SCOPE_THREAD_ID_ATTR] === undefined) {\n span.setAttribute(SCOPE_THREAD_ID_ATTR, ctx.threadId);\n }\n if (ctx.url && span.attributes[SCOPE_URL_ATTR] === undefined) {\n span.setAttribute(SCOPE_URL_ATTR, ctx.url);\n }\n }\n\n onEnd(_span: ReadableSpan): void {\n // no-op: shipping happens in the exporter behind the BatchSpanProcessor.\n }\n\n shutdown(): Promise<void> {\n return Promise.resolve();\n }\n\n forceFlush(): Promise<void> {\n return Promise.resolve();\n }\n}\n","// Zero-code bootstrap entry: `NODE_OPTIONS=\"--import @scope-analytics/node/register\" node server.js`.\n// Loaded before the app's own modules, so the instrumentations are in place before the app imports\n// its LLM SDKs. NEVER throws — a misconfiguration (e.g. missing key) degrades to a warning rather\n// than crashing the host's startup (rule b: honest non-coverage > a broken app).\nimport { enableEsmInstrumentation } from './esm-hook';\nimport { init } from './index';\n\n// Register the ESM import-in-the-middle loader FIRST — before init()'s registerInstrumentations and,\n// crucially, before the app imports any provider module — so `import`s are instrumented too, not just\n// `require`s. Best-effort and never throws; on the CJS build / older Node it no-ops and CJS capture\n// still works via the require-hook.\n// INVARIANT: the loader only instruments a module loaded AFTER it registers. The app's provider\n// imports run after this bootstrap, so they're covered — but @scope-analytics/node's OWN graph (./index and\n// everything it imports) must never `import 'ai'` (it would load before the loader, breaking ESM\n// capture). The instrumentations read provider shapes structurally, never import them. See\n// vercel-ai-instrumentation.ts (LOAD-ORDER INVARIANT) + the bootstrap regression test.\nenableEsmInstrumentation();\n\ntry {\n init();\n} catch (err) {\n console.warn(`[scope] tracer not started: ${err instanceof Error ? err.message : String(err)}`);\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;AAAA,iBAA4B;AAC5B,iBAAqB;AAQrB,kCAAqB;AATrB;AA6BA,IAAM,iBAAiB;AAMvB,IAAI,oBAAoB;AAExB,SAAS,kBAA2B;AAClC,QAAM,IAAI,QAAQ,IAAI;AACtB,SAAO,MAAM,OAAO,MAAM,UAAU,MAAM;AAC5C;AAIA,SAAS,YAAgC;AACvC,MAAI;AAEF,WAAO,YAAY;AAAA,EACrB,QAAQ;AACN,WAAO;AAAA,EACT;AACF;AAIO,SAAS,2BAAiC;AAC/C,MAAI,gBAAgB,EAAG;AACvB,QAAM,YAAY,UAAU;AAC5B,MAAI,CAAC,UAAW;AAChB,QAAMA,YAA4E;AAClF,MAAI,OAAOA,cAAa,WAAY;AACpC,MAAI;AACF,IAAAA,UAAS,gBAAgB,SAAS;AAClC,wBAAoB;AACpB,oBAAK,MAAM,oFAAoF;AAAA,EACjG,SAAS,KAAK;AACZ,oBAAK;AAAA,MACH,iDAAiD,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG,CAAC;AAAA,IAEnG;AAAA,EACF;AACF;AAoBO,SAAS,4BACd,SACM;AACN,MAAI,CAAC,kBAAmB;AAExB,QAAM,WAAW,oBAAI,IAAkC;AACvD,aAAW,EAAE,SAAS,gBAAgB,KAAK,SAAS;AAClD,eAAW,KAAK,QAAS,UAAS,IAAI,GAAG,eAAe;AAAA,EAC1D;AACA,MAAI,SAAS,SAAS,EAAG;AACzB,MAAI;AAEF,QAAI,iCAAK,CAAC,GAAG,SAAS,KAAK,CAAC,GAAG,CAAC,UAAmB,SAAiB;AAClE,YAAM,kBAAkB,SAAS,IAAI,IAAI;AACzC,UAAI,CAAC,gBAAiB,QAAO;AAC7B,UAAI;AACF,wBAAgB,mBAAmB,QAAQ;AAAA,MAC7C,SAAS,KAAK;AACZ,wBAAK;AAAA,UACH,qCAAqC,IAAI,aAAa,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG,CAAC;AAAA,QACxG;AAAA,MACF;AACA,aAAO;AAAA,IACT,CAAC;AACD,oBAAK,MAAM,sDAAsD,CAAC,GAAG,SAAS,KAAK,CAAC,EAAE,KAAK,IAAI,CAAC,GAAG;AAAA,EACrG,SAAS,KAAK;AACZ,oBAAK;AAAA,MACH,sDAAsD,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG,CAAC;AAAA,IACxG;AAAA,EACF;AACF;;;ACzHA,IAAAC,0BAAyC;AACzC,4BAAmC;AACnC,kDAAsC;AACtC,qDAAyC;AACzC,kCAAgD;;;ACJhD,IAAAC,cAQO;AACP,kBAAoC;AACpC,6BAKO;AACP,gDAKO;;;AClBA,IAAM,cAAc;AACpB,IAAM,aAAa;AACnB,IAAM,iBAAiB,qBAAqB,WAAW;;;ADmD9D,IAAM,cAAc;AACpB,IAAM,uBAAuB;AAE7B,IAAI,aAAa;AAwDjB,SAAS,eAAe,GAAgC;AACtD,MAAI,OAAO,MAAM,YAAY,OAAO,SAAS,CAAC,EAAG,QAAO;AACxD,MAAI,OAAO,MAAM,YAAY,EAAE,KAAK,MAAM,MAAM,OAAO,SAAS,OAAO,CAAC,CAAC,EAAG,QAAO,OAAO,CAAC;AAC3F,SAAO;AACT;AAEA,SAAS,kBAAkB,GAAoB;AAC7C,MAAI;AACF,WAAO,KAAK,UAAU,CAAC,KAAK,OAAO,CAAC;AAAA,EACtC,QAAQ;AACN,WAAO;AAAA,EACT;AACF;AAEA,SAAS,WAAW,KAAsB;AACxC,QAAM,IAAK,KAAsC;AACjD,SAAO,KAAK,OAAO,OAAO,CAAC,IAAI;AACjC;AAEA,SAAS,cAAc,GAAmC;AACxD,SAAO,KAAK,QAAQ,OAAQ,EAAyB,SAAS;AAChE;AAGA,SAAS,UAAU,QAAgC;AACjD,QAAM,IAAI,OAAO,OAAO,UAAU,WAAW,OAAO,QAAQ;AAC5D,SAAO,EAAE,WAAW,SAAS,IAAI,EAAE,MAAM,UAAU,MAAM,IAAI;AAC/D;AAOA,SAAS,kBAAkB,UAAwC;AACjE,MAAI,OAAO,aAAa,SAAU,QAAO,CAAC,EAAE,MAAM,QAAQ,SAAS,SAAS,CAAC;AAC7E,MAAI,MAAM,QAAQ,QAAQ,GAAG;AAC3B,UAAM,OAA4B,CAAC;AACnC,eAAW,QAAQ,UAAU;AAC3B,UAAI,OAAO,SAAS,UAAU;AAC5B,aAAK,KAAK,EAAE,MAAM,QAAQ,SAAS,KAAK,CAAC;AAAA,MAC3C,WAAW,QAAQ,OAAO,SAAS,UAAU;AAC3C,cAAM,MAAM;AACZ,YAAI,aAAa,KAAK;AAEpB,eAAK,KAAK;AAAA,YACR,MAAM,OAAO,IAAI,SAAS,WAAW,IAAI,OAAO;AAAA,YAChD,SAAS,OAAO,IAAI,YAAY,WAAW,IAAI,UAAU,kBAAkB,IAAI,OAAO;AAAA,UACxF,CAAC;AAAA,QACH,WAAW,WAAW,KAAK;AAEzB,gBAAM,QAAQ,MAAM,QAAQ,IAAI,KAAK,IAAK,IAAI,QAAwB,CAAC;AACvE,gBAAM,UAAU,MACb,OAAO,CAAC,MAAM,KAAK,OAAO,EAAE,SAAS,QAAQ,EAC7C,IAAI,CAAC,MAAM,EAAE,IAAc,EAC3B,KAAK,EAAE;AACV,eAAK,KAAK,EAAE,MAAM,OAAO,IAAI,SAAS,WAAW,IAAI,OAAO,QAAQ,QAAQ,CAAC;AAAA,QAC/E,WAAW,OAAO,IAAI,SAAS,UAAU;AAEvC,eAAK,KAAK,EAAE,MAAM,QAAQ,SAAS,IAAI,KAAK,CAAC;AAAA,QAC/C;AAAA,MACF;AAAA,IACF;AACA,WAAO,KAAK,SAAS,OAAO,CAAC,EAAE,MAAM,QAAQ,SAAS,kBAAkB,QAAQ,EAAE,CAAC;AAAA,EACrF;AACA,MAAI,YAAY,KAAM,QAAO,CAAC;AAC9B,SAAO,CAAC,EAAE,MAAM,QAAQ,SAAS,kBAAkB,QAAQ,EAAE,CAAC;AAChE;AAIA,SAAS,aAAa,MAAyC;AAC7D,MAAI;AACJ,MAAI;AACF,WAAO,MAAM;AAAA,EACf,QAAQ;AACN,WAAO;AAAA,EACT;AACA,MAAI,OAAO,SAAS,YAAY,KAAM,QAAO;AAC7C,MAAI,MAAM;AAGV,QAAM,aAAa,MAAM,QAAQ,MAAM,UAAU,IAAK,MAAM,aAAkC,CAAC;AAC/F,aAAW,QAAQ,YAAY;AAC7B,UAAM,QAAQ,MAAM,QAAQ,MAAM,SAAS,KAAK,IAAK,MAAM,SAAS,QAAwB,CAAC;AAC7F,eAAW,QAAQ,OAAO;AACxB,UAAI,OAAO,MAAM,SAAS,SAAU,QAAO,KAAK;AAAA,IAClD;AAAA,EACF;AACA,SAAO;AACT;AAEA,SAAS,gBAAgB,QAAoC;AAC3D,QAAM,QAAoB;AAAA,IACxB,CAAC,0CAAAC,oBAAG,uBAAuB,GAAG,gEAAsB;AAAA,IACpD,CAAC,0CAAAA,oBAAG,YAAY,GAAG,sDAAY;AAAA,IAC/B,CAAC,0CAAAA,oBAAG,cAAc,GAAG,UAAU,MAAM;AAAA,IACrC,CAAC,0CAAAA,oBAAG,WAAW,GAAG,kBAAkB,MAAM;AAAA,IAC1C,CAAC,0CAAAA,oBAAG,eAAe,GAAG,mDAAS;AAAA,EACjC;AACA,oBAAkB,OAAO,QAAQ,EAAE,QAAQ,CAAC,KAAK,MAAM;AACrD,UAAM,SAAS,GAAG,0CAAAA,oBAAG,kBAAkB,IAAI,CAAC;AAC5C,QAAI,IAAI,SAAS,OAAW,OAAM,GAAG,MAAM,GAAG,0CAAAA,oBAAG,YAAY,EAAE,IAAI,IAAI;AACvE,QAAI,IAAI,YAAY,OAAW,OAAM,GAAG,MAAM,GAAG,0CAAAA,oBAAG,eAAe,EAAE,IAAI,IAAI;AAAA,EAC/E,CAAC;AACD,SAAO;AACT;AAEA,SAAS,oBAAoB,MAAY,MAAc,OAAqC;AAC1F,QAAM,QAAoB;AAAA,IACxB,CAAC,0CAAAA,oBAAG,YAAY,GAAG;AAAA,IACnB,CAAC,0CAAAA,oBAAG,gBAAgB,GAAG,mDAAS;AAAA,IAChC,CAAC,GAAG,0CAAAA,oBAAG,mBAAmB,MAAM,0CAAAA,oBAAG,YAAY,EAAE,GAAG;AAAA,IACpD,CAAC,GAAG,0CAAAA,oBAAG,mBAAmB,MAAM,0CAAAA,oBAAG,eAAe,EAAE,GAAG;AAAA,EACzD;AACA,MAAI,OAAO;AAGT,UAAM,0CAAAA,oBAAG,sBAAsB,IAAI,eAAe,MAAM,gBAAgB,KAAK;AAC7E,UAAM,0CAAAA,oBAAG,0BAA0B,IAAI,eAAe,MAAM,oBAAoB,KAAK;AACrF,UAAM,0CAAAA,oBAAG,qBAAqB,IAAI,eAAe,MAAM,eAAe,KAAK;AAAA,EAC7E;AACA,OAAK,cAAc,KAAK;AAC1B;AAKA,SAAS,MAAM,MAAY,MAAuC;AAChE,MAAI;AACF,wBAAoB,MAAM,aAAa,IAAI,GAAG,MAAM,aAAa;AACjE,SAAK,UAAU,EAAE,MAAM,2BAAe,GAAG,CAAC;AAAA,EAC5C,QAAQ;AAAA,EAER;AACA,MAAI;AACF,SAAK,IAAI;AAAA,EACX,QAAQ;AAAA,EAER;AACF;AAEA,SAAS,aAAa,MAAY,KAAoB;AACpD,MAAI;AACF,SAAK,gBAAgB,GAAY;AACjC,SAAK,UAAU,EAAE,MAAM,2BAAe,OAAO,SAAS,WAAW,GAAG,EAAE,CAAC;AAAA,EACzE,QAAQ;AAAA,EAER;AACA,MAAI;AACF,SAAK,IAAI;AAAA,EACX,QAAQ;AAAA,EAER;AACF;AAEO,IAAM,6BAAN,cAAyC,2CAAoB;AAAA,EAClE,YAAY,SAAgC,CAAC,GAAG;AAC9C,UAAM,sBAAsB,aAAa,MAAM;AAAA,EACjD;AAAA,EAEU,OAA4C;AACpD,WAAO,IAAI;AAAA,MACT;AAAA,MACA,CAAC,GAAG;AAAA,MACJ,CAAC,kBAAsC,KAAK,MAAM,aAAa;AAAA,MAC/D,CAAC,kBAAsC,KAAK,QAAQ,aAAa;AAAA,IACnE;AAAA,EACF;AAAA;AAAA,EAGA,mBAAmB,eAAyC;AAC1D,qBAAK,MAAM,0BAA0B,WAAW,EAAE;AAClD,SAAK,MAAM,aAAa;AAAA,EAC1B;AAAA,EAEQ,MAAM,eAAuD;AACnE,QAAI,CAAC,iBAAiB,cAAc,gBAAgB,WAAY,QAAO;AACvE,UAAM,IAAI,cAAc,WAAW;AACnC,UAAM,QAAQ,GAAG,QAAQ;AACzB,QAAI,CAAC,SAAS,OAAO,MAAM,4BAA4B,YAAY;AACjE,uBAAK,KAAK,mEAAmE,WAAW,EAAE;AAC1F,aAAO;AAAA,IACT;AACA,UAAM,YAAY;AAClB,SAAK,MAAM,WAAW,2BAA2B,KAAK,cAAc,KAAK,CAAC;AAC1E,QAAI,OAAO,MAAM,kCAAkC,YAAY;AAC7D,WAAK,MAAM,WAAW,iCAAiC,KAAK,cAAc,IAAI,CAAC;AAAA,IACjF;AACA,iBAAa;AACb,QAAI;AACF,oBAAc,eAAe;AAAA,IAC/B,QAAQ;AAAA,IAER;AACA,WAAO;AAAA,EACT;AAAA,EAEQ,QAAQ,eAAyC;AACvD,UAAM,IAAI,eAAe,WAAW;AACpC,UAAM,QAAQ,GAAG,QAAQ;AACzB,QAAI,OAAO;AAET,cAAI,kCAAU,MAAM,uBAAuB,GAAG;AAC5C,aAAK,QAAQ,OAAoC,yBAAyB;AAAA,MAC5E;AACA,cAAI,kCAAU,MAAM,6BAA6B,GAAG;AAClD,aAAK,QAAQ,OAAoC,+BAA+B;AAAA,MAClF;AAAA,IACF;AACA,iBAAa;AACb,QAAI;AACF,UAAI,cAAe,eAAc,eAAe;AAAA,IAClD,QAAQ;AAAA,IAER;AAAA,EACF;AAAA,EAEQ,cAAc,WAA0D;AAC9E,UAAM,kBAAkB;AACxB,WAAO,CAAC,aACN,SAAS,WAA0B,MAA0B;AAE3D,cAAI,iCAAoB,oBAAQ,OAAO,CAAC,GAAG;AACzC,eAAO,SAAS,MAAM,MAAM,IAAI;AAAA,MAClC;AAGA,UAAI;AACJ,UAAI;AACF,cAAM,SAAU,KAAK,CAAC,KAAK,CAAC;AAC5B,eAAO,gBAAgB,OAAO,UAAU,+BAA+B;AAAA,UACrE,MAAM,qBAAS;AAAA,UACf,YAAY,gBAAgB,MAAM;AAAA,QACpC,CAAC;AAAA,MACH,QAAQ;AACN,eAAO;AAAA,MACT;AACA,UAAI,CAAC,KAAM,QAAO,SAAS,MAAM,MAAM,IAAI;AAC3C,YAAM,aAAa;AAEnB,YAAM,gBAAgB,kBAAM,QAAQ,oBAAQ,OAAO,GAAG,UAAU;AAChE,UAAI;AACJ,UAAI;AACF,iBAAS,oBAAQ,KAAK,eAAe,MAAM,SAAS,MAAM,MAAM,IAAI,CAAC;AAAA,MACvE,SAAS,KAAK;AAEZ,qBAAa,YAAY,GAAG;AAC5B,cAAM;AAAA,MACR;AAEA,UAAI,CAAC,cAAc,MAAM,GAAG;AAE1B,cAAM,YAAY,MAAS;AAC3B,eAAO;AAAA,MACT;AAEA,UAAI,WAAW;AACb,eAAQ,OAAiD;AAAA,UACvD,CAAC,QAAQ,gBAAgB,YAAY,KAAK,UAAU;AAAA,UACpD,CAAC,QAAQ;AACP,yBAAa,YAAY,GAAG;AAC5B,kBAAM;AAAA,UACR;AAAA,QACF;AAAA,MACF;AACA,aAAQ,OAAkC;AAAA,QACxC,CAAC,SAAS;AACR,gBAAM,YAAY,IAAI;AACtB,iBAAO;AAAA,QACT;AAAA,QACA,CAAC,QAAQ;AACP,uBAAa,YAAY,GAAG;AAC5B,gBAAM;AAAA,QACR;AAAA,MACF;AAAA,IACF;AAAA,EACJ;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAYA,OAAe,YACb,KACA,MAC+B;AAC/B,UAAM,QAAkB,CAAC;AACzB,QAAI;AACJ,QAAI,UAAU;AACd,QAAI;AACF,uBAAiB,SAAS,KAAK;AAC7B,YAAI;AACF,gBAAM,KAAK,aAAa,KAAK,CAAC;AAC9B,cAAI,OAAO,cAAe,SAAQ,MAAM;AAAA,QAC1C,QAAQ;AAAA,QAER;AACA,cAAM;AAAA,MACR;AAAA,IACF,SAAS,KAAK;AACZ,gBAAU;AACV,UAAI;AACF,aAAK,gBAAgB,GAAY;AACjC,aAAK,UAAU,EAAE,MAAM,2BAAe,OAAO,SAAS,WAAW,GAAG,EAAE,CAAC;AAAA,MACzE,QAAQ;AAAA,MAER;AACA,YAAM;AAAA,IACR,UAAE;AACA,UAAI,CAAC,SAAS;AACZ,YAAI;AACF,8BAAoB,MAAM,MAAM,KAAK,EAAE,GAAG,KAAK;AAC/C,eAAK,UAAU,EAAE,MAAM,2BAAe,GAAG,CAAC;AAAA,QAC5C,QAAQ;AAAA,QAER;AAAA,MACF;AACA,UAAI;AACF,aAAK,IAAI;AAAA,MACX,QAAQ;AAAA,MAER;AAAA,IACF;AAAA,EACF;AACF;;;AE9bA,IAAAC,cAAqB;AACrB,IAAAC,0BAKO;AAwCP,IAAMC,eAAc;AACpB,IAAMC,wBAAuB;AAM7B,IAAM,mBAAmB,CAAC,gBAAgB,cAAc,kBAAkB,cAAc;AAExF,IAAIC,cAAa;AAoBV,SAAS,oBAAoB,MAA4B;AAC9D,MAAI;AACF,UAAM,OAAO,KAAK,CAAC;AACnB,QAAI,CAAC,QAAQ,OAAO,SAAS,YAAY,MAAM,QAAQ,IAAI,EAAG,QAAO;AACrE,UAAM,IAAI;AACV,UAAM,WAAW,EAAE;AACnB,UAAM,cAAc,CAAC,CAAC,YAAY,OAAO,aAAa,YAAY,CAAC,MAAM,QAAQ,QAAQ;AAEzF,QAAI,eAAe,SAAU,cAAc,MAAO,QAAO;AAEzD,QAAI,eAAe,SAAU,cAAc,KAAM,QAAO;AACxD,UAAM,kBAAqC;AAAA,MACzC,GAAI,cAAc,WAAY,CAAC;AAAA,MAC/B,WAAW;AAAA,IACb;AACA,WAAO,CAAC,EAAE,GAAG,GAAG,wBAAwB,gBAAgB,GAAG,GAAG,KAAK,MAAM,CAAC,CAAC;AAAA,EAC7E,QAAQ;AACN,WAAO;AAAA,EACT;AACF;AAIA,SAAS,qBAAqB,UAAwB;AACpD,SAAO,SAAS,+BAA8C,MAA0B;AACtF,WAAO,SAAS,MAAM,MAAM,oBAAoB,IAAI,CAAC;AAAA,EACvD;AACF;AAOA,SAAS,gBAAgB,KAAa,MAAuB;AAC3D,QAAM,IAAI,OAAO,yBAAyB,KAAK,IAAI;AACnD,MAAI,CAAC,EAAG,QAAO;AACf,MAAI,OAAO,EAAE,QAAQ,WAAY,QAAO;AACxC,MAAI,EAAE,aAAa,KAAM,QAAO;AAChC,MAAI,EAAE,iBAAiB,KAAM,QAAO;AACpC,SAAO;AACT;AAEO,IAAM,0BAAN,cAAsC,4CAAoB;AAAA;AAAA,EAE9C,cAAc,oBAAI,QAAwB;AAAA,EAE3D,YAAY,SAAgC,CAAC,GAAG;AAC9C,UAAMC,uBAAsB,aAAa,MAAM;AAAA,EACjD;AAAA,EAEU,OAA4C;AACpD,WAAO,IAAI;AAAA,MACTC;AAAA,MACA,CAAC,GAAG;AAAA,MACJ,CAAC,kBAA2C,KAAK,MAAM,aAAa;AAAA,MACpE,CAAC,kBAA2C,KAAK,QAAQ,aAAa;AAAA,IACxE;AAAA,EACF;AAAA;AAAA,EAGA,mBAAmB,eAAiE;AAClF,qBAAK,MAAM,0BAA0BA,YAAW,EAAE;AAClD,WAAO,KAAK,MAAM,aAAa;AAAA,EACjC;AAAA,EAEQ,MAAM,eAAiE;AAC7E,QAAI,CAAC,cAAe,QAAO;AAC3B,UAAM,UAAU,iBAAiB,OAAO,CAAC,MAAM,OAAO,cAAc,CAAC,MAAM,UAAU;AACrF,QAAI,QAAQ,WAAW,GAAG;AACxB,uBAAK,KAAK,yCAAyCA,YAAW,sCAAsC;AACpG,aAAO;AAAA,IACT;AAIA,QAAI,QAAQ,MAAM,CAAC,MAAM,gBAAgB,eAAe,CAAC,CAAC,GAAG;AAC3D,iBAAW,KAAK,SAAS;AACvB,YAAI,KAAC,mCAAU,cAAc,CAAC,CAAC,GAAG;AAChC,eAAK,MAAM,eAAe,GAAG,CAAC,aAAsB,qBAAqB,QAAiB,CAAC;AAAA,QAC7F;AAAA,MACF;AACA,MAAAC,cAAa;AACb,aAAO;AAAA,IACT;AAGA,UAAM,SAAS,KAAK,YAAY,IAAI,aAAa;AACjD,QAAI,QAAQ;AACV,MAAAA,cAAa;AACb,aAAO;AAAA,IACT;AACA,UAAM,UAAU,IAAI,IAAY,OAAO;AACvC,UAAM,UAAU,oBAAI,IAAmB;AACvC,UAAM,QAAQ,IAAI,MAAM,eAAe;AAAA,MACrC,IAAI,QAAQ,MAAM,UAAU;AAC1B,cAAM,QAAQ,QAAQ,IAAI,QAAQ,MAAM,QAAQ;AAChD,YAAI,OAAO,SAAS,YAAY,QAAQ,IAAI,IAAI,KAAK,OAAO,UAAU,YAAY;AAChF,cAAI,UAAU,QAAQ,IAAI,IAAI;AAC9B,cAAI,CAAC,SAAS;AACZ,sBAAU,qBAAqB,KAAc;AAC7C,oBAAQ,IAAI,MAAM,OAAO;AAAA,UAC3B;AACA,iBAAO;AAAA,QACT;AACA,eAAO;AAAA,MACT;AAAA,IACF,CAAC;AACD,SAAK,YAAY,IAAI,eAAe,KAAK;AACzC,IAAAA,cAAa;AACb,WAAO;AAAA,EACT;AAAA,EAEQ,QAAQ,eAAiE;AAC/E,QAAI,eAAe;AAIjB,iBAAW,KAAK,kBAAkB;AAChC,YAAI,OAAO,cAAc,CAAC,MAAM,kBAAc,mCAAU,cAAc,CAAC,CAAC,GAAG;AACzE,eAAK,QAAQ,eAAe,CAAC;AAAA,QAC/B;AAAA,MACF;AACA,WAAK,YAAY,OAAO,aAAa;AAAA,IACvC;AACA,IAAAA,cAAa;AACb,WAAO;AAAA,EACT;AACF;;;ACjKO,IAAM,mBAAN,cAA+B,MAAM;AAAA,EAC1C,YAAY,SAAiB;AAC3B,UAAM,OAAO;AACb,SAAK,OAAO;AAAA,EACd;AACF;AAEA,IAAM,mBAAmB;AASlB,SAAS,cACd,UAAwB,CAAC,GACzB,MAAyB,QAAQ,KACpB;AACb,QAAM,UAAU,QAAQ,UAAU,IAAI,iBAAiB,IAAI,KAAK;AAChE,MAAI,CAAC,QAAQ;AACX,UAAM,IAAI;AAAA,MACR;AAAA,IAEF;AAAA,EACF;AACA,MAAI,EAAE,OAAO,WAAW,UAAU,KAAK,OAAO,WAAW,UAAU,IAAI;AACrE,UAAM,IAAI;AAAA,MACR;AAAA,IAEF;AAAA,EACF;AAEA,QAAM,eAAe,QAAQ,YAAY,IAAI,kBAAkB,kBAAkB,KAAK;AACtF,QAAM,YAAY,eAAe,kBAAkB,QAAQ,QAAQ,EAAE;AACrE,QAAM,eACH,QAAQ,eAAe,IAAI,qBAAqB,cAAc,KAAK,KAAK;AAC3E,QAAM,QAAQ,QAAQ,UAAU,IAAI,eAAe,IAAI,YAAY,MAAM;AACzE,QAAM,eACH,QAAQ,eAAe,IAAI,sBAAsB,IAAI,qBAAqB,aAAa,KAAK,KAC7F;AAEF,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA,WAAW,GAAG,QAAQ;AAAA,IACtB;AAAA,IACA;AAAA,IACA;AAAA,IACA,YAAY;AAAA,IACZ,gBAAgB,QAAQ,kBAAkB,CAAC;AAAA,EAC7C;AACF;;;ACzFA,IAAM,mBAAmB;AAAA,EACvB;AAAA;AAAA,EACA;AAAA;AAAA,EACA;AAAA;AAAA,EACA;AAAA;AAAA,EACA;AAAA;AAAA,EACA;AAAA;AAAA,EACA;AAAA;AACF;AAUO,SAAS,aAAa,MAAyB,QAAQ,KAAyB;AACrF,aAAW,QAAQ,kBAAkB;AACnC,UAAM,QAAQ,IAAI,IAAI;AACtB,QAAI,SAAS,MAAM,KAAK,EAAG,QAAO,MAAM,KAAK;AAAA,EAC/C;AACA,SAAO;AACT;AAMO,SAAS,kBACd,WACA,MAAyB,QAAQ,KACrB;AACZ,QAAM,SAAS,aAAa,GAAG;AAC/B,MAAI,CAAC,OAAQ,QAAO,CAAC;AAErB,QAAM,WAAW,UAAU,YAAY,EAAE,QAAQ,aAAa,GAAG;AACjE,SAAO,EAAE,QAAQ,cAAc,GAAG,QAAQ,IAAI,OAAO,MAAM,GAAG,CAAC,CAAC,GAAG;AACrE;AAMO,SAAS,gBACd,OACA,YACG;AACH,MAAI,WAAW,UAAU,MAAM,YAAY,QAAW;AACpD,IAAC,MAAkC,UAAU,WAAW;AACxD,QAAI,WAAW,gBAAgB,MAAM,kBAAkB,QAAW;AAChE,MAAC,MAAkC,gBAAgB,WAAW;AAAA,IAChE;AAAA,EACF;AACA,SAAO;AACT;;;AC9DA,IAAAC,eAAoD;;;ACApD,IAAAC,6CAGO;AACP,IAAAC,cAA+B;;;ACExB,IAAM,uBAAuB;AAC7B,IAAM,iBAAiB;;;ACP9B,8BAAkC;AAClC,yBAA4B;AAe5B,IAAM,UAAU,IAAI,0CAAoC;AAQjD,SAAS,aAA2C;AACzD,SAAO,QAAQ,SAAS;AAC1B;AAaO,SAAS,wBAAgC;AAC9C,SAAO,YAAQ,gCAAY,CAAC,EAAE,SAAS,KAAK,CAAC;AAC/C;;;AFDA,SAAS,SAAS,GAAgC;AAChD,MAAI,OAAO,MAAM,SAAU,QAAO;AAClC,MAAI,MAAM,UAAa,MAAM,KAAM,QAAO;AAC1C,SAAO,OAAO,CAAC;AACjB;AAEA,SAAS,SAAS,GAAgC;AAChD,MAAI,OAAO,MAAM,YAAY,OAAO,SAAS,CAAC,EAAG,QAAO;AACxD,MAAI,OAAO,MAAM,YAAY,EAAE,KAAK,MAAM,MAAM,OAAO,SAAS,OAAO,CAAC,CAAC,EAAG,QAAO,OAAO,CAAC;AAC3F,SAAO;AACT;AAQA,IAAM,qBAAqB;AAC3B,IAAM,6BAA6B;AAmBnC,SAAS,WAAW,MAA0B,UAAiD;AAC7F,MAAI,SAAS,UAAa,SAAS,WAAW,EAAG,QAAO;AACxD,MAAI,MAAM;AACV,aAAW,MAAM,SAAU,OAAM,IAAI,QAAQ,IAAI,kBAAkB;AACnE,SAAO;AACT;AAEA,SAAS,WAAW,GAA6B;AAC/C,SAAO,EAAE,CAAC,IAAI,MAAO,EAAE,CAAC,IAAI;AAC9B;AAEA,SAAS,SAAS,GAAmB;AACnC,SAAO,EAAE,QAAQ,uBAAuB,MAAM;AAChD;AAYA,SAAS,gBAAgB,OAAgC,QAA+B;AACtF,QAAM,IAAI,SAAS,MAAM;AACzB,QAAM,SAAS,IAAI,OAAO,IAAI,CAAC,eAAe,SAAS,2CAAAC,oBAAG,YAAY,CAAC,GAAG;AAC1E,QAAM,YAAY,IAAI,OAAO,IAAI,CAAC,eAAe,SAAS,2CAAAA,oBAAG,eAAe,CAAC,GAAG;AAChF,QAAM,SAAS,IAAI;AAAA,IACjB,IAAI,CAAC,eAAe,SAAS,2CAAAA,oBAAG,gBAAgB,CAAC,eAAe,SAAS,2CAAAA,oBAAG,oBAAoB,CAAC;AAAA,EACnG;AAEA,QAAM,QAAQ,oBAAI,IAAgC;AAClD,QAAM,gBAAgB,oBAAI,IAAgC;AAC1D,QAAM,QAAQ,oBAAI,IAAiC;AAEnD,aAAW,CAAC,KAAK,KAAK,KAAK,OAAO,QAAQ,KAAK,GAAG;AAChD,QAAI;AACJ,QAAK,IAAI,OAAO,KAAK,GAAG,GAAI;AAC1B,YAAM,IAAI,OAAO,EAAE,CAAC,CAAC,GAAG,SAAS,KAAK,CAAC;AAAA,IACzC,WAAY,IAAI,UAAU,KAAK,GAAG,GAAI;AACpC,oBAAc,IAAI,OAAO,EAAE,CAAC,CAAC,GAAG,SAAS,KAAK,CAAC;AAAA,IACjD,WAAY,IAAI,OAAO,KAAK,GAAG,GAAI;AACjC,YAAM,IAAI,OAAO,EAAE,CAAC,CAAC;AACrB,YAAM,OAAO,SAAS,KAAK;AAC3B,UAAI,SAAS,QAAW;AACtB,cAAM,SAAS,MAAM,IAAI,CAAC,KAAK,oBAAI,IAAoB;AACvD,eAAO,IAAI,OAAO,EAAE,CAAC,CAAC,GAAG,IAAI;AAC7B,cAAM,IAAI,GAAG,MAAM;AAAA,MACrB;AAAA,IACF;AAAA,EACF;AAEA,QAAM,UAAU,CAAC,GAAG,oBAAI,IAAI,CAAC,GAAG,MAAM,KAAK,GAAG,GAAG,cAAc,KAAK,GAAG,GAAG,MAAM,KAAK,CAAC,CAAC,CAAC,EAAE;AAAA,IACxF,CAAC,GAAG,MAAM,IAAI;AAAA,EAChB;AACA,SAAO,QAAQ,IAAI,CAAC,MAAM;AACxB,UAAM,UAAuB,CAAC;AAC9B,UAAM,OAAO,MAAM,IAAI,CAAC;AACxB,QAAI,SAAS,OAAW,SAAQ,OAAO;AACvC,QAAI,UAAU,cAAc,IAAI,CAAC;AACjC,QAAI,YAAY,UAAa,MAAM,IAAI,CAAC,GAAG;AACzC,YAAM,SAAS,MAAM,IAAI,CAAC;AAC1B,gBAAU,CAAC,GAAG,OAAO,KAAK,CAAC,EACxB,KAAK,CAAC,GAAG,MAAM,IAAI,CAAC,EACpB,IAAI,CAAC,MAAM,OAAO,IAAI,CAAC,CAAC,EACxB,KAAK,EAAE;AAAA,IACZ;AACA,QAAI,YAAY,OAAW,SAAQ,UAAU;AAC7C,WAAO;AAAA,EACT,CAAC;AACH;AAGO,SAAS,UAAU,MAAyB;AACjD,SAAO,KAAK,WAAW,2CAAAA,oBAAG,uBAAuB,MAAM,iEAAsB;AAC/E;AAMO,SAAS,iBACd,MACA,KACmB;AACnB,MAAI,CAAC,UAAU,IAAI,EAAG,QAAO;AAE7B,QAAM,IAAI,KAAK;AACf,QAAM,gBAAgB,gBAAgB,GAAG,2CAAAA,oBAAG,kBAAkB;AAC9D,QAAM,iBAAiB,gBAAgB,GAAG,2CAAAA,oBAAG,mBAAmB;AAGhE,QAAM,WAAW,CAAC,GAAG,aAAa,EAAE,QAAQ,EAAE,KAAK,CAAC,OAAO,EAAE,QAAQ,IAAI,YAAY,MAAM,MAAM;AACjG,QAAM,WAAW,IAAI,OAAO,kBAAkB,CAAC;AAC/C,QAAM,SAAS;AAAA,IACb,UAAU,WAAW,cAAc,GAAG,EAAE,GAAG,WAAW,SAAS,EAAE,2CAAAA,oBAAG,WAAW,CAAC;AAAA,IAChF;AAAA,EACF;AACA,QAAM,WAAW,WAAW,eAAe,CAAC,GAAG,WAAW,SAAS,EAAE,2CAAAA,oBAAG,YAAY,CAAC,GAAG,QAAQ;AAEhG,QAAM,SAAiC,CAAC;AACxC,QAAM,eAAe,SAAS,EAAE,2CAAAA,oBAAG,sBAAsB,CAAC;AAC1D,MAAI,iBAAiB,OAAW,QAAO,gBAAgB;AACvD,QAAM,mBAAmB,SAAS,EAAE,2CAAAA,oBAAG,0BAA0B,CAAC;AAClE,MAAI,qBAAqB,OAAW,QAAO,oBAAoB;AAC/D,QAAM,cAAc,SAAS,EAAE,2CAAAA,oBAAG,qBAAqB,CAAC;AACxD,MAAI,gBAAgB,OAAW,QAAO,eAAe;AAErD,QAAM,YAAY,SAAS,EAAE,2CAAAA,oBAAG,UAAU,CAAC,KAAK,sBAAsB;AACtE,QAAM,SAAS,SAAS,EAAE,2CAAAA,oBAAG,OAAO,CAAC,KAAK;AAC1C,QAAM,UAAU,KAAK,QAAQ,SAAS,2BAAe;AACrD,QAAM,MAAM,IAAI,OAAO,oBAAI,KAAK;AAChC,QAAM,SAAS,IAAI,YAAY;AAE/B,QAAM,QAAoB;AAAA,IACxB,YAAY;AAAA,IACZ,QAAQ;AAAA,IACR,WAAW;AAAA,IACX,YAAY;AAAA,IACZ,SAAS;AAAA,IACT,gBAAgB,CAAC,UAAU,WAAW,OAAO;AAAA,IAC7C,UACE,SAAS,EAAE,2CAAAA,oBAAG,YAAY,CAAC,KAC3B,SAAS,EAAE,2CAAAA,oBAAG,UAAU,CAAC,KACzB,SAAS,EAAE,kBAAkB,CAAC,KAC9B,SAAS,EAAE,0BAA0B,CAAC;AAAA,IACxC,OAAO,SAAS,EAAE,2CAAAA,oBAAG,cAAc,CAAC;AAAA,IACpC;AAAA,IACA;AAAA,IACA,UAAU,SAAS,SACf,cAAc;AAAA,MAAI,CAAC,MACjB,EAAE,YAAY,SAAY,EAAE,GAAG,GAAG,SAAS,WAAW,EAAE,SAAS,QAAQ,EAAE,IAAI;AAAA,IACjF,IACA;AAAA,IACJ;AAAA,IACA,YAAY,KAAK,IAAI,GAAG,WAAW,KAAK,OAAO,IAAI,WAAW,KAAK,SAAS,CAAC;AAAA,IAC7E,OAAO,UAAW,KAAK,QAAQ,WAAW,UAAW;AAAA,IACrD,SAAS,CAAC;AAAA,IACV,aAAa,IAAI,OAAO;AAAA,IACxB,aAAa,IAAI,OAAO;AAAA,IACxB,kBAAkB;AAAA,EACpB;AAIA,QAAM,WAAW,SAAS,EAAE,oBAAoB,CAAC;AACjD,MAAI,aAAa,OAAW,OAAM,YAAY;AAC9C,QAAM,MAAM,SAAS,EAAE,cAAc,CAAC;AACtC,MAAI,QAAQ,OAAW,OAAM,MAAM;AAEnC,SAAO,gBAAgB,OAAO,IAAI,UAAU;AAC9C;;;AG7NA,eAAsB,WAAW,QAAsB,QAAuC;AAC5F,MAAI,OAAO,WAAW,EAAG,QAAO;AAChC,MAAI;AACF,UAAM,WAAW,MAAM,MAAM,OAAO,WAAW;AAAA,MAC7C,QAAQ;AAAA,MACR,SAAS;AAAA,QACP,eAAe,UAAU,OAAO,MAAM;AAAA,QACtC,gBAAgB;AAAA,QAChB,cAAc;AAAA,MAChB;AAAA,MACA,MAAM,KAAK,UAAU,EAAE,QAAQ,QAAQ,WAAW,CAAC;AAAA,IACrD,CAAC;AACD,QAAI,SAAS,IAAI;AACf,UAAI,OAAO,MAAO,SAAQ,IAAI,mBAAmB,OAAO,MAAM,WAAW;AACzE,aAAO;AAAA,IACT;AACA,QAAI,OAAO,MAAO,SAAQ,KAAK,6BAA6B,SAAS,MAAM,EAAE;AAC7E,WAAO;AAAA,EACT,SAAS,KAAK;AACZ,QAAI,OAAO,OAAO;AAChB,cAAQ,KAAK,uBAAuB,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG,CAAC,EAAE;AAAA,IACxF;AACA,WAAO;AAAA,EACT;AACF;;;AJrBO,IAAM,oBAAN,MAAgD;AAAA,EACrD,YACmB,QACA,YACjB;AAFiB;AACA;AAAA,EAChB;AAAA,EAFgB;AAAA,EACA;AAAA,EAGnB,OAAO,OAAuB,gBAAsD;AAClF,UAAM,SAAuB,CAAC;AAC9B,eAAW,QAAQ,OAAO;AACxB,YAAM,QAAQ,iBAAiB,MAAM,EAAE,QAAQ,KAAK,QAAQ,YAAY,KAAK,WAAW,CAAC;AACzF,UAAI,MAAO,QAAO,KAAK,KAAK;AAAA,IAC9B;AACA,QAAI,OAAO,WAAW,GAAG;AACvB,qBAAe,EAAE,MAAM,8BAAiB,QAAQ,CAAC;AACjD;AAAA,IACF;AACA,eAAW,QAAQ,KAAK,MAAM,EAC3B,KAAK,CAAC,OAAO,eAAe,EAAE,MAAM,KAAK,8BAAiB,UAAU,8BAAiB,OAAO,CAAC,CAAC,EAC9F,MAAM,MAAM,eAAe,EAAE,MAAM,8BAAiB,OAAO,CAAC,CAAC;AAAA,EAClE;AAAA,EAEA,WAA0B;AACxB,WAAO,QAAQ,QAAQ;AAAA,EACzB;AAAA,EAEA,aAA4B;AAC1B,WAAO,QAAQ,QAAQ;AAAA,EACzB;AACF;;;AKvCA,IAAAC,6CAA0C;AAUnC,IAAM,4BAAN,MAAyD;AAAA,EAC9D,QAAQ,MAAY,gBAA+B;AACjD,UAAM,MAAM,WAAW;AACvB,QAAI,CAAC,IAAK;AACV,QAAI,IAAI,aAAa,KAAK,WAAW,2CAAAC,oBAAG,UAAU,MAAM,QAAW;AACjE,WAAK,aAAa,2CAAAA,oBAAG,YAAY,IAAI,SAAS;AAAA,IAChD;AACA,QAAI,IAAI,UAAU,KAAK,WAAW,2CAAAA,oBAAG,OAAO,MAAM,QAAW;AAC3D,WAAK,aAAa,2CAAAA,oBAAG,SAAS,IAAI,MAAM;AAAA,IAC1C;AACA,QAAI,IAAI,YAAY,KAAK,WAAW,oBAAoB,MAAM,QAAW;AACvE,WAAK,aAAa,sBAAsB,IAAI,QAAQ;AAAA,IACtD;AACA,QAAI,IAAI,OAAO,KAAK,WAAW,cAAc,MAAM,QAAW;AAC5D,WAAK,aAAa,gBAAgB,IAAI,GAAG;AAAA,IAC3C;AAAA,EACF;AAAA,EAEA,MAAM,OAA2B;AAAA,EAEjC;AAAA,EAEA,WAA0B;AACxB,WAAO,QAAQ,QAAQ;AAAA,EACzB;AAAA,EAEA,aAA4B;AAC1B,WAAO,QAAQ,QAAQ;AAAA,EACzB;AACF;;;AXzBA,IAAM,aAAa,oBAAI,KAAK;AAS5B,IAAI,SAA6B;AAqB1B,SAAS,KAAK,UAAwB,CAAC,GAAgB;AAC5D,MAAI,QAAQ;AACV,QAAI,OAAO,OAAO,MAAO,SAAQ,KAAK,0DAA0D;AAChG,WAAO;AAAA,EACT;AAEA,QAAM,SAAS,cAAc,OAAO;AACpC,QAAM,aAAa,kBAAkB,UAAU;AAE/C,QAAM,WAAW,IAAI,yCAAmB;AAAA,IACtC,gBAAgB;AAAA;AAAA,MAEd,IAAI,0BAA0B;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,MAa9B,IAAI,4DAAgC,EAAE,UAAU,IAAI,kBAAkB,QAAQ,UAAU,EAAE,CAAC;AAAA,IAC7F;AAAA,EACF,CAAC;AACD,WAAS,SAAS;AAElB,QAAM,wBAAwB,IAAI,kEAAsB;AACxD,QAAM,2BAA2B,IAAI,wEAAyB;AAG9D,QAAM,6BAA6B,IAAI,2BAA2B;AAIlE,QAAM,0BAA0B,IAAI,wBAAwB;AAC5D,wDAAyB;AAAA,IACvB,gBAAgB;AAAA,IAChB,kBAAkB;AAAA,MAChB;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IACF;AAAA,EACF,CAAC;AAOD,8BAA4B;AAAA,IAC1B,EAAE,SAAS,CAAC,QAAQ,GAAG,iBAAiB,sBAAsB;AAAA,IAC9D,EAAE,SAAS,CAAC,mBAAmB,GAAG,iBAAiB,yBAAyB;AAAA,IAC5E,EAAE,SAAS,CAAC,eAAe,GAAG,iBAAiB,2BAA2B;AAAA,EAC5E,CAAC;AAED,WAAS;AAAA,IACP;AAAA,IACA;AAAA,IACA,UAAU,YAAY;AACpB,UAAI;AACF,cAAM,SAAS,SAAS;AAAA,MAC1B,UAAE;AACA,iBAAS;AAAA,MACX;AAAA,IACF;AAAA,EACF;AAIA,MAAI,WAAW,OAAQ,MAAK,uBAAuB,QAAQ,UAAU;AAErE,MAAI,OAAO,OAAO;AAChB,YAAQ;AAAA,MACN,oCAAoC,OAAO,QAAQ,SAAS,OAAO,WAAW,MAC3E,WAAW,SAAS,aAAa,WAAW,OAAO,MAAM,GAAG,CAAC,CAAC,KAAK,MACpE;AAAA,IACJ;AAAA,EACF;AACA,SAAO;AACT;AAEA,eAAe,uBAAuB,QAAqB,YAAuC;AAChG,QAAM,UAAS,oBAAI,KAAK,GAAE,YAAY;AACtC,QAAM;AAAA,IACJ;AAAA,MACE;AAAA,QACE,YAAY;AAAA,QACZ,QAAQ;AAAA,QACR,WAAW;AAAA,QACX,kBAAkB;AAAA,QAClB,YAAY,UAAU,WAAW,YAAY;AAAA,QAC7C,SAAS,WAAW;AAAA,QACpB,eAAe,WAAW;AAAA,QAC1B,gBAAgB;AAAA,QAChB,SAAS;AAAA,QACT,aAAa,OAAO;AAAA,QACpB,aAAa,OAAO;AAAA,MACtB;AAAA,IACF;AAAA,IACA;AAAA,EACF;AACF;;;AYxIA,yBAAyB;AAEzB,IAAI;AACF,OAAK;AACP,SAAS,KAAK;AACZ,UAAQ,KAAK,+BAA+B,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG,CAAC,EAAE;AAChG;","names":["register","import_instrumentation","import_api","SC","import_api","import_instrumentation","MODULE_NAME","INSTRUMENTATION_NAME","_isPatched","INSTRUMENTATION_NAME","MODULE_NAME","_isPatched","import_core","import_openinference_semantic_conventions","import_api","SC","import_openinference_semantic_conventions","SC"]}
|
|
1
|
+
{"version":3,"sources":["../src/esm-hook.ts","../src/index.ts","../src/google-genai-instrumentation.ts","../src/version.ts","../src/vercel-ai-instrumentation.ts","../src/config.ts","../src/deployment.ts","../src/exporter.ts","../src/event.ts","../src/attributes.ts","../src/session.ts","../src/transport.ts","../src/processor.ts","../src/register.ts"],"sourcesContent":["import * as nodeModule from 'node:module';\nimport { diag } from '@opentelemetry/api';\n// LOAD-BEARING DEDUP INVARIANT: this `Hook` MUST come from the SAME import-in-the-middle instance as the\n// loader we register (`@opentelemetry/instrumentation/hook.mjs`, which imports its own iitm) — otherwise\n// our hook registers in a different registry and its callback never fires (silent big-3 ESM no-capture,\n// while CJS keeps working). We pin `import-in-the-middle` to the same `^3` range @opentelemetry/\n// instrumentation uses so npm dedupes them to one instance. version-pin.test.ts guards this invariant\n// directly (asserts both resolve to one physical package); the esm-bootstrap subprocess test is the\n// functional backstop. If you bump @opentelemetry/instrumentation, re-verify the dedup.\nimport { Hook } from 'import-in-the-middle';\n\n// Turn on ESM auto-instrumentation. Node's module hooks come in two halves: a require-hook\n// (require-in-the-middle) that fires for CJS `require(...)`, and an import-hook (import-in-the-middle)\n// that fires for ESM `import ...`. @opentelemetry/instrumentation sets the require-hook up on its own,\n// but the IMPORT-hook only fires if the import-in-the-middle loader is registered at startup — which\n// nothing does by default. So without this, ESM apps (the majority of modern AI apps — Next.js et al.)\n// get NO auto-capture for ANY provider, because every provider resolves its `import` condition to true\n// ESM. This registers the loader hook @opentelemetry/instrumentation ships, so ESM imports are\n// instrumented too.\n//\n// Constraints (all load-bearing):\n// - Only meaningful on the `--import @scope-analytics/node/register` bootstrap: an ESM loader must be\n// registered BEFORE the app's modules load, which `--import` guarantees and a late init() cannot.\n// In the CJS (`--require`) build, import.meta.url is unavailable, so we no-op there (CJS apps are\n// captured via the require-hook regardless).\n// - module.register() needs Node >= 18.19 / >= 20.6; we feature-detect and no-op on older runtimes.\n// - NEVER throws (rule b): any failure degrades to CJS-only capture, never a crashed host startup.\n// - Opt-out via SCOPE_DISABLE_ESM_HOOK=1 for hosts that don't want a loader processing their imports.\n\nconst HOOK_SPECIFIER = '@opentelemetry/instrumentation/hook.mjs';\n\n// True once we've actually registered the IITM loader (only on the `--import` ESM bootstrap). Gates\n// registerEsmManualInstrument so we never create IITM hooks when the loader isn't active (e.g. the CJS\n// build or the explicit init() path). register.ts is bundled standalone, so enableEsmInstrumentation()\n// and registerEsmManualInstrument() share this module instance within the bootstrap bundle.\nlet _loaderRegistered = false;\n\nfunction esmHookDisabled(): boolean {\n const v = process.env.SCOPE_DISABLE_ESM_HOOK;\n return v === '1' || v === 'true' || v === 'TRUE';\n}\n\n/** Resolve the parent URL used to resolve the loader specifier. Only available when running as ESM\n * (the `--import` build); returns undefined in the CJS build, where the ESM hook does not apply. */\nfunction moduleUrl(): string | undefined {\n try {\n // In the ESM build this is the register.js module URL; in the CJS build import.meta is absent.\n return import.meta.url;\n } catch {\n return undefined;\n }\n}\n\n/** Register the import-in-the-middle ESM loader hook (best-effort). Idempotent enough for our use —\n * called once at bootstrap. */\nexport function enableEsmInstrumentation(): void {\n if (esmHookDisabled()) return;\n const parentURL = moduleUrl();\n if (!parentURL) return; // CJS build / no ESM context — require-hook still covers CJS apps.\n const register = (nodeModule as { register?: (s: string, p: string) => unknown }).register;\n if (typeof register !== 'function') return; // Node < 18.19 / < 20.6\n try {\n register(HOOK_SPECIFIER, parentURL);\n _loaderRegistered = true;\n diag.debug('[scope] ESM auto-instrumentation enabled (import-in-the-middle loader registered).');\n } catch (err) {\n diag.debug(\n `[scope] ESM auto-instrumentation not enabled (${err instanceof Error ? err.message : String(err)}); ` +\n 'CJS apps are still captured via the require-hook.',\n );\n }\n}\n\n/** A provider instrumentation that can be applied to an already-loaded module namespace. */\nexport interface ManualInstrumentable {\n manuallyInstrument(moduleExports: unknown): unknown;\n}\n\n/**\n * Force the require-hook instrumentations to also apply under ESM. OpenTelemetry's own IITM hook does\n * NOT auto-invoke these instrumentations' patch under ESM (their entry modules are re-export shims — the\n * auto-hook doesn't fire), yet their patch logic works fine on the ESM namespace (verified). So when the\n * ESM loader is active (the `--import` bootstrap), we register our OWN import-in-the-middle hook that\n * calls each instrumentation's `manuallyInstrument(moduleExports)` as the module is imported.\n *\n * Only the openai/anthropic/google-genai instrumentations need this. The Vercel AI SDK is excluded — its\n * OTel auto-patch DOES fire under ESM (its `ai` entry points are top-level functions IITM intercepts).\n *\n * No-ops unless we registered the loader (CJS build / explicit init() path → ESM capture isn't in play;\n * those are covered by the require-hook). NEVER throws (rule b: a telemetry failure can't break startup).\n */\nexport function registerEsmManualInstrument(\n entries: Array<{ modules: string[]; instrumentation: ManualInstrumentable }>,\n): void {\n if (!_loaderRegistered) return;\n // Map every module specifier → its instrumentation, then one hook routes by the imported name.\n const byModule = new Map<string, ManualInstrumentable>();\n for (const { modules, instrumentation } of entries) {\n for (const m of modules) byModule.set(m, instrumentation);\n }\n if (byModule.size === 0) return;\n try {\n // eslint-disable-next-line no-new -- the Hook self-registers with the active IITM loader.\n new Hook([...byModule.keys()], (exported: unknown, name: string) => {\n const instrumentation = byModule.get(name);\n if (!instrumentation) return exported;\n try {\n instrumentation.manuallyInstrument(exported);\n } catch (err) {\n diag.debug(\n `[scope] ESM manual instrument of '${name}' failed (${err instanceof Error ? err.message : String(err)}).`,\n );\n }\n return exported;\n });\n diag.debug(`[scope] ESM manual instrumentation registered for: ${[...byModule.keys()].join(', ')}.`);\n } catch (err) {\n diag.debug(\n `[scope] ESM manual instrumentation not registered (${err instanceof Error ? err.message : String(err)}).`,\n );\n }\n}\n","import { createRequire } from 'node:module';\nimport { pathToFileURL } from 'node:url';\nimport { registerInstrumentations, type Instrumentation } from '@opentelemetry/instrumentation';\nimport { NodeTracerProvider } from '@opentelemetry/sdk-trace-node';\nimport { OpenInferenceBatchSpanProcessor } from '@arizeai/openinference-vercel';\nimport { GoogleGenAIInstrumentation } from './google-genai-instrumentation';\nimport { VercelAIInstrumentation } from './vercel-ai-instrumentation';\nimport { registerEsmManualInstrument, type ManualInstrumentable } from './esm-hook';\nimport { resolveConfig, type ScopeConfig, type ScopeOptions } from './config';\nimport { resolveDeployment, type Deployment } from './deployment';\nimport { ScopeSpanExporter } from './exporter';\nimport { ScopeContextSpanProcessor } from './processor';\nimport { shipEvents } from './transport';\nimport { SDK_SOURCE } from './version';\n\n// A require() that resolves from THIS module, working in both the ESM and CJS builds. We deliberately\n// do NOT reference the bare `require` keyword — esbuild rewrites it to a non-functional shim in the ESM\n// bundle. Instead we synthesize one via createRequire from the module's own location (ESM:\n// import.meta.url; CJS: the esbuild stub leaves import.meta.url undefined, so fall back to __filename).\n// Used to OPTIONALLY load the Arize provider instrumentations: the openai instrumentation package\n// `require()`s `openai` at MODULE TOP-LEVEL (anthropic's doesn't today but may in a future version), so a\n// static import would throw and crash a host that doesn't have that SDK installed (rule b — telemetry\n// must never break the host). We therefore load BOTH only when the provider SDK is resolvable in the\n// host, and swallow any load failure. Our own google-genai/vercel instrumentations read the SDK\n// structurally (no top-level require), so they're always safe to construct.\nfunction _makeRequire(): NodeRequire | null {\n try {\n if (typeof import.meta !== 'undefined' && import.meta.url) return createRequire(import.meta.url);\n } catch {\n /* import.meta unavailable in this build */\n }\n try {\n if (typeof __filename === 'string') return createRequire(pathToFileURL(__filename).href);\n } catch {\n /* __filename unavailable in this build */\n }\n return null;\n}\nconst _require = _makeRequire();\n\ntype LoadedInstrumentation = Instrumentation & ManualInstrumentable;\n\nfunction loadInstrumentationIfPresent(\n providerPackage: string,\n load: (req: NodeRequire) => LoadedInstrumentation,\n): LoadedInstrumentation | null {\n if (!_require) return null;\n try {\n _require.resolve(providerPackage); // is the provider SDK installed in the host app?\n } catch {\n return null; // not installed — nothing to instrument (a provider they don't use)\n }\n try {\n return load(_require);\n } catch {\n return null; // defensive: a load failure must never crash the host\n }\n}\n\n// Process start time, captured once at module load — used for a stable deployment_id.\nconst STARTED_AT = new Date();\n\nexport interface ScopeHandle {\n config: ScopeConfig;\n deployment: Deployment;\n /** Flush + stop the tracer (best-effort). Safe to call multiple times. */\n shutdown: () => Promise<void>;\n}\n\nlet active: ScopeHandle | null = null;\n\n/**\n * Start the Scope tracer: wire an OpenTelemetry NodeTracerProvider whose LLM spans — from the\n * OpenInference OpenAI/Anthropic instrumentations, our hand-built Google Gen AI instrumentation,\n * and (translated) the Vercel AI SDK — are mapped to Scope events and shipped to the Scope backend.\n * Idempotent — a second call returns the existing handle.\n *\n * Zero-code path: `NODE_OPTIONS=\"--import @scope-analytics/node/register\" node server.js`.\n * Explicit path: `import { init } from '@scope-analytics/node'; init();` (before importing your LLM SDK).\n *\n * NOTE (Vercel AI SDK): the `ai` package emits NOTHING unless its telemetry is enabled per call. The\n * VercelAIInstrumentation registered below makes capture zero-code by injecting\n * `experimental_telemetry: { isEnabled: true }` into generateText/streamText/generateObject/streamObject\n * (deep-merged with any telemetry config you already pass; an explicit `isEnabled: false` is respected).\n *\n * NOTE (ESM): auto-instrumentation of ESM `import`s requires the import-in-the-middle loader, which the\n * `--import @scope-analytics/node/register` bootstrap registers (see src/esm-hook.ts). On that path, all four\n * providers are captured under both CommonJS and ESM. The explicit init() path covers CommonJS via the\n * require-hook (an ESM loader can't retroactively hook already-imported modules).\n */\nexport function init(options: ScopeOptions = {}): ScopeHandle {\n if (active) {\n if (active.config.debug) console.warn('[scope] init() called again; reusing the running tracer.');\n return active;\n }\n\n const config = resolveConfig(options);\n const deployment = resolveDeployment(STARTED_AT);\n\n const provider = new NodeTracerProvider({\n spanProcessors: [\n // Stamp session/user from AsyncLocalStorage onto each span before it's read at export.\n new ScopeContextSpanProcessor(),\n // Batch spans, then translate + ship them to Scope. We route through the OpenInference Vercel\n // span processor (rather than a plain BatchSpanProcessor) so the Vercel AI SDK's own\n // `ai.*`/`gen_ai.*` spans are translated to OpenInference `llm.*` attributes before our exporter\n // reads them — the only way to capture the Vercel AI SDK, which emits its own spans instead of\n // calling a provider SDK we instrument. On spans that are ALREADY OpenInference\n // (OpenAI/Anthropic/Gemini) the translation is additive-only (it just re-affirms their span\n // kind), so those keep flowing through unchanged. NB: the adapter tags EVERY span the process\n // ends (a non-LLM span just gets an OpenInference span-kind attribute), but ScopeSpanExporter\n // stays the single gate for which spans become events (LLM only) — so no spanFilter is needed,\n // and any non-LLM span (Vercel's AGENT/TOOL spans, or a host's own HTTP/DB spans) is dropped\n // there. Vercel emits a parent (AGENT) + child (LLM) span per call; the AGENT span is dropped,\n // leaving exactly one llm_call per call.\n new OpenInferenceBatchSpanProcessor({ exporter: new ScopeSpanExporter(config, deployment) }),\n ],\n });\n provider.register();\n\n // Arize provider instrumentations — loaded ONLY if the provider SDK is installed in the host (the\n // openai package require()s its SDK at top-level; see loadInstrumentationIfPresent). A host that uses,\n // say, only the Vercel AI SDK won't have `openai`/`@anthropic-ai/sdk` installed — and must not crash.\n const openaiInstrumentation = loadInstrumentationIfPresent(\n 'openai',\n (req) => new (req('@arizeai/openinference-instrumentation-openai').OpenAIInstrumentation)(),\n );\n const anthropicInstrumentation = loadInstrumentationIfPresent(\n '@anthropic-ai/sdk',\n (req) => new (req('@arizeai/openinference-instrumentation-anthropic').AnthropicInstrumentation)(),\n );\n // Scope-authored OTel instrumentation: no Arize drop-in exists for @google/genai. Reads the SDK\n // structurally (no top-level require), so it's always safe to construct + flows through the same pipeline.\n const googleGenAIInstrumentation = new GoogleGenAIInstrumentation();\n // Scope-authored instrumentation for the Vercel AI SDK. Emits no spans — it only injects\n // `experimental_telemetry: { isEnabled: true }` into the `ai` entry points so the SDK's own spans are\n // emitted (captured by the OpenInferenceBatchSpanProcessor above). No top-level `ai` require — always safe.\n const vercelAIInstrumentation = new VercelAIInstrumentation();\n\n const instrumentations: Instrumentation[] = [googleGenAIInstrumentation, vercelAIInstrumentation];\n if (openaiInstrumentation) instrumentations.push(openaiInstrumentation);\n if (anthropicInstrumentation) instrumentations.push(anthropicInstrumentation);\n registerInstrumentations({ tracerProvider: provider, instrumentations });\n\n // ESM coverage (only on the `--import` bootstrap, which registered the IITM loader): OpenTelemetry's\n // own IITM hook does NOT auto-invoke the openai/anthropic/google-genai instrumentations under ESM\n // (their entry modules are re-export shims, so the hook doesn't fire), even though their patch works\n // on the ESM namespace. So apply them explicitly as those modules are imported — only for the ones we\n // actually loaded. Vercel is excluded — its auto-patch DOES fire under ESM. No-op off the bootstrap.\n const esmManual: Array<{ modules: string[]; instrumentation: ManualInstrumentable }> = [];\n if (openaiInstrumentation) esmManual.push({ modules: ['openai'], instrumentation: openaiInstrumentation });\n if (anthropicInstrumentation)\n esmManual.push({ modules: ['@anthropic-ai/sdk'], instrumentation: anthropicInstrumentation });\n esmManual.push({ modules: ['@google/genai'], instrumentation: googleGenAIInstrumentation });\n registerEsmManualInstrument(esmManual);\n\n active = {\n config,\n deployment,\n shutdown: async () => {\n try {\n await provider.shutdown();\n } finally {\n active = null;\n }\n },\n };\n\n // Announce this deploy once per process (PRODUCT.md §4.2). The backend dedups by\n // (tenant, git_sha), so emit-once-per-process is safe across workers/cold starts.\n if (deployment.gitSha) void emitDeploymentDetected(config, deployment);\n\n if (config.debug) {\n console.log(\n `[scope] tracer started (endpoint=${config.endpoint}, env=${config.environment}` +\n (deployment.gitSha ? `, git_sha=${deployment.gitSha.slice(0, 7)}` : '') +\n ').',\n );\n }\n return active;\n}\n\nasync function emitDeploymentDetected(config: ScopeConfig, deployment: Deployment): Promise<void> {\n const nowIso = new Date().toISOString();\n await shipEvents(\n [\n {\n event_type: 'deployment_detected',\n source: SDK_SOURCE,\n timestamp: nowIso,\n server_timestamp: nowIso,\n session_id: `deploy_${deployment.deploymentId}`,\n git_sha: deployment.gitSha,\n deployment_id: deployment.deploymentId,\n is_user_facing: false,\n success: true,\n environment: config.environment,\n sdk_version: config.sdkVersion,\n },\n ],\n config,\n );\n}\n\nexport { resolveConfig, ScopeConfigError } from './config';\nexport type { ScopeConfig, ScopeOptions } from './config';\nexport { runWithContext, getContext, setUser } from './session';\nexport type { ScopeContextData } from './session';\nexport { spanToScopeEvent, isLlmSpan, CREDENTIAL_REDACT_PATTERNS } from './event';\nexport type { ScopeEvent, SpanLike } from './event';\nexport { GoogleGenAIInstrumentation, isGoogleGenAIPatched } from './google-genai-instrumentation';\nexport { VercelAIInstrumentation, isVercelAIPatched } from './vercel-ai-instrumentation';\nexport { ScopeSpanExporter } from './exporter';\nexport { detectGitSha, resolveDeployment } from './deployment';\nexport type { Deployment } from './deployment';\n","import {\n context,\n diag,\n SpanKind,\n SpanStatusCode,\n trace,\n type Attributes,\n type Span,\n} from '@opentelemetry/api';\nimport { isTracingSuppressed } from '@opentelemetry/core';\nimport {\n InstrumentationBase,\n InstrumentationNodeModuleDefinition,\n isWrapped,\n type InstrumentationConfig,\n} from '@opentelemetry/instrumentation';\nimport {\n LLMProvider,\n MimeType,\n OpenInferenceSpanKind,\n SemanticConventions as SC,\n} from '@arizeai/openinference-semantic-conventions';\nimport { SDK_VERSION } from './version';\n\n// Scope-authored OpenTelemetry instrumentation for the unified Google Gen AI SDK (@google/genai).\n//\n// WHY HAND-BUILT: there is no Arize OpenInference instrumentation for @google/genai on npm (unlike\n// openai/anthropic, which we get as drop-ins). So we author a minimal OTel instrumentation that emits\n// the SAME OpenInference `llm.*` span attributes our event.ts mapper already reads — the span then\n// flows through the exact same pipeline (ScopeContextSpanProcessor → ScopeSpanExporter →\n// spanToScopeEvent) as every other provider. This is the reusable pattern for any provider without a\n// drop-in (Mistral next).\n//\n// PATCH POINT (load-bearing, see the @google/genai probe): the PUBLIC `models.generateContent` /\n// `generateContentStream` are INSTANCE arrow-function properties (own props on each Models instance) —\n// NOT prototype methods — so they cannot be wrapped on the prototype. The public methods delegate to\n// `Models.prototype.generateContentInternal` / `generateContentStreamInternal`, which ARE real\n// prototype methods. Wrapping those covers every client/instance with one wrap. (Internal-method names\n// are version-sensitive → @google/genai is pinned and the version-pin drift guard forces re-verification\n// on every bump.)\n//\n// EXTRACTION PARITY: extraction mirrors backend-sdk/.../patches/google_genai_patch.py (provider\n// \"google\", model stripped of \"models/\", `.text` read under a guard with a candidates[] fallback,\n// `contents` normalized to {role,content}, usage → prompt/completion/total) so the Python and Node SDKs\n// emit a wire-identical EVENT SHAPE (CLAUDE.md §1.6). Like the Python SDK, `config.systemInstruction`\n// is intentionally NOT captured (a shared, tracked gap — keeping the two SDKs identical beats adding it\n// to one). Two known behavioral divergences from the Python patcher, both because we wrap the INTERNAL\n// method (Python wraps the public one):\n// - Automatic Function Calling (a CallableTool in config.tools): the public method loops, calling the\n// internal method once per remote round → Node emits one llm_call PER ROUND (each a real model\n// round-trip with its own tokens), whereas the Python patcher emits a single event for the final\n// result. Tracked for cross-SDK alignment; the common (no-AFC) path is 1:1.\n// - chats.sendMessage routes through the same internal method, so it IS captured on Node (with the\n// conversation history as `contents`); the Python patcher defers the Chat surface. A Node bonus,\n// noted here for honesty about the prompt shape on that path.\n\nconst MODULE_NAME = '@google/genai';\nconst INSTRUMENTATION_NAME = '@scope-analytics/node/instrumentation-google-genai';\n\nlet _isPatched = false;\n/** True once @google/genai's Models prototype has been patched (mirrors the Arize isPatched()). */\nexport function isGoogleGenAIPatched(): boolean {\n return _isPatched;\n}\n\n// --- minimal structural types we read at runtime. @google/genai is a peer/devDependency, NEVER a\n// runtime dependency of @scope-analytics/node (the host app brings its own), so we read its shapes\n// structurally rather than importing its types. ---\ntype GenerateFn = (this: unknown, ...args: unknown[]) => unknown;\ninterface GenAIPart {\n text?: unknown;\n}\ninterface GenAIContent {\n role?: unknown;\n parts?: GenAIPart[];\n}\ninterface GenAICandidate {\n content?: GenAIContent;\n}\ninterface GenAIUsage {\n promptTokenCount?: unknown;\n candidatesTokenCount?: unknown;\n totalTokenCount?: unknown;\n}\ninterface GenAIResponse {\n // `text` is a convenience GETTER: on the pinned 2.8.0 it console.warns + returns the concatenation\n // of text parts (or undefined) on multi-part/function-call responses; on other versions in the\n // supported range it can THROW. We read it under a guard and fall back to candidates[] either way.\n readonly text?: unknown;\n candidates?: GenAICandidate[];\n usageMetadata?: GenAIUsage;\n}\ninterface GenerateParams {\n model?: unknown;\n contents?: unknown;\n}\ninterface ModelsProto {\n generateContentInternal?: GenerateFn;\n generateContentStreamInternal?: GenerateFn;\n}\ninterface WrappableProto {\n generateContentInternal: GenerateFn;\n generateContentStreamInternal: GenerateFn;\n}\ninterface GenAIModuleExports {\n Models?: { prototype?: ModelsProto };\n default?: GenAIModuleExports;\n scopePatched?: boolean;\n}\ninterface NormalizedMessage {\n role?: string;\n content?: string;\n}\n\n// --- pure helpers (mirror the Python patcher) --------------------------------\nfunction asFiniteNumber(v: unknown): number | undefined {\n if (typeof v === 'number' && Number.isFinite(v)) return v;\n if (typeof v === 'string' && v.trim() !== '' && Number.isFinite(Number(v))) return Number(v);\n return undefined;\n}\n\nfunction safeJsonStringify(v: unknown): string {\n try {\n return JSON.stringify(v) ?? String(v);\n } catch {\n return '[unserializable]';\n }\n}\n\nfunction errMessage(err: unknown): string {\n const m = (err as { message?: unknown } | null)?.message;\n return m != null ? String(m) : 'error';\n}\n\nfunction isPromiseLike(v: unknown): v is Promise<unknown> {\n return v != null && typeof (v as { then?: unknown }).then === 'function';\n}\n\n/** Model name from request params, stripping the \"models/\" prefix (Python `_model_name`). */\nfunction modelName(params: GenerateParams): string {\n const m = typeof params.model === 'string' ? params.model : 'gemini';\n return m.startsWith('models/') ? m.slice('models/'.length) : m;\n}\n\n/**\n * Normalize @google/genai `contents` (string | Content[] | Part[] | {role,content}[]) into the\n * universal {role,content} messages — the same normalization as the Python SDK's\n * GoogleGenaiPatcher._messages, so both SDKs emit a wire-identical event.\n */\nfunction normalizeContents(contents: unknown): NormalizedMessage[] {\n if (typeof contents === 'string') return [{ role: 'user', content: contents }];\n if (Array.isArray(contents)) {\n const msgs: NormalizedMessage[] = [];\n for (const item of contents) {\n if (typeof item === 'string') {\n msgs.push({ role: 'user', content: item });\n } else if (item && typeof item === 'object') {\n const obj = item as Record<string, unknown>;\n if ('content' in obj) {\n // already a {role, content} message — pass through (stringify non-string content for OTel)\n msgs.push({\n role: typeof obj.role === 'string' ? obj.role : 'user',\n content: typeof obj.content === 'string' ? obj.content : safeJsonStringify(obj.content),\n });\n } else if ('parts' in obj) {\n // the idiomatic unified-SDK turn: {role, parts:[{text}]} — flatten the parts' text\n const parts = Array.isArray(obj.parts) ? (obj.parts as GenAIPart[]) : [];\n const content = parts\n .filter((p) => p && typeof p.text === 'string')\n .map((p) => p.text as string)\n .join('');\n msgs.push({ role: typeof obj.role === 'string' ? obj.role : 'user', content });\n } else if (typeof obj.text === 'string') {\n // a bare Part with .text\n msgs.push({ role: 'user', content: obj.text });\n }\n }\n }\n return msgs.length ? msgs : [{ role: 'user', content: safeJsonStringify(contents) }];\n }\n if (contents == null) return [];\n return [{ role: 'user', content: safeJsonStringify(contents) }];\n}\n\n/** Response text, reading the `.text` getter under a broad guard (it can throw or warn), then falling\n * back to candidates[].content.parts[].text — exactly the Python `_response_text`. */\nfunction responseText(resp: GenAIResponse | undefined): string {\n let text: unknown;\n try {\n text = resp?.text;\n } catch {\n text = undefined;\n }\n if (typeof text === 'string' && text) return text;\n let out = '';\n // Array.isArray (not just `?? []`) so a truthy non-array candidates/parts can't throw \"not iterable\"\n // — keeps the helper safe in isolation (the template the next hand-built instrumentation copies).\n const candidates = Array.isArray(resp?.candidates) ? (resp?.candidates as GenAICandidate[]) : [];\n for (const cand of candidates) {\n const parts = Array.isArray(cand?.content?.parts) ? (cand?.content?.parts as GenAIPart[]) : [];\n for (const part of parts) {\n if (typeof part?.text === 'string') out += part.text;\n }\n }\n return out;\n}\n\nfunction inputAttributes(params: GenerateParams): Attributes {\n const attrs: Attributes = {\n [SC.OPENINFERENCE_SPAN_KIND]: OpenInferenceSpanKind.LLM,\n [SC.LLM_PROVIDER]: LLMProvider.GOOGLE,\n [SC.LLM_MODEL_NAME]: modelName(params),\n [SC.INPUT_VALUE]: safeJsonStringify(params),\n [SC.INPUT_MIME_TYPE]: MimeType.JSON,\n };\n normalizeContents(params.contents).forEach((msg, i) => {\n const prefix = `${SC.LLM_INPUT_MESSAGES}.${i}.`;\n if (msg.role !== undefined) attrs[`${prefix}${SC.MESSAGE_ROLE}`] = msg.role;\n if (msg.content !== undefined) attrs[`${prefix}${SC.MESSAGE_CONTENT}`] = msg.content;\n });\n return attrs;\n}\n\nfunction setOutputAttributes(span: Span, text: string, usage: GenAIUsage | undefined): void {\n const attrs: Attributes = {\n [SC.OUTPUT_VALUE]: text,\n [SC.OUTPUT_MIME_TYPE]: MimeType.TEXT,\n [`${SC.LLM_OUTPUT_MESSAGES}.0.${SC.MESSAGE_ROLE}`]: 'model',\n [`${SC.LLM_OUTPUT_MESSAGES}.0.${SC.MESSAGE_CONTENT}`]: text,\n };\n if (usage) {\n // Match the Python SDK: when usage is present, always emit all three counts (0-filled), so the\n // event's `tokens` object is {prompt_tokens, completion_tokens, total_tokens} for both SDKs.\n attrs[SC.LLM_TOKEN_COUNT_PROMPT] = asFiniteNumber(usage.promptTokenCount) ?? 0;\n attrs[SC.LLM_TOKEN_COUNT_COMPLETION] = asFiniteNumber(usage.candidatesTokenCount) ?? 0;\n attrs[SC.LLM_TOKEN_COUNT_TOTAL] = asFiniteNumber(usage.totalTokenCount) ?? 0;\n }\n span.setAttributes(attrs);\n}\n\n// endOk / endWithError must NEVER throw: they run in the user's promise continuations, so a capture-side\n// error here would otherwise reject a successful call (or mask the real error). The whole body is\n// guarded, and the span is always ended (rule b: a telemetry failure must never break the host app).\nfunction endOk(span: Span, resp: GenAIResponse | undefined): void {\n try {\n setOutputAttributes(span, responseText(resp), resp?.usageMetadata);\n span.setStatus({ code: SpanStatusCode.OK });\n } catch {\n /* capture-side error swallowed — must not surface to the caller */\n }\n try {\n span.end();\n } catch {\n /* ignore */\n }\n}\n\nfunction endWithError(span: Span, err: unknown): void {\n try {\n span.recordException(err as Error);\n span.setStatus({ code: SpanStatusCode.ERROR, message: errMessage(err) });\n } catch {\n /* ignore */\n }\n try {\n span.end();\n } catch {\n /* ignore */\n }\n}\n\nexport class GoogleGenAIInstrumentation extends InstrumentationBase {\n constructor(config: InstrumentationConfig = {}) {\n super(INSTRUMENTATION_NAME, SDK_VERSION, config);\n }\n\n protected init(): InstrumentationNodeModuleDefinition {\n return new InstrumentationNodeModuleDefinition(\n MODULE_NAME,\n ['*'],\n (moduleExports: GenAIModuleExports) => this.patch(moduleExports),\n (moduleExports: GenAIModuleExports) => this.unpatch(moduleExports),\n );\n }\n\n /** ESM escape hatch — the require-hook doesn't fire for `import` (mirrors the Arize instrumentations). */\n manuallyInstrument(moduleExports: GenAIModuleExports): void {\n diag.debug(`Manually instrumenting ${MODULE_NAME}`);\n this.patch(moduleExports);\n }\n\n private patch(moduleExports: GenAIModuleExports): GenAIModuleExports {\n if (!moduleExports || moduleExports.scopePatched || _isPatched) return moduleExports;\n const m = moduleExports.default || moduleExports;\n const proto = m?.Models?.prototype;\n if (!proto || typeof proto.generateContentInternal !== 'function') {\n diag.warn(`[scope] cannot find Models.prototype.generateContentInternal in ${MODULE_NAME}`);\n return moduleExports;\n }\n const wrappable = proto as unknown as WrappableProto;\n this._wrap(wrappable, 'generateContentInternal', this._wrapGenerate(false));\n if (typeof proto.generateContentStreamInternal === 'function') {\n this._wrap(wrappable, 'generateContentStreamInternal', this._wrapGenerate(true));\n }\n _isPatched = true;\n try {\n moduleExports.scopePatched = true;\n } catch {\n /* module frozen (bundler/Deno) — the _isPatched flag still guards double-patching */\n }\n return moduleExports;\n }\n\n private unpatch(moduleExports: GenAIModuleExports): void {\n const m = moduleExports?.default || moduleExports;\n const proto = m?.Models?.prototype;\n if (proto) {\n // Only unwrap what we actually wrapped — `_unwrap` on a never-wrapped method logs a spurious error.\n if (isWrapped(proto.generateContentInternal)) {\n this._unwrap(proto as unknown as WrappableProto, 'generateContentInternal');\n }\n if (isWrapped(proto.generateContentStreamInternal)) {\n this._unwrap(proto as unknown as WrappableProto, 'generateContentStreamInternal');\n }\n }\n _isPatched = false;\n try {\n if (moduleExports) moduleExports.scopePatched = false;\n } catch {\n /* ignore */\n }\n }\n\n private _wrapGenerate(streaming: boolean): (original: GenerateFn) => GenerateFn {\n const instrumentation = this;\n return (original: GenerateFn): GenerateFn =>\n function patched(this: unknown, ...args: unknown[]): unknown {\n // Respect OTel tracing suppression (e.g. a re-entrant internal call).\n if (isTracingSuppressed(context.active())) {\n return original.apply(this, args);\n }\n // Build the span + input attributes DEFENSIVELY: if anything here throws, fall back to the\n // untouched call so capture never breaks the user's request (rule b).\n let span: Span | undefined;\n try {\n const params = (args[0] ?? {}) as GenerateParams;\n span = instrumentation.tracer.startSpan('GoogleGenAI.generateContent', {\n kind: SpanKind.INTERNAL,\n attributes: inputAttributes(params),\n });\n } catch {\n span = undefined;\n }\n if (!span) return original.apply(this, args);\n const activeSpan = span;\n\n const activeContext = trace.setSpan(context.active(), activeSpan);\n let result: unknown;\n try {\n result = context.with(activeContext, () => original.apply(this, args));\n } catch (err) {\n // a synchronous throw from the SDK call itself — record + rethrow to the caller\n endWithError(activeSpan, err);\n throw err;\n }\n\n if (!isPromiseLike(result)) {\n // Defensive: these methods always return a promise, but never break the caller otherwise.\n endOk(activeSpan, undefined);\n return result;\n }\n\n if (streaming) {\n return (result as Promise<AsyncIterable<GenAIResponse>>).then(\n (gen) => instrumentation._wrapStream(gen, activeSpan),\n (err) => {\n endWithError(activeSpan, err);\n throw err;\n },\n );\n }\n return (result as Promise<GenAIResponse>).then(\n (resp) => {\n endOk(activeSpan, resp); // never throws — a successful call stays successful\n return resp;\n },\n (err) => {\n endWithError(activeSpan, err);\n throw err;\n },\n );\n };\n }\n\n /**\n * Wrap the streaming async-generator: yield every chunk through to the caller while accumulating the\n * full text + final usage, then end the span. Capture is fully isolated from the caller's stream:\n * - per-chunk extraction is swallowed, so a malformed chunk never aborts the user's iteration;\n * - the catch handles ONLY a real error thrown by the underlying stream (records it, rethrows);\n * - the finally ends the span exactly once, even on early abandonment (the generator's .return()\n * runs `finally`) — capturing whatever text/usage arrived so far.\n * Mirrors the Python _wrap_stream_iter + _capture_streaming_response (chunks carry text; the final\n * chunk carries usage).\n */\n private async *_wrapStream(\n gen: AsyncIterable<GenAIResponse>,\n span: Span,\n ): AsyncGenerator<GenAIResponse> {\n const texts: string[] = [];\n let usage: GenAIUsage | undefined;\n let errored = false;\n try {\n for await (const chunk of gen) {\n try {\n texts.push(responseText(chunk));\n if (chunk?.usageMetadata) usage = chunk.usageMetadata; // last non-null wins (final chunk)\n } catch {\n /* a capture/extraction error must never abort the caller's stream */\n }\n yield chunk;\n }\n } catch (err) {\n errored = true;\n try {\n span.recordException(err as Error);\n span.setStatus({ code: SpanStatusCode.ERROR, message: errMessage(err) });\n } catch {\n /* ignore */\n }\n throw err; // a real error from the underlying stream — surface it to the caller\n } finally {\n if (!errored) {\n try {\n setOutputAttributes(span, texts.join(''), usage);\n span.setStatus({ code: SpanStatusCode.OK });\n } catch {\n /* ignore */\n }\n }\n try {\n span.end();\n } catch {\n /* ignore */\n }\n }\n }\n}\n","// SDK identity constants. `SDK_SOURCE` MUST be \"backend_sdk\" — the Scope backend keys off\n// it (belt-and-suspenders with the secret-key type) to skip browser-origin/domain validation\n// and mark events active (see backend main.py is_backend_sdk).\n// Keep in lockstep with package.json \"version\" — it's stamped on every event's `sdk_version` and the\n// User-Agent (version-pin.test.ts asserts the two match, so a published build can't mislabel itself).\nexport const SDK_VERSION = '0.1.1';\nexport const SDK_SOURCE = 'backend_sdk';\nexport const SDK_USER_AGENT = `scope-tracer-node/${SDK_VERSION}`;\n","import { diag } from '@opentelemetry/api';\nimport {\n InstrumentationBase,\n InstrumentationNodeModuleDefinition,\n isWrapped,\n type InstrumentationConfig,\n} from '@opentelemetry/instrumentation';\nimport { SDK_VERSION } from './version';\n\n// Scope-authored OpenTelemetry instrumentation for the Vercel AI SDK (`ai`) — the \"make Vercel\n// zero-code\" piece. Unlike the openai/anthropic Arize drop-ins and our hand-built Google Gen AI\n// instrumentation, this one DOES NOT emit spans. The `ai` package emits its OWN OTel spans, captured\n// downstream by `@arizeai/openinference-vercel`'s OpenInferenceBatchSpanProcessor (wired in index.ts).\n// The single problem this instrumentation solves: the AI SDK emits NOTHING unless telemetry is enabled\n// PER CALL (`experimental_telemetry: { isEnabled: true }`) — verified against ai@6.0.197: getTracer()\n// returns a noopTracer unless isEnabled, and there is NO global on-switch. So to make capture truly\n// zero-code, we wrap the `ai` package's public entry points and INJECT `isEnabled: true` into the call\n// options (deep-merged with any telemetry config the user already passed). Once enabled — and as long\n// as the user does not pass their OWN tracer — the AI SDK calls the GLOBAL tracer `trace.getTracer(\"ai\")`,\n// which is the provider init() registers, so the spans flow into our pipeline with no further setup.\n//\n// TWO PATCH STRATEGIES (decided per call, because the `ai` exports differ by module system — both\n// verified empirically against ai@6.0.197):\n// - CJS (`require('ai')`): the exports are esbuild's NON-CONFIGURABLE GETTER-ONLY properties, so they\n// cannot be wrapped in place (shimmer's `_wrap`/`Object.defineProperty` both fail). Instead we\n// RETURN a Proxy that injects telemetry on the target functions and passes everything else through;\n// require-in-the-middle hands consumers our returned object.\n// - ESM (`import { generateText } from 'ai'`, via the import-in-the-middle loader registered by\n// src/esm-hook.ts on the `--import` bootstrap): named imports bind to the live export, so a\n// returned Proxy is NOT seen — but IITM makes the exports settable, so we `_wrap` them IN PLACE and\n// return the same (mutated) namespace.\n// NB: this is the ONE provider whose ESM capture currently works (its entry points are top-level\n// functions in the module IITM intercepts). openai/anthropic/gemini patch a class prototype reached\n// through an ESM re-export that IITM does not connect, so they remain CJS-only under ESM (tracked\n// follow-up). The require-hook (CJS) path covers all four.\n//\n// LOAD-ORDER INVARIANT (load-bearing — do NOT `import` from 'ai' here, or anywhere index.ts pulls in):\n// the ESM loader (src/esm-hook.ts, registered by register.ts) only instruments `ai` if `ai` is loaded\n// AFTER the loader is registered. `import`s are hoisted, and a bundler lifts external imports to the\n// top of the bootstrap, so any `import … from 'ai'` in @scope-analytics/node's own graph would materialize the\n// `ai` module before the loader exists → the app's later `import { generateText } from 'ai'` resolves\n// to the un-instrumented cached module → ESM capture silently dies. We therefore read `ai`'s shapes\n// STRUCTURALLY at patch time (the module object the hook hands us) and never import it — same as the\n// Gemini instrumentation. instrumentation.vercel-ai-bootstrap.test.ts is the regression guard: it\n// would fail (0 events) if `ai` ever loaded early.\n\nconst MODULE_NAME = 'ai';\nconst INSTRUMENTATION_NAME = '@scope-analytics/node/instrumentation-vercel-ai';\n\n// The Vercel AI SDK top-level entry points whose telemetry we auto-enable. Each emits a child\n// `ai.<fn>.doGenerate`/`.doStream` span (OpenInference LLM kind) that our pipeline maps to exactly\n// one llm_call (the parent AGENT span is dropped by the LLM-only export gate). `embed`/`embedMany`\n// are intentionally excluded — they map to EMBEDDING spans Scope does not ship as llm_call events.\nconst TARGET_FUNCTIONS = ['generateText', 'streamText', 'generateObject', 'streamObject'] as const;\n\nlet _isPatched = false;\n/** True once the `ai` package's entry points have been wrapped (CJS or ESM). Mirrors isGoogleGenAIPatched(). */\nexport function isVercelAIPatched(): boolean {\n return _isPatched;\n}\n\ntype AnyFn = (this: unknown, ...args: unknown[]) => unknown;\ninterface TelemetrySettings {\n isEnabled?: unknown;\n [k: string]: unknown;\n}\n\n/**\n * Return a NEW args array with `experimental_telemetry.isEnabled` forced `true` on the call options\n * (args[0]), DEEP-MERGED so every other telemetry field the user set is preserved\n * (tracer/functionId/metadata/recordInputs/recordOutputs/integrations). Pure and NEVER throws — on any\n * unexpected argument shape it returns the original args untouched (rule b: capture must never break the\n * call). An explicit `isEnabled: false` is RESPECTED — a deliberate per-call opt-out, so that call is\n * not captured (and, by the AI SDK's own gate, emits no spans). Exported for unit testing.\n */\nexport function injectTelemetryArgs(args: unknown[]): unknown[] {\n try {\n const opts = args[0];\n if (!opts || typeof opts !== 'object' || Array.isArray(opts)) return args;\n const o = opts as Record<string, unknown>;\n const existing = o.experimental_telemetry as TelemetrySettings | undefined;\n const hasExisting = !!existing && typeof existing === 'object' && !Array.isArray(existing);\n // Respect an explicit opt-out: never override a user's deliberate `isEnabled: false`.\n if (hasExisting && existing!.isEnabled === false) return args;\n // No-op fast path: telemetry already explicitly enabled — nothing to inject (avoids a clone).\n if (hasExisting && existing!.isEnabled === true) return args;\n const mergedTelemetry: TelemetrySettings = {\n ...(hasExisting ? existing! : {}),\n isEnabled: true,\n };\n return [{ ...o, experimental_telemetry: mergedTelemetry }, ...args.slice(1)];\n } catch {\n return args;\n }\n}\n\n/** A telemetry-injecting wrapper around an `ai` entry point — transparent passthrough of `this` and\n * the return value; only args[0].experimental_telemetry is (deep-)merged. */\nfunction makeTelemetryWrapper(original: AnyFn): AnyFn {\n return function scopeVercelTelemetryWrapper(this: unknown, ...args: unknown[]): unknown {\n return original.apply(this, injectTelemetryArgs(args));\n };\n}\n\n/**\n * Can `obj[name]` be replaced in place? True for an accessor with a setter (the IITM ESM namespace), a\n * writable data property, or a configurable property (redefinable). False for esbuild's CJS output —\n * non-configurable getter-only — which must instead be handled by returning a Proxy.\n */\nfunction settableInPlace(obj: object, name: string): boolean {\n const d = Object.getOwnPropertyDescriptor(obj, name);\n if (!d) return false;\n if (typeof d.set === 'function') return true;\n if (d.writable === true) return true;\n if (d.configurable === true) return true;\n return false;\n}\n\nexport class VercelAIInstrumentation extends InstrumentationBase {\n // Same original-exports → Proxy, so repeated patch() calls (re-entrancy) return one stable Proxy.\n private readonly _proxyCache = new WeakMap<object, object>();\n\n constructor(config: InstrumentationConfig = {}) {\n super(INSTRUMENTATION_NAME, SDK_VERSION, config);\n }\n\n protected init(): InstrumentationNodeModuleDefinition {\n return new InstrumentationNodeModuleDefinition(\n MODULE_NAME,\n ['*'],\n (moduleExports: Record<string, unknown>) => this.patch(moduleExports),\n (moduleExports: Record<string, unknown>) => this.unpatch(moduleExports),\n );\n }\n\n /** ESM escape hatch — the require-hook doesn't fire for `import` (mirrors the Arize instrumentations). */\n manuallyInstrument(moduleExports: Record<string, unknown>): Record<string, unknown> {\n diag.debug(`Manually instrumenting ${MODULE_NAME}`);\n return this.patch(moduleExports);\n }\n\n private patch(moduleExports: Record<string, unknown>): Record<string, unknown> {\n if (!moduleExports) return moduleExports;\n const present = TARGET_FUNCTIONS.filter((n) => typeof moduleExports[n] === 'function');\n if (present.length === 0) {\n diag.warn(`[scope] no target functions found in '${MODULE_NAME}'; AI SDK telemetry not auto-enabled`);\n return moduleExports;\n }\n\n // ESM (IITM namespace) or a plain CJS object: wrap each export in place; the require/import hook\n // hands consumers the same (mutated) module object.\n if (present.every((n) => settableInPlace(moduleExports, n))) {\n for (const n of present) {\n if (!isWrapped(moduleExports[n])) {\n this._wrap(moduleExports, n, (original: unknown) => makeTelemetryWrapper(original as AnyFn));\n }\n }\n _isPatched = true;\n return moduleExports;\n }\n\n // CJS esbuild output: non-configurable getter-only exports — return a Proxy.\n const cached = this._proxyCache.get(moduleExports);\n if (cached) {\n _isPatched = true;\n return cached as Record<string, unknown>;\n }\n const targets = new Set<string>(present);\n const fnCache = new Map<string, AnyFn>();\n const proxy = new Proxy(moduleExports, {\n get(target, prop, receiver) {\n const value = Reflect.get(target, prop, receiver);\n if (typeof prop === 'string' && targets.has(prop) && typeof value === 'function') {\n let wrapped = fnCache.get(prop);\n if (!wrapped) {\n wrapped = makeTelemetryWrapper(value as AnyFn);\n fnCache.set(prop, wrapped);\n }\n return wrapped;\n }\n return value;\n },\n });\n this._proxyCache.set(moduleExports, proxy);\n _isPatched = true;\n return proxy as Record<string, unknown>;\n }\n\n private unpatch(moduleExports: Record<string, unknown>): Record<string, unknown> {\n if (moduleExports) {\n // Only the in-place (ESM/IITM) path leaves wrapped functions to unwrap; the CJS Proxy is simply\n // discarded by the require-hook on unpatch (consumers that already captured it keep it — telemetry\n // injection is harmless either way).\n for (const n of TARGET_FUNCTIONS) {\n if (typeof moduleExports[n] === 'function' && isWrapped(moduleExports[n])) {\n this._unwrap(moduleExports, n);\n }\n }\n this._proxyCache.delete(moduleExports);\n }\n _isPatched = false;\n return moduleExports;\n }\n}\n","import { SDK_VERSION } from './version';\n\n/** User-supplied options to {@link init}. Anything omitted falls back to an env var. */\nexport interface ScopeOptions {\n /** Project SECRET key (sk_live_… / sk_test_…). Env: SCOPE_API_KEY. */\n apiKey?: string;\n /** Scope ingest base URL. Env: SCOPE_ENDPOINT. Default https://api.scopeai.dev. */\n endpoint?: string;\n /** Logical environment tag on every event. Env: SCOPE_ENVIRONMENT. Default \"production\". */\n environment?: string;\n /** Verbose logging. Env: SCOPE_DEBUG=true. */\n debug?: boolean;\n /** OTel service.name for the tracer resource. Env: SCOPE_SERVICE_NAME / OTEL_SERVICE_NAME. */\n serviceName?: string;\n /**\n * OPT-IN regex patterns to scrub from captured prompt/response/message text. Default: none\n * (RAW — full fidelity, so the analyst sees the real interaction). Pass\n * {@link CREDENTIAL_REDACT_PATTERNS} (from this package) for a credential scrub, or your own —\n * each pattern must capture the key as group 1; the value is replaced with ***REDACTED***.\n * Best-effort over free text (applied to prompt + response + message contents), NOT a structural\n * guarantee — it won't catch secrets in non-`key=value` shapes (e.g. JSON `\"api_key\":\"…\"`).\n */\n redactPatterns?: readonly RegExp[];\n}\n\n/** Fully-resolved, validated configuration. */\nexport interface ScopeConfig {\n apiKey: string;\n /** Normalized base URL (no trailing slash). */\n endpoint: string;\n /** Fully-qualified ingest URL: `${endpoint}/api/events`. */\n eventsUrl: string;\n environment: string;\n debug: boolean;\n serviceName: string;\n sdkVersion: string;\n /** Opt-in redaction patterns (empty/undefined = raw, the default). Always set by resolveConfig;\n * optional here so hand-built config literals (tests, custom wiring) can omit it. */\n redactPatterns?: readonly RegExp[];\n}\n\n/** Thrown when configuration is missing or malformed (e.g. no/invalid API key). */\nexport class ScopeConfigError extends Error {\n constructor(message: string) {\n super(message);\n this.name = 'ScopeConfigError';\n }\n}\n\nconst DEFAULT_ENDPOINT = 'https://api.scopeai.dev';\n\n/**\n * Resolve options + environment into a validated {@link ScopeConfig}.\n *\n * Mirrors the Python SDK's contract exactly: the key MUST be a project SECRET key\n * (sk_live_… / sk_test_…) — a public pk_… key is rejected so a misconfigured backend\n * install fails loudly rather than silently dropping data (rule b: honest non-coverage).\n */\nexport function resolveConfig(\n options: ScopeOptions = {},\n env: NodeJS.ProcessEnv = process.env,\n): ScopeConfig {\n const apiKey = (options.apiKey ?? env.SCOPE_API_KEY ?? '').trim();\n if (!apiKey) {\n throw new ScopeConfigError(\n 'Scope: missing API key. Set SCOPE_API_KEY (your project secret key, sk_live_… or ' +\n 'sk_test_…) or pass { apiKey } to init().',\n );\n }\n if (!(apiKey.startsWith('sk_live_') || apiKey.startsWith('sk_test_'))) {\n throw new ScopeConfigError(\n 'Scope: invalid API key. The backend SDK needs a project SECRET key starting with ' +\n '\"sk_live_\" or \"sk_test_\" (a public \"pk_…\" key will not work for server-side ingest).',\n );\n }\n\n const rawEndpoint = (options.endpoint ?? env.SCOPE_ENDPOINT ?? DEFAULT_ENDPOINT).trim();\n const endpoint = (rawEndpoint || DEFAULT_ENDPOINT).replace(/\\/+$/, '');\n const environment =\n (options.environment ?? env.SCOPE_ENVIRONMENT ?? 'production').trim() || 'production';\n const debug = options.debug ?? (env.SCOPE_DEBUG ?? '').toLowerCase() === 'true';\n const serviceName =\n (options.serviceName ?? env.SCOPE_SERVICE_NAME ?? env.OTEL_SERVICE_NAME ?? 'scope-app').trim() ||\n 'scope-app';\n\n return {\n apiKey,\n endpoint,\n eventsUrl: `${endpoint}/api/events`,\n environment,\n debug,\n serviceName,\n sdkVersion: SDK_VERSION,\n redactPatterns: options.redactPatterns ?? [],\n };\n}\n","// Deploy-aware identity (PRODUCT.md §4.2). Read the deployed commit SHA from whatever\n// platform env var the host exposes, once at startup, and stamp every event with\n// git_sha + deployment_id so the analyst can reason about \"what changed before the drop?\".\n// Mirrors the Python SDK's deployment.py exactly (same env vars, same precedence, same id format).\n\n/** Platform commit-SHA env vars, in priority order. First non-empty wins. */\nconst GIT_SHA_ENV_VARS = [\n 'RAILWAY_GIT_COMMIT_SHA', // Railway\n 'VERCEL_GIT_COMMIT_SHA', // Vercel\n 'RENDER_GIT_COMMIT', // Render\n 'HEROKU_RELEASE_VERSION', // Heroku\n 'K_REVISION', // Cloud Run / Cloud Functions / Firebase\n 'AWS_LAMBDA_FUNCTION_VERSION', // AWS Lambda\n 'GIT_COMMIT_SHA', // Generic fallback\n] as const;\n\nexport interface Deployment {\n /** The deployed commit SHA, or undefined when no platform env var is set. */\n gitSha?: string;\n /** `${ISO_START}-${gitSha.slice(0,7)}`, or undefined when no SHA is known. */\n deploymentId?: string;\n}\n\n/** Return the deployed commit SHA from platform env vars, or undefined. Never invents one. */\nexport function detectGitSha(env: NodeJS.ProcessEnv = process.env): string | undefined {\n for (const name of GIT_SHA_ENV_VARS) {\n const value = env[name];\n if (value && value.trim()) return value.trim();\n }\n return undefined;\n}\n\n/**\n * Resolve the deployment identity for this process.\n * @param startedAt process start time (UTC), used to build a stable deployment_id.\n */\nexport function resolveDeployment(\n startedAt: Date,\n env: NodeJS.ProcessEnv = process.env,\n): Deployment {\n const gitSha = detectGitSha(env);\n if (!gitSha) return {};\n // Match the Python SDK's id format: \"2024-01-15T10:30:00Z-abc1234\" (no millis).\n const startIso = startedAt.toISOString().replace(/\\.\\d{3}Z$/, 'Z');\n return { gitSha, deploymentId: `${startIso}-${gitSha.slice(0, 7)}` };\n}\n\n/**\n * Add git_sha + deployment_id to an event when known. Never overwrites a value the caller\n * already set (parity with the Python enricher's setdefault semantics).\n */\nexport function stampDeployment<T extends Record<string, unknown>>(\n event: T,\n deployment: Deployment,\n): T {\n if (deployment.gitSha && event.git_sha === undefined) {\n (event as Record<string, unknown>).git_sha = deployment.gitSha;\n if (deployment.deploymentId && event.deployment_id === undefined) {\n (event as Record<string, unknown>).deployment_id = deployment.deploymentId;\n }\n }\n return event;\n}\n","import { ExportResultCode, type ExportResult } from '@opentelemetry/core';\nimport type { ReadableSpan, SpanExporter } from '@opentelemetry/sdk-trace-base';\nimport type { ScopeConfig } from './config';\nimport type { Deployment } from './deployment';\nimport { spanToScopeEvent, type ScopeEvent } from './event';\nimport { shipEvents } from './transport';\n\n/**\n * An OTel SpanExporter that translates OpenInference GenAI spans into Scope events and ships\n * them. Batching/timeout/flush are handled by the OTel BatchSpanProcessor that wraps this — we\n * just map the batch and POST it (the \"wrap OpenTelemetry, don't reinvent\" philosophy, PLAN\n * Track B). Non-LLM spans are dropped (this slice maps LLM spans only).\n */\nexport class ScopeSpanExporter implements SpanExporter {\n constructor(\n private readonly config: ScopeConfig,\n private readonly deployment: Deployment,\n ) {}\n\n export(spans: ReadableSpan[], resultCallback: (result: ExportResult) => void): void {\n const events: ScopeEvent[] = [];\n for (const span of spans) {\n const event = spanToScopeEvent(span, { config: this.config, deployment: this.deployment });\n if (event) events.push(event);\n }\n if (events.length === 0) {\n resultCallback({ code: ExportResultCode.SUCCESS });\n return;\n }\n shipEvents(events, this.config)\n .then((ok) => resultCallback({ code: ok ? ExportResultCode.SUCCESS : ExportResultCode.FAILED }))\n .catch(() => resultCallback({ code: ExportResultCode.FAILED }));\n }\n\n shutdown(): Promise<void> {\n return Promise.resolve();\n }\n\n forceFlush(): Promise<void> {\n return Promise.resolve();\n }\n}\n","import {\n SemanticConventions as SC,\n OpenInferenceSpanKind,\n} from '@arizeai/openinference-semantic-conventions';\nimport { SpanStatusCode } from '@opentelemetry/api';\nimport { SCOPE_THREAD_ID_ATTR, SCOPE_URL_ATTR } from './attributes';\nimport { stampDeployment, type Deployment } from './deployment';\nimport { generateTempSessionId } from './session';\nimport { SDK_SOURCE } from './version';\nimport type { ScopeConfig } from './config';\n\n// The load-bearing translation: an OpenInference GenAI span -> a wire-compatible Scope event.\n// We deliberately read OpenInference's published semantic-convention constants (SC.*) rather\n// than hardcoding attribute strings, so a convention rename surfaces at build time, not as a\n// silently malformed event. The output is the SAME universal event shape the Python SDK emits\n// (CLAUDE.md §1.6 universal storage) so both SDKs are wire-identical to the backend.\n\n/** A Scope universal event. The three required fields plus arbitrary extras (backend allows them). */\nexport interface ScopeEvent {\n event_type: string;\n source: string;\n timestamp: string;\n session_id: string;\n user_id?: string | null;\n [key: string]: unknown;\n}\n\n/** The structural subset of an OTel ReadableSpan we read. ReadableSpan satisfies this. */\nexport interface SpanLike {\n attributes: Record<string, unknown>;\n startTime: [number, number]; // HrTime [seconds, nanoseconds]\n endTime: [number, number];\n status?: { code: number; message?: string };\n}\n\ninterface ChatMessage {\n role?: string;\n content?: string;\n}\n\nfunction asString(v: unknown): string | undefined {\n if (typeof v === 'string') return v;\n if (v === undefined || v === null) return undefined;\n return String(v);\n}\n\nfunction asNumber(v: unknown): number | undefined {\n if (typeof v === 'number' && Number.isFinite(v)) return v;\n if (typeof v === 'string' && v.trim() !== '' && Number.isFinite(Number(v))) return Number(v);\n return undefined;\n}\n\n// Provider-name fallbacks for spans translated from the Vercel AI SDK by @arizeai/openinference-vercel.\n// That adapter does NOT emit llm.provider/llm.system, but the span retains the OpenTelemetry GenAI\n// `gen_ai.system` and the Vercel `ai.model.provider` attributes. Reading them (in order) lets\n// Vercel-captured events carry a provider label, consistent with the OpenAI/Anthropic/Gemini SDKs —\n// which DO set llm.provider/llm.system, so these fallbacks never change their value. These are\n// standard upstream attribute names (OTel GenAI / Vercel AI), captured as-is — not Scope keyword logic.\nconst GEN_AI_SYSTEM_ATTR = 'gen_ai.system';\nconst VERCEL_MODEL_PROVIDER_ATTR = 'ai.model.provider';\n\n/**\n * Opt-in credential-scrub patterns. Pass to `init({ redactPatterns: CREDENTIAL_REDACT_PATTERNS })`.\n * Each captures the KEY as group 1 and matches the secret VALUE OUTSIDE the group, so the\n * substitution keeps the key and DROPS the value: \"password=hunter2\" -> \"password=***REDACTED***\".\n * Wire-identical to the Python SDK's DEFAULT_REDACT_PATTERNS. NOT applied unless opted in (raw default).\n * Best-effort free-text scrub over `key=value` forms — NOT a structural guarantee: it won't catch a\n * secret written as JSON (`\"api_key\":\"…\"`) or in other non-`=` shapes.\n */\nexport const CREDENTIAL_REDACT_PATTERNS: readonly RegExp[] = [\n /(password\\s*=\\s*['\"]?)[^'\"\\s]+/gi,\n /(api[_-]?key\\s*=\\s*['\"]?)[^'\"\\s]+/gi,\n /(token\\s*=\\s*['\"]?)[^'\"\\s]+/gi,\n /(secret\\s*=\\s*['\"]?)[^'\"\\s]+/gi,\n];\n\n/** Apply opt-in redaction patterns to text. No-op when none are configured (the default) — raw text\n * for full fidelity. Patterns capture the key as group 1; the matched value is replaced. */\nfunction redactText(text: string | undefined, patterns: readonly RegExp[]): string | undefined {\n if (text === undefined || patterns.length === 0) return text;\n let out = text;\n for (const re of patterns) out = out.replace(re, '$1***REDACTED***');\n return out;\n}\n\nfunction hrTimeToMs(t: [number, number]): number {\n return t[0] * 1000 + t[1] / 1e6;\n}\n\nfunction escapeRe(s: string): string {\n return s.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\$&');\n}\n\n/**\n * Collect the flattened, indexed message attributes under a prefix (e.g. \"llm.input_messages\")\n * into an ordered array of {role, content}.\n *\n * Handles BOTH content shapes OpenInference emits:\n * - scalar: {prefix}.{i}.message.content (chat-completions, string content)\n * - array: {prefix}.{i}.message.contents.{j}.message_content.text (Responses API + multimodal/vision)\n * For the array shape we join the text parts in order. Missing this second shape would drop the\n * prompt/response text for the modern OpenAI Responses API and leave a raw JSON blob behind.\n */\nfunction collectMessages(attrs: Record<string, unknown>, prefix: string): ChatMessage[] {\n const p = escapeRe(prefix);\n const roleRe = new RegExp(`^${p}\\\\.(\\\\d+)\\\\.${escapeRe(SC.MESSAGE_ROLE)}$`);\n const contentRe = new RegExp(`^${p}\\\\.(\\\\d+)\\\\.${escapeRe(SC.MESSAGE_CONTENT)}$`);\n const partRe = new RegExp(\n `^${p}\\\\.(\\\\d+)\\\\.${escapeRe(SC.MESSAGE_CONTENTS)}\\\\.(\\\\d+)\\\\.${escapeRe(SC.MESSAGE_CONTENT_TEXT)}$`,\n );\n\n const roles = new Map<number, string | undefined>();\n const scalarContent = new Map<number, string | undefined>();\n const parts = new Map<number, Map<number, string>>(); // messageIndex -> partIndex -> text\n\n for (const [key, value] of Object.entries(attrs)) {\n let m: RegExpExecArray | null;\n if ((m = roleRe.exec(key))) {\n roles.set(Number(m[1]), asString(value));\n } else if ((m = contentRe.exec(key))) {\n scalarContent.set(Number(m[1]), asString(value));\n } else if ((m = partRe.exec(key))) {\n const i = Number(m[1]);\n const text = asString(value);\n if (text !== undefined) {\n const byPart = parts.get(i) ?? new Map<number, string>();\n byPart.set(Number(m[2]), text);\n parts.set(i, byPart);\n }\n }\n }\n\n const indices = [...new Set([...roles.keys(), ...scalarContent.keys(), ...parts.keys()])].sort(\n (a, b) => a - b,\n );\n return indices.map((i) => {\n const message: ChatMessage = {};\n const role = roles.get(i);\n if (role !== undefined) message.role = role;\n let content = scalarContent.get(i);\n if (content === undefined && parts.has(i)) {\n const byPart = parts.get(i)!;\n content = [...byPart.keys()]\n .sort((a, b) => a - b)\n .map((j) => byPart.get(j))\n .join('');\n }\n if (content !== undefined) message.content = content;\n return message;\n });\n}\n\n/** True if the span is an OpenInference LLM span (the only kind this slice maps). */\nexport function isLlmSpan(span: SpanLike): boolean {\n return span.attributes[SC.OPENINFERENCE_SPAN_KIND] === OpenInferenceSpanKind.LLM;\n}\n\n/**\n * Map an OpenInference LLM span to a Scope `llm_call` event, or null if the span isn't an LLM\n * span. `now` is injectable for deterministic tests.\n */\nexport function spanToScopeEvent(\n span: SpanLike,\n ctx: { config: ScopeConfig; deployment: Deployment; now?: Date },\n): ScopeEvent | null {\n if (!isLlmSpan(span)) return null;\n\n const a = span.attributes;\n const inputMessages = collectMessages(a, SC.LLM_INPUT_MESSAGES);\n const outputMessages = collectMessages(a, SC.LLM_OUTPUT_MESSAGES);\n\n // Prompt = the last user turn (fall back to the last input turn, then the raw input value).\n const lastUser = [...inputMessages].reverse().find((m) => (m.role ?? '').toLowerCase() === 'user');\n const patterns = ctx.config.redactPatterns ?? [];\n const prompt = redactText(\n lastUser?.content ?? inputMessages.at(-1)?.content ?? asString(a[SC.INPUT_VALUE]),\n patterns,\n );\n const response = redactText(outputMessages[0]?.content ?? asString(a[SC.OUTPUT_VALUE]), patterns);\n\n const tokens: Record<string, number> = {};\n const promptTokens = asNumber(a[SC.LLM_TOKEN_COUNT_PROMPT]);\n if (promptTokens !== undefined) tokens.prompt_tokens = promptTokens;\n const completionTokens = asNumber(a[SC.LLM_TOKEN_COUNT_COMPLETION]);\n if (completionTokens !== undefined) tokens.completion_tokens = completionTokens;\n const totalTokens = asNumber(a[SC.LLM_TOKEN_COUNT_TOTAL]);\n if (totalTokens !== undefined) tokens.total_tokens = totalTokens;\n\n const sessionId = asString(a[SC.SESSION_ID]) ?? generateTempSessionId();\n const userId = asString(a[SC.USER_ID]) ?? null;\n const isError = span.status?.code === SpanStatusCode.ERROR;\n const now = ctx.now ?? new Date();\n const nowIso = now.toISOString();\n\n const event: ScopeEvent = {\n event_type: 'llm_call',\n source: SDK_SOURCE,\n timestamp: nowIso,\n session_id: sessionId,\n user_id: userId,\n is_user_facing: !sessionId.startsWith('temp_'),\n provider:\n asString(a[SC.LLM_PROVIDER]) ??\n asString(a[SC.LLM_SYSTEM]) ??\n asString(a[GEN_AI_SYSTEM_ATTR]) ??\n asString(a[VERCEL_MODEL_PROVIDER_ATTR]),\n model: asString(a[SC.LLM_MODEL_NAME]),\n prompt,\n response,\n messages: patterns.length\n ? inputMessages.map((m) =>\n m.content !== undefined ? { ...m, content: redactText(m.content, patterns) } : m,\n )\n : inputMessages,\n tokens,\n latency_ms: Math.max(0, hrTimeToMs(span.endTime) - hrTimeToMs(span.startTime)),\n error: isError ? (span.status?.message ?? 'error') : null,\n success: !isError,\n environment: ctx.config.environment,\n sdk_version: ctx.config.sdkVersion,\n server_timestamp: nowIso,\n };\n\n // Conversation-continuity hints (§1.8). Emitted only when present so the backend's fallback\n // chain (thread_id -> session_id+url -> session_id) behaves like it does for the Python SDK.\n const threadId = asString(a[SCOPE_THREAD_ID_ATTR]);\n if (threadId !== undefined) event.thread_id = threadId;\n const url = asString(a[SCOPE_URL_ATTR]);\n if (url !== undefined) event.url = url;\n\n return stampDeployment(event, ctx.deployment);\n}\n","// Custom span attributes Scope stamps from AsyncLocalStorage context — these have no\n// OpenInference equivalent (OpenInference covers session.id/user.id but not the host app's\n// thread/url). The ScopeContextSpanProcessor writes them at span start; the exporter reads\n// them back at export time and emits them as top-level event fields, so the backend's\n// conversation-continuity fallback chain (thread_id -> session_id+url -> session_id, §1.8)\n// works for Node services exactly as it does for the Python SDK.\nexport const SCOPE_THREAD_ID_ATTR = 'scope.thread_id';\nexport const SCOPE_URL_ATTR = 'scope.url';\n","import { AsyncLocalStorage } from 'node:async_hooks';\nimport { randomBytes } from 'node:crypto';\n\n// Session/user context propagation via AsyncLocalStorage (PLAN.md Track B). The host app\n// wraps a request in runWithContext({ sessionId, userId }) so that any LLM span created\n// during that request inherits the session — letting Scope stitch a user's activity across\n// frontend + backend + LLM (CLAUDE.md §1.8). The ScopeContextSpanProcessor reads this at\n// span start; the exporter falls back to a temp_ session when none is set.\n\nexport interface ScopeContextData {\n sessionId?: string;\n userId?: string;\n threadId?: string;\n url?: string;\n}\n\nconst storage = new AsyncLocalStorage<ScopeContextData>();\n\n/** Run `fn` with the given Scope context bound for its whole async subtree. */\nexport function runWithContext<T>(ctx: ScopeContextData, fn: () => T): T {\n return storage.run({ ...ctx }, fn);\n}\n\n/** The context bound to the current async execution, if any. */\nexport function getContext(): ScopeContextData | undefined {\n return storage.getStore();\n}\n\n/** Attach/replace the identified user on the current context (e.g. after auth resolves). */\nexport function setUser(userId: string): void {\n const store = storage.getStore();\n if (store) store.userId = userId;\n}\n\n/**\n * A temporary, non-user-facing session id used when no session context is present.\n * Matches the Python SDK's `temp_{16 hex}` shape; the backend treats `temp_`-prefixed\n * sessions as not user-facing.\n */\nexport function generateTempSessionId(): string {\n return `temp_${randomBytes(8).toString('hex')}`;\n}\n","import type { ScopeConfig } from './config';\nimport type { ScopeEvent } from './event';\nimport { SDK_SOURCE, SDK_USER_AGENT } from './version';\n\n// The HTTP shipper. POSTs the batch envelope the Scope backend expects:\n// POST {endpoint}/api/events { \"events\": [...], \"source\": \"backend_sdk\" }\n// Authorization: Bearer sk_...\n// Best-effort and NEVER throws — a telemetry failure must not crash or slow the host app\n// (rule b). Uses the global fetch (Node >= 18).\n\nexport async function shipEvents(events: ScopeEvent[], config: ScopeConfig): Promise<boolean> {\n if (events.length === 0) return true;\n try {\n const response = await fetch(config.eventsUrl, {\n method: 'POST',\n headers: {\n Authorization: `Bearer ${config.apiKey}`,\n 'Content-Type': 'application/json',\n 'User-Agent': SDK_USER_AGENT,\n },\n body: JSON.stringify({ events, source: SDK_SOURCE }),\n });\n if (response.ok) {\n if (config.debug) console.log(`[scope] shipped ${events.length} event(s)`);\n return true;\n }\n if (config.debug) console.warn(`[scope] ship failed: HTTP ${response.status}`);\n return false;\n } catch (err) {\n if (config.debug) {\n console.warn(`[scope] ship error: ${err instanceof Error ? err.message : String(err)}`);\n }\n return false;\n }\n}\n","import type { Context } from '@opentelemetry/api';\nimport type { ReadableSpan, Span, SpanProcessor } from '@opentelemetry/sdk-trace-base';\nimport { SemanticConventions as SC } from '@arizeai/openinference-semantic-conventions';\nimport { SCOPE_THREAD_ID_ATTR, SCOPE_URL_ATTR } from './attributes';\nimport { getContext } from './session';\n\n/**\n * Stamps the current AsyncLocalStorage Scope context (session/user/thread/url) onto each span\n * as it starts — so the exporter can read it back at export time (when the request's async\n * context is already gone). Session/user use OpenInference's own attributes; thread/url use\n * Scope's custom attributes. Never overwrites an attribute the instrumentation already set.\n */\nexport class ScopeContextSpanProcessor implements SpanProcessor {\n onStart(span: Span, _parentContext: Context): void {\n const ctx = getContext();\n if (!ctx) return;\n if (ctx.sessionId && span.attributes[SC.SESSION_ID] === undefined) {\n span.setAttribute(SC.SESSION_ID, ctx.sessionId);\n }\n if (ctx.userId && span.attributes[SC.USER_ID] === undefined) {\n span.setAttribute(SC.USER_ID, ctx.userId);\n }\n if (ctx.threadId && span.attributes[SCOPE_THREAD_ID_ATTR] === undefined) {\n span.setAttribute(SCOPE_THREAD_ID_ATTR, ctx.threadId);\n }\n if (ctx.url && span.attributes[SCOPE_URL_ATTR] === undefined) {\n span.setAttribute(SCOPE_URL_ATTR, ctx.url);\n }\n }\n\n onEnd(_span: ReadableSpan): void {\n // no-op: shipping happens in the exporter behind the BatchSpanProcessor.\n }\n\n shutdown(): Promise<void> {\n return Promise.resolve();\n }\n\n forceFlush(): Promise<void> {\n return Promise.resolve();\n }\n}\n","// Zero-code bootstrap entry: `NODE_OPTIONS=\"--import @scope-analytics/node/register\" node server.js`.\n// Loaded before the app's own modules, so the instrumentations are in place before the app imports\n// its LLM SDKs. NEVER throws — a misconfiguration (e.g. missing key) degrades to a warning rather\n// than crashing the host's startup (rule b: honest non-coverage > a broken app).\nimport { enableEsmInstrumentation } from './esm-hook';\nimport { init } from './index';\n\n// Register the ESM import-in-the-middle loader FIRST — before init()'s registerInstrumentations and,\n// crucially, before the app imports any provider module — so `import`s are instrumented too, not just\n// `require`s. Best-effort and never throws; on the CJS build / older Node it no-ops and CJS capture\n// still works via the require-hook.\n// INVARIANT: the loader only instruments a module loaded AFTER it registers. The app's provider\n// imports run after this bootstrap, so they're covered — but @scope-analytics/node's OWN graph (./index and\n// everything it imports) must never `import 'ai'` (it would load before the loader, breaking ESM\n// capture). The instrumentations read provider shapes structurally, never import them. See\n// vercel-ai-instrumentation.ts (LOAD-ORDER INVARIANT) + the bootstrap regression test.\nenableEsmInstrumentation();\n\ntry {\n init();\n} catch (err) {\n console.warn(`[scope] tracer not started: ${err instanceof Error ? err.message : String(err)}`);\n}\n"],"mappings":"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","names":["register","import_instrumentation","import_api","SC","import_api","import_instrumentation","MODULE_NAME","INSTRUMENTATION_NAME","_isPatched","INSTRUMENTATION_NAME","MODULE_NAME","_isPatched","import_core","import_openinference_semantic_conventions","import_api","SC","import_openinference_semantic_conventions","SC","import_meta"]}
|