@interfere/next 10.0.0 → 10.0.1-canary.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (132) hide show
  1. package/README.md +6 -1
  2. package/dist/config.d.mts +1 -0
  3. package/dist/config.d.mts.map +1 -1
  4. package/dist/config.mjs +1 -110
  5. package/dist/config.mjs.map +1 -1
  6. package/dist/instrument-client.d.mts +7 -10
  7. package/dist/instrument-client.d.mts.map +1 -1
  8. package/dist/instrument-client.mjs +1 -9
  9. package/dist/instrument-client.mjs.map +1 -1
  10. package/dist/instrumentation-client.mjs +1 -22
  11. package/dist/instrumentation-client.mjs.map +1 -1
  12. package/dist/instrumentation.d.mts +3 -3
  13. package/dist/instrumentation.d.mts.map +1 -1
  14. package/dist/instrumentation.edge.d.mts +1 -1
  15. package/dist/instrumentation.edge.d.mts.map +1 -1
  16. package/dist/instrumentation.edge.mjs +1 -34
  17. package/dist/instrumentation.edge.mjs.map +1 -1
  18. package/dist/instrumentation.mjs +1 -165
  19. package/dist/instrumentation.mjs.map +1 -1
  20. package/dist/internal/build/configure-build.d.mts +2 -0
  21. package/dist/internal/build/configure-build.d.mts.map +1 -1
  22. package/dist/internal/build/configure-build.mjs +1 -95
  23. package/dist/internal/build/configure-build.mjs.map +1 -1
  24. package/dist/internal/build/detect-bundler.d.mts +3 -2
  25. package/dist/internal/build/detect-bundler.d.mts.map +1 -1
  26. package/dist/internal/build/detect-bundler.mjs +1 -9
  27. package/dist/internal/build/detect-bundler.mjs.map +1 -1
  28. package/dist/internal/build/pipeline.d.mts +5 -7
  29. package/dist/internal/build/pipeline.d.mts.map +1 -1
  30. package/dist/internal/build/pipeline.mjs +1 -82
  31. package/dist/internal/build/pipeline.mjs.map +1 -1
  32. package/dist/internal/build/release/destinations/index.mjs +1 -13
  33. package/dist/internal/build/release/destinations/index.mjs.map +1 -1
  34. package/dist/internal/build/release/destinations/vercel.d.mts.map +1 -1
  35. package/dist/internal/build/release/destinations/vercel.mjs +1 -23
  36. package/dist/internal/build/release/destinations/vercel.mjs.map +1 -1
  37. package/dist/internal/build/release/git.d.mts.map +1 -1
  38. package/dist/internal/build/release/git.mjs +1 -32
  39. package/dist/internal/build/release/git.mjs.map +1 -1
  40. package/dist/internal/build/release/index.d.mts.map +1 -1
  41. package/dist/internal/build/release/index.mjs +1 -18
  42. package/dist/internal/build/release/index.mjs.map +1 -1
  43. package/dist/internal/build/release/sources/github.d.mts.map +1 -1
  44. package/dist/internal/build/release/sources/github.mjs +1 -13
  45. package/dist/internal/build/release/sources/github.mjs.map +1 -1
  46. package/dist/internal/build/release/sources/index.d.mts.map +1 -1
  47. package/dist/internal/build/release/sources/index.mjs +1 -20
  48. package/dist/internal/build/release/sources/index.mjs.map +1 -1
  49. package/dist/internal/build/source-maps/discover-turbopack.d.mts.map +1 -1
  50. package/dist/internal/build/source-maps/discover-turbopack.mjs +1 -68
  51. package/dist/internal/build/source-maps/discover-turbopack.mjs.map +1 -1
  52. package/dist/internal/build/source-maps/discover-webpack.d.mts.map +1 -1
  53. package/dist/internal/build/source-maps/discover-webpack.mjs +1 -112
  54. package/dist/internal/build/source-maps/discover-webpack.mjs.map +1 -1
  55. package/dist/internal/build/source-maps/discover.d.mts +4 -4
  56. package/dist/internal/build/source-maps/discover.d.mts.map +1 -1
  57. package/dist/internal/build/source-maps/discover.mjs +1 -26
  58. package/dist/internal/build/source-maps/discover.mjs.map +1 -1
  59. package/dist/internal/build/source-maps/index.d.mts.map +1 -1
  60. package/dist/internal/build/source-maps/index.mjs +1 -18
  61. package/dist/internal/build/source-maps/index.mjs.map +1 -1
  62. package/dist/internal/build/source-maps/paths.d.mts.map +1 -1
  63. package/dist/internal/build/source-maps/paths.mjs +1 -49
  64. package/dist/internal/build/source-maps/paths.mjs.map +1 -1
  65. package/dist/internal/build/source-maps/upload.d.mts.map +1 -1
  66. package/dist/internal/build/source-maps/upload.mjs +1 -134
  67. package/dist/internal/build/source-maps/upload.mjs.map +1 -1
  68. package/dist/internal/build/value-injection-loader.d.mts.map +1 -1
  69. package/dist/internal/build/value-injection-loader.mjs +2 -24
  70. package/dist/internal/build/value-injection-loader.mjs.map +1 -1
  71. package/dist/internal/env.d.mts +2 -1
  72. package/dist/internal/env.d.mts.map +1 -1
  73. package/dist/internal/env.mjs +1 -32
  74. package/dist/internal/env.mjs.map +1 -1
  75. package/dist/internal/logger.d.mts.map +1 -1
  76. package/dist/internal/logger.mjs +1 -68
  77. package/dist/internal/logger.mjs.map +1 -1
  78. package/dist/internal/release-slug.d.mts.map +1 -1
  79. package/dist/internal/release-slug.mjs +1 -32
  80. package/dist/internal/release-slug.mjs.map +1 -1
  81. package/dist/internal/route/handle-get.d.mts.map +1 -1
  82. package/dist/internal/route/handle-get.mjs +1 -43
  83. package/dist/internal/route/handle-get.mjs.map +1 -1
  84. package/dist/internal/route/handle-post.d.mts.map +1 -1
  85. package/dist/internal/route/handle-post.mjs +1 -31
  86. package/dist/internal/route/handle-post.mjs.map +1 -1
  87. package/dist/internal/route/proxy.d.mts +8 -6
  88. package/dist/internal/route/proxy.d.mts.map +1 -1
  89. package/dist/internal/route/proxy.mjs +1 -134
  90. package/dist/internal/route/proxy.mjs.map +1 -1
  91. package/dist/internal/server/capture.d.mts.map +1 -1
  92. package/dist/internal/server/capture.mjs +1 -89
  93. package/dist/internal/server/capture.mjs.map +1 -1
  94. package/dist/internal/server/console-bridge.d.mts.map +1 -1
  95. package/dist/internal/server/console-bridge.mjs +1 -112
  96. package/dist/internal/server/console-bridge.mjs.map +1 -1
  97. package/dist/internal/server/id-generator.d.mts.map +1 -1
  98. package/dist/internal/server/id-generator.mjs +1 -68
  99. package/dist/internal/server/id-generator.mjs.map +1 -1
  100. package/dist/internal/server/instrumentation-options.d.mts.map +1 -1
  101. package/dist/internal/server/instrumentation-options.mjs +1 -1
  102. package/dist/internal/server/remote-config.d.mts.map +1 -1
  103. package/dist/internal/server/remote-config.mjs +1 -29
  104. package/dist/internal/server/remote-config.mjs.map +1 -1
  105. package/dist/internal/server/trace-meta.d.mts +1 -3
  106. package/dist/internal/server/trace-meta.d.mts.map +1 -1
  107. package/dist/internal/server/trace-meta.mjs +1 -41
  108. package/dist/internal/server/trace-meta.mjs.map +1 -1
  109. package/dist/internal/server/traceparent.d.mts.map +1 -1
  110. package/dist/internal/server/traceparent.mjs +1 -26
  111. package/dist/internal/server/traceparent.mjs.map +1 -1
  112. package/dist/internal/server/types.d.mts.map +1 -1
  113. package/dist/internal/server/types.mjs +1 -1
  114. package/dist/internal/setup-warnings.d.mts +1 -1
  115. package/dist/internal/setup-warnings.d.mts.map +1 -1
  116. package/dist/internal/setup-warnings.mjs +1 -45
  117. package/dist/internal/setup-warnings.mjs.map +1 -1
  118. package/dist/internal/url.d.mts +4 -0
  119. package/dist/internal/url.d.mts.map +1 -0
  120. package/dist/internal/url.mjs +1 -0
  121. package/dist/internal/url.mjs.map +1 -0
  122. package/dist/internal/version.mjs +1 -5
  123. package/dist/internal/version.mjs.map +1 -1
  124. package/dist/package.mjs +1 -5
  125. package/dist/provider.d.mts.map +1 -1
  126. package/dist/provider.mjs +1 -25
  127. package/dist/provider.mjs.map +1 -1
  128. package/dist/route-handler.d.mts.map +1 -1
  129. package/dist/route-handler.mjs +1 -33
  130. package/dist/route-handler.mjs.map +1 -1
  131. package/dist/server.mjs +1 -3
  132. package/package.json +29 -30
@@ -1 +1 @@
1
- {"version":3,"file":"instrumentation.mjs","names":[],"sources":["../src/instrumentation.ts"],"sourcesContent":["import type {\n AttributeValue,\n Span,\n TextMapPropagator,\n} from \"@opentelemetry/api\";\nimport { metrics, propagation } from \"@opentelemetry/api\";\nimport { BaggageSpanProcessor } from \"@opentelemetry/baggage-span-processor\";\nimport { AsyncLocalStorageContextManager } from \"@opentelemetry/context-async-hooks\";\nimport {\n CompositePropagator,\n W3CBaggagePropagator,\n W3CTraceContextPropagator,\n} from \"@opentelemetry/core\";\nimport { OTLPLogExporter } from \"@opentelemetry/exporter-logs-otlp-http\";\nimport {\n AggregationTemporalityPreference,\n OTLPMetricExporter,\n} from \"@opentelemetry/exporter-metrics-otlp-http\";\nimport { OTLPTraceExporter } from \"@opentelemetry/exporter-trace-otlp-http\";\nimport {\n type Instrumentation,\n registerInstrumentations,\n} from \"@opentelemetry/instrumentation\";\nimport { UndiciInstrumentation } from \"@opentelemetry/instrumentation-undici\";\nimport { resourceFromAttributes } from \"@opentelemetry/resources\";\nimport {\n BatchLogRecordProcessor,\n LoggerProvider,\n type LogRecordProcessor,\n} from \"@opentelemetry/sdk-logs\";\nimport {\n MeterProvider,\n type MetricReader,\n PeriodicExportingMetricReader,\n} from \"@opentelemetry/sdk-metrics\";\nimport {\n BatchSpanProcessor,\n type SpanProcessor,\n} from \"@opentelemetry/sdk-trace-base\";\nimport { NodeTracerProvider } from \"@opentelemetry/sdk-trace-node\";\n\nimport { readInterfereEnv } from \"./internal/env.js\";\nimport { resolveReleaseSlug } from \"./internal/release-slug.js\";\nimport { bridgeConsoleToOtel } from \"./internal/server/console-bridge.js\";\nimport { PrerenderSafeIdGenerator } from \"./internal/server/id-generator.js\";\nimport type { ServerInstrumentationOptions } from \"./internal/server/instrumentation-options.js\";\nimport { fetchAndCacheRemoteConfig } from \"./internal/server/remote-config.js\";\nimport { PRODUCER_VERSION } from \"./internal/version.js\";\n\nexport { PrerenderSafeIdGenerator } from \"./internal/server/id-generator.js\";\nexport type { ServerInstrumentationOptions } from \"./internal/server/instrumentation-options.js\";\n\nconst DEFAULT_SERVICE_NAME = \"interfere-sdk-next-server\";\nconst SERVICE_NAMESPACE = \"interfere\";\n\nlet registered = false;\n\nfunction matchesAny(url: string, patterns: (string | RegExp)[]): boolean {\n for (const pattern of patterns) {\n if (pattern instanceof RegExp ? pattern.test(url) : url.includes(pattern)) {\n return true;\n }\n }\n return false;\n}\n\n/**\n * Composable building blocks the Interfere SDK contributes to OTel —\n * span / log / metric processors, baggage propagator, undici\n * instrumentation, plus the resource attributes and side-effect\n * installers (console bridge + remote-config fetch).\n *\n * Use this when you want to plug Interfere into an existing OTel\n * bootstrap (e.g. `@vercel/otel`'s `registerOTel({...})`, DataDog's\n * `dd-trace-js`, or any custom `NodeTracerProvider` setup) instead of\n * the standalone `register()` path. The kit holds no global state and\n * touches no global slots — composition is the consumer's job.\n *\n * The standalone `register()` builds the kit internally and wires it\n * into private providers, so customer DX stays a one-liner export.\n *\n * Returns `null` when `INTERFERE_API_KEY` is unset — callers can spread\n * `kit?.spanProcessors ?? []` without a no-op guard.\n */\nexport interface InterfereOtelKit {\n /**\n * Patches `console.{debug,log,info,warn,error}` to also emit OTel\n * `LogRecord`s via the global `LoggerProvider`. Caller is responsible\n * for ensuring a `LoggerProvider` is registered globally before\n * calling — `register()` handles this; for composed setups, call\n * after your bootstrap (`registerOTel({...})` etc.) has run. Returns\n * a disposer that restores the original `console.*` methods.\n */\n enableConsoleBridge: () => () => void;\n /**\n * Fetches the SDK's remote plugin config and caches it for the\n * runtime. Customer code's `isPluginEnabled(...)` checks read from\n * the cache. Safe to call repeatedly.\n */\n fetchRemoteConfig: () => Promise<void>;\n /**\n * Instrumentations the SDK ships. Currently `UndiciInstrumentation`\n * pre-configured with `propagateContextUrls` / `ignoreUrls` semantics\n * from `ServerInstrumentationOptions`.\n *\n * **Composition with `@vercel/otel`**: `instrumentations: [\"auto\"]`\n * registers Vercel's `globalThis.fetch` wrapper, which only\n * auto-propagates `traceparent` to Vercel deployment URLs — outbound\n * fetches to a different origin (e.g. `in.interfere.com`) get a\n * span but no header injection unless\n * `instrumentationConfig.fetch.propagateContextUrls` is set, and\n * even then it doesn't cover the lower-level undici dispatcher path\n * Next.js route handlers use. Spread `kit.instrumentations` after\n * `\"auto\"` to layer this UndiciInstrumentation on top — propagation\n * extends to every outbound undici call (filtered via `ignoreUrls`).\n * Risk of double span emission on overlapping call sites is bounded:\n * Vercel's fetch wraps `globalThis.fetch`, this hooks the undici\n * dispatcher one layer lower, so duplicates only appear when both\n * paths actually fire on the same call.\n */\n instrumentations: Instrumentation[];\n logRecordProcessors: LogRecordProcessor[];\n metricReaders: MetricReader[];\n /**\n * W3C baggage propagator. Trace context is intentionally *not*\n * included — `@vercel/otel`'s `propagators: [\"auto\"]` already\n * registers it, and standalone `register()` adds it itself when\n * the global slot is empty. Composing this on top extends rather\n * than overrides.\n */\n propagators: TextMapPropagator[];\n /**\n * Pre-built resource attribute set. Pass into your provider's\n * `Resource` directly, or into `@vercel/otel`'s `attributes` field\n * (which merges with Vercel's own auto-detected `vercel.*` attrs).\n */\n resourceAttributes: Record<string, AttributeValue>;\n spanProcessors: SpanProcessor[];\n}\n\n/**\n * Pure factory — no global registration, no provider construction. Returns\n * the OTel primitives the SDK contributes so a host bootstrap (Vercel,\n * DataDog, custom) can compose them in.\n *\n * Returns `null` when `INTERFERE_API_KEY` isn't set, so callers can\n * unconditionally spread `kit?.spanProcessors ?? []` in dev where the\n * SDK isn't configured.\n */\nexport function buildInterfereOtelKit(\n opts: ServerInstrumentationOptions = {}\n): InterfereOtelKit | null {\n const env = readInterfereEnv();\n if (!env.apiKey) {\n return null;\n }\n\n const { slug: releaseSlug } = resolveReleaseSlug();\n if (!releaseSlug) {\n console.warn(\n \"[interfere] No commit SHA available; server spans will ship without `release.slug`. Set `INTERFERE_SOURCE_ID` (or any of `VERCEL_GIT_COMMIT_SHA`, `GITHUB_SHA`) on the runtime env.\"\n );\n }\n\n const sinkUrl = `${env.apiUrl}/v2/sink`;\n // Always-on ignore: the OTLP exporter posting to /v2/sink would\n // otherwise be re-traced by UndiciInstrumentation in an infinite\n // loop.\n const ignoreUrls = [sinkUrl, ...(opts.ignoreUrls ?? [])];\n const propagateContextUrls = opts.propagateContextUrls ?? [];\n\n const exporterHeaders: Record<string, string> = {\n \"x-api-key\": env.apiKey,\n \"x-interfere-producer-version\": PRODUCER_VERSION,\n };\n\n const resourceAttributes: Record<string, AttributeValue> = {\n \"service.name\": opts.serviceName ?? DEFAULT_SERVICE_NAME,\n \"service.namespace\": SERVICE_NAMESPACE,\n \"deployment.environment.name\": env.nodeEnvironment ?? \"unknown\",\n \"telemetry.sdk.language\": \"nodejs\",\n \"interfere.sdk.name\": \"@interfere/next\",\n \"interfere.sdk.version\": PRODUCER_VERSION,\n ...(releaseSlug ? { \"release.slug\": releaseSlug } : {}),\n };\n\n // `BaggageSpanProcessor` runs at span start (before the batch\n // processor schedules export) so every span carries the full baggage\n // attribute set when batched. Default `keyFilter` accepts everything;\n // browser SDK only writes `interfere.*`-prefixed entries via baggage\n // propagation, so the server side stays scoped without an explicit\n // filter.\n const spanProcessors: SpanProcessor[] = [\n new BaggageSpanProcessor(() => true),\n new BatchSpanProcessor(\n new OTLPTraceExporter({ url: sinkUrl, headers: exporterHeaders })\n ),\n ...(opts._internalAdditionalSpanProcessors ?? []),\n ];\n\n const logRecordProcessors: LogRecordProcessor[] = [\n new BatchLogRecordProcessor(\n new OTLPLogExporter({ url: sinkUrl, headers: exporterHeaders })\n ),\n ...(opts._internalAdditionalLogRecordProcessors ?? []),\n ];\n\n // `DELTA` temporality matches what `@vercel/otel`'s default\n // `metricReader: \"auto\"` used to install (see vercel/otel\n // `defaultMetricReader`) so the wire shape downstream consumers\n // (ClickHouse via Tinybird, the OTel collector's BetterStack export)\n // receive is unchanged across the migration. The 30s interval matches\n // the browser SDK's primary metric reader so server + client\n // datapoints land at the same cadence.\n const metricReaders: MetricReader[] = [\n new PeriodicExportingMetricReader({\n exporter: new OTLPMetricExporter({\n url: sinkUrl,\n headers: exporterHeaders,\n temporalityPreference: AggregationTemporalityPreference.DELTA,\n }),\n exportIntervalMillis: 30_000,\n }),\n ...(opts._internalAdditionalMetricReaders ?? []),\n ];\n\n // Just W3C baggage. Trace context is contributed by the host\n // bootstrap (`@vercel/otel`'s `propagators: [\"auto\"]`, or the\n // CompositePropagator standalone `register()` constructs). Composing\n // this on top extends rather than overrides.\n const propagators: TextMapPropagator[] = [new W3CBaggagePropagator()];\n\n // Standalone-path instrumentations. Conflicts with `@vercel/otel`'s\n // `instrumentations: [\"auto\"]` (Vercel ships its own runtime-aware\n // fetch instrumentation) — see the JSDoc on `InterfereOtelKit`.\n const instrumentations: Instrumentation[] = [\n new UndiciInstrumentation({\n ignoreRequestHook: (req: { origin: string; path: string }) => {\n const url = `${req.origin}${req.path}`;\n return matchesAny(url, ignoreUrls);\n },\n requestHook: (span: Span, req: { origin: string; path: string }) => {\n const url = `${req.origin}${req.path}`;\n if (matchesAny(url, propagateContextUrls)) {\n span.setAttribute(\"interfere.propagated\", true);\n }\n },\n }),\n ];\n\n return {\n resourceAttributes,\n spanProcessors,\n logRecordProcessors,\n metricReaders,\n propagators,\n instrumentations,\n enableConsoleBridge: () => bridgeConsoleToOtel(),\n fetchRemoteConfig: () => fetchAndCacheRemoteConfig(),\n };\n}\n\n/**\n * One-line server-side bootstrap for Next.js. Customers' `instrumentation.ts`\n * becomes:\n *\n * ```ts\n * export { register } from \"@interfere/next/instrumentation\";\n * ```\n *\n * Or, with overrides:\n *\n * ```ts\n * import { register as base } from \"@interfere/next/instrumentation\";\n * export const register = () => base({ serviceName: \"@my-org/api\" });\n * ```\n *\n * Customers who already run another OTel bootstrap (`@vercel/otel`,\n * DataDog `dd-trace-js`, custom `NodeTracerProvider`) should use\n * `buildInterfereOtelKit({...})` instead and compose the returned\n * processors / readers / propagators into their existing setup —\n * see the kit's JSDoc for examples.\n *\n * Constructs private `NodeTracerProvider` / `LoggerProvider` /\n * `MeterProvider` and registers them on the global slots. Last writer\n * wins on the globals, so customers running another OTel bootstrap\n * alongside this one will end up with whichever booted last; the kit\n * path avoids that fight entirely.\n *\n * Wired against the Node OTel SDK (`NodeTracerProvider`,\n * `AsyncLocalStorageContextManager`) — so this entry only ships into the\n * `nodejs` runtime bundle. The Edge runtime gets the no-op stub at\n * `instrumentation.edge.ts` via `package.json`'s `edge-light` /\n * `workerd` export conditions.\n *\n * Idempotent — repeat calls (e.g. HMR) short-circuit on the\n * module-scoped `registered` flag.\n *\n * Bails silently when `INTERFERE_API_KEY` is unset so dev runs without\n * the SDK configured don't crash.\n */\nexport async function register(\n opts: ServerInstrumentationOptions = {}\n): Promise<void> {\n if (registered) {\n return;\n }\n\n const kit = buildInterfereOtelKit(opts);\n if (!kit) {\n return;\n }\n\n const resource = resourceFromAttributes(kit.resourceAttributes);\n\n // Next 16's prerender extension throws on `Math.random()` /\n // `crypto.getRandomValues()` calls inside a Server Component that hasn't\n // awaited Request data first. OTel's default `RandomIdGenerator` calls\n // `Math.random()` for every span ID, so any span Next opens around a\n // prerendered route render blows up the build with\n // `next-prerender-random`. The counter-based generator below seeds its\n // randomness once at register-time (outside any prerender ALS frame) and\n // keeps span minting deterministic afterwards.\n const tracerProvider = new NodeTracerProvider({\n resource,\n spanProcessors: kit.spanProcessors,\n idGenerator: new PrerenderSafeIdGenerator(),\n });\n\n // Composed W3C trace context + baggage. `UndiciInstrumentation`\n // injects both `traceparent` and `baggage` on outgoing requests\n // matching `propagateContextUrls`, so cross-process correlation +\n // customer baggage propagation work without per-call code.\n //\n // Only set the global propagator when none is registered — customers\n // who installed their own propagator (B3, Jaeger, composite, ...) are\n // preserved. Mirrors the browser-side guard in\n // `react/internal/otel/provider.ts`.\n if (propagation.fields().length === 0) {\n propagation.setGlobalPropagator(\n new CompositePropagator({\n propagators: [new W3CTraceContextPropagator(), ...kit.propagators],\n })\n );\n }\n\n tracerProvider.register({\n contextManager: new AsyncLocalStorageContextManager().enable(),\n });\n\n const loggerProvider = new LoggerProvider({\n resource,\n processors: kit.logRecordProcessors,\n });\n // `logs.setGlobalLoggerProvider` is the single global slot OTel\n // exposes. Customers with their own LoggerProvider boot last and\n // win; we accept the trade-off — same constraint we live with on\n // the global propagator and context manager.\n const { logs: logsApi } = await import(\"@opentelemetry/api-logs\");\n logsApi.setGlobalLoggerProvider(loggerProvider);\n\n const meterProvider = new MeterProvider({\n resource,\n readers: kit.metricReaders,\n });\n // `MeterProvider` has no `register()` method — wire it into the\n // single global slot manually. Same trade-off as\n // `setGlobalLoggerProvider`: customers with their own MeterProvider\n // boot last and win.\n metrics.setGlobalMeterProvider(meterProvider);\n\n // Pass the meter provider explicitly so `UndiciInstrumentation`\n // records `http.client.request.duration` histograms against it.\n registerInstrumentations({\n tracerProvider,\n meterProvider,\n instrumentations: kit.instrumentations,\n });\n\n if (opts.consoleBridge !== false) {\n kit.enableConsoleBridge();\n }\n\n registered = true;\n\n // Preserve the existing `register` semantics from `@interfere/next/server` —\n // remote config gates plugin enable/disable. Customers migrating to this\n // subpath shouldn't lose that behaviour.\n await kit.fetchRemoteConfig();\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"instrumentation.mjs","names":[],"sources":["../src/instrumentation.ts"],"sourcesContent":["import type {\n AttributeValue,\n Span,\n TextMapPropagator,\n} from \"@opentelemetry/api\";\nimport { metrics, propagation } from \"@opentelemetry/api\";\nimport { BaggageSpanProcessor } from \"@opentelemetry/baggage-span-processor\";\nimport { AsyncLocalStorageContextManager } from \"@opentelemetry/context-async-hooks\";\nimport {\n CompositePropagator,\n W3CBaggagePropagator,\n W3CTraceContextPropagator,\n} from \"@opentelemetry/core\";\nimport { OTLPLogExporter } from \"@opentelemetry/exporter-logs-otlp-http\";\nimport {\n AggregationTemporalityPreference,\n OTLPMetricExporter,\n} from \"@opentelemetry/exporter-metrics-otlp-http\";\nimport { OTLPTraceExporter } from \"@opentelemetry/exporter-trace-otlp-http\";\nimport {\n type Instrumentation,\n registerInstrumentations,\n} from \"@opentelemetry/instrumentation\";\nimport { UndiciInstrumentation } from \"@opentelemetry/instrumentation-undici\";\nimport { resourceFromAttributes } from \"@opentelemetry/resources\";\nimport {\n BatchLogRecordProcessor,\n LoggerProvider,\n type LogRecordProcessor,\n} from \"@opentelemetry/sdk-logs\";\nimport {\n MeterProvider,\n type MetricReader,\n PeriodicExportingMetricReader,\n} from \"@opentelemetry/sdk-metrics\";\nimport {\n BatchSpanProcessor,\n type SpanProcessor,\n} from \"@opentelemetry/sdk-trace-base\";\nimport { NodeTracerProvider } from \"@opentelemetry/sdk-trace-node\";\n\nimport { readInterfereEnv } from \"./internal/env.js\";\nimport { resolveReleaseSlug } from \"./internal/release-slug.js\";\nimport { bridgeConsoleToOtel } from \"./internal/server/console-bridge.js\";\nimport { PrerenderSafeIdGenerator } from \"./internal/server/id-generator.js\";\nimport type { ServerInstrumentationOptions } from \"./internal/server/instrumentation-options.js\";\nimport { fetchAndCacheRemoteConfig } from \"./internal/server/remote-config.js\";\nimport { withPublicKey } from \"./internal/url.js\";\nimport { PRODUCER_VERSION } from \"./internal/version.js\";\n\nexport { PrerenderSafeIdGenerator } from \"./internal/server/id-generator.js\";\nexport type { ServerInstrumentationOptions } from \"./internal/server/instrumentation-options.js\";\n\nconst DEFAULT_SERVICE_NAME = \"interfere-sdk-next-server\";\nconst SERVICE_NAMESPACE = \"interfere\";\n\nlet registered = false;\n\nfunction matchesAny(url: string, patterns: (string | RegExp)[]): boolean {\n for (const pattern of patterns) {\n if (pattern instanceof RegExp ? pattern.test(url) : url.includes(pattern)) {\n return true;\n }\n }\n return false;\n}\n\n/**\n * Composable building blocks the Interfere SDK contributes to OTel —\n * span / log / metric processors, baggage propagator, undici\n * instrumentation, plus the resource attributes and side-effect\n * installers (console bridge + remote-config fetch).\n *\n * Use this when you want to plug Interfere into an existing OTel\n * bootstrap (e.g. `@vercel/otel`'s `registerOTel({...})`, DataDog's\n * `dd-trace-js`, or any custom `NodeTracerProvider` setup) instead of\n * the standalone `register()` path. The kit holds no global state and\n * touches no global slots — composition is the consumer's job.\n *\n * The standalone `register()` builds the kit internally and wires it\n * into private providers, so customer DX stays a one-liner export.\n *\n * Returns `null` when `INTERFERE_PUBLIC_KEY` is unset — callers can spread\n * `kit?.spanProcessors ?? []` without a no-op guard.\n */\nexport interface InterfereOtelKit {\n /**\n * Patches `console.{debug,log,info,warn,error}` to also emit OTel\n * `LogRecord`s via the global `LoggerProvider`. Caller is responsible\n * for ensuring a `LoggerProvider` is registered globally before\n * calling — `register()` handles this; for composed setups, call\n * after your bootstrap (`registerOTel({...})` etc.) has run. Returns\n * a disposer that restores the original `console.*` methods.\n */\n enableConsoleBridge: () => () => void;\n /**\n * Fetches the SDK's remote plugin config and caches it for the\n * runtime. Customer code's `isPluginEnabled(...)` checks read from\n * the cache. Safe to call repeatedly.\n */\n fetchRemoteConfig: () => Promise<void>;\n /**\n * Instrumentations the SDK ships. Currently `UndiciInstrumentation`\n * pre-configured with `propagateContextUrls` / `ignoreUrls` semantics\n * from `ServerInstrumentationOptions`.\n *\n * **Composition with `@vercel/otel`**: `instrumentations: [\"auto\"]`\n * registers Vercel's `globalThis.fetch` wrapper, which only\n * auto-propagates `traceparent` to Vercel deployment URLs — outbound\n * fetches to a different origin (e.g. `in.interfere.com`) get a\n * span but no header injection unless\n * `instrumentationConfig.fetch.propagateContextUrls` is set, and\n * even then it doesn't cover the lower-level undici dispatcher path\n * Next.js route handlers use. Spread `kit.instrumentations` after\n * `\"auto\"` to layer this UndiciInstrumentation on top — propagation\n * extends to every outbound undici call (filtered via `ignoreUrls`).\n * Risk of double span emission on overlapping call sites is bounded:\n * Vercel's fetch wraps `globalThis.fetch`, this hooks the undici\n * dispatcher one layer lower, so duplicates only appear when both\n * paths actually fire on the same call.\n */\n instrumentations: Instrumentation[];\n logRecordProcessors: LogRecordProcessor[];\n metricReaders: MetricReader[];\n /**\n * W3C baggage propagator. Trace context is intentionally *not*\n * included — `@vercel/otel`'s `propagators: [\"auto\"]` already\n * registers it, and standalone `register()` adds it itself when\n * the global slot is empty. Composing this on top extends rather\n * than overrides.\n */\n propagators: TextMapPropagator[];\n /**\n * Pre-built resource attribute set. Pass into your provider's\n * `Resource` directly, or into `@vercel/otel`'s `attributes` field\n * (which merges with Vercel's own auto-detected `vercel.*` attrs).\n */\n resourceAttributes: Record<string, AttributeValue>;\n spanProcessors: SpanProcessor[];\n}\n\n/**\n * Pure factory — no global registration, no provider construction. Returns\n * the OTel primitives the SDK contributes so a host bootstrap (Vercel,\n * DataDog, custom) can compose them in.\n *\n * Returns `null` when `INTERFERE_PUBLIC_KEY` isn't set, so callers can\n * unconditionally spread `kit?.spanProcessors ?? []` in dev where the\n * SDK isn't configured.\n */\nexport function buildInterfereOtelKit(\n opts: ServerInstrumentationOptions = {}\n): InterfereOtelKit | null {\n const env = readInterfereEnv();\n if (!env.publicKey) {\n return null;\n }\n\n const { slug: releaseSlug } = resolveReleaseSlug();\n if (!releaseSlug) {\n console.warn(\n \"[interfere] No commit SHA available; server spans will ship without `release.slug`. Set `INTERFERE_SOURCE_ID` (or any of `VERCEL_GIT_COMMIT_SHA`, `GITHUB_SHA`) on the runtime env.\"\n );\n }\n\n const sinkUrl = withPublicKey(`${env.apiUrl}/v2/sink`, env.publicKey);\n // Always-on ignore: the OTLP exporter posting to /v2/sink would\n // otherwise be re-traced by UndiciInstrumentation in an infinite\n // loop.\n const ignoreUrls = [sinkUrl, ...(opts.ignoreUrls ?? [])];\n const propagateContextUrls = opts.propagateContextUrls ?? [];\n\n const exporterHeaders: Record<string, string> = {\n \"x-interfere-producer-version\": PRODUCER_VERSION,\n };\n\n const resourceAttributes: Record<string, AttributeValue> = {\n \"service.name\": opts.serviceName ?? DEFAULT_SERVICE_NAME,\n \"service.namespace\": SERVICE_NAMESPACE,\n \"deployment.environment.name\": env.nodeEnvironment ?? \"unknown\",\n \"telemetry.sdk.language\": \"nodejs\",\n \"interfere.sdk.name\": \"@interfere/next\",\n \"interfere.sdk.version\": PRODUCER_VERSION,\n ...(releaseSlug ? { \"release.slug\": releaseSlug } : {}),\n };\n\n // `BaggageSpanProcessor` runs at span start (before the batch\n // processor schedules export) so every span carries the full baggage\n // attribute set when batched. Default `keyFilter` accepts everything;\n // browser SDK only writes `interfere.*`-prefixed entries via baggage\n // propagation, so the server side stays scoped without an explicit\n // filter.\n const spanProcessors: SpanProcessor[] = [\n new BaggageSpanProcessor(() => true),\n new BatchSpanProcessor(\n new OTLPTraceExporter({ url: sinkUrl, headers: exporterHeaders })\n ),\n ...(opts._internalAdditionalSpanProcessors ?? []),\n ];\n\n const logRecordProcessors: LogRecordProcessor[] = [\n new BatchLogRecordProcessor(\n new OTLPLogExporter({ url: sinkUrl, headers: exporterHeaders })\n ),\n ...(opts._internalAdditionalLogRecordProcessors ?? []),\n ];\n\n // `DELTA` temporality matches what `@vercel/otel`'s default\n // `metricReader: \"auto\"` used to install (see vercel/otel\n // `defaultMetricReader`) so the wire shape downstream consumers\n // (ClickHouse via Tinybird, the OTel collector's BetterStack export)\n // receive is unchanged across the migration. The 30s interval matches\n // the browser SDK's primary metric reader so server + client\n // datapoints land at the same cadence.\n const metricReaders: MetricReader[] = [\n new PeriodicExportingMetricReader({\n exporter: new OTLPMetricExporter({\n url: sinkUrl,\n headers: exporterHeaders,\n temporalityPreference: AggregationTemporalityPreference.DELTA,\n }),\n exportIntervalMillis: 30_000,\n }),\n ...(opts._internalAdditionalMetricReaders ?? []),\n ];\n\n // Just W3C baggage. Trace context is contributed by the host\n // bootstrap (`@vercel/otel`'s `propagators: [\"auto\"]`, or the\n // CompositePropagator standalone `register()` constructs). Composing\n // this on top extends rather than overrides.\n const propagators: TextMapPropagator[] = [new W3CBaggagePropagator()];\n\n // Standalone-path instrumentations. Conflicts with `@vercel/otel`'s\n // `instrumentations: [\"auto\"]` (Vercel ships its own runtime-aware\n // fetch instrumentation) — see the JSDoc on `InterfereOtelKit`.\n const instrumentations: Instrumentation[] = [\n new UndiciInstrumentation({\n ignoreRequestHook: (req: { origin: string; path: string }) => {\n const url = `${req.origin}${req.path}`;\n return matchesAny(url, ignoreUrls);\n },\n requestHook: (span: Span, req: { origin: string; path: string }) => {\n const url = `${req.origin}${req.path}`;\n if (matchesAny(url, propagateContextUrls)) {\n span.setAttribute(\"interfere.propagated\", true);\n }\n },\n }),\n ];\n\n return {\n resourceAttributes,\n spanProcessors,\n logRecordProcessors,\n metricReaders,\n propagators,\n instrumentations,\n enableConsoleBridge: () => bridgeConsoleToOtel(),\n fetchRemoteConfig: () => fetchAndCacheRemoteConfig(),\n };\n}\n\n/**\n * One-line server-side bootstrap for Next.js. Customers' `instrumentation.ts`\n * becomes:\n *\n * ```ts\n * export { register } from \"@interfere/next/instrumentation\";\n * ```\n *\n * Or, with overrides:\n *\n * ```ts\n * import { register as base } from \"@interfere/next/instrumentation\";\n * export const register = () => base({ serviceName: \"@my-org/api\" });\n * ```\n *\n * Customers who already run another OTel bootstrap (`@vercel/otel`,\n * DataDog `dd-trace-js`, custom `NodeTracerProvider`) should use\n * `buildInterfereOtelKit({...})` instead and compose the returned\n * processors / readers / propagators into their existing setup —\n * see the kit's JSDoc for examples.\n *\n * Constructs private `NodeTracerProvider` / `LoggerProvider` /\n * `MeterProvider` and registers them on the global slots. Last writer\n * wins on the globals, so customers running another OTel bootstrap\n * alongside this one will end up with whichever booted last; the kit\n * path avoids that fight entirely.\n *\n * Wired against the Node OTel SDK (`NodeTracerProvider`,\n * `AsyncLocalStorageContextManager`) — so this entry only ships into the\n * `nodejs` runtime bundle. The Edge runtime gets the no-op stub at\n * `instrumentation.edge.ts` via `package.json`'s `edge-light` /\n * `workerd` export conditions.\n *\n * Idempotent — repeat calls (e.g. HMR) short-circuit on the\n * module-scoped `registered` flag.\n *\n * Bails silently when `INTERFERE_PUBLIC_KEY` is unset so dev runs without\n * the SDK configured don't crash.\n */\nexport async function register(\n opts: ServerInstrumentationOptions = {}\n): Promise<void> {\n if (registered) {\n return;\n }\n\n const kit = buildInterfereOtelKit(opts);\n if (!kit) {\n return;\n }\n\n const resource = resourceFromAttributes(kit.resourceAttributes);\n\n // Next 16's prerender extension throws on `Math.random()` /\n // `crypto.getRandomValues()` calls inside a Server Component that hasn't\n // awaited Request data first. OTel's default `RandomIdGenerator` calls\n // `Math.random()` for every span ID, so any span Next opens around a\n // prerendered route render blows up the build with\n // `next-prerender-random`. The counter-based generator below seeds its\n // randomness once at register-time (outside any prerender ALS frame) and\n // keeps span minting deterministic afterwards.\n const tracerProvider = new NodeTracerProvider({\n resource,\n spanProcessors: kit.spanProcessors,\n idGenerator: new PrerenderSafeIdGenerator(),\n });\n\n // Composed W3C trace context + baggage. `UndiciInstrumentation`\n // injects both `traceparent` and `baggage` on outgoing requests\n // matching `propagateContextUrls`, so cross-process correlation +\n // customer baggage propagation work without per-call code.\n //\n // Only set the global propagator when none is registered — customers\n // who installed their own propagator (B3, Jaeger, composite, ...) are\n // preserved. Mirrors the browser-side guard in\n // `react/internal/otel/provider.ts`.\n if (propagation.fields().length === 0) {\n propagation.setGlobalPropagator(\n new CompositePropagator({\n propagators: [new W3CTraceContextPropagator(), ...kit.propagators],\n })\n );\n }\n\n tracerProvider.register({\n contextManager: new AsyncLocalStorageContextManager().enable(),\n });\n\n const loggerProvider = new LoggerProvider({\n resource,\n processors: kit.logRecordProcessors,\n });\n // `logs.setGlobalLoggerProvider` is the single global slot OTel\n // exposes. Customers with their own LoggerProvider boot last and\n // win; we accept the trade-off — same constraint we live with on\n // the global propagator and context manager.\n const { logs: logsApi } = await import(\"@opentelemetry/api-logs\");\n logsApi.setGlobalLoggerProvider(loggerProvider);\n\n const meterProvider = new MeterProvider({\n resource,\n readers: kit.metricReaders,\n });\n // `MeterProvider` has no `register()` method — wire it into the\n // single global slot manually. Same trade-off as\n // `setGlobalLoggerProvider`: customers with their own MeterProvider\n // boot last and win.\n metrics.setGlobalMeterProvider(meterProvider);\n\n // Pass the meter provider explicitly so `UndiciInstrumentation`\n // records `http.client.request.duration` histograms against it.\n registerInstrumentations({\n tracerProvider,\n meterProvider,\n instrumentations: kit.instrumentations,\n });\n\n if (opts.consoleBridge !== false) {\n kit.enableConsoleBridge();\n }\n\n registered = true;\n\n // Preserve the existing `register` semantics from `@interfere/next/server` —\n // remote config gates plugin enable/disable. Customers migrating to this\n // subpath shouldn't lose that behaviour.\n await kit.fetchRemoteConfig();\n}\n"],"mappings":"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"}
@@ -3,6 +3,8 @@ import { NextConfig } from "next";
3
3
  //#region src/internal/build/configure-build.d.ts
4
4
  interface InterfereInjectedValues {
5
5
  readonly __INTERFERE_FORCE_ENABLE__?: boolean;
6
+ readonly __INTERFERE_PROXY_MODE__?: boolean;
7
+ readonly __INTERFERE_PUBLIC_KEY__?: string;
6
8
  readonly __INTERFERE_RELEASE_SLUG__: string | null;
7
9
  }
8
10
  interface ConfigureBuildInput {
@@ -1 +1 @@
1
- {"version":3,"file":"configure-build.d.mts","names":[],"sources":["../../../src/internal/build/configure-build.ts"],"mappings":";;;UAKiB,uBAAA;EAAA,SACN,0BAAA;EAAA,SACA,0BAAA;AAAA;AAAA,UAqBD,mBAAA;EAAA,SACC,iBAAA,EAAmB,UAAA;EAAA,SACnB,eAAA,EAAiB,UAAA;EAAA,SACjB,UAAA;EAAA,SACA,MAAA,EAAQ,uBAAA;AAAA;AAAA,UAGT,oBAAA;EAAA,SACC,SAAA,EAAW,UAAA;EAAA,SACX,OAAA,EAAS,UAAA;AAAA;AAAA,iBAGJ,cAAA,CAAA;EACd,eAAA;EACA,iBAAA;EACA,UAAA;EACA;AAAA,GACC,mBAAA,GAAsB,oBAAA"}
1
+ {"version":3,"file":"configure-build.d.mts","names":[],"sources":["../../../src/internal/build/configure-build.ts"],"mappings":";;;UAKiB,uBAAA;EAAA,SACN,0BAAA;EAAA,SACA,wBAAA;EAAA,SACA,wBAAA;EAAA,SACA,0BAAA;AAAA;AAAA,UAqBD,mBAAA;EAAA,SACC,iBAAA,EAAmB,UAAA;EAAA,SACnB,eAAA,EAAiB,UAAA;EAAA,SACjB,UAAA;EAAA,SACA,MAAA,EAAQ,uBAAA;AAAA;AAAA,UAGT,oBAAA;EAAA,SACC,SAAA,EAAW,UAAA;EAAA,SACX,OAAA,EAAS,UAAU;AAAA;AAAA,iBAGd,cAAA,CAAA;EACd,eAAA;EACA,iBAAA;EACA,UAAA;EACA;AAAA,GACC,mBAAA,GAAsB,oBAAA"}
@@ -1,95 +1 @@
1
- import { existsSync } from "node:fs";
2
- import { basename, dirname, join, normalize, resolve } from "node:path";
3
- import { fileURLToPath } from "node:url";
4
- //#region src/internal/build/configure-build.ts
5
- const INSTRUMENTATION_CLIENT_FILES = [
6
- "instrumentation-client.ts",
7
- "instrumentation-client.tsx",
8
- "instrumentation-client.js",
9
- "instrumentation-client.jsx",
10
- "src/instrumentation-client.ts",
11
- "src/instrumentation-client.tsx",
12
- "src/instrumentation-client.js",
13
- "src/instrumentation-client.jsx"
14
- ];
15
- const LOADER_FILE_CANDIDATES = [
16
- "value-injection-loader.ts",
17
- "value-injection-loader.js",
18
- "value-injection-loader.mjs",
19
- "value-injection-loader.cjs"
20
- ];
21
- function configureBuild({ existingWebpack, existingTurbopack, projectDir, values }) {
22
- const instrumentationClientPath = resolveInstrumentationClientPath(projectDir);
23
- return {
24
- webpack: buildWebpackHook(existingWebpack, instrumentationClientPath, values),
25
- turbopack: buildTurbopackConfig(existingTurbopack, instrumentationClientPath, values)
26
- };
27
- }
28
- function hasInjectedMetadata(metadata) {
29
- return metadata.__INTERFERE_RELEASE_SLUG__ !== null;
30
- }
31
- function buildWebpackHook(existingWebpack, instrumentationClientPath, values) {
32
- if (!(instrumentationClientPath && hasInjectedMetadata(values))) return existingWebpack;
33
- const normalizedPath = normalize(instrumentationClientPath);
34
- const loaderPath = resolveLoaderPath();
35
- return (webpackConfig, options) => {
36
- const outputConfig = existingWebpack ? existingWebpack(webpackConfig, options) : webpackConfig;
37
- const mutableConfig = outputConfig;
38
- const injectionRule = {
39
- test: (resource) => Boolean(resource) && normalize(resource) === normalizedPath,
40
- use: [{
41
- loader: loaderPath,
42
- options: { values }
43
- }]
44
- };
45
- mutableConfig.module ??= {};
46
- mutableConfig.module.rules ??= [];
47
- mutableConfig.module.rules.push(injectionRule);
48
- return outputConfig;
49
- };
50
- }
51
- function buildTurbopackConfig(existingTurbopack, instrumentationClientPath, values) {
52
- const baseConfig = existingTurbopack ?? {};
53
- const debugIds = baseConfig.debugIds ?? true;
54
- if (!(instrumentationClientPath && hasInjectedMetadata(values))) {
55
- if (existingTurbopack === void 0 && debugIds === baseConfig.debugIds) return existingTurbopack;
56
- return {
57
- ...baseConfig,
58
- debugIds
59
- };
60
- }
61
- const ruleKey = `**/${basename(instrumentationClientPath)}`;
62
- const existingRule = baseConfig.rules?.[ruleKey] ?? {};
63
- const existingLoaders = Array.isArray(existingRule.loaders) ? existingRule.loaders : [];
64
- return {
65
- ...baseConfig,
66
- debugIds,
67
- rules: {
68
- ...baseConfig.rules,
69
- [ruleKey]: {
70
- ...existingRule,
71
- loaders: [...existingLoaders, {
72
- loader: resolveLoaderPath(),
73
- options: { serializedValues: JSON.stringify(values) }
74
- }]
75
- }
76
- }
77
- };
78
- }
79
- function resolveInstrumentationClientPath(projectDir) {
80
- for (const candidate of INSTRUMENTATION_CLIENT_FILES) {
81
- const filePath = resolve(projectDir, candidate);
82
- if (existsSync(filePath)) return filePath;
83
- }
84
- return null;
85
- }
86
- function resolveLoaderPath() {
87
- const directory = resolve(dirname(fileURLToPath(import.meta.url)));
88
- for (const candidate of LOADER_FILE_CANDIDATES) {
89
- const filePath = join(directory, candidate);
90
- if (existsSync(filePath)) return filePath;
91
- }
92
- return join(directory, "value-injection-loader.js");
93
- }
94
- //#endregion
95
- export { configureBuild };
1
+ import{existsSync}from"node:fs";import{basename,dirname,join,normalize,resolve}from"node:path";import{fileURLToPath}from"node:url";const INSTRUMENTATION_CLIENT_FILES=[`instrumentation-client.ts`,`instrumentation-client.tsx`,`instrumentation-client.js`,`instrumentation-client.jsx`,`src/instrumentation-client.ts`,`src/instrumentation-client.tsx`,`src/instrumentation-client.js`,`src/instrumentation-client.jsx`],LOADER_FILE_CANDIDATES=[`value-injection-loader.ts`,`value-injection-loader.js`,`value-injection-loader.mjs`,`value-injection-loader.cjs`];function configureBuild({existingWebpack,existingTurbopack,projectDir,values}){let instrumentationClientPath=resolveInstrumentationClientPath(projectDir);return{webpack:buildWebpackHook(existingWebpack,instrumentationClientPath,values),turbopack:buildTurbopackConfig(existingTurbopack,instrumentationClientPath,values)}}function hasInjectedMetadata(metadata){return metadata.__INTERFERE_RELEASE_SLUG__!==null||metadata.__INTERFERE_PUBLIC_KEY__!==void 0}function buildWebpackHook(existingWebpack,instrumentationClientPath,values){if(!(instrumentationClientPath&&hasInjectedMetadata(values)))return existingWebpack;let normalizedPath=normalize(instrumentationClientPath),loaderPath=resolveLoaderPath();return(webpackConfig,options)=>{let outputConfig=existingWebpack?existingWebpack(webpackConfig,options):webpackConfig,mutableConfig=outputConfig,injectionRule={test:resource=>!!resource&&normalize(resource)===normalizedPath,use:[{loader:loaderPath,options:{values}}]};return mutableConfig.module??={},mutableConfig.module.rules??=[],mutableConfig.module.rules.push(injectionRule),outputConfig}}function buildTurbopackConfig(existingTurbopack,instrumentationClientPath,values){let baseConfig=existingTurbopack??{},debugIds=baseConfig.debugIds??!0;if(!(instrumentationClientPath&&hasInjectedMetadata(values)))return existingTurbopack===void 0&&debugIds===baseConfig.debugIds?existingTurbopack:{...baseConfig,debugIds};let ruleKey=`**/${basename(instrumentationClientPath)}`,existingRule=baseConfig.rules?.[ruleKey]??{},existingLoaders=Array.isArray(existingRule.loaders)?existingRule.loaders:[];return{...baseConfig,debugIds,rules:{...baseConfig.rules,[ruleKey]:{...existingRule,loaders:[...existingLoaders,{loader:resolveLoaderPath(),options:{serializedValues:JSON.stringify(values)}}]}}}}function resolveInstrumentationClientPath(projectDir){for(let candidate of INSTRUMENTATION_CLIENT_FILES){let filePath=resolve(projectDir,candidate);if(existsSync(filePath))return filePath}return null}function resolveLoaderPath(){let directory=resolve(dirname(fileURLToPath(import.meta.url)));for(let candidate of LOADER_FILE_CANDIDATES){let filePath=join(directory,candidate);if(existsSync(filePath))return filePath}return join(directory,`value-injection-loader.js`)}export{configureBuild};
@@ -1 +1 @@
1
- {"version":3,"file":"configure-build.mjs","names":[],"sources":["../../../src/internal/build/configure-build.ts"],"sourcesContent":["import { existsSync } from \"node:fs\";\nimport { basename, dirname, join, normalize, resolve } from \"node:path\";\nimport { fileURLToPath } from \"node:url\";\nimport type { NextConfig } from \"next\";\n\nexport interface InterfereInjectedValues {\n readonly __INTERFERE_FORCE_ENABLE__?: boolean;\n readonly __INTERFERE_RELEASE_SLUG__: string | null;\n}\n\nconst INSTRUMENTATION_CLIENT_FILES = [\n \"instrumentation-client.ts\",\n \"instrumentation-client.tsx\",\n \"instrumentation-client.js\",\n \"instrumentation-client.jsx\",\n \"src/instrumentation-client.ts\",\n \"src/instrumentation-client.tsx\",\n \"src/instrumentation-client.js\",\n \"src/instrumentation-client.jsx\",\n] as const;\n\nconst LOADER_FILE_CANDIDATES = [\n \"value-injection-loader.ts\",\n \"value-injection-loader.js\",\n \"value-injection-loader.mjs\",\n \"value-injection-loader.cjs\",\n] as const;\n\ninterface ConfigureBuildInput {\n readonly existingTurbopack: NextConfig[\"turbopack\"] | undefined;\n readonly existingWebpack: NextConfig[\"webpack\"] | undefined;\n readonly projectDir: string;\n readonly values: InterfereInjectedValues;\n}\n\ninterface ConfigureBuildOutput {\n readonly turbopack: NextConfig[\"turbopack\"] | undefined;\n readonly webpack: NextConfig[\"webpack\"] | undefined;\n}\n\nexport function configureBuild({\n existingWebpack,\n existingTurbopack,\n projectDir,\n values,\n}: ConfigureBuildInput): ConfigureBuildOutput {\n const instrumentationClientPath =\n resolveInstrumentationClientPath(projectDir);\n\n return {\n webpack: buildWebpackHook(\n existingWebpack,\n instrumentationClientPath,\n values\n ),\n turbopack: buildTurbopackConfig(\n existingTurbopack,\n instrumentationClientPath,\n values\n ),\n };\n}\n\nfunction hasInjectedMetadata(metadata: InterfereInjectedValues): boolean {\n return metadata.__INTERFERE_RELEASE_SLUG__ !== null;\n}\n\nfunction buildWebpackHook(\n existingWebpack: NextConfig[\"webpack\"] | undefined,\n instrumentationClientPath: string | null,\n values: InterfereInjectedValues\n): NextConfig[\"webpack\"] | undefined {\n if (!(instrumentationClientPath && hasInjectedMetadata(values))) {\n return existingWebpack;\n }\n\n const normalizedPath = normalize(instrumentationClientPath);\n const loaderPath = resolveLoaderPath();\n\n return (webpackConfig, options) => {\n const outputConfig = existingWebpack\n ? existingWebpack(webpackConfig, options)\n : webpackConfig;\n const mutableConfig = outputConfig as {\n module?: { rules?: unknown[] };\n };\n\n const injectionRule = {\n test: (resource: string): boolean =>\n Boolean(resource) && normalize(resource) === normalizedPath,\n use: [\n {\n loader: loaderPath,\n options: { values },\n },\n ],\n };\n\n mutableConfig.module ??= {};\n mutableConfig.module.rules ??= [];\n mutableConfig.module.rules.push(injectionRule);\n\n return outputConfig;\n };\n}\n\nfunction buildTurbopackConfig(\n existingTurbopack: NextConfig[\"turbopack\"] | undefined,\n instrumentationClientPath: string | null,\n values: InterfereInjectedValues\n): NextConfig[\"turbopack\"] | undefined {\n // Turbopack natively pairs JS chunks to source maps via debug IDs (it\n // injects matching `//# debugId=…` into the chunk and a `\"debugId\"` field\n // into the map). We rely on this in `discoverTurbopack`, because the\n // `//# sourceMappingURL=…` URL in the chunk is the source map's content\n // hash — not the `.js.map` filename on disk — so URL-based pairing always\n // fails for turbopack output.\n //\n // We force `debugIds: true` unless the user opted out explicitly. The\n // user keeps full control: any user-provided value (including `false`)\n // wins via `??`.\n const baseConfig = (existingTurbopack ?? {}) as {\n rules?: Record<string, unknown>;\n debugIds?: boolean;\n };\n const debugIds = baseConfig.debugIds ?? true;\n\n // No instrumentation client → only the debugIds patch is needed, and only\n // if the user hasn't already declared turbopack config (in which case we\n // leave their object untouched but layered with our default).\n if (!(instrumentationClientPath && hasInjectedMetadata(values))) {\n if (existingTurbopack === undefined && debugIds === baseConfig.debugIds) {\n return existingTurbopack;\n }\n \n return { ...baseConfig, debugIds } as NextConfig[\"turbopack\"];\n }\n\n const ruleKey = `**/${basename(instrumentationClientPath)}`;\n const existingRule = (baseConfig.rules?.[ruleKey] ?? {}) as {\n loaders?: unknown[];\n };\n const existingLoaders = Array.isArray(existingRule.loaders)\n ? existingRule.loaders\n : [];\n\n return {\n ...baseConfig,\n debugIds,\n rules: {\n ...baseConfig.rules,\n [ruleKey]: {\n ...existingRule,\n loaders: [\n ...existingLoaders,\n {\n loader: resolveLoaderPath(),\n options: {\n serializedValues: JSON.stringify(values),\n },\n },\n ],\n },\n },\n } as NextConfig[\"turbopack\"];\n}\n\nfunction resolveInstrumentationClientPath(projectDir: string): string | null {\n for (const candidate of INSTRUMENTATION_CLIENT_FILES) {\n const filePath = resolve(projectDir, candidate);\n if (existsSync(filePath)) {\n return filePath;\n }\n }\n\n return null;\n}\n\nfunction resolveLoaderPath(): string {\n const directory = resolve(dirname(fileURLToPath(import.meta.url)));\n\n for (const candidate of LOADER_FILE_CANDIDATES) {\n const filePath = join(directory, candidate);\n if (existsSync(filePath)) {\n return filePath;\n }\n }\n\n return join(directory, \"value-injection-loader.js\");\n}\n"],"mappings":";;;;AAUA,MAAM,+BAA+B;CACnC;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACD;AAED,MAAM,yBAAyB;CAC7B;CACA;CACA;CACA;CACD;AAcD,SAAgB,eAAe,EAC7B,iBACA,mBACA,YACA,UAC4C;CAC5C,MAAM,4BACJ,iCAAiC,WAAW;CAE9C,OAAO;EACL,SAAS,iBACP,iBACA,2BACA,OACD;EACD,WAAW,qBACT,mBACA,2BACA,OACD;EACF;;AAGH,SAAS,oBAAoB,UAA4C;CACvE,OAAO,SAAS,+BAA+B;;AAGjD,SAAS,iBACP,iBACA,2BACA,QACmC;CACnC,IAAI,EAAE,6BAA6B,oBAAoB,OAAO,GAC5D,OAAO;CAGT,MAAM,iBAAiB,UAAU,0BAA0B;CAC3D,MAAM,aAAa,mBAAmB;CAEtC,QAAQ,eAAe,YAAY;EACjC,MAAM,eAAe,kBACjB,gBAAgB,eAAe,QAAQ,GACvC;EACJ,MAAM,gBAAgB;EAItB,MAAM,gBAAgB;GACpB,OAAO,aACL,QAAQ,SAAS,IAAI,UAAU,SAAS,KAAK;GAC/C,KAAK,CACH;IACE,QAAQ;IACR,SAAS,EAAE,QAAQ;IACpB,CACF;GACF;EAED,cAAc,WAAW,EAAE;EAC3B,cAAc,OAAO,UAAU,EAAE;EACjC,cAAc,OAAO,MAAM,KAAK,cAAc;EAE9C,OAAO;;;AAIX,SAAS,qBACP,mBACA,2BACA,QACqC;CAWrC,MAAM,aAAc,qBAAqB,EAAE;CAI3C,MAAM,WAAW,WAAW,YAAY;CAKxC,IAAI,EAAE,6BAA6B,oBAAoB,OAAO,GAAG;EAC/D,IAAI,sBAAsB,KAAA,KAAa,aAAa,WAAW,UAC7D,OAAO;EAGT,OAAO;GAAE,GAAG;GAAY;GAAU;;CAGpC,MAAM,UAAU,MAAM,SAAS,0BAA0B;CACzD,MAAM,eAAgB,WAAW,QAAQ,YAAY,EAAE;CAGvD,MAAM,kBAAkB,MAAM,QAAQ,aAAa,QAAQ,GACvD,aAAa,UACb,EAAE;CAEN,OAAO;EACL,GAAG;EACH;EACA,OAAO;GACL,GAAG,WAAW;IACb,UAAU;IACT,GAAG;IACH,SAAS,CACP,GAAG,iBACH;KACE,QAAQ,mBAAmB;KAC3B,SAAS,EACP,kBAAkB,KAAK,UAAU,OAAO,EACzC;KACF,CACF;IACF;GACF;EACF;;AAGH,SAAS,iCAAiC,YAAmC;CAC3E,KAAK,MAAM,aAAa,8BAA8B;EACpD,MAAM,WAAW,QAAQ,YAAY,UAAU;EAC/C,IAAI,WAAW,SAAS,EACtB,OAAO;;CAIX,OAAO;;AAGT,SAAS,oBAA4B;CACnC,MAAM,YAAY,QAAQ,QAAQ,cAAc,OAAO,KAAK,IAAI,CAAC,CAAC;CAElE,KAAK,MAAM,aAAa,wBAAwB;EAC9C,MAAM,WAAW,KAAK,WAAW,UAAU;EAC3C,IAAI,WAAW,SAAS,EACtB,OAAO;;CAIX,OAAO,KAAK,WAAW,4BAA4B"}
1
+ {"version":3,"file":"configure-build.mjs","names":[],"sources":["../../../src/internal/build/configure-build.ts"],"sourcesContent":["import { existsSync } from \"node:fs\";\nimport { basename, dirname, join, normalize, resolve } from \"node:path\";\nimport { fileURLToPath } from \"node:url\";\nimport type { NextConfig } from \"next\";\n\nexport interface InterfereInjectedValues {\n readonly __INTERFERE_FORCE_ENABLE__?: boolean;\n readonly __INTERFERE_PROXY_MODE__?: boolean;\n readonly __INTERFERE_PUBLIC_KEY__?: string;\n readonly __INTERFERE_RELEASE_SLUG__: string | null;\n}\n\nconst INSTRUMENTATION_CLIENT_FILES = [\n \"instrumentation-client.ts\",\n \"instrumentation-client.tsx\",\n \"instrumentation-client.js\",\n \"instrumentation-client.jsx\",\n \"src/instrumentation-client.ts\",\n \"src/instrumentation-client.tsx\",\n \"src/instrumentation-client.js\",\n \"src/instrumentation-client.jsx\",\n] as const;\n\nconst LOADER_FILE_CANDIDATES = [\n \"value-injection-loader.ts\",\n \"value-injection-loader.js\",\n \"value-injection-loader.mjs\",\n \"value-injection-loader.cjs\",\n] as const;\n\ninterface ConfigureBuildInput {\n readonly existingTurbopack: NextConfig[\"turbopack\"] | undefined;\n readonly existingWebpack: NextConfig[\"webpack\"] | undefined;\n readonly projectDir: string;\n readonly values: InterfereInjectedValues;\n}\n\ninterface ConfigureBuildOutput {\n readonly turbopack: NextConfig[\"turbopack\"] | undefined;\n readonly webpack: NextConfig[\"webpack\"] | undefined;\n}\n\nexport function configureBuild({\n existingWebpack,\n existingTurbopack,\n projectDir,\n values,\n}: ConfigureBuildInput): ConfigureBuildOutput {\n const instrumentationClientPath =\n resolveInstrumentationClientPath(projectDir);\n\n return {\n webpack: buildWebpackHook(\n existingWebpack,\n instrumentationClientPath,\n values\n ),\n turbopack: buildTurbopackConfig(\n existingTurbopack,\n instrumentationClientPath,\n values\n ),\n };\n}\n\nfunction hasInjectedMetadata(metadata: InterfereInjectedValues): boolean {\n return (\n metadata.__INTERFERE_RELEASE_SLUG__ !== null ||\n metadata.__INTERFERE_PUBLIC_KEY__ !== undefined\n );\n}\n\nfunction buildWebpackHook(\n existingWebpack: NextConfig[\"webpack\"] | undefined,\n instrumentationClientPath: string | null,\n values: InterfereInjectedValues\n): NextConfig[\"webpack\"] | undefined {\n if (!(instrumentationClientPath && hasInjectedMetadata(values))) {\n return existingWebpack;\n }\n\n const normalizedPath = normalize(instrumentationClientPath);\n const loaderPath = resolveLoaderPath();\n\n return (webpackConfig, options) => {\n const outputConfig = existingWebpack\n ? existingWebpack(webpackConfig, options)\n : webpackConfig;\n const mutableConfig = outputConfig as {\n module?: { rules?: unknown[] };\n };\n\n const injectionRule = {\n test: (resource: string): boolean =>\n Boolean(resource) && normalize(resource) === normalizedPath,\n use: [\n {\n loader: loaderPath,\n options: { values },\n },\n ],\n };\n\n mutableConfig.module ??= {};\n mutableConfig.module.rules ??= [];\n mutableConfig.module.rules.push(injectionRule);\n\n return outputConfig;\n };\n}\n\nfunction buildTurbopackConfig(\n existingTurbopack: NextConfig[\"turbopack\"] | undefined,\n instrumentationClientPath: string | null,\n values: InterfereInjectedValues\n): NextConfig[\"turbopack\"] | undefined {\n // Turbopack natively pairs JS chunks to source maps via debug IDs (it\n // injects matching `//# debugId=…` into the chunk and a `\"debugId\"` field\n // into the map). We rely on this in `discoverTurbopack`, because the\n // `//# sourceMappingURL=…` URL in the chunk is the source map's content\n // hash — not the `.js.map` filename on disk — so URL-based pairing always\n // fails for turbopack output.\n //\n // We force `debugIds: true` unless the user opted out explicitly. The\n // user keeps full control: any user-provided value (including `false`)\n // wins via `??`.\n const baseConfig = (existingTurbopack ?? {}) as {\n rules?: Record<string, unknown>;\n debugIds?: boolean;\n };\n const debugIds = baseConfig.debugIds ?? true;\n\n // No instrumentation client → only the debugIds patch is needed, and only\n // if the user hasn't already declared turbopack config (in which case we\n // leave their object untouched but layered with our default).\n if (!(instrumentationClientPath && hasInjectedMetadata(values))) {\n if (existingTurbopack === undefined && debugIds === baseConfig.debugIds) {\n return existingTurbopack;\n }\n \n return { ...baseConfig, debugIds } as NextConfig[\"turbopack\"];\n }\n\n const ruleKey = `**/${basename(instrumentationClientPath)}`;\n const existingRule = (baseConfig.rules?.[ruleKey] ?? {}) as {\n loaders?: unknown[];\n };\n const existingLoaders = Array.isArray(existingRule.loaders)\n ? existingRule.loaders\n : [];\n\n return {\n ...baseConfig,\n debugIds,\n rules: {\n ...baseConfig.rules,\n [ruleKey]: {\n ...existingRule,\n loaders: [\n ...existingLoaders,\n {\n loader: resolveLoaderPath(),\n options: {\n serializedValues: JSON.stringify(values),\n },\n },\n ],\n },\n },\n } as NextConfig[\"turbopack\"];\n}\n\nfunction resolveInstrumentationClientPath(projectDir: string): string | null {\n for (const candidate of INSTRUMENTATION_CLIENT_FILES) {\n const filePath = resolve(projectDir, candidate);\n if (existsSync(filePath)) {\n return filePath;\n }\n }\n\n return null;\n}\n\nfunction resolveLoaderPath(): string {\n const directory = resolve(dirname(fileURLToPath(import.meta.url)));\n\n for (const candidate of LOADER_FILE_CANDIDATES) {\n const filePath = join(directory, candidate);\n if (existsSync(filePath)) {\n return filePath;\n }\n }\n\n return join(directory, \"value-injection-loader.js\");\n}\n"],"mappings":"mIAYA,MAAM,6BAA+B,CACnC,4BACA,6BACA,4BACA,6BACA,gCACA,iCACA,gCACA,gCACF,EAEM,uBAAyB,CAC7B,4BACA,4BACA,6BACA,4BACF,EAcA,SAAgB,eAAe,CAC7B,gBACA,kBACA,WACA,QAC4C,CAC5C,IAAM,0BACJ,iCAAiC,UAAU,EAE7C,MAAO,CACL,QAAS,iBACP,gBACA,0BACA,MACF,EACA,UAAW,qBACT,kBACA,0BACA,MACF,CACF,CACF,CAEA,SAAS,oBAAoB,SAA4C,CACvE,OACE,SAAS,6BAA+B,MACxC,SAAS,2BAA6B,IAAA,EAE1C,CAEA,SAAS,iBACP,gBACA,0BACA,OACmC,CACnC,GAAI,EAAE,2BAA6B,oBAAoB,MAAM,GAC3D,OAAO,gBAGT,IAAM,eAAiB,UAAU,yBAAyB,EACpD,WAAa,kBAAkB,EAErC,OAAQ,cAAe,UAAY,CACjC,IAAM,aAAe,gBACjB,gBAAgB,cAAe,OAAO,EACtC,cACE,cAAgB,aAIhB,cAAgB,CACpB,KAAO,UACL,EAAQ,UAAa,UAAU,QAAQ,IAAM,eAC/C,IAAK,CACH,CACE,OAAQ,WACR,QAAS,CAAE,MAAO,CACpB,CACF,CACF,EAMA,MAJA,eAAc,SAAW,CAAC,EAC1B,cAAc,OAAO,QAAU,CAAC,EAChC,cAAc,OAAO,MAAM,KAAK,aAAa,EAEtC,YACT,CACF,CAEA,SAAS,qBACP,kBACA,0BACA,OACqC,CAWrC,IAAM,WAAc,mBAAqB,CAAC,EAIpC,SAAW,WAAW,UAAY,GAKxC,GAAI,EAAE,2BAA6B,oBAAoB,MAAM,GAK3D,OAJI,oBAAsB,IAAA,IAAa,WAAa,WAAW,SACtD,kBAGF,CAAE,GAAG,WAAY,QAAS,EAGnC,IAAM,QAAU,MAAM,SAAS,yBAAyB,IAClD,aAAgB,WAAW,QAAQ,UAAY,CAAC,EAGhD,gBAAkB,MAAM,QAAQ,aAAa,OAAO,EACtD,aAAa,QACb,CAAC,EAEL,MAAO,CACL,GAAG,WACH,SACA,MAAO,CACL,GAAG,WAAW,OACb,SAAU,CACT,GAAG,aACH,QAAS,CACP,GAAG,gBACH,CACE,OAAQ,kBAAkB,EAC1B,QAAS,CACP,iBAAkB,KAAK,UAAU,MAAM,CACzC,CACF,CACF,CACF,CACF,CACF,CACF,CAEA,SAAS,iCAAiC,WAAmC,CAC3E,IAAK,IAAM,aAAa,6BAA8B,CACpD,IAAM,SAAW,QAAQ,WAAY,SAAS,EAC9C,GAAI,WAAW,QAAQ,EACrB,OAAO,QAEX,CAEA,OAAO,IACT,CAEA,SAAS,mBAA4B,CACnC,IAAM,UAAY,QAAQ,QAAQ,cAAc,OAAO,KAAK,GAAG,CAAC,CAAC,EAEjE,IAAK,IAAM,aAAa,uBAAwB,CAC9C,IAAM,SAAW,KAAK,UAAW,SAAS,EAC1C,GAAI,WAAW,QAAQ,EACrB,OAAO,QAEX,CAEA,OAAO,KAAK,UAAW,2BAA2B,CACpD"}
@@ -1,6 +1,7 @@
1
1
  import { ManifestBundler } from "@interfere/types/data/source-maps";
2
2
 
3
3
  //#region src/internal/build/detect-bundler.d.ts
4
- declare function detectActiveBundler(env?: Readonly<Record<string, string | undefined>>, argv?: readonly string[]): Exclude<ManifestBundler, "tsc">;
4
+ type NextBuildBundler = Extract<ManifestBundler, "webpack" | "turbopack">;
5
+ declare function detectActiveBundler(env?: Readonly<Record<string, string | undefined>>, argv?: readonly string[]): NextBuildBundler;
5
6
  //#endregion
6
- export { detectActiveBundler };
7
+ export { NextBuildBundler, detectActiveBundler };
@@ -1 +1 @@
1
- {"version":3,"file":"detect-bundler.d.mts","names":[],"sources":["../../../src/internal/build/detect-bundler.ts"],"mappings":";;;iBAIgB,mBAAA,CACd,GAAA,GAAK,QAAA,CAAS,MAAA,+BACd,IAAA,uBACC,OAAA,CAAQ,eAAA"}
1
+ {"version":3,"file":"detect-bundler.d.mts","names":[],"sources":["../../../src/internal/build/detect-bundler.ts"],"mappings":";;;KAIY,gBAAA,GAAmB,OAAO,CAAC,eAAA;AAAA,iBAEvB,mBAAA,CACd,GAAA,GAAK,QAAA,CAAS,MAAA,+BACd,IAAA,uBACC,gBAAA"}
@@ -1,9 +1 @@
1
- //#region src/internal/build/detect-bundler.ts
2
- const TURBOPACK_FLAGS = ["--turbo", "--turbopack"];
3
- function detectActiveBundler(env = process.env, argv = process.argv) {
4
- if (env["TURBOPACK"] === "1") return "turbopack";
5
- if (TURBOPACK_FLAGS.some((flag) => argv.includes(flag))) return "turbopack";
6
- return "webpack";
7
- }
8
- //#endregion
9
- export { detectActiveBundler };
1
+ const TURBOPACK_FLAGS=[`--turbo`,`--turbopack`];function detectActiveBundler(env=process.env,argv=process.argv){return env.TURBOPACK===`1`||TURBOPACK_FLAGS.some(flag=>argv.includes(flag))?`turbopack`:`webpack`}export{detectActiveBundler};
@@ -1 +1 @@
1
- {"version":3,"file":"detect-bundler.mjs","names":[],"sources":["../../../src/internal/build/detect-bundler.ts"],"sourcesContent":["import type { ManifestBundler } from \"@interfere/types/data/source-maps\";\n\nconst TURBOPACK_FLAGS = [\"--turbo\", \"--turbopack\"] as const;\n\nexport function detectActiveBundler(\n env: Readonly<Record<string, string | undefined>> = process.env,\n argv: readonly string[] = process.argv\n): Exclude<ManifestBundler, \"tsc\"> {\n if (env[\"TURBOPACK\"] === \"1\") {\n return \"turbopack\";\n }\n if (TURBOPACK_FLAGS.some((flag) => argv.includes(flag))) {\n return \"turbopack\";\n }\n return \"webpack\";\n}\n"],"mappings":";AAEA,MAAM,kBAAkB,CAAC,WAAW,cAAc;AAElD,SAAgB,oBACd,MAAoD,QAAQ,KAC5D,OAA0B,QAAQ,MACD;CACjC,IAAI,IAAI,iBAAiB,KACvB,OAAO;CAET,IAAI,gBAAgB,MAAM,SAAS,KAAK,SAAS,KAAK,CAAC,EACrD,OAAO;CAET,OAAO"}
1
+ {"version":3,"file":"detect-bundler.mjs","names":[],"sources":["../../../src/internal/build/detect-bundler.ts"],"sourcesContent":["import type { ManifestBundler } from \"@interfere/types/data/source-maps\";\n\nconst TURBOPACK_FLAGS = [\"--turbo\", \"--turbopack\"] as const;\n\nexport type NextBuildBundler = Extract<ManifestBundler, \"webpack\" | \"turbopack\">;\n\nexport function detectActiveBundler(\n env: Readonly<Record<string, string | undefined>> = process.env,\n argv: readonly string[] = process.argv\n): NextBuildBundler {\n if (env[\"TURBOPACK\"] === \"1\") {\n return \"turbopack\";\n }\n if (TURBOPACK_FLAGS.some((flag) => argv.includes(flag))) {\n return \"turbopack\";\n }\n return \"webpack\";\n}\n"],"mappings":"AAEA,MAAM,gBAAkB,CAAC,UAAW,aAAa,EAIjD,SAAgB,oBACd,IAAoD,QAAQ,IAC5D,KAA0B,QAAQ,KAChB,CAOlB,OANI,IAAI,YAAiB,KAGrB,gBAAgB,KAAM,MAAS,KAAK,SAAS,IAAI,CAAC,EAC7C,YAEF,SACT"}
@@ -1,7 +1,5 @@
1
1
  import { ProductionCompileContext, ResolvedBuildConfig } from "../../config.mjs";
2
2
  import { ReleaseSlug } from "@interfere/types/releases/slug";
3
- import * as _$_interfere_sdk_models0 from "@interfere/sdk/models";
4
- import * as _$zod from "zod";
5
3
  import { ReleasesConfigResponse } from "@interfere/sdk/models/releases-config-response.js";
6
4
  import { CreateReleaseResponse } from "@interfere/types/releases/definition";
7
5
 
@@ -45,14 +43,14 @@ declare function runBuildPipeline(context: ProductionCompileContext, metadata: R
45
43
  ready: true;
46
44
  fileCount: number;
47
45
  release: {
48
- org: _$_interfere_sdk_models0.OrgRef;
49
- surface: _$_interfere_sdk_models0.SurfaceRef;
50
- source: _$_interfere_sdk_models0.ReleaseSourceRef;
51
- build: _$_interfere_sdk_models0.ReleaseBuildRef;
46
+ org: import("@interfere/sdk/models").OrgRef;
47
+ surface: import("@interfere/sdk/models").SurfaceRef;
48
+ source: import("@interfere/sdk/models").ReleaseSourceRef;
49
+ build: import("@interfere/sdk/models").ReleaseBuildRef;
52
50
  destination: {
53
51
  id: string;
54
52
  environment: string | null;
55
- slug: `rel_${string}` & _$zod.$brand<"ReleaseSlug">;
53
+ slug: `rel_${string}` & import("zod").$brand<"ReleaseSlug">;
56
54
  };
57
55
  };
58
56
  config: ReleasesConfigResponse;
@@ -1 +1 @@
1
- {"version":3,"file":"pipeline.d.mts","names":[],"sources":["../../../src/internal/build/pipeline.ts"],"mappings":";;;;;;;;UAciB,WAAA;EACf,OAAA;EACA,aAAA;EACA,QAAA;EACA,SAAA;EACA,SAAA;EACA,KAAA;EACA,UAAA;EACA,MAAA;AAAA;AAAA,KAGU,cAAA;EACN,KAAA;EAAc,MAAA;EAA0B,SAAA;AAAA;EAExC,KAAA;EACA,SAAA;EACA,OAAA,EAAS,qBAAA;EACT,MAAA,EAAQ,sBAAA;EACR,OAAA;EACA,MAAA,EAAQ,WAAA;AAAA;AAAA,iBAUQ,gBAAA,CACpB,OAAA,EAAS,wBAAA,EACT,QAAA,EAAU,mBAAA;EACR,MAAA;EACA,OAAA;EACA,WAAA,EAAa,WAAA;AAAA,IACd,OAAA;;;;;;;;;;;;;SADyB,wBAAA,CAAA,MAAA"}
1
+ {"version":3,"file":"pipeline.d.mts","names":[],"sources":["../../../src/internal/build/pipeline.ts"],"mappings":";;;;;;UAciB,WAAA;EACf,OAAA;EACA,aAAA;EACA,QAAA;EACA,SAAA;EACA,SAAA;EACA,KAAA;EACA,UAAA;EACA,MAAA;AAAA;AAAA,KAGU,cAAA;EACN,KAAA;EAAc,MAAA;EAA0B,SAAA;AAAA;EAExC,KAAA;EACA,SAAA;EACA,OAAA,EAAS,qBAAA;EACT,MAAA,EAAQ,sBAAA;EACR,OAAA;EACA,MAAA,EAAQ,WAAA;AAAA;AAAA,iBASQ,gBAAA,CACpB,OAAA,EAAS,wBAAA,EACT,QAAA,EAAU,mBAAA;EACR,MAAA;EACA,OAAA;EACA,WAAA,EAAa,WAAA;AAAA,IACd,OAAA"}
@@ -1,82 +1 @@
1
- import { detectActiveBundler } from "./detect-bundler.mjs";
2
- import { resolveReleaseRequest } from "./release/index.mjs";
3
- import { discoverSourceMaps } from "./source-maps/discover.mjs";
4
- import { uploadSourceMaps } from "./source-maps/upload.mjs";
5
- import { cleanupSourceMaps } from "./source-maps/index.mjs";
6
- import { releaseSlugSchema } from "@interfere/types/releases/slug";
7
- import { HTTPClient, Interfere } from "@interfere/sdk";
8
- //#region src/internal/build/pipeline.ts
9
- async function timed(fn) {
10
- const start = performance.now();
11
- return [await fn(), Math.round(performance.now() - start)];
12
- }
13
- async function runBuildPipeline(context, metadata) {
14
- const { apiUrl, apiKey } = metadata;
15
- const httpClient = new HTTPClient();
16
- httpClient.addHook("beforeRequest", (request) => {
17
- const nextRequest = new Request(request);
18
- nextRequest.headers.set("x-api-key", apiKey);
19
- return nextRequest;
20
- });
21
- const sdk = new Interfere({
22
- serverURL: apiUrl,
23
- httpClient
24
- });
25
- const start = performance.now();
26
- const bundler = detectActiveBundler();
27
- const [{ discovered, config }, discoverMs] = await timed(async () => {
28
- const [discovered, config] = await Promise.all([discoverSourceMaps({
29
- bundler,
30
- projectDir: context.projectDir,
31
- distDir: context.distDir
32
- }), sdk.releases.getConfig()]);
33
- return {
34
- discovered,
35
- config
36
- };
37
- });
38
- if (discovered.files.length === 0) return {
39
- ready: false,
40
- reason: "no_source_maps",
41
- fileCount: 0
42
- };
43
- const releaseRequest = resolveReleaseRequest(metadata.buildId, metadata.releaseSlug, config);
44
- const [release, createReleaseMs] = await timed(() => sdk.releases.create(releaseRequest));
45
- const releaseSlug = releaseSlugSchema.parse(release.destination.slug);
46
- const buildId = release.build.hash ?? metadata.buildId;
47
- const [{ totalBytes }, uploadMs] = await timed(() => uploadSourceMaps({
48
- apiUrl,
49
- bundler,
50
- discovered,
51
- httpClient,
52
- releaseSlug
53
- }));
54
- const [, preflightMs] = await timed(() => sdk.releases.preflight({ releaseSlug }));
55
- const [, cleanupMs] = await timed(() => cleanupSourceMaps(discovered.files));
56
- const timing = {
57
- discover: discoverMs,
58
- createRelease: createReleaseMs,
59
- upload: uploadMs,
60
- preflight: preflightMs,
61
- cleanup: cleanupMs,
62
- total: Math.round(performance.now() - start),
63
- fileCount: discovered.files.length,
64
- totalBytes
65
- };
66
- return {
67
- ready: true,
68
- fileCount: discovered.files.length,
69
- release: {
70
- ...release,
71
- destination: {
72
- ...release.destination,
73
- slug: releaseSlug
74
- }
75
- },
76
- config,
77
- buildId,
78
- timing
79
- };
80
- }
81
- //#endregion
82
- export { runBuildPipeline };
1
+ import{detectActiveBundler}from"./detect-bundler.mjs";import{resolveReleaseRequest}from"./release/index.mjs";import{discoverSourceMaps}from"./source-maps/discover.mjs";import{uploadSourceMaps}from"./source-maps/upload.mjs";import{cleanupSourceMaps}from"./source-maps/index.mjs";import{releaseSlugSchema}from"@interfere/types/releases/slug";import{HTTPClient,Interfere}from"@interfere/sdk";async function timed(fn){let start=performance.now();return[await fn(),Math.round(performance.now()-start)]}async function runBuildPipeline(context,metadata){let{apiUrl,apiKey}=metadata,httpClient=new HTTPClient;httpClient.addHook(`beforeRequest`,request=>{let nextRequest=new Request(request);return nextRequest.headers.set(`Authorization`,`Bearer ${apiKey}`),nextRequest});let sdk=new Interfere({serverURL:apiUrl,httpClient}),start=performance.now(),bundler=detectActiveBundler(),[{discovered,config},discoverMs]=await timed(async()=>{let[discovered,config]=await Promise.all([discoverSourceMaps({bundler,projectDir:context.projectDir,distDir:context.distDir}),sdk.releases.getConfig()]);return{discovered,config}});if(discovered.files.length===0)return{ready:!1,reason:`no_source_maps`,fileCount:0};let releaseRequest=resolveReleaseRequest(metadata.buildId,metadata.releaseSlug,config),[release,createReleaseMs]=await timed(()=>sdk.releases.create(releaseRequest)),releaseSlug=releaseSlugSchema.parse(release.destination.slug),buildId=release.build.hash??metadata.buildId,[{totalBytes},uploadMs]=await timed(()=>uploadSourceMaps({apiUrl,bundler,discovered,httpClient,releaseSlug})),[,preflightMs]=await timed(()=>sdk.releases.preflight({releaseSlug})),[,cleanupMs]=await timed(()=>cleanupSourceMaps(discovered.files)),timing={discover:discoverMs,createRelease:createReleaseMs,upload:uploadMs,preflight:preflightMs,cleanup:cleanupMs,total:Math.round(performance.now()-start),fileCount:discovered.files.length,totalBytes};return{ready:!0,fileCount:discovered.files.length,release:{...release,destination:{...release.destination,slug:releaseSlug}},config,buildId,timing}}export{runBuildPipeline};
@@ -1 +1 @@
1
- {"version":3,"file":"pipeline.mjs","names":[],"sources":["../../../src/internal/build/pipeline.ts"],"sourcesContent":["import { HTTPClient, Interfere } from \"@interfere/sdk\";\nimport type { ReleasesConfigResponse } from \"@interfere/sdk/models/releases-config-response.js\";\nimport type { CreateReleaseResponse } from \"@interfere/types/releases/definition\";\nimport { type ReleaseSlug, releaseSlugSchema } from \"@interfere/types/releases/slug\";\n\nimport type {\n ProductionCompileContext,\n ResolvedBuildConfig,\n} from \"../../config.js\";\nimport { detectActiveBundler } from \"./detect-bundler.js\";\nimport { resolveReleaseRequest } from \"./release/index.js\";\nimport { discoverSourceMaps } from \"./source-maps/discover.js\";\nimport { cleanupSourceMaps, uploadSourceMaps } from \"./source-maps/index.js\";\n\nexport interface BuildTiming {\n cleanup: number;\n createRelease: number;\n discover: number;\n fileCount: number;\n preflight: number;\n total: number;\n totalBytes: number;\n upload: number;\n}\n\nexport type PipelineResult =\n | { ready: false; reason: \"no_source_maps\"; fileCount: 0 }\n | {\n ready: true;\n fileCount: number;\n release: CreateReleaseResponse;\n config: ReleasesConfigResponse;\n buildId: string;\n timing: BuildTiming;\n };\n\nasync function timed<T>(fn: () => Promise<T>): Promise<[T, number]> {\n const start = performance.now();\n const result = await fn();\n return [result, Math.round(performance.now() - start)];\n}\n\n\nexport async function runBuildPipeline(\n context: ProductionCompileContext,\n metadata: ResolvedBuildConfig & {\n apiKey: string;\n buildId: string;\n releaseSlug: ReleaseSlug;\n }\n) {\n const { apiUrl, apiKey } = metadata;\n\n const httpClient = new HTTPClient();\n\n httpClient.addHook(\"beforeRequest\", (request) => {\n const nextRequest = new Request(request);\n\n nextRequest.headers.set(\"x-api-key\", apiKey);\n\n return nextRequest;\n });\n\n const sdk = new Interfere({ serverURL: apiUrl, httpClient });\n\n const start = performance.now();\n\n const bundler = detectActiveBundler();\n\n const [{ discovered, config }, discoverMs] = await timed(async () => {\n const [discovered, config] = await Promise.all([\n discoverSourceMaps({\n bundler,\n projectDir: context.projectDir,\n distDir: context.distDir,\n }),\n sdk.releases.getConfig(),\n ]);\n return { discovered, config };\n });\n\n if (discovered.files.length === 0) {\n return { ready: false, reason: \"no_source_maps\", fileCount: 0 };\n }\n\n const releaseRequest = resolveReleaseRequest(\n metadata.buildId,\n metadata.releaseSlug,\n config\n );\n\n const [release, createReleaseMs] = await timed(() =>\n sdk.releases.create(releaseRequest)\n );\n\n // The SDK response carries the slug as a plain `string`. Brand it\n // here at the API boundary so every downstream caller (upload,\n // preflight, cleanup) reads a `ReleaseSlug`.\n const releaseSlug = releaseSlugSchema.parse(release.destination.slug);\n const buildId = release.build.hash ?? metadata.buildId;\n\n const [{ totalBytes }, uploadMs] = await timed(() =>\n uploadSourceMaps({ apiUrl, bundler, discovered, httpClient, releaseSlug: releaseSlug })\n );\n\n // Cleanup runs *after* preflight, not before (PRD draft had it inverted).\n // Preflight only depends on the upload having succeeded; if local cleanup\n // fails we still want the release marked confirmed and the build to fail\n // loudly via the cleanup error, rather than leaving a confirmed-but-uncleaned\n // workspace and a release that needs a redeploy to recover.\n const [, preflightMs] = await timed(() =>\n sdk.releases.preflight({ releaseSlug })\n );\n\n const [, cleanupMs] = await timed(() => cleanupSourceMaps(discovered.files));\n\n const timing: BuildTiming = {\n discover: discoverMs,\n createRelease: createReleaseMs,\n upload: uploadMs,\n preflight: preflightMs,\n cleanup: cleanupMs,\n total: Math.round(performance.now() - start),\n fileCount: discovered.files.length,\n totalBytes,\n };\n\n return {\n ready: true,\n fileCount: discovered.files.length,\n release: { ...release, destination: { ...release.destination, slug: releaseSlug } },\n config,\n buildId,\n timing,\n } satisfies PipelineResult;\n}\n"],"mappings":";;;;;;;;AAoCA,eAAe,MAAS,IAA4C;CAClE,MAAM,QAAQ,YAAY,KAAK;CAE/B,OAAO,CAAC,MADa,IAAI,EACT,KAAK,MAAM,YAAY,KAAK,GAAG,MAAM,CAAC;;AAIxD,eAAsB,iBACpB,SACA,UAKA;CACA,MAAM,EAAE,QAAQ,WAAW;CAE3B,MAAM,aAAa,IAAI,YAAY;CAEnC,WAAW,QAAQ,kBAAkB,YAAY;EAC/C,MAAM,cAAc,IAAI,QAAQ,QAAQ;EAExC,YAAY,QAAQ,IAAI,aAAa,OAAO;EAE5C,OAAO;GACP;CAEF,MAAM,MAAM,IAAI,UAAU;EAAE,WAAW;EAAQ;EAAY,CAAC;CAE5D,MAAM,QAAQ,YAAY,KAAK;CAE/B,MAAM,UAAU,qBAAqB;CAErC,MAAM,CAAC,EAAE,YAAY,UAAU,cAAc,MAAM,MAAM,YAAY;EACnE,MAAM,CAAC,YAAY,UAAU,MAAM,QAAQ,IAAI,CAC7C,mBAAmB;GACjB;GACA,YAAY,QAAQ;GACpB,SAAS,QAAQ;GAClB,CAAC,EACF,IAAI,SAAS,WAAW,CACzB,CAAC;EACF,OAAO;GAAE;GAAY;GAAQ;GAC7B;CAEF,IAAI,WAAW,MAAM,WAAW,GAC9B,OAAO;EAAE,OAAO;EAAO,QAAQ;EAAkB,WAAW;EAAG;CAGjE,MAAM,iBAAiB,sBACrB,SAAS,SACT,SAAS,aACT,OACD;CAED,MAAM,CAAC,SAAS,mBAAmB,MAAM,YACvC,IAAI,SAAS,OAAO,eAAe,CACpC;CAKD,MAAM,cAAc,kBAAkB,MAAM,QAAQ,YAAY,KAAK;CACrE,MAAM,UAAU,QAAQ,MAAM,QAAQ,SAAS;CAE/C,MAAM,CAAC,EAAE,cAAc,YAAY,MAAM,YACvC,iBAAiB;EAAE;EAAQ;EAAS;EAAY;EAAyB;EAAa,CAAC,CACxF;CAOD,MAAM,GAAG,eAAe,MAAM,YAC5B,IAAI,SAAS,UAAU,EAAE,aAAa,CAAC,CACxC;CAED,MAAM,GAAG,aAAa,MAAM,YAAY,kBAAkB,WAAW,MAAM,CAAC;CAE5E,MAAM,SAAsB;EAC1B,UAAU;EACV,eAAe;EACf,QAAQ;EACR,WAAW;EACX,SAAS;EACT,OAAO,KAAK,MAAM,YAAY,KAAK,GAAG,MAAM;EAC5C,WAAW,WAAW,MAAM;EAC5B;EACD;CAED,OAAO;EACL,OAAO;EACP,WAAW,WAAW,MAAM;EAC5B,SAAS;GAAE,GAAG;GAAS,aAAa;IAAE,GAAG,QAAQ;IAAa,MAAM;IAAa;GAAE;EACnF;EACA;EACA;EACD"}
1
+ {"version":3,"file":"pipeline.mjs","names":[],"sources":["../../../src/internal/build/pipeline.ts"],"sourcesContent":["import { HTTPClient, Interfere } from \"@interfere/sdk\";\nimport type { ReleasesConfigResponse } from \"@interfere/sdk/models/releases-config-response.js\";\nimport type { CreateReleaseResponse } from \"@interfere/types/releases/definition\";\nimport { type ReleaseSlug, releaseSlugSchema } from \"@interfere/types/releases/slug\";\n\nimport type {\n ProductionCompileContext,\n ResolvedBuildConfig,\n} from \"../../config.js\";\nimport { detectActiveBundler } from \"./detect-bundler.js\";\nimport { resolveReleaseRequest } from \"./release/index.js\";\nimport { discoverSourceMaps } from \"./source-maps/discover.js\";\nimport { cleanupSourceMaps, uploadSourceMaps } from \"./source-maps/index.js\";\n\nexport interface BuildTiming {\n cleanup: number;\n createRelease: number;\n discover: number;\n fileCount: number;\n preflight: number;\n total: number;\n totalBytes: number;\n upload: number;\n}\n\nexport type PipelineResult =\n | { ready: false; reason: \"no_source_maps\"; fileCount: 0 }\n | {\n ready: true;\n fileCount: number;\n release: CreateReleaseResponse;\n config: ReleasesConfigResponse;\n buildId: string;\n timing: BuildTiming;\n };\n\nasync function timed<T>(fn: () => Promise<T>): Promise<[T, number]> {\n const start = performance.now();\n const result = await fn();\n return [result, Math.round(performance.now() - start)];\n}\n\nexport async function runBuildPipeline(\n context: ProductionCompileContext,\n metadata: ResolvedBuildConfig & {\n apiKey: string;\n buildId: string;\n releaseSlug: ReleaseSlug;\n }\n) {\n const { apiUrl, apiKey } = metadata;\n\n const httpClient = new HTTPClient();\n\n httpClient.addHook(\"beforeRequest\", (request) => {\n const nextRequest = new Request(request);\n\n nextRequest.headers.set(\"Authorization\", `Bearer ${apiKey}`);\n\n return nextRequest;\n });\n\n const sdk = new Interfere({ serverURL: apiUrl, httpClient });\n\n const start = performance.now();\n\n const bundler = detectActiveBundler();\n\n const [{ discovered, config }, discoverMs] = await timed(async () => {\n const [discovered, config] = await Promise.all([\n discoverSourceMaps({\n bundler,\n projectDir: context.projectDir,\n distDir: context.distDir,\n }),\n sdk.releases.getConfig(),\n ]);\n return { discovered, config };\n });\n\n if (discovered.files.length === 0) {\n return { ready: false, reason: \"no_source_maps\", fileCount: 0 };\n }\n\n const releaseRequest = resolveReleaseRequest(\n metadata.buildId,\n metadata.releaseSlug,\n config\n );\n\n const [release, createReleaseMs] = await timed(() =>\n sdk.releases.create(releaseRequest)\n );\n\n // The SDK response carries the slug as a plain `string`. Brand it\n // here at the API boundary so every downstream caller (upload,\n // preflight, cleanup) reads a `ReleaseSlug`.\n const releaseSlug = releaseSlugSchema.parse(release.destination.slug);\n const buildId = release.build.hash ?? metadata.buildId;\n\n const [{ totalBytes }, uploadMs] = await timed(() =>\n uploadSourceMaps({ apiUrl, bundler, discovered, httpClient, releaseSlug: releaseSlug })\n );\n\n // Cleanup runs *after* preflight, not before (PRD draft had it inverted).\n // Preflight only depends on the upload having succeeded; if local cleanup\n // fails we still want the release marked confirmed and the build to fail\n // loudly via the cleanup error, rather than leaving a confirmed-but-uncleaned\n // workspace and a release that needs a redeploy to recover.\n const [, preflightMs] = await timed(() =>\n sdk.releases.preflight({ releaseSlug })\n );\n\n const [, cleanupMs] = await timed(() => cleanupSourceMaps(discovered.files));\n\n const timing: BuildTiming = {\n discover: discoverMs,\n createRelease: createReleaseMs,\n upload: uploadMs,\n preflight: preflightMs,\n cleanup: cleanupMs,\n total: Math.round(performance.now() - start),\n fileCount: discovered.files.length,\n totalBytes,\n };\n\n return {\n ready: true,\n fileCount: discovered.files.length,\n release: { ...release, destination: { ...release.destination, slug: releaseSlug } },\n config,\n buildId,\n timing,\n } satisfies PipelineResult;\n}\n"],"mappings":"qYAoCA,eAAe,MAAS,GAA4C,CAClE,IAAM,MAAQ,YAAY,IAAI,EAE9B,MAAO,CAAC,MADa,GAAG,EACR,KAAK,MAAM,YAAY,IAAI,EAAI,KAAK,CAAC,CACvD,CAEA,eAAsB,iBACpB,QACA,SAKA,CACA,GAAM,CAAE,OAAQ,QAAW,SAErB,WAAa,IAAI,WAEvB,WAAW,QAAQ,gBAAkB,SAAY,CAC/C,IAAM,YAAc,IAAI,QAAQ,OAAO,EAIvC,OAFA,YAAY,QAAQ,IAAI,gBAAiB,UAAU,QAAQ,EAEpD,WACT,CAAC,EAED,IAAM,IAAM,IAAI,UAAU,CAAE,UAAW,OAAQ,UAAW,CAAC,EAErD,MAAQ,YAAY,IAAI,EAExB,QAAU,oBAAoB,EAE9B,CAAC,CAAE,WAAY,QAAU,YAAc,MAAM,MAAM,SAAY,CACnE,GAAM,CAAC,WAAY,QAAU,MAAM,QAAQ,IAAI,CAC7C,mBAAmB,CACjB,QACA,WAAY,QAAQ,WACpB,QAAS,QAAQ,OACnB,CAAC,EACD,IAAI,SAAS,UAAU,CACzB,CAAC,EACD,MAAO,CAAE,WAAY,MAAO,CAC9B,CAAC,EAED,GAAI,WAAW,MAAM,SAAW,EAC9B,MAAO,CAAE,MAAO,GAAO,OAAQ,iBAAkB,UAAW,CAAE,EAGhE,IAAM,eAAiB,sBACrB,SAAS,QACT,SAAS,YACT,MACF,EAEM,CAAC,QAAS,iBAAmB,MAAM,UACvC,IAAI,SAAS,OAAO,cAAc,CACpC,EAKM,YAAc,kBAAkB,MAAM,QAAQ,YAAY,IAAI,EAC9D,QAAU,QAAQ,MAAM,MAAQ,SAAS,QAEzC,CAAC,CAAE,YAAc,UAAY,MAAM,UACvC,iBAAiB,CAAE,OAAQ,QAAS,WAAY,WAAyB,WAAY,CAAC,CACxF,EAOM,EAAG,aAAe,MAAM,UAC5B,IAAI,SAAS,UAAU,CAAE,WAAY,CAAC,CACxC,EAEM,EAAG,WAAa,MAAM,UAAY,kBAAkB,WAAW,KAAK,CAAC,EAErE,OAAsB,CAC1B,SAAU,WACV,cAAe,gBACf,OAAQ,SACR,UAAW,YACX,QAAS,UACT,MAAO,KAAK,MAAM,YAAY,IAAI,EAAI,KAAK,EAC3C,UAAW,WAAW,MAAM,OAC5B,UACF,EAEA,MAAO,CACL,MAAO,GACP,UAAW,WAAW,MAAM,OAC5B,QAAS,CAAE,GAAG,QAAS,YAAa,CAAE,GAAG,QAAQ,YAAa,KAAM,WAAY,CAAE,EAClF,OACA,QACA,MACF,CACF"}
@@ -1,13 +1 @@
1
- import { resolve } from "./vercel.mjs";
2
- //#region src/internal/build/release/destinations/index.ts
3
- /**
4
- * Per-provider destination metadata resolvers. Mirrors `sources/` —
5
- * each entry knows how to read its platform's deployment env vars and
6
- * returns a `ReleaseDestinationMetadata` blob.
7
- *
8
- * Adding a new destination (cloudflare-pages, fly, render, …) is one
9
- * new file under this directory + one entry here.
10
- */
11
- const destinations = { vercel: resolve };
12
- //#endregion
13
- export { destinations };
1
+ import{resolve}from"./vercel.mjs";const destinations={vercel:resolve};export{destinations};
@@ -1 +1 @@
1
- {"version":3,"file":"index.mjs","names":["resolveVercel"],"sources":["../../../../../src/internal/build/release/destinations/index.ts"],"sourcesContent":["import type {\n DestinationProvider,\n ReleaseDestinationMetadata,\n} from \"@interfere/types/integrations\";\n\nimport { resolve as resolveVercel } from \"./vercel.js\";\n\n/**\n * Per-provider destination metadata resolvers. Mirrors `sources/` —\n * each entry knows how to read its platform's deployment env vars and\n * returns a `ReleaseDestinationMetadata` blob.\n *\n * Adding a new destination (cloudflare-pages, fly, render, …) is one\n * new file under this directory + one entry here.\n */\nexport const destinations: Record<\n DestinationProvider,\n () => ReleaseDestinationMetadata\n> = {\n vercel: resolveVercel,\n};\n"],"mappings":";;;;;;;;;;AAeA,MAAa,eAGT,EACF,QAAQA,SACT"}
1
+ {"version":3,"file":"index.mjs","names":["resolveVercel"],"sources":["../../../../../src/internal/build/release/destinations/index.ts"],"sourcesContent":["import type {\n DestinationProvider,\n ReleaseDestinationMetadata,\n} from \"@interfere/types/integrations\";\n\nimport { resolve as resolveVercel } from \"./vercel.js\";\n\n/**\n * Per-provider destination metadata resolvers. Mirrors `sources/` —\n * each entry knows how to read its platform's deployment env vars and\n * returns a `ReleaseDestinationMetadata` blob.\n *\n * Adding a new destination (cloudflare-pages, fly, render, …) is one\n * new file under this directory + one entry here.\n */\nexport const destinations: Record<\n DestinationProvider,\n () => ReleaseDestinationMetadata\n> = {\n vercel: resolveVercel,\n};\n"],"mappings":"kCAeA,MAAa,aAGT,CACF,OAAQA,OACV"}
@@ -1 +1 @@
1
- {"version":3,"file":"vercel.d.mts","names":[],"sources":["../../../../../src/internal/build/release/destinations/vercel.ts"],"mappings":";;;iBAGgB,OAAA,CAAA,GAAW,0BAAA"}
1
+ {"version":3,"file":"vercel.d.mts","names":[],"sources":["../../../../../src/internal/build/release/destinations/vercel.ts"],"mappings":";;;iBAGgB,OAAA,CAAA,GAAW,0BAA0B"}
@@ -1,23 +1 @@
1
- import { parseEnvValue } from "@interfere/types/sdk/env";
2
- //#region src/internal/build/release/destinations/vercel.ts
3
- function resolve() {
4
- const environment = parseEnvValue(process.env["VERCEL_ENV"] ?? process.env["VERCEL_TARGET_ENV"]);
5
- const deploymentId = parseEnvValue(process.env["VERCEL_DEPLOYMENT_ID"]);
6
- return {
7
- provider: "vercel",
8
- destinationReleaseId: deploymentId,
9
- environment,
10
- deploymentId,
11
- deploymentUrl: resolveDeploymentUrl(),
12
- environmentName: environment,
13
- environmentTarget: environment
14
- };
15
- }
16
- function resolveDeploymentUrl() {
17
- const deploymentUrl = parseEnvValue(process.env["VERCEL_URL"]);
18
- if (deploymentUrl === null) return null;
19
- if (deploymentUrl.startsWith("https://") || deploymentUrl.startsWith("http://")) return deploymentUrl;
20
- return `https://${deploymentUrl}`;
21
- }
22
- //#endregion
23
- export { resolve };
1
+ import{parseEnvValue}from"@interfere/types/sdk/env";function resolve(){let environment=parseEnvValue(process.env.VERCEL_ENV??process.env.VERCEL_TARGET_ENV),deploymentId=parseEnvValue(process.env.VERCEL_DEPLOYMENT_ID);return{provider:`vercel`,destinationReleaseId:deploymentId,environment,deploymentId,deploymentUrl:resolveDeploymentUrl(),environmentName:environment,environmentTarget:environment}}function resolveDeploymentUrl(){let deploymentUrl=parseEnvValue(process.env.VERCEL_URL);return deploymentUrl===null?null:deploymentUrl.startsWith(`https://`)||deploymentUrl.startsWith(`http://`)?deploymentUrl:`https://${deploymentUrl}`}export{resolve};
@@ -1 +1 @@
1
- {"version":3,"file":"vercel.mjs","names":[],"sources":["../../../../../src/internal/build/release/destinations/vercel.ts"],"sourcesContent":["import type { ReleaseDestinationMetadata } from \"@interfere/types/integrations\";\nimport { parseEnvValue } from \"@interfere/types/sdk/env\";\n\nexport function resolve(): ReleaseDestinationMetadata {\n const environment = parseEnvValue(\n process.env[\"VERCEL_ENV\"] ?? process.env[\"VERCEL_TARGET_ENV\"]\n );\n\n const deploymentId = parseEnvValue(process.env[\"VERCEL_DEPLOYMENT_ID\"]);\n\n return {\n provider: \"vercel\",\n destinationReleaseId: deploymentId,\n environment,\n deploymentId,\n deploymentUrl: resolveDeploymentUrl(),\n environmentName: environment,\n environmentTarget: environment,\n };\n}\n\nfunction resolveDeploymentUrl(): string | null {\n const deploymentUrl = parseEnvValue(process.env[\"VERCEL_URL\"]);\n\n if (deploymentUrl === null) {\n return null;\n }\n\n if (\n deploymentUrl.startsWith(\"https://\") ||\n deploymentUrl.startsWith(\"http://\")\n ) {\n return deploymentUrl;\n }\n\n return `https://${deploymentUrl}`;\n}\n"],"mappings":";;AAGA,SAAgB,UAAsC;CACpD,MAAM,cAAc,cAClB,QAAQ,IAAI,iBAAiB,QAAQ,IAAI,qBAC1C;CAED,MAAM,eAAe,cAAc,QAAQ,IAAI,wBAAwB;CAEvE,OAAO;EACL,UAAU;EACV,sBAAsB;EACtB;EACA;EACA,eAAe,sBAAsB;EACrC,iBAAiB;EACjB,mBAAmB;EACpB;;AAGH,SAAS,uBAAsC;CAC7C,MAAM,gBAAgB,cAAc,QAAQ,IAAI,cAAc;CAE9D,IAAI,kBAAkB,MACpB,OAAO;CAGT,IACE,cAAc,WAAW,WAAW,IACpC,cAAc,WAAW,UAAU,EAEnC,OAAO;CAGT,OAAO,WAAW"}
1
+ {"version":3,"file":"vercel.mjs","names":[],"sources":["../../../../../src/internal/build/release/destinations/vercel.ts"],"sourcesContent":["import type { ReleaseDestinationMetadata } from \"@interfere/types/integrations\";\nimport { parseEnvValue } from \"@interfere/types/sdk/env\";\n\nexport function resolve(): ReleaseDestinationMetadata {\n const environment = parseEnvValue(\n process.env[\"VERCEL_ENV\"] ?? process.env[\"VERCEL_TARGET_ENV\"]\n );\n\n const deploymentId = parseEnvValue(process.env[\"VERCEL_DEPLOYMENT_ID\"]);\n\n return {\n provider: \"vercel\",\n destinationReleaseId: deploymentId,\n environment,\n deploymentId,\n deploymentUrl: resolveDeploymentUrl(),\n environmentName: environment,\n environmentTarget: environment,\n };\n}\n\nfunction resolveDeploymentUrl(): string | null {\n const deploymentUrl = parseEnvValue(process.env[\"VERCEL_URL\"]);\n\n if (deploymentUrl === null) {\n return null;\n }\n\n if (\n deploymentUrl.startsWith(\"https://\") ||\n deploymentUrl.startsWith(\"http://\")\n ) {\n return deploymentUrl;\n }\n\n return `https://${deploymentUrl}`;\n}\n"],"mappings":"oDAGA,SAAgB,SAAsC,CACpD,IAAM,YAAc,cAClB,QAAQ,IAAI,YAAiB,QAAQ,IAAI,iBAC3C,EAEM,aAAe,cAAc,QAAQ,IAAI,oBAAuB,EAEtE,MAAO,CACL,SAAU,SACV,qBAAsB,aACtB,YACA,aACA,cAAe,qBAAqB,EACpC,gBAAiB,YACjB,kBAAmB,WACrB,CACF,CAEA,SAAS,sBAAsC,CAC7C,IAAM,cAAgB,cAAc,QAAQ,IAAI,UAAa,EAa7D,OAXI,gBAAkB,KACb,KAIP,cAAc,WAAW,UAAU,GACnC,cAAc,WAAW,SAAS,EAE3B,cAGF,WAAW,eACpB"}
@@ -1 +1 @@
1
- {"version":3,"file":"git.d.mts","names":[],"sources":["../../../../src/internal/build/release/git.ts"],"mappings":";;AAeA;;;;;;;;;;;;iBAAgB,aAAA,CAAc,OAAA"}
1
+ {"version":3,"file":"git.d.mts","names":[],"sources":["../../../../src/internal/build/release/git.ts"],"mappings":";;AAeA;;;;AAA6C;;;;;;;;iBAA7B,aAAA,CAAc,OAAe"}
@@ -1,32 +1 @@
1
- import { execSync } from "node:child_process";
2
- //#region src/internal/build/release/git.ts
3
- /**
4
- * Runs a git command and returns its stdout, or `null` when git isn't
5
- * available (no `.git` checkout, git binary missing, command errored).
6
- *
7
- * The ignore-on-failure shape lets callers compose this with env-var
8
- * reads as a fallback chain — env vars first (CI environments where
9
- * git isn't checked out), git as a last resort (local dev).
10
- *
11
- * Build-time only. `node:child_process` isn't available in the Edge
12
- * runtime, so this helper must never end up in `instrumentation.ts`'s
13
- * import graph (the SDK ships that entrypoint to both Node + Edge
14
- * runtimes via conditional exports).
15
- */
16
- function runGitCommand(command) {
17
- try {
18
- const output = execSync(command, {
19
- encoding: "utf8",
20
- stdio: [
21
- "ignore",
22
- "pipe",
23
- "ignore"
24
- ]
25
- }).trim();
26
- return output.length > 0 ? output : null;
27
- } catch {
28
- return null;
29
- }
30
- }
31
- //#endregion
32
- export { runGitCommand };
1
+ import{execSync}from"node:child_process";function runGitCommand(command){try{let output=execSync(command,{encoding:`utf8`,stdio:[`ignore`,`pipe`,`ignore`]}).trim();return output.length>0?output:null}catch{return null}}export{runGitCommand};
@@ -1 +1 @@
1
- {"version":3,"file":"git.mjs","names":[],"sources":["../../../../src/internal/build/release/git.ts"],"sourcesContent":["import { execSync } from \"node:child_process\";\n\n/**\n * Runs a git command and returns its stdout, or `null` when git isn't\n * available (no `.git` checkout, git binary missing, command errored).\n *\n * The ignore-on-failure shape lets callers compose this with env-var\n * reads as a fallback chain — env vars first (CI environments where\n * git isn't checked out), git as a last resort (local dev).\n *\n * Build-time only. `node:child_process` isn't available in the Edge\n * runtime, so this helper must never end up in `instrumentation.ts`'s\n * import graph (the SDK ships that entrypoint to both Node + Edge\n * runtimes via conditional exports).\n */\nexport function runGitCommand(command: string): string | null {\n try {\n const output = execSync(command, {\n encoding: \"utf8\",\n stdio: [\"ignore\", \"pipe\", \"ignore\"],\n }).trim();\n\n return output.length > 0 ? output : null;\n } catch {\n return null;\n }\n}\n"],"mappings":";;;;;;;;;;;;;;;AAeA,SAAgB,cAAc,SAAgC;CAC5D,IAAI;EACF,MAAM,SAAS,SAAS,SAAS;GAC/B,UAAU;GACV,OAAO;IAAC;IAAU;IAAQ;IAAS;GACpC,CAAC,CAAC,MAAM;EAET,OAAO,OAAO,SAAS,IAAI,SAAS;SAC9B;EACN,OAAO"}
1
+ {"version":3,"file":"git.mjs","names":[],"sources":["../../../../src/internal/build/release/git.ts"],"sourcesContent":["import { execSync } from \"node:child_process\";\n\n/**\n * Runs a git command and returns its stdout, or `null` when git isn't\n * available (no `.git` checkout, git binary missing, command errored).\n *\n * The ignore-on-failure shape lets callers compose this with env-var\n * reads as a fallback chain — env vars first (CI environments where\n * git isn't checked out), git as a last resort (local dev).\n *\n * Build-time only. `node:child_process` isn't available in the Edge\n * runtime, so this helper must never end up in `instrumentation.ts`'s\n * import graph (the SDK ships that entrypoint to both Node + Edge\n * runtimes via conditional exports).\n */\nexport function runGitCommand(command: string): string | null {\n try {\n const output = execSync(command, {\n encoding: \"utf8\",\n stdio: [\"ignore\", \"pipe\", \"ignore\"],\n }).trim();\n\n return output.length > 0 ? output : null;\n } catch {\n return null;\n }\n}\n"],"mappings":"yCAeA,SAAgB,cAAc,QAAgC,CAC5D,GAAI,CACF,IAAM,OAAS,SAAS,QAAS,CAC/B,SAAU,OACV,MAAO,CAAC,SAAU,OAAQ,QAAQ,CACpC,CAAC,EAAE,KAAK,EAER,OAAO,OAAO,OAAS,EAAI,OAAS,IACtC,MAAQ,CACN,OAAO,IACT,CACF"}
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.mts","names":[],"sources":["../../../../src/internal/build/release/index.ts"],"mappings":";;;;;iBASgB,qBAAA,CACd,OAAA,UACA,WAAA,EAAa,WAAA,EACb,MAAA,EAAQ,sBAAA,GACP,oBAAA"}
1
+ {"version":3,"file":"index.d.mts","names":[],"sources":["../../../../src/internal/build/release/index.ts"],"mappings":";;;;;iBAUgB,qBAAA,CACd,OAAA,UACA,WAAA,EAAa,WAAA,EACb,MAAA,EAAQ,sBAAA,GACP,oBAAA"}
@@ -1,18 +1 @@
1
- import { log } from "../../logger.mjs";
2
- import { PRODUCER_VERSION } from "../../version.mjs";
3
- import { destinations } from "./destinations/index.mjs";
4
- import { sources } from "./sources/index.mjs";
5
- //#region src/internal/build/release/index.ts
6
- function resolveReleaseRequest(buildId, releaseSlug, config) {
7
- if (!config.surface.sourceProvider) return log.fatal("Missing version control provider", ["This surface does not have a version control provider configured.", `Configure one at https://interfere.com/~/${config.org.slug}/surfaces/${config.surface.slug}`]);
8
- if (!config.surface.destinationProvider) return log.fatal("Missing deployment target", ["This surface does not have a deployment target integration configured.", `Configure one at https://interfere.com/~/${config.org.slug}/surfaces/${config.surface.slug}`]);
9
- return {
10
- source: sources[config.surface.sourceProvider](),
11
- destination: destinations[config.surface.destinationProvider](),
12
- buildId,
13
- slug: releaseSlug,
14
- producerVersion: PRODUCER_VERSION
15
- };
16
- }
17
- //#endregion
18
- export { resolveReleaseRequest };
1
+ import{log}from"../../logger.mjs";import{PRODUCER_VERSION}from"../../version.mjs";import{destinations}from"./destinations/index.mjs";import{sources}from"./sources/index.mjs";import{destinationProviderSchema}from"@interfere/types/integrations";function resolveReleaseRequest(buildId,releaseSlug,config){if(!config.surface.sourceProvider)return log.fatal(`Missing version control provider`,[`This surface does not have a version control provider configured.`,`Configure one at https://interfere.com/~/${config.org.slug}/surfaces/${config.surface.slug}`]);let destinationProvider=destinationProviderSchema.safeParse(config.surface.destinationProvider);return destinationProvider.success?{source:sources[config.surface.sourceProvider](),destination:destinations[destinationProvider.data](),buildId,slug:releaseSlug,producerVersion:PRODUCER_VERSION}:log.fatal(`Missing deployment target`,[`This surface does not have a deployment target integration configured.`,`Configure one at https://interfere.com/~/${config.org.slug}/surfaces/${config.surface.slug}`])}export{resolveReleaseRequest};