@interfere/next 9.0.2 → 10.0.1-canary.0

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 (180) hide show
  1. package/README.md +39 -6
  2. package/dist/config.d.mts +25 -5
  3. package/dist/config.d.mts.map +1 -1
  4. package/dist/config.mjs +1 -100
  5. package/dist/config.mjs.map +1 -1
  6. package/dist/instrument-client.d.mts +11 -3
  7. package/dist/instrument-client.d.mts.map +1 -1
  8. package/dist/instrument-client.mjs +1 -11
  9. package/dist/instrument-client.mjs.map +1 -1
  10. package/dist/instrumentation-client.d.mts +1 -0
  11. package/dist/instrumentation-client.mjs +1 -0
  12. package/dist/instrumentation-client.mjs.map +1 -0
  13. package/dist/instrumentation.d.mts +134 -0
  14. package/dist/instrumentation.d.mts.map +1 -0
  15. package/dist/instrumentation.edge.d.mts +35 -0
  16. package/dist/instrumentation.edge.d.mts.map +1 -0
  17. package/dist/instrumentation.edge.mjs +1 -0
  18. package/dist/instrumentation.edge.mjs.map +1 -0
  19. package/dist/instrumentation.mjs +1 -0
  20. package/dist/instrumentation.mjs.map +1 -0
  21. package/dist/internal/build/configure-build.d.mts +3 -2
  22. package/dist/internal/build/configure-build.d.mts.map +1 -1
  23. package/dist/internal/build/configure-build.mjs +1 -87
  24. package/dist/internal/build/configure-build.mjs.map +1 -1
  25. package/dist/internal/build/detect-bundler.d.mts +7 -0
  26. package/dist/internal/build/detect-bundler.d.mts.map +1 -0
  27. package/dist/internal/build/detect-bundler.mjs +1 -0
  28. package/dist/internal/build/detect-bundler.mjs.map +1 -0
  29. package/dist/internal/build/pipeline.d.mts +13 -2
  30. package/dist/internal/build/pipeline.d.mts.map +1 -1
  31. package/dist/internal/build/pipeline.mjs +1 -66
  32. package/dist/internal/build/pipeline.mjs.map +1 -1
  33. package/dist/internal/build/release/destinations/index.d.mts +14 -0
  34. package/dist/internal/build/release/destinations/index.d.mts.map +1 -0
  35. package/dist/internal/build/release/destinations/index.mjs +1 -0
  36. package/dist/internal/build/release/destinations/index.mjs.map +1 -0
  37. package/dist/internal/build/release/destinations/vercel.d.mts.map +1 -1
  38. package/dist/internal/build/release/destinations/vercel.mjs +1 -23
  39. package/dist/internal/build/release/destinations/vercel.mjs.map +1 -1
  40. package/dist/internal/build/release/git.d.mts +13 -0
  41. package/dist/internal/build/release/git.d.mts.map +1 -1
  42. package/dist/internal/build/release/git.mjs +1 -21
  43. package/dist/internal/build/release/git.mjs.map +1 -1
  44. package/dist/internal/build/release/index.d.mts +2 -1
  45. package/dist/internal/build/release/index.d.mts.map +1 -1
  46. package/dist/internal/build/release/index.mjs +1 -19
  47. package/dist/internal/build/release/index.mjs.map +1 -1
  48. package/dist/internal/build/release/sources/github.d.mts.map +1 -1
  49. package/dist/internal/build/release/sources/github.mjs +1 -13
  50. package/dist/internal/build/release/sources/github.mjs.map +1 -1
  51. package/dist/internal/build/release/sources/index.d.mts +21 -0
  52. package/dist/internal/build/release/sources/index.d.mts.map +1 -0
  53. package/dist/internal/build/release/sources/index.mjs +1 -0
  54. package/dist/internal/build/release/sources/index.mjs.map +1 -0
  55. package/dist/internal/build/source-maps/discover-turbopack.d.mts +32 -0
  56. package/dist/internal/build/source-maps/discover-turbopack.d.mts.map +1 -0
  57. package/dist/internal/build/source-maps/discover-turbopack.mjs +1 -0
  58. package/dist/internal/build/source-maps/discover-turbopack.mjs.map +1 -0
  59. package/dist/internal/build/source-maps/discover-webpack.d.mts +53 -0
  60. package/dist/internal/build/source-maps/discover-webpack.d.mts.map +1 -0
  61. package/dist/internal/build/source-maps/discover-webpack.mjs +1 -0
  62. package/dist/internal/build/source-maps/discover-webpack.mjs.map +1 -0
  63. package/dist/internal/build/source-maps/discover.d.mts +28 -10
  64. package/dist/internal/build/source-maps/discover.d.mts.map +1 -1
  65. package/dist/internal/build/source-maps/discover.mjs +1 -87
  66. package/dist/internal/build/source-maps/discover.mjs.map +1 -1
  67. package/dist/internal/build/source-maps/index.d.mts +2 -24
  68. package/dist/internal/build/source-maps/index.d.mts.map +1 -1
  69. package/dist/internal/build/source-maps/index.mjs +1 -28
  70. package/dist/internal/build/source-maps/index.mjs.map +1 -1
  71. package/dist/internal/build/source-maps/paths.d.mts +28 -0
  72. package/dist/internal/build/source-maps/paths.d.mts.map +1 -0
  73. package/dist/internal/build/source-maps/paths.mjs +1 -0
  74. package/dist/internal/build/source-maps/paths.mjs.map +1 -0
  75. package/dist/internal/build/source-maps/upload.d.mts +46 -0
  76. package/dist/internal/build/source-maps/upload.d.mts.map +1 -0
  77. package/dist/internal/build/source-maps/upload.mjs +1 -0
  78. package/dist/internal/build/source-maps/upload.mjs.map +1 -0
  79. package/dist/internal/build/value-injection-loader.d.mts.map +1 -1
  80. package/dist/internal/build/value-injection-loader.mjs +2 -24
  81. package/dist/internal/build/value-injection-loader.mjs.map +1 -1
  82. package/dist/internal/env.d.mts +13 -3
  83. package/dist/internal/env.d.mts.map +1 -1
  84. package/dist/internal/env.mjs +1 -23
  85. package/dist/internal/env.mjs.map +1 -1
  86. package/dist/internal/logger.d.mts +9 -1
  87. package/dist/internal/logger.d.mts.map +1 -1
  88. package/dist/internal/logger.mjs +1 -60
  89. package/dist/internal/logger.mjs.map +1 -1
  90. package/dist/internal/release-slug.d.mts +25 -0
  91. package/dist/internal/release-slug.d.mts.map +1 -0
  92. package/dist/internal/release-slug.mjs +1 -0
  93. package/dist/internal/release-slug.mjs.map +1 -0
  94. package/dist/internal/route/handle-get.d.mts +14 -1
  95. package/dist/internal/route/handle-get.d.mts.map +1 -1
  96. package/dist/internal/route/handle-get.mjs +1 -22
  97. package/dist/internal/route/handle-get.mjs.map +1 -1
  98. package/dist/internal/route/handle-post.d.mts +11 -0
  99. package/dist/internal/route/handle-post.d.mts.map +1 -1
  100. package/dist/internal/route/handle-post.mjs +1 -70
  101. package/dist/internal/route/handle-post.mjs.map +1 -1
  102. package/dist/internal/route/proxy.d.mts +26 -4
  103. package/dist/internal/route/proxy.d.mts.map +1 -1
  104. package/dist/internal/route/proxy.mjs +1 -89
  105. package/dist/internal/route/proxy.mjs.map +1 -1
  106. package/dist/internal/server/capture.d.mts +2 -2
  107. package/dist/internal/server/capture.d.mts.map +1 -1
  108. package/dist/internal/server/capture.mjs +1 -55
  109. package/dist/internal/server/capture.mjs.map +1 -1
  110. package/dist/internal/server/console-bridge.d.mts +19 -0
  111. package/dist/internal/server/console-bridge.d.mts.map +1 -0
  112. package/dist/internal/server/console-bridge.mjs +1 -0
  113. package/dist/internal/server/console-bridge.mjs.map +1 -0
  114. package/dist/internal/server/id-generator.d.mts +38 -0
  115. package/dist/internal/server/id-generator.d.mts.map +1 -0
  116. package/dist/internal/server/id-generator.mjs +1 -0
  117. package/dist/internal/server/id-generator.mjs.map +1 -0
  118. package/dist/internal/server/instrumentation-options.d.mts +86 -0
  119. package/dist/internal/server/instrumentation-options.d.mts.map +1 -0
  120. package/dist/internal/server/instrumentation-options.mjs +1 -0
  121. package/dist/internal/server/remote-config.d.mts.map +1 -1
  122. package/dist/internal/server/remote-config.mjs +1 -29
  123. package/dist/internal/server/remote-config.mjs.map +1 -1
  124. package/dist/internal/server/trace-meta.d.mts +32 -0
  125. package/dist/internal/server/trace-meta.d.mts.map +1 -0
  126. package/dist/internal/server/trace-meta.mjs +1 -0
  127. package/dist/internal/server/trace-meta.mjs.map +1 -0
  128. package/dist/internal/server/traceparent.d.mts +16 -0
  129. package/dist/internal/server/traceparent.d.mts.map +1 -0
  130. package/dist/internal/server/traceparent.mjs +1 -0
  131. package/dist/internal/server/traceparent.mjs.map +1 -0
  132. package/dist/internal/server/types.d.mts +1 -7
  133. package/dist/internal/server/types.d.mts.map +1 -1
  134. package/dist/internal/server/types.mjs +1 -1
  135. package/dist/internal/setup-warnings.d.mts +17 -0
  136. package/dist/internal/setup-warnings.d.mts.map +1 -0
  137. package/dist/internal/setup-warnings.mjs +1 -0
  138. package/dist/internal/setup-warnings.mjs.map +1 -0
  139. package/dist/internal/url.d.mts +4 -0
  140. package/dist/internal/url.d.mts.map +1 -0
  141. package/dist/internal/url.mjs +1 -0
  142. package/dist/internal/url.mjs.map +1 -0
  143. package/dist/internal/version.mjs +1 -5
  144. package/dist/internal/version.mjs.map +1 -1
  145. package/dist/package.mjs +1 -5
  146. package/dist/provider.d.mts +23 -2
  147. package/dist/provider.d.mts.map +1 -0
  148. package/dist/provider.mjs +1 -3
  149. package/dist/provider.mjs.map +1 -0
  150. package/dist/route-handler.d.mts +7 -2
  151. package/dist/route-handler.d.mts.map +1 -1
  152. package/dist/route-handler.mjs +1 -31
  153. package/dist/route-handler.mjs.map +1 -1
  154. package/dist/server.d.mts +2 -2
  155. package/dist/server.mjs +1 -3
  156. package/package.json +78 -26
  157. package/dist/internal/route/sw-script.d.mts +0 -4
  158. package/dist/internal/route/sw-script.d.mts.map +0 -1
  159. package/dist/internal/route/sw-script.mjs +0 -38
  160. package/dist/internal/route/sw-script.mjs.map +0 -1
  161. package/dist/internal/server/dedupe.d.mts +0 -5
  162. package/dist/internal/server/dedupe.d.mts.map +0 -1
  163. package/dist/internal/server/dedupe.mjs +0 -11
  164. package/dist/internal/server/dedupe.mjs.map +0 -1
  165. package/dist/internal/server/envelope.d.mts +0 -14
  166. package/dist/internal/server/envelope.d.mts.map +0 -1
  167. package/dist/internal/server/envelope.mjs +0 -59
  168. package/dist/internal/server/envelope.mjs.map +0 -1
  169. package/dist/internal/server/normalize-request.d.mts +0 -7
  170. package/dist/internal/server/normalize-request.d.mts.map +0 -1
  171. package/dist/internal/server/normalize-request.mjs +0 -50
  172. package/dist/internal/server/normalize-request.mjs.map +0 -1
  173. package/dist/internal/server/runtime.d.mts +0 -14
  174. package/dist/internal/server/runtime.d.mts.map +0 -1
  175. package/dist/internal/server/runtime.mjs +0 -18
  176. package/dist/internal/server/runtime.mjs.map +0 -1
  177. package/dist/internal/server/transport.d.mts +0 -12
  178. package/dist/internal/server/transport.d.mts.map +0 -1
  179. package/dist/internal/server/transport.mjs +0 -26
  180. package/dist/internal/server/transport.mjs.map +0 -1
package/README.md CHANGED
@@ -2,16 +2,16 @@
2
2
  <a href="https://interfere.com">
3
3
  <picture>
4
4
  <source media="(prefers-color-scheme: dark)" srcset="https://qyzkf4cgb8ydxtq1.public.blob.vercel-storage.com/v2/header/logo-dark.png">
5
- <img src="https://qyzkf4cgb8ydxtq1.public.blob.vercel-storage.com/v2/header/logo-light.png" height="64">
5
+ <img src="https://qyzkf4cgb8ydxtq1.public.blob.vercel-storage.com/v2/header/logo-light.png" height="64" alt="Interfere">
6
6
  </picture>
7
7
  </a>
8
8
  <h1 align="center">@interfere/next</h1>
9
9
  </p>
10
10
 
11
11
  <p align="center">
12
- <a href="https://www.npmjs.com/package/@interfere/next"><img src="https://img.shields.io/npm/v/@interfere/next.svg" /></a>
13
- <a href="https://github.com/interfere-inc/interfere/blob/main/LICENSE"><img src="https://img.shields.io/npm/l/@interfere/next.svg" /></a>
14
- <a href="https://www.npmjs.com/package/@interfere/next"><img src="https://img.shields.io/npm/dm/@interfere/next.svg" /></a>
12
+ <a href="https://www.npmjs.com/package/@interfere/next"><img src="https://img.shields.io/npm/v/@interfere/next.svg" alt="npm version" /></a>
13
+ <a href="https://github.com/interfere-inc/interfere/blob/main/LICENSE"><img src="https://img.shields.io/npm/l/@interfere/next.svg" alt="License" /></a>
14
+ <a href="https://www.npmjs.com/package/@interfere/next"><img src="https://img.shields.io/npm/dm/@interfere/next.svg" alt="npm downloads" /></a>
15
15
  </p>
16
16
 
17
17
  <p align="center">
@@ -69,7 +69,7 @@ export { onRequestError } from "@interfere/next/server";
69
69
 
70
70
  ```ts
71
71
  // app/api/interfere/[[...path]]/route.ts
72
- export { GET, POST, OPTIONS } from "@interfere/next/route-handler";
72
+ export * from "@interfere/next/route-handler";
73
73
  ```
74
74
 
75
75
  **4. Add the provider**
@@ -97,7 +97,40 @@ export default function RootLayout({
97
97
 
98
98
  | Variable | Required | Description |
99
99
  | --- | --- | --- |
100
- | `INTERFERE_API_KEY` | Yes | Your project API key |
100
+ | `INTERFERE_PUBLIC_KEY` | Yes | Surface public key in the `interfere_pk_*` format. Public by design; used for ingestion. |
101
+ | `INTERFERE_API_KEY` | Yes for release metadata | Interfere API key in the `interfere_ak_*` format. Server-side build credential; never expose in browser code. |
102
+ | `NEXT_PUBLIC_INTERFERE_ROUTE_PREFIX` | No | Override the proxy route prefix (default: `/api/interfere`). Must match the path you mount the route handler at — e.g. set this to `/__telemetry` and mount the handler at `app/__telemetry/[[...path]]/route.ts`. Read by both the server route handler and the client SDK. |
103
+
104
+ ### Migrating From 0.x
105
+
106
+ Upgrade all `@interfere/*` SDK packages together. Keep the env var names, but replace old `int_pub_*` values with the dashboard's new `interfere_pk_*` public key, and replace old `ak_*` build keys with the `interfere_ak_*` Interfere API key.
107
+
108
+ ## Custom Route Prefix
109
+
110
+ By default the SDK proxies all telemetry through `/api/interfere`. You can move this to any path by setting `NEXT_PUBLIC_INTERFERE_ROUTE_PREFIX` and mounting the route handler at the matching location.
111
+
112
+ **Why change it?** A custom prefix lets you avoid ad-blocker deny-lists that target well-known SDK paths, or align with your own API routing conventions.
113
+
114
+ **1. Set the environment variable**
115
+
116
+ ```env
117
+ NEXT_PUBLIC_INTERFERE_ROUTE_PREFIX=/__telemetry
118
+ ```
119
+
120
+ **2. Mount the route handler at the matching path**
121
+
122
+ ```ts
123
+ // app/__telemetry/[[...path]]/route.ts
124
+ export * from "@interfere/next/route-handler";
125
+ ```
126
+
127
+ **Normalization rules**
128
+
129
+ | Input | Resolved |
130
+ | --- | --- |
131
+ | `/__telemetry` | `/__telemetry` |
132
+ | `__telemetry/` | `/__telemetry` |
133
+ | *(empty)* or `/` | `/api/interfere` (default) |
101
134
 
102
135
  ## Identity Management
103
136
 
package/dist/config.d.mts CHANGED
@@ -1,16 +1,36 @@
1
- import { Envelope } from "@interfere/types/sdk/envelope";
1
+ import { ReleaseSlug } from "@interfere/types/releases/slug";
2
2
  import { NextConfig } from "next";
3
3
 
4
4
  //#region src/config.d.ts
5
- interface InterfereConfig extends Partial<Pick<Envelope, "buildId" | "releaseId">> {}
6
5
  interface NextConfigWithInterfere extends NextConfig {
7
- interfere?: InterfereConfig;
6
+ /**
7
+ * Reserved for future SDK config. Setting `buildId` here is rejected
8
+ * loudly — it caused server/client slug drift in 9.x. Override the
9
+ * commit SHA via the `INTERFERE_SOURCE_ID` env var (set on both build
10
+ * and runtime envs) instead.
11
+ */
12
+ interfere?: {
13
+ readonly buildId?: never;
14
+ };
8
15
  }
9
16
  interface ResolvedBuildConfig {
10
17
  readonly apiKey: string | null;
11
18
  readonly apiUrl: string;
19
+ /**
20
+ * Server-internal — the build pipeline still uses this to key R2
21
+ * source-map paths until Phase 7 re-keys them to slug. Never injected
22
+ * into the bundle; never exposed via env.
23
+ */
12
24
  readonly buildId: string | null;
13
- readonly releaseId: string | null;
25
+ readonly publicKey: string | null;
26
+ /**
27
+ * Deterministically derived from the leading 16 hex of the commit SHA, so
28
+ * the build step and the collector arrive at the same
29
+ * `rel_xxxxxxxxxxxxxxxx` without a round-trip. Stamped into the bundle as
30
+ * `__INTERFERE_RELEASE_SLUG__`. `null` when no commit SHA is available —
31
+ * release-pipeline calls bail in that case.
32
+ */
33
+ readonly releaseSlug: ReleaseSlug | null;
14
34
  }
15
35
  declare function withInterfere(nextConfig?: NextConfigWithInterfere): NextConfig;
16
36
  interface ProductionCompileContext {
@@ -18,4 +38,4 @@ interface ProductionCompileContext {
18
38
  readonly projectDir: string;
19
39
  }
20
40
  //#endregion
21
- export { InterfereConfig, NextConfigWithInterfere, ProductionCompileContext, ResolvedBuildConfig, withInterfere };
41
+ export { NextConfigWithInterfere, ProductionCompileContext, ResolvedBuildConfig, withInterfere };
@@ -1 +1 @@
1
- {"version":3,"file":"config.d.mts","names":[],"sources":["../src/config.ts"],"mappings":";;;;UAeiB,eAAA,SACP,OAAA,CAAQ,IAAA,CAAK,QAAA;AAAA,UAEN,uBAAA,SAAgC,UAAA;EAC/C,SAAA,GAAY,eAAA;AAAA;AAAA,UAGG,mBAAA;EAAA,SACN,MAAA;EAAA,SACA,MAAA;EAAA,SACA,OAAA;EAAA,SACA,SAAA;AAAA;AAAA,iBAGK,aAAA,CACd,UAAA,GAAY,uBAAA,GACX,UAAA;AAAA,UA6Fc,wBAAA;EAAA,SACN,OAAA;EAAA,SACA,UAAA;AAAA"}
1
+ {"version":3,"file":"config.d.mts","names":[],"sources":["../src/config.ts"],"mappings":";;;;UAmBiB,uBAAA,SAAgC,UAAU;;AAA3D;;;;;EAOE,SAAA;IAAA,SAAuB,OAAA;EAAA;AAAA;AAAA,UAGR,mBAAA;EAAA,SACN,MAAA;EAAA,SACA,MAAA;EAewB;;;;;EAAA,SATxB,OAAA;EAAA,SACA,SAAA;EAQwB;AAAA;AAGnC;;;;;EAHmC,SAAxB,WAAA,EAAa,WAAW;AAAA;AAAA,iBAGnB,aAAA,CACd,UAAA,GAAY,uBAAA,GACX,UAAU;AAAA,UA6II,wBAAA;EAAA,SACN,OAAA;EAAA,SACA,UAAU;AAAA"}
package/dist/config.mjs CHANGED
@@ -1,100 +1 @@
1
- import { configureBuild } from "./internal/build/configure-build.mjs";
2
- import { log } from "./internal/logger.mjs";
3
- import { runGitCommand } from "./internal/build/release/git.mjs";
4
- import { readInterfereEnv } from "./internal/env.mjs";
5
- import { omitUndefined } from "@interfere/helpers/omit-undefined";
6
- import { releaseDestinationIdEnvKeys, releaseSourceIdEnvKeys } from "@interfere/types/integrations";
7
- import { parseEnvValue, readFirstEnvValue } from "@interfere/types/sdk/env";
8
- //#region src/config.ts
9
- function withInterfere(nextConfig = {}) {
10
- const { interfere, env: userEnv, webpack, turbopack, compiler, productionBrowserSourceMaps, ...rest } = nextConfig;
11
- const config = resolveBuildConfig(interfere);
12
- const forceEnable = !!process.env["NEXT_PUBLIC_INTERFERE_FORCE_ENABLE"];
13
- const build = configureBuild({
14
- existingWebpack: webpack,
15
- existingTurbopack: turbopack,
16
- projectDir: process.cwd(),
17
- values: {
18
- __INTERFERE_BUILD_ID__: config.buildId,
19
- __INTERFERE_RELEASE_ID__: config.releaseId,
20
- ...forceEnable && { __INTERFERE_FORCE_ENABLE__: true }
21
- }
22
- });
23
- if (config.apiKey !== null && !build.webpack && !build.turbopack) return log.fatal("Missing instrumentation client", ["INTERFERE_API_KEY is set but no instrumentation-client file was found.", "Create an instrumentation-client.ts file in your project root or src/ directory."]);
24
- const existingHook = compiler?.runAfterProductionCompile;
25
- const browserSourceMaps = config.apiKey === null ? productionBrowserSourceMaps : true;
26
- return {
27
- ...rest,
28
- env: mergeEnvConfig(userEnv, config),
29
- compiler: {
30
- ...omitUndefined(compiler ?? {}),
31
- async runAfterProductionCompile(context) {
32
- if (existingHook) await existingHook(context);
33
- await runBuildReleasePipeline(context, config);
34
- }
35
- },
36
- ...omitUndefined({
37
- productionBrowserSourceMaps: browserSourceMaps,
38
- turbopack: build.turbopack,
39
- webpack: build.webpack
40
- })
41
- };
42
- }
43
- function resolveBuildConfig(interfere) {
44
- const { apiKey, apiUrl } = readInterfereEnv();
45
- const buildId = parseEnvValue(interfere?.buildId) ?? readFirstEnvValue(process.env, releaseSourceIdEnvKeys) ?? runGitCommand("git rev-parse HEAD");
46
- const releaseId = parseEnvValue(interfere?.releaseId) ?? readFirstEnvValue(process.env, releaseDestinationIdEnvKeys) ?? buildId;
47
- return {
48
- apiKey: apiKey ?? null,
49
- apiUrl,
50
- buildId,
51
- releaseId
52
- };
53
- }
54
- function mergeEnvConfig(userEnv, config) {
55
- const merged = {};
56
- if (config.buildId !== null) merged["NEXT_PUBLIC_INTERFERE_BUILD_ID"] = config.buildId;
57
- if (config.releaseId !== null) merged["NEXT_PUBLIC_INTERFERE_RELEASE_ID"] = config.releaseId;
58
- return {
59
- ...merged,
60
- ...userEnv
61
- };
62
- }
63
- async function runBuildReleasePipeline(context, config) {
64
- const { apiKey, buildId } = config;
65
- if (!apiKey) return log.fatal("API key not set", [
66
- "withInterfere() requires an API key to upload source maps during production builds.",
67
- "Set the INTERFERE_API_KEY environment variable, or remove withInterfere() from your Next.js config.",
68
- "See: https://support.interfere.com/docs/guides/next-js"
69
- ]);
70
- if (!buildId) return log.fatal("Build ID missing", ["Could not resolve a build ID from config, environment variables, or git.", "Set INTERFERE_BUILD_ID, or ensure git is available in your build environment."]);
71
- const { runBuildPipeline } = await import("./internal/build/pipeline.mjs");
72
- try {
73
- const result = await runBuildPipeline(context, {
74
- ...config,
75
- apiKey,
76
- buildId
77
- });
78
- if (!result.ready) {
79
- log.warn("Skipping", ["No source maps found"]);
80
- return;
81
- }
82
- log.info("Completed", [
83
- `https://interfere.com/~/${result.config?.org.slug}/surfaces/${result.config?.surface.slug}`,
84
- `Release: ${result.release?.destination.slug ?? "Unknown"}`,
85
- `Build: ${result.buildId}`,
86
- `Artifacts: ${result.fileCount} source maps`
87
- ]);
88
- } catch (error) {
89
- const message = error instanceof Error ? error.message : String(error);
90
- log.warn("Skipping release pipeline", [
91
- "Interfere failed to process this release.",
92
- "Events from this release will be ingested, but ignored as evidence when generating insights.",
93
- "Please check https://status.interfere.com for any outages, or contact support@interfere.com if the problem persists.",
94
- `Error: ${message}`
95
- ]);
96
- return;
97
- }
98
- }
99
- //#endregion
100
- export { withInterfere };
1
+ import{configureBuild}from"./internal/build/configure-build.mjs";import{readInterfereEnv}from"./internal/env.mjs";import{FatalError,log}from"./internal/logger.mjs";import{resolveReleaseSlug}from"./internal/release-slug.mjs";import{readNextMajorVersion,warnIfServerInstrumentationMissing}from"./internal/setup-warnings.mjs";import{omitUndefined}from"@interfere/helpers/omit-undefined";import{LOCAL_DEV_RELEASE_SLUG}from"@interfere/types/releases/slug";function withInterfere(nextConfig={}){let{interfere,env:userEnv,webpack,turbopack,compiler,productionBrowserSourceMaps,...rest}=nextConfig;if(interfere&&`buildId`in interfere&&interfere.buildId!==void 0)return log.fatal(`Removed: interfere.buildId`,["`interfere.buildId` was removed in SDK 10. It only worked at build time, so server-side spans drifted from the bundle's slug.","Override the commit SHA via the `INTERFERE_SOURCE_ID` env var on both build and runtime envs instead."]);let projectDir=process.cwd(),config=resolveBuildConfig(),forceEnable=!!process.env.NEXT_PUBLIC_INTERFERE_FORCE_ENABLE,build=configureBuild({existingWebpack:webpack,existingTurbopack:turbopack,projectDir,values:{__INTERFERE_RELEASE_SLUG__:forceEnable?LOCAL_DEV_RELEASE_SLUG:config.releaseSlug,...config.publicKey&&{__INTERFERE_PROXY_MODE__:!0,__INTERFERE_PUBLIC_KEY__:config.publicKey},...forceEnable&&{__INTERFERE_FORCE_ENABLE__:!0}}});if(config.publicKey!==null&&!build.webpack&&!build.turbopack)return log.fatal(`Missing instrumentation client`,[`INTERFERE_PUBLIC_KEY is set but no instrumentation-client file was found.`,`Create an instrumentation-client.ts file in your project root or src/ directory.`]);config.publicKey!==null&&warnIfServerInstrumentationMissing(projectDir);let nextMajor=readNextMajorVersion(projectDir),needsInstrumentationHookFlag=nextMajor===null||nextMajor<=14,existingHook=compiler?.runAfterProductionCompile,browserSourceMaps=config.apiKey===null?productionBrowserSourceMaps:!0;return config.apiKey!==null&&productionBrowserSourceMaps===!1&&log.warn(`Forcing productionBrowserSourceMaps`,[`withInterfere() requires production source maps to symbolicate errors.`,"Your `productionBrowserSourceMaps: false` was overridden to `true`."]),{...rest,...userEnv?{env:userEnv}:{},compiler:{...omitUndefined(compiler??{}),async runAfterProductionCompile(context){existingHook&&await existingHook(context);try{await runBuildReleasePipeline(context,config)}catch(error){if(error instanceof FatalError)throw error;let message=error instanceof Error?error.message:String(error);log.warn(`Skipping release pipeline`,[`Interfere encountered an unexpected error.`,`Build will continue, but this release's data will be ingested, but ignored as evidence when generating insights.`,`Error: ${message}`])}}},...omitUndefined({productionBrowserSourceMaps:browserSourceMaps,turbopack:build.turbopack,webpack:build.webpack}),...needsInstrumentationHookFlag?{experimental:{...rest.experimental??{},instrumentationHook:!0}}:{}}}function resolveBuildConfig(){let{apiKey,apiUrl,publicKey}=readInterfereEnv(),{commitSha,slug}=resolveReleaseSlug();return{apiKey:apiKey??null,apiUrl,buildId:commitSha,publicKey:publicKey??null,releaseSlug:slug}}async function runBuildReleasePipeline(context,config){let{apiKey,buildId,releaseSlug}=config;if(!apiKey)return log.fatal(`API key not set`,[`withInterfere() requires an API key to publish release metadata during production builds.`,`Set the INTERFERE_API_KEY environment variable, or remove withInterfere() from your Next.js config.`,`See: https://support.interfere.com/docs/guides/next-js`]);if(!(buildId&&releaseSlug))return log.fatal(`Commit SHA missing`,[`Could not resolve a commit SHA from environment variables or git.`,"Set `INTERFERE_SOURCE_ID`, ensure your CI exposes its git SHA env var (e.g. `VERCEL_GIT_COMMIT_SHA`, `GITHUB_SHA`), or run inside a git checkout."]);let{runBuildPipeline}=await import(`./internal/build/pipeline.mjs`);try{let result=await runBuildPipeline(context,{...config,apiKey,buildId,releaseSlug});if(!result.ready){log.warn(`Skipping`,[`No source maps found`]);return}log.info(`Completed`,[`https://interfere.com/~/${result.config?.org.slug}/surfaces/${result.config?.surface.slug}`,`Release: ${result.release?.destination.slug??`Unknown`}`,`Build: ${result.buildId}`,`Artifacts: ${result.fileCount} source maps`])}catch(error){let message=error instanceof Error?error.message:String(error);log.warn(`Skipping release pipeline`,[`Interfere failed to process this release.`,`Events from this release will be ingested, but ignored as evidence when generating insights.`,`Please check https://status.interfere.com for any outages, or contact support@interfere.com if the problem persists.`,`Error: ${message}`]);return}}export{withInterfere};
@@ -1 +1 @@
1
- {"version":3,"file":"config.mjs","names":[],"sources":["../src/config.ts"],"sourcesContent":["import { omitUndefined } from \"@interfere/helpers/omit-undefined\";\nimport {\n releaseDestinationIdEnvKeys,\n releaseSourceIdEnvKeys,\n} from \"@interfere/types/integrations\";\nimport { parseEnvValue, readFirstEnvValue } from \"@interfere/types/sdk/env\";\nimport type { Envelope } from \"@interfere/types/sdk/envelope\";\n\nimport type { NextConfig } from \"next\";\n\nimport { configureBuild } from \"./internal/build/configure-build.js\";\nimport { runGitCommand } from \"./internal/build/release/git.js\";\nimport { readInterfereEnv } from \"./internal/env.js\";\nimport { log } from \"./internal/logger.js\";\n\nexport interface InterfereConfig\n extends Partial<Pick<Envelope, \"buildId\" | \"releaseId\">> {}\n\nexport interface NextConfigWithInterfere extends NextConfig {\n interfere?: InterfereConfig;\n}\n\nexport interface ResolvedBuildConfig {\n readonly apiKey: string | null;\n readonly apiUrl: string;\n readonly buildId: string | null;\n readonly releaseId: string | null;\n}\n\nexport function withInterfere(\n nextConfig: NextConfigWithInterfere = {}\n): NextConfig {\n const {\n interfere,\n env: userEnv,\n webpack,\n turbopack,\n compiler,\n productionBrowserSourceMaps,\n ...rest\n } = nextConfig;\n\n const config = resolveBuildConfig(interfere);\n const forceEnable = !!process.env[\"NEXT_PUBLIC_INTERFERE_FORCE_ENABLE\"];\n const build = configureBuild({\n existingWebpack: webpack,\n existingTurbopack: turbopack,\n projectDir: process.cwd(),\n values: {\n __INTERFERE_BUILD_ID__: config.buildId,\n __INTERFERE_RELEASE_ID__: config.releaseId,\n ...(forceEnable && { __INTERFERE_FORCE_ENABLE__: true }),\n },\n });\n\n if (config.apiKey !== null && !build.webpack && !build.turbopack) {\n return log.fatal(\"Missing instrumentation client\", [\n \"INTERFERE_API_KEY is set but no instrumentation-client file was found.\",\n \"Create an instrumentation-client.ts file in your project root or src/ directory.\",\n ]);\n }\n\n const existingHook = (compiler as NextCompilerWithProductionHook | undefined)\n ?.runAfterProductionCompile;\n\n const browserSourceMaps =\n config.apiKey === null ? productionBrowserSourceMaps : true;\n\n return {\n ...rest,\n env: mergeEnvConfig(userEnv, config),\n\n compiler: {\n ...omitUndefined(compiler ?? {}),\n async runAfterProductionCompile(context: ProductionCompileContext) {\n if (existingHook) {\n await existingHook(context);\n }\n\n await runBuildReleasePipeline(context, config);\n },\n },\n\n ...omitUndefined({\n productionBrowserSourceMaps: browserSourceMaps,\n turbopack: build.turbopack,\n webpack: build.webpack,\n }),\n };\n}\n\nfunction resolveBuildConfig(interfere?: InterfereConfig): ResolvedBuildConfig {\n const { apiKey, apiUrl } = readInterfereEnv();\n\n const buildId =\n parseEnvValue(interfere?.buildId) ??\n readFirstEnvValue(process.env, releaseSourceIdEnvKeys) ??\n runGitCommand(\"git rev-parse HEAD\");\n\n const releaseId =\n parseEnvValue(interfere?.releaseId) ??\n readFirstEnvValue(process.env, releaseDestinationIdEnvKeys) ??\n buildId;\n\n return { apiKey: apiKey ?? null, apiUrl, buildId, releaseId };\n}\n\nfunction mergeEnvConfig(\n userEnv: NextConfig[\"env\"] | undefined,\n config: ResolvedBuildConfig\n): Record<string, string | undefined> {\n const merged: Record<string, string> = {};\n\n if (config.buildId !== null) {\n merged[\"NEXT_PUBLIC_INTERFERE_BUILD_ID\"] = config.buildId;\n }\n\n if (config.releaseId !== null) {\n merged[\"NEXT_PUBLIC_INTERFERE_RELEASE_ID\"] = config.releaseId;\n }\n\n return { ...merged, ...userEnv };\n}\n\nexport interface ProductionCompileContext {\n readonly distDir: string;\n readonly projectDir: string;\n}\n\ntype NextCompilerWithProductionHook = NonNullable<NextConfig[\"compiler\"]> & {\n runAfterProductionCompile?: (\n context: ProductionCompileContext\n ) => void | Promise<void>;\n};\n\nasync function runBuildReleasePipeline(\n context: ProductionCompileContext,\n config: ResolvedBuildConfig\n): Promise<void> {\n const { apiKey, buildId } = config;\n\n if (!apiKey) {\n return log.fatal(\"API key not set\", [\n \"withInterfere() requires an API key to upload source maps during production builds.\",\n \"Set the INTERFERE_API_KEY environment variable, or remove withInterfere() from your Next.js config.\",\n \"See: https://support.interfere.com/docs/guides/next-js\",\n ]);\n }\n\n if (!buildId) {\n return log.fatal(\"Build ID missing\", [\n \"Could not resolve a build ID from config, environment variables, or git.\",\n \"Set INTERFERE_BUILD_ID, or ensure git is available in your build environment.\",\n ]);\n }\n\n const { runBuildPipeline } = await import(\"./internal/build/pipeline.js\");\n\n try {\n const result = await runBuildPipeline(context, {\n ...config,\n apiKey,\n buildId,\n });\n\n if (!result.ready) {\n log.warn(\"Skipping\", [\"No source maps found\"]);\n return;\n }\n\n log.info(\"Completed\", [\n `https://interfere.com/~/${result.config?.org.slug}/surfaces/${result.config?.surface.slug}`,\n `Release: ${result.release?.destination.slug ?? \"Unknown\"}`,\n `Build: ${result.buildId}`,\n `Artifacts: ${result.fileCount} source maps`,\n ]);\n } catch (error) {\n const message = error instanceof Error ? error.message : String(error);\n\n log.warn(\"Skipping release pipeline\", [\n \"Interfere failed to process this release.\",\n \"Events from this release will be ingested, but ignored as evidence when generating insights.\",\n \"Please check https://status.interfere.com for any outages, or contact support@interfere.com if the problem persists.\",\n `Error: ${message}`,\n ]);\n\n return;\n }\n}\n"],"mappings":";;;;;;;;AA6BA,SAAgB,cACd,aAAsC,EAAE,EAC5B;CACZ,MAAM,EACJ,WACA,KAAK,SACL,SACA,WACA,UACA,6BACA,GAAG,SACD;CAEJ,MAAM,SAAS,mBAAmB,UAAU;CAC5C,MAAM,cAAc,CAAC,CAAC,QAAQ,IAAI;CAClC,MAAM,QAAQ,eAAe;EAC3B,iBAAiB;EACjB,mBAAmB;EACnB,YAAY,QAAQ,KAAK;EACzB,QAAQ;GACN,wBAAwB,OAAO;GAC/B,0BAA0B,OAAO;GACjC,GAAI,eAAe,EAAE,4BAA4B,MAAM;GACxD;EACF,CAAC;AAEF,KAAI,OAAO,WAAW,QAAQ,CAAC,MAAM,WAAW,CAAC,MAAM,UACrD,QAAO,IAAI,MAAM,kCAAkC,CACjD,0EACA,mFACD,CAAC;CAGJ,MAAM,eAAgB,UAClB;CAEJ,MAAM,oBACJ,OAAO,WAAW,OAAO,8BAA8B;AAEzD,QAAO;EACL,GAAG;EACH,KAAK,eAAe,SAAS,OAAO;EAEpC,UAAU;GACR,GAAG,cAAc,YAAY,EAAE,CAAC;GAChC,MAAM,0BAA0B,SAAmC;AACjE,QAAI,aACF,OAAM,aAAa,QAAQ;AAG7B,UAAM,wBAAwB,SAAS,OAAO;;GAEjD;EAED,GAAG,cAAc;GACf,6BAA6B;GAC7B,WAAW,MAAM;GACjB,SAAS,MAAM;GAChB,CAAC;EACH;;AAGH,SAAS,mBAAmB,WAAkD;CAC5E,MAAM,EAAE,QAAQ,WAAW,kBAAkB;CAE7C,MAAM,UACJ,cAAc,WAAW,QAAQ,IACjC,kBAAkB,QAAQ,KAAK,uBAAuB,IACtD,cAAc,qBAAqB;CAErC,MAAM,YACJ,cAAc,WAAW,UAAU,IACnC,kBAAkB,QAAQ,KAAK,4BAA4B,IAC3D;AAEF,QAAO;EAAE,QAAQ,UAAU;EAAM;EAAQ;EAAS;EAAW;;AAG/D,SAAS,eACP,SACA,QACoC;CACpC,MAAM,SAAiC,EAAE;AAEzC,KAAI,OAAO,YAAY,KACrB,QAAO,oCAAoC,OAAO;AAGpD,KAAI,OAAO,cAAc,KACvB,QAAO,sCAAsC,OAAO;AAGtD,QAAO;EAAE,GAAG;EAAQ,GAAG;EAAS;;AAclC,eAAe,wBACb,SACA,QACe;CACf,MAAM,EAAE,QAAQ,YAAY;AAE5B,KAAI,CAAC,OACH,QAAO,IAAI,MAAM,mBAAmB;EAClC;EACA;EACA;EACD,CAAC;AAGJ,KAAI,CAAC,QACH,QAAO,IAAI,MAAM,oBAAoB,CACnC,4EACA,gFACD,CAAC;CAGJ,MAAM,EAAE,qBAAqB,MAAM,OAAO;AAE1C,KAAI;EACF,MAAM,SAAS,MAAM,iBAAiB,SAAS;GAC7C,GAAG;GACH;GACA;GACD,CAAC;AAEF,MAAI,CAAC,OAAO,OAAO;AACjB,OAAI,KAAK,YAAY,CAAC,uBAAuB,CAAC;AAC9C;;AAGF,MAAI,KAAK,aAAa;GACpB,2BAA2B,OAAO,QAAQ,IAAI,KAAK,YAAY,OAAO,QAAQ,QAAQ;GACtF,YAAY,OAAO,SAAS,YAAY,QAAQ;GAChD,UAAU,OAAO;GACjB,cAAc,OAAO,UAAU;GAChC,CAAC;UACK,OAAO;EACd,MAAM,UAAU,iBAAiB,QAAQ,MAAM,UAAU,OAAO,MAAM;AAEtE,MAAI,KAAK,6BAA6B;GACpC;GACA;GACA;GACA,UAAU;GACX,CAAC;AAEF"}
1
+ {"version":3,"file":"config.mjs","names":[],"sources":["../src/config.ts"],"sourcesContent":["import { omitUndefined } from \"@interfere/helpers/omit-undefined\";\nimport {\n LOCAL_DEV_RELEASE_SLUG,\n type ReleaseSlug,\n} from \"@interfere/types/releases/slug\";\n\nimport type { NextConfig } from \"next\";\n\nimport { configureBuild } from \"./internal/build/configure-build.js\";\nimport { readInterfereEnv } from \"./internal/env.js\";\nimport { FatalError, log } from \"./internal/logger.js\";\nimport { resolveReleaseSlug } from \"./internal/release-slug.js\";\nimport {\n readNextMajorVersion,\n warnIfServerInstrumentationMissing,\n} from \"./internal/setup-warnings.js\";\n\nconst NEXT_INSTRUMENTATION_HOOK_FLAG_LAST_MAJOR = 14;\n\nexport interface NextConfigWithInterfere extends NextConfig {\n /**\n * Reserved for future SDK config. Setting `buildId` here is rejected\n * loudly — it caused server/client slug drift in 9.x. Override the\n * commit SHA via the `INTERFERE_SOURCE_ID` env var (set on both build\n * and runtime envs) instead.\n */\n interfere?: { readonly buildId?: never };\n}\n\nexport interface ResolvedBuildConfig {\n readonly apiKey: string | null;\n readonly apiUrl: string;\n /**\n * Server-internal — the build pipeline still uses this to key R2\n * source-map paths until Phase 7 re-keys them to slug. Never injected\n * into the bundle; never exposed via env.\n */\n readonly buildId: string | null;\n readonly publicKey: string | null;\n /**\n * Deterministically derived from the leading 16 hex of the commit SHA, so\n * the build step and the collector arrive at the same\n * `rel_xxxxxxxxxxxxxxxx` without a round-trip. Stamped into the bundle as\n * `__INTERFERE_RELEASE_SLUG__`. `null` when no commit SHA is available —\n * release-pipeline calls bail in that case.\n */\n readonly releaseSlug: ReleaseSlug | null;\n}\n\nexport function withInterfere(\n nextConfig: NextConfigWithInterfere = {}\n): NextConfig {\n const {\n interfere,\n env: userEnv,\n webpack,\n turbopack,\n compiler,\n productionBrowserSourceMaps,\n ...rest\n } = nextConfig;\n\n if (interfere && \"buildId\" in interfere && interfere.buildId !== undefined) {\n return log.fatal(\"Removed: interfere.buildId\", [\n \"`interfere.buildId` was removed in SDK 10. It only worked at build time, so server-side spans drifted from the bundle's slug.\",\n \"Override the commit SHA via the `INTERFERE_SOURCE_ID` env var on both build and runtime envs instead.\",\n ]);\n }\n\n const projectDir = process.cwd();\n const config = resolveBuildConfig();\n const forceEnable = !!process.env[\"NEXT_PUBLIC_INTERFERE_FORCE_ENABLE\"];\n // Force-enable overrides the derived slug with a known sentinel. `next\n // dev` doesn't run the build pipeline, so any commit-derived slug\n // wouldn't be preflight-confirmed at the collector. The local DB seeds\n // this slug as preflight-confirmed (see ENG-1353); prod\n // collectors silently drop force-enabled batches by header (ENG-1356).\n const releaseSlug = forceEnable ? LOCAL_DEV_RELEASE_SLUG : config.releaseSlug;\n const build = configureBuild({\n existingWebpack: webpack,\n existingTurbopack: turbopack,\n projectDir,\n values: {\n __INTERFERE_RELEASE_SLUG__: releaseSlug,\n ...(config.publicKey && {\n __INTERFERE_PROXY_MODE__: true,\n __INTERFERE_PUBLIC_KEY__: config.publicKey,\n }),\n ...(forceEnable && { __INTERFERE_FORCE_ENABLE__: true }),\n },\n });\n\n if (config.publicKey !== null && !build.webpack && !build.turbopack) {\n return log.fatal(\"Missing instrumentation client\", [\n \"INTERFERE_PUBLIC_KEY is set but no instrumentation-client file was found.\",\n \"Create an instrumentation-client.ts file in your project root or src/ directory.\",\n ]);\n }\n\n if (config.publicKey !== null) {\n warnIfServerInstrumentationMissing(projectDir);\n }\n\n // `experimental.instrumentationHook` is required to opt in to\n // `instrumentation.ts` on Next 13–14, then becomes default-on (and the\n // flag is removed) in 15+. Default to setting the flag if we can't read\n // the version (monorepo hoist, weird resolve) — cheap on 15+ and avoids\n // silent breakage on 13/14.\n const nextMajor = readNextMajorVersion(projectDir);\n const needsInstrumentationHookFlag =\n nextMajor === null ||\n nextMajor <= NEXT_INSTRUMENTATION_HOOK_FLAG_LAST_MAJOR;\n\n const existingHook = (compiler as NextCompilerWithProductionHook | undefined)\n ?.runAfterProductionCompile;\n\n // Production source maps are required for symbolication. We force them\n // on whenever an API key is present; flip the customer's explicit\n // `false` to `true` and log so the change is visible.\n const browserSourceMaps =\n config.apiKey === null ? productionBrowserSourceMaps : true;\n if (config.apiKey !== null && productionBrowserSourceMaps === false) {\n log.warn(\"Forcing productionBrowserSourceMaps\", [\n \"withInterfere() requires production source maps to symbolicate errors.\",\n \"Your `productionBrowserSourceMaps: false` was overridden to `true`.\",\n ]);\n }\n\n return {\n ...rest,\n ...(userEnv ? { env: userEnv } : {}),\n\n compiler: {\n ...omitUndefined(compiler ?? {}),\n async runAfterProductionCompile(context: ProductionCompileContext) {\n if (existingHook) {\n await existingHook(context);\n }\n\n try {\n await runBuildReleasePipeline(context, config);\n } catch (error) {\n if (error instanceof FatalError) {\n throw error;\n }\n\n const message =\n error instanceof Error ? error.message : String(error);\n\n log.warn(\"Skipping release pipeline\", [\n \"Interfere encountered an unexpected error.\",\n \"Build will continue, but this release's data will be ingested, but ignored as evidence when generating insights.\",\n `Error: ${message}`,\n ]);\n }\n },\n },\n\n ...omitUndefined({\n productionBrowserSourceMaps: browserSourceMaps,\n turbopack: build.turbopack,\n webpack: build.webpack,\n }),\n\n // `instrumentationHook` is a Next 13–14 flag — required to opt into\n // `instrumentation.ts`, removed in 15+ where the hook is default-on. The\n // current Next type defs (peer-dep `^16`) no longer declare it, so we\n // cast through to set it without touching the input config's type.\n ...(needsInstrumentationHookFlag\n ? {\n experimental: {\n ...(rest.experimental ?? {}),\n instrumentationHook: true,\n } as NonNullable<NextConfig[\"experimental\"]>,\n }\n : {}),\n };\n}\n\nfunction resolveBuildConfig(): ResolvedBuildConfig {\n const { apiKey, apiUrl, publicKey } = readInterfereEnv();\n const { commitSha, slug } = resolveReleaseSlug();\n\n return {\n apiKey: apiKey ?? null,\n apiUrl,\n buildId: commitSha,\n publicKey: publicKey ?? null,\n releaseSlug: slug,\n };\n}\n\nexport interface ProductionCompileContext {\n readonly distDir: string;\n readonly projectDir: string;\n}\n\ntype NextCompilerWithProductionHook = NonNullable<NextConfig[\"compiler\"]> & {\n runAfterProductionCompile?: (\n context: ProductionCompileContext\n ) => void | Promise<void>;\n};\n\nasync function runBuildReleasePipeline(\n context: ProductionCompileContext,\n config: ResolvedBuildConfig\n): Promise<void> {\n const { apiKey, buildId, releaseSlug } = config;\n\n if (!apiKey) {\n return log.fatal(\"API key not set\", [\n \"withInterfere() requires an API key to publish release metadata during production builds.\",\n \"Set the INTERFERE_API_KEY environment variable, or remove withInterfere() from your Next.js config.\",\n \"See: https://support.interfere.com/docs/guides/next-js\",\n ]);\n }\n\n if (!(buildId && releaseSlug)) {\n return log.fatal(\"Commit SHA missing\", [\n \"Could not resolve a commit SHA from environment variables or git.\",\n \"Set `INTERFERE_SOURCE_ID`, ensure your CI exposes its git SHA env var (e.g. `VERCEL_GIT_COMMIT_SHA`, `GITHUB_SHA`), or run inside a git checkout.\",\n ]);\n }\n\n const { runBuildPipeline } = await import(\"./internal/build/pipeline.js\");\n\n try {\n const result = await runBuildPipeline(context, {\n ...config,\n apiKey,\n buildId,\n releaseSlug,\n });\n\n if (!result.ready) {\n log.warn(\"Skipping\", [\"No source maps found\"]);\n return;\n }\n\n log.info(\"Completed\", [\n `https://interfere.com/~/${result.config?.org.slug}/surfaces/${result.config?.surface.slug}`,\n `Release: ${result.release?.destination.slug ?? \"Unknown\"}`,\n `Build: ${result.buildId}`,\n `Artifacts: ${result.fileCount} source maps`,\n ]);\n } catch (error) {\n const message = error instanceof Error ? error.message : String(error);\n\n log.warn(\"Skipping release pipeline\", [\n \"Interfere failed to process this release.\",\n \"Events from this release will be ingested, but ignored as evidence when generating insights.\",\n \"Please check https://status.interfere.com for any outages, or contact support@interfere.com if the problem persists.\",\n `Error: ${message}`,\n ]);\n\n return;\n }\n}\n"],"mappings":"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"}
@@ -1,6 +1,14 @@
1
- import { ClientOptions, ClientOptions as ClientOptions$1, consent } from "@interfere/react/internal/client";
1
+ import { capture, span } from "@interfere/react/api";
2
+ import { Kernel, KernelInternalOptions, KernelOptions } from "@interfere/react/internal/kernel";
3
+ import { ConsentCategory, ConsentState, GateableCategory } from "@interfere/types/sdk/plugins/manifest";
2
4
 
3
5
  //#region src/instrument-client.d.ts
4
- declare function init(opts?: ClientOptions$1): void;
6
+ declare const close: () => Promise<void>, consent: {
7
+ get(): import("@interfere/types/sdk/plugins/manifest").ConsentState | null;
8
+ set(value?: import("@interfere/types/sdk/plugins/manifest").ConsentState): void;
9
+ }, getKernel: () => import("@interfere/react/internal/kernel").Kernel, getKernelOrNull: () => import("@interfere/react/internal/kernel").Kernel | null, identity: {
10
+ get(): import("@interfere/types/sdk/identify").IdentifyParams | null;
11
+ set(params: import("@interfere/types/sdk/identify").IdentifyParams): Promise<void>;
12
+ }, init: (opts?: import("@interfere/react/internal/kernel").KernelOptions) => Promise<import("@interfere/react/internal/kernel").Kernel | null>, subscribeToKernel: (listener: () => void) => () => void;
5
13
  //#endregion
6
- export { type ClientOptions, consent, init };
14
+ export { type ConsentCategory, type ConsentState, type GateableCategory, type Kernel, type KernelInternalOptions, type KernelOptions, capture, close, consent, getKernel, getKernelOrNull, identity, init, span, subscribeToKernel };
@@ -1 +1 @@
1
- {"version":3,"file":"instrument-client.d.mts","names":[],"sources":["../src/instrument-client.ts"],"mappings":";;;iBAYgB,IAAA,CAAK,IAAA,GAAO,eAAA"}
1
+ {"version":3,"file":"instrument-client.d.mts","names":[],"sources":["../src/instrument-client.ts"],"mappings":";;;;;cAuBE,KAAA,QAAK,OAAA,QAAA,OAAA;;;iEAEI,MAAA,EAAA,eAAA,mDACM,MAAA,SAAA,QAAA;;;YAEX,IAAA,8CAAA,aAAA,KAAA,OAAA,4CAAA,MAAA,UAAA,iBAAA,GACa,QAAA"}
@@ -1,11 +1 @@
1
- import { PRODUCER_VERSION } from "./internal/version.mjs";
2
- import { consent, init as init$1 } from "@interfere/react/internal/client";
3
- //#region src/instrument-client.ts
4
- function init(opts) {
5
- init$1({
6
- ...opts,
7
- _wrapperVersions: [PRODUCER_VERSION, ...opts?._wrapperVersions ?? []]
8
- });
9
- }
10
- //#endregion
11
- export { consent, init };
1
+ import{PRODUCER_VERSION}from"./internal/version.mjs";import{createWrapperSingleton}from"@interfere/react/internal/wrapper-singleton";import{capture,span}from"@interfere/react/api";const{close,consent,getKernel,getKernelOrNull,identity,init,subscribeToKernel}=createWrapperSingleton({producerVersion:PRODUCER_VERSION,initEntryName:`instrumentation-client`});export{capture,close,consent,getKernel,getKernelOrNull,identity,init,span,subscribeToKernel};
@@ -1 +1 @@
1
- {"version":3,"file":"instrument-client.mjs","names":[],"sources":["../src/instrument-client.ts"],"sourcesContent":["import { init as coreInit } from \"@interfere/react/internal/client\";\n\n// biome-ignore lint/performance/noBarrelFile: Next.js instrument-client entrypoint should be a direct re-export.\nexport {\n type ClientOptions,\n consent,\n} from \"@interfere/react/internal/client\";\n\nimport type { ClientOptions } from \"@interfere/react/internal/client\";\n\nimport { PRODUCER_VERSION } from \"./internal/version.js\";\n\nexport function init(opts?: ClientOptions): void {\n coreInit({\n ...opts,\n _wrapperVersions: [PRODUCER_VERSION, ...(opts?._wrapperVersions ?? [])],\n });\n}\n"],"mappings":";;;AAYA,SAAgB,KAAK,MAA4B;AAC/C,QAAS;EACP,GAAG;EACH,kBAAkB,CAAC,kBAAkB,GAAI,MAAM,oBAAoB,EAAE,CAAE;EACxE,CAAC"}
1
+ {"version":3,"file":"instrument-client.mjs","names":[],"sources":["../src/instrument-client.ts"],"sourcesContent":["import { createWrapperSingleton } from \"@interfere/react/internal/wrapper-singleton\";\n\nimport { PRODUCER_VERSION } from \"./internal/version.js\";\n\n// biome-ignore lint/performance/noBarrelFile: customer-facing one-import surface `@interfere/next` re-exports the runtime helpers so callers don't have to also import `@interfere/react/api`.\nexport { capture, span } from \"@interfere/react/api\";\nexport type {\n Kernel,\n KernelInternalOptions,\n KernelOptions,\n} from \"@interfere/react/internal/kernel\";\nexport type {\n ConsentCategory,\n ConsentState,\n GateableCategory,\n} from \"@interfere/types/sdk/plugins/manifest\";\n\nconst wrapper = createWrapperSingleton({\n producerVersion: PRODUCER_VERSION,\n initEntryName: \"instrumentation-client\",\n});\n\nexport const {\n close,\n consent,\n getKernel,\n getKernelOrNull,\n identity,\n init,\n subscribeToKernel,\n} = wrapper;\n"],"mappings":"oLAsBA,KAAa,CACX,MACA,QACA,UACA,gBACA,SACA,KACA,mBAZc,uBAAuB,CACrC,gBAAiB,iBACjB,cAAe,wBACjB,CAUI"}
@@ -0,0 +1 @@
1
+ export { };
@@ -0,0 +1 @@
1
+ import{init}from"./instrument-client.mjs";init().catch(error=>{process.env.NODE_ENV!==`production`&&console.warn(`[interfere] init() threw during boot`,error)});export{};
@@ -0,0 +1 @@
1
+ {"version":3,"file":"instrumentation-client.mjs","names":[],"sources":["../src/instrumentation-client.ts"],"sourcesContent":["import { init } from \"./instrument-client.js\";\n\n/**\n * Side-effect entry for Next.js 15.3+ which auto-loads `instrumentation-client.ts`\n * on every page load. Customer's `instrumentation-client.ts` becomes:\n *\n * ```ts\n * import \"@interfere/next/instrumentation-client\";\n * ```\n *\n * That single import boots the kernel with sensible defaults. Customers who\n * need overrides can call `init({...})` from `@interfere/next` directly —\n * `init()` is idempotent so the side-effect call here turns into a no-op.\n *\n * The `.catch` surfaces sync boot errors in dev — production swallows them\n * (a misconfigured SDK shouldn't take the customer's app down).\n */\ninit().catch((error: unknown) => {\n if (process.env[\"NODE_ENV\"] !== \"production\") {\n console.warn(\"[interfere] init() threw during boot\", error);\n }\n});\n"],"mappings":"0CAiBA,KAAK,EAAE,MAAO,OAAmB,CAC3B,QAAQ,IAAI,WAAgB,cAC9B,QAAQ,KAAK,uCAAwC,KAAK,CAE9D,CAAC"}
@@ -0,0 +1,134 @@
1
+ import { ServerInstrumentationOptions } from "./internal/server/instrumentation-options.mjs";
2
+ import { PrerenderSafeIdGenerator } from "./internal/server/id-generator.mjs";
3
+ import { AttributeValue, TextMapPropagator } from "@opentelemetry/api";
4
+ import { Instrumentation } from "@opentelemetry/instrumentation";
5
+ import { LogRecordProcessor } from "@opentelemetry/sdk-logs";
6
+ import { MetricReader } from "@opentelemetry/sdk-metrics";
7
+ import { SpanProcessor } from "@opentelemetry/sdk-trace-base";
8
+
9
+ //#region src/instrumentation.d.ts
10
+ /**
11
+ * Composable building blocks the Interfere SDK contributes to OTel —
12
+ * span / log / metric processors, baggage propagator, undici
13
+ * instrumentation, plus the resource attributes and side-effect
14
+ * installers (console bridge + remote-config fetch).
15
+ *
16
+ * Use this when you want to plug Interfere into an existing OTel
17
+ * bootstrap (e.g. `@vercel/otel`'s `registerOTel({...})`, DataDog's
18
+ * `dd-trace-js`, or any custom `NodeTracerProvider` setup) instead of
19
+ * the standalone `register()` path. The kit holds no global state and
20
+ * touches no global slots — composition is the consumer's job.
21
+ *
22
+ * The standalone `register()` builds the kit internally and wires it
23
+ * into private providers, so customer DX stays a one-liner export.
24
+ *
25
+ * Returns `null` when `INTERFERE_PUBLIC_KEY` is unset — callers can spread
26
+ * `kit?.spanProcessors ?? []` without a no-op guard.
27
+ */
28
+ interface InterfereOtelKit {
29
+ /**
30
+ * Patches `console.{debug,log,info,warn,error}` to also emit OTel
31
+ * `LogRecord`s via the global `LoggerProvider`. Caller is responsible
32
+ * for ensuring a `LoggerProvider` is registered globally before
33
+ * calling — `register()` handles this; for composed setups, call
34
+ * after your bootstrap (`registerOTel({...})` etc.) has run. Returns
35
+ * a disposer that restores the original `console.*` methods.
36
+ */
37
+ enableConsoleBridge: () => () => void;
38
+ /**
39
+ * Fetches the SDK's remote plugin config and caches it for the
40
+ * runtime. Customer code's `isPluginEnabled(...)` checks read from
41
+ * the cache. Safe to call repeatedly.
42
+ */
43
+ fetchRemoteConfig: () => Promise<void>;
44
+ /**
45
+ * Instrumentations the SDK ships. Currently `UndiciInstrumentation`
46
+ * pre-configured with `propagateContextUrls` / `ignoreUrls` semantics
47
+ * from `ServerInstrumentationOptions`.
48
+ *
49
+ * **Composition with `@vercel/otel`**: `instrumentations: ["auto"]`
50
+ * registers Vercel's `globalThis.fetch` wrapper, which only
51
+ * auto-propagates `traceparent` to Vercel deployment URLs — outbound
52
+ * fetches to a different origin (e.g. `in.interfere.com`) get a
53
+ * span but no header injection unless
54
+ * `instrumentationConfig.fetch.propagateContextUrls` is set, and
55
+ * even then it doesn't cover the lower-level undici dispatcher path
56
+ * Next.js route handlers use. Spread `kit.instrumentations` after
57
+ * `"auto"` to layer this UndiciInstrumentation on top — propagation
58
+ * extends to every outbound undici call (filtered via `ignoreUrls`).
59
+ * Risk of double span emission on overlapping call sites is bounded:
60
+ * Vercel's fetch wraps `globalThis.fetch`, this hooks the undici
61
+ * dispatcher one layer lower, so duplicates only appear when both
62
+ * paths actually fire on the same call.
63
+ */
64
+ instrumentations: Instrumentation[];
65
+ logRecordProcessors: LogRecordProcessor[];
66
+ metricReaders: MetricReader[];
67
+ /**
68
+ * W3C baggage propagator. Trace context is intentionally *not*
69
+ * included — `@vercel/otel`'s `propagators: ["auto"]` already
70
+ * registers it, and standalone `register()` adds it itself when
71
+ * the global slot is empty. Composing this on top extends rather
72
+ * than overrides.
73
+ */
74
+ propagators: TextMapPropagator[];
75
+ /**
76
+ * Pre-built resource attribute set. Pass into your provider's
77
+ * `Resource` directly, or into `@vercel/otel`'s `attributes` field
78
+ * (which merges with Vercel's own auto-detected `vercel.*` attrs).
79
+ */
80
+ resourceAttributes: Record<string, AttributeValue>;
81
+ spanProcessors: SpanProcessor[];
82
+ }
83
+ /**
84
+ * Pure factory — no global registration, no provider construction. Returns
85
+ * the OTel primitives the SDK contributes so a host bootstrap (Vercel,
86
+ * DataDog, custom) can compose them in.
87
+ *
88
+ * Returns `null` when `INTERFERE_PUBLIC_KEY` isn't set, so callers can
89
+ * unconditionally spread `kit?.spanProcessors ?? []` in dev where the
90
+ * SDK isn't configured.
91
+ */
92
+ declare function buildInterfereOtelKit(opts?: ServerInstrumentationOptions): InterfereOtelKit | null;
93
+ /**
94
+ * One-line server-side bootstrap for Next.js. Customers' `instrumentation.ts`
95
+ * becomes:
96
+ *
97
+ * ```ts
98
+ * export { register } from "@interfere/next/instrumentation";
99
+ * ```
100
+ *
101
+ * Or, with overrides:
102
+ *
103
+ * ```ts
104
+ * import { register as base } from "@interfere/next/instrumentation";
105
+ * export const register = () => base({ serviceName: "@my-org/api" });
106
+ * ```
107
+ *
108
+ * Customers who already run another OTel bootstrap (`@vercel/otel`,
109
+ * DataDog `dd-trace-js`, custom `NodeTracerProvider`) should use
110
+ * `buildInterfereOtelKit({...})` instead and compose the returned
111
+ * processors / readers / propagators into their existing setup —
112
+ * see the kit's JSDoc for examples.
113
+ *
114
+ * Constructs private `NodeTracerProvider` / `LoggerProvider` /
115
+ * `MeterProvider` and registers them on the global slots. Last writer
116
+ * wins on the globals, so customers running another OTel bootstrap
117
+ * alongside this one will end up with whichever booted last; the kit
118
+ * path avoids that fight entirely.
119
+ *
120
+ * Wired against the Node OTel SDK (`NodeTracerProvider`,
121
+ * `AsyncLocalStorageContextManager`) — so this entry only ships into the
122
+ * `nodejs` runtime bundle. The Edge runtime gets the no-op stub at
123
+ * `instrumentation.edge.ts` via `package.json`'s `edge-light` /
124
+ * `workerd` export conditions.
125
+ *
126
+ * Idempotent — repeat calls (e.g. HMR) short-circuit on the
127
+ * module-scoped `registered` flag.
128
+ *
129
+ * Bails silently when `INTERFERE_PUBLIC_KEY` is unset so dev runs without
130
+ * the SDK configured don't crash.
131
+ */
132
+ declare function register(opts?: ServerInstrumentationOptions): Promise<void>;
133
+ //#endregion
134
+ export { InterfereOtelKit, PrerenderSafeIdGenerator, type ServerInstrumentationOptions, buildInterfereOtelKit, register };
@@ -0,0 +1 @@
1
+ {"version":3,"file":"instrumentation.d.mts","names":[],"sources":["../src/instrumentation.ts"],"mappings":";;;;;;;;;;AAqFA;;;;;;;;;;;;;;;;;UAAiB,gBAAA;EAqCf;;;;;;;;EA5BA,mBAAA;EA4CA;;;AAA6B;AAY/B;EAlDE,iBAAA,QAAyB,OAAA;;;;;;;AAoDR;AAqJnB;;;;;;;;AAEU;;;;;EAtLR,gBAAA,EAAkB,eAAA;EAClB,mBAAA,EAAqB,kBAAA;EACrB,aAAA,EAAe,YAAA;;;;;;;;EAQf,WAAA,EAAa,iBAAA;;;;;;EAMb,kBAAA,EAAoB,MAAA,SAAe,cAAA;EACnC,cAAA,EAAgB,aAAA;AAAA;;;;;;;;;;iBAYF,qBAAA,CACd,IAAA,GAAM,4BAAA,GACL,gBAAgB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBAqJG,QAAA,CACpB,IAAA,GAAM,4BAAA,GACL,OAAO"}
@@ -0,0 +1,35 @@
1
+ import { ServerInstrumentationOptions } from "./internal/server/instrumentation-options.mjs";
2
+ import { InterfereOtelKit } from "./instrumentation.mjs";
3
+
4
+ //#region src/instrumentation.edge.d.ts
5
+ /**
6
+ * Edge-runtime entry for `@interfere/next/instrumentation`. Selected by
7
+ * `package.json`'s `edge-light` / `workerd` / `worker` export conditions
8
+ * — Next.js + Vercel pick this bundle when compiling
9
+ * `instrumentation.ts` for the Edge runtime.
10
+ *
11
+ * The Node entry (`instrumentation.ts`) is built around
12
+ * `NodeTracerProvider`, `AsyncLocalStorageContextManager`, undici
13
+ * instrumentation, and a console→OTel bridge — none of which work in
14
+ * the Edge runtime. Pulling that import graph into an Edge bundle would
15
+ * (a) trip Next's `node:*`-in-edge warnings (release-slug derivation
16
+ * uses `node:child_process` + `node:crypto`) and (b) crash on module
17
+ * load if the Edge bundle were ever actually invoked.
18
+ *
19
+ * Both `register()` and `buildInterfereOtelKit()` are exported as
20
+ * no-op stubs so customer TypeScript code compiles unchanged
21
+ * regardless of which runtime the file ends up in. Edge-runtime
22
+ * tracing (middleware spans, edge route handlers) needs an
23
+ * `@opentelemetry/sdk-trace-base`-based pipeline with a fetch-based
24
+ * exporter — tracked separately.
25
+ */
26
+ declare function register(_opts?: ServerInstrumentationOptions): Promise<void>;
27
+ /**
28
+ * Edge stub for the kit factory. Returns `null` so callers spreading
29
+ * `kit?.spanProcessors ?? []` into a host bootstrap behave as if the
30
+ * SDK is unconfigured — same shape as the Node entry returns when
31
+ * `INTERFERE_PUBLIC_KEY` is unset.
32
+ */
33
+ declare function buildInterfereOtelKit(_opts?: ServerInstrumentationOptions): null;
34
+ //#endregion
35
+ export { type InterfereOtelKit, type ServerInstrumentationOptions, buildInterfereOtelKit, register };
@@ -0,0 +1 @@
1
+ {"version":3,"file":"instrumentation.edge.d.mts","names":[],"sources":["../src/instrumentation.edge.ts"],"mappings":";;;;;AA0BA;;;;;;;;AAEU;AAUV;;;;AAC0C;;;;;;;iBAbpB,QAAA,CACpB,KAAA,GAAO,4BAAA,GACN,OAAO;;;;;;;iBAUM,qBAAA,CACd,KAAwC,GAAjC,4BAAiC"}
@@ -0,0 +1 @@
1
+ async function register(_opts={}){}function buildInterfereOtelKit(_opts={}){return null}export{buildInterfereOtelKit,register};
@@ -0,0 +1 @@
1
+ {"version":3,"file":"instrumentation.edge.mjs","names":[],"sources":["../src/instrumentation.edge.ts"],"sourcesContent":["import type { ServerInstrumentationOptions } from \"./internal/server/instrumentation-options.js\";\n\nexport type { InterfereOtelKit } from \"./instrumentation.js\";\nexport type { ServerInstrumentationOptions } from \"./internal/server/instrumentation-options.js\";\n\n/**\n * Edge-runtime entry for `@interfere/next/instrumentation`. Selected by\n * `package.json`'s `edge-light` / `workerd` / `worker` export conditions\n * — Next.js + Vercel pick this bundle when compiling\n * `instrumentation.ts` for the Edge runtime.\n *\n * The Node entry (`instrumentation.ts`) is built around\n * `NodeTracerProvider`, `AsyncLocalStorageContextManager`, undici\n * instrumentation, and a console→OTel bridge — none of which work in\n * the Edge runtime. Pulling that import graph into an Edge bundle would\n * (a) trip Next's `node:*`-in-edge warnings (release-slug derivation\n * uses `node:child_process` + `node:crypto`) and (b) crash on module\n * load if the Edge bundle were ever actually invoked.\n *\n * Both `register()` and `buildInterfereOtelKit()` are exported as\n * no-op stubs so customer TypeScript code compiles unchanged\n * regardless of which runtime the file ends up in. Edge-runtime\n * tracing (middleware spans, edge route handlers) needs an\n * `@opentelemetry/sdk-trace-base`-based pipeline with a fetch-based\n * exporter — tracked separately.\n */\nexport async function register(\n _opts: ServerInstrumentationOptions = {}\n): Promise<void> {\n // Intentionally empty. See file header for the design rationale.\n}\n\n/**\n * Edge stub for the kit factory. Returns `null` so callers spreading\n * `kit?.spanProcessors ?? []` into a host bootstrap behave as if the\n * SDK is unconfigured — same shape as the Node entry returns when\n * `INTERFERE_PUBLIC_KEY` is unset.\n */\nexport function buildInterfereOtelKit(\n _opts: ServerInstrumentationOptions = {}\n): null {\n return null;\n}\n"],"mappings":"AA0BA,eAAsB,SACpB,MAAsC,CAAC,EACxB,CAEjB,CAQA,SAAgB,sBACd,MAAsC,CAAC,EACjC,CACN,OAAO,IACT"}
@@ -0,0 +1 @@
1
+ import{readInterfereEnv}from"./internal/env.mjs";import{resolveReleaseSlug}from"./internal/release-slug.mjs";import{PRODUCER_VERSION}from"./internal/version.mjs";import{bridgeConsoleToOtel}from"./internal/server/console-bridge.mjs";import{PrerenderSafeIdGenerator}from"./internal/server/id-generator.mjs";import{withPublicKey}from"./internal/url.mjs";import{fetchAndCacheRemoteConfig}from"./internal/server/remote-config.mjs";import{metrics,propagation}from"@opentelemetry/api";import{BaggageSpanProcessor}from"@opentelemetry/baggage-span-processor";import{AsyncLocalStorageContextManager}from"@opentelemetry/context-async-hooks";import{CompositePropagator,W3CBaggagePropagator,W3CTraceContextPropagator}from"@opentelemetry/core";import{OTLPLogExporter}from"@opentelemetry/exporter-logs-otlp-http";import{AggregationTemporalityPreference,OTLPMetricExporter}from"@opentelemetry/exporter-metrics-otlp-http";import{OTLPTraceExporter}from"@opentelemetry/exporter-trace-otlp-http";import{registerInstrumentations}from"@opentelemetry/instrumentation";import{UndiciInstrumentation}from"@opentelemetry/instrumentation-undici";import{resourceFromAttributes}from"@opentelemetry/resources";import{BatchLogRecordProcessor,LoggerProvider}from"@opentelemetry/sdk-logs";import{MeterProvider,PeriodicExportingMetricReader}from"@opentelemetry/sdk-metrics";import{BatchSpanProcessor}from"@opentelemetry/sdk-trace-base";import{NodeTracerProvider}from"@opentelemetry/sdk-trace-node";let registered=!1;function matchesAny(url,patterns){for(let pattern of patterns)if(pattern instanceof RegExp?pattern.test(url):url.includes(pattern))return!0;return!1}function buildInterfereOtelKit(opts={}){let env=readInterfereEnv();if(!env.publicKey)return null;let{slug:releaseSlug}=resolveReleaseSlug();releaseSlug||console.warn("[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.");let sinkUrl=withPublicKey(`${env.apiUrl}/v2/sink`,env.publicKey),ignoreUrls=[sinkUrl,...opts.ignoreUrls??[]],propagateContextUrls=opts.propagateContextUrls??[],exporterHeaders={"x-interfere-producer-version":PRODUCER_VERSION};return{resourceAttributes:{"service.name":opts.serviceName??`interfere-sdk-next-server`,"service.namespace":`interfere`,"deployment.environment.name":env.nodeEnvironment??`unknown`,"telemetry.sdk.language":`nodejs`,"interfere.sdk.name":`@interfere/next`,"interfere.sdk.version":PRODUCER_VERSION,...releaseSlug?{"release.slug":releaseSlug}:{}},spanProcessors:[new BaggageSpanProcessor(()=>!0),new BatchSpanProcessor(new OTLPTraceExporter({url:sinkUrl,headers:exporterHeaders})),...opts._internalAdditionalSpanProcessors??[]],logRecordProcessors:[new BatchLogRecordProcessor(new OTLPLogExporter({url:sinkUrl,headers:exporterHeaders})),...opts._internalAdditionalLogRecordProcessors??[]],metricReaders:[new PeriodicExportingMetricReader({exporter:new OTLPMetricExporter({url:sinkUrl,headers:exporterHeaders,temporalityPreference:AggregationTemporalityPreference.DELTA}),exportIntervalMillis:3e4}),...opts._internalAdditionalMetricReaders??[]],propagators:[new W3CBaggagePropagator],instrumentations:[new UndiciInstrumentation({ignoreRequestHook:req=>matchesAny(`${req.origin}${req.path}`,ignoreUrls),requestHook:(span,req)=>{matchesAny(`${req.origin}${req.path}`,propagateContextUrls)&&span.setAttribute(`interfere.propagated`,!0)}})],enableConsoleBridge:()=>bridgeConsoleToOtel(),fetchRemoteConfig:()=>fetchAndCacheRemoteConfig()}}async function register(opts={}){if(registered)return;let kit=buildInterfereOtelKit(opts);if(!kit)return;let resource=resourceFromAttributes(kit.resourceAttributes),tracerProvider=new NodeTracerProvider({resource,spanProcessors:kit.spanProcessors,idGenerator:new PrerenderSafeIdGenerator});propagation.fields().length===0&&propagation.setGlobalPropagator(new CompositePropagator({propagators:[new W3CTraceContextPropagator,...kit.propagators]})),tracerProvider.register({contextManager:new AsyncLocalStorageContextManager().enable()});let loggerProvider=new LoggerProvider({resource,processors:kit.logRecordProcessors}),{logs:logsApi}=await import(`@opentelemetry/api-logs`);logsApi.setGlobalLoggerProvider(loggerProvider);let meterProvider=new MeterProvider({resource,readers:kit.metricReaders});metrics.setGlobalMeterProvider(meterProvider),registerInstrumentations({tracerProvider,meterProvider,instrumentations:kit.instrumentations}),opts.consoleBridge!==!1&&kit.enableConsoleBridge(),registered=!0,await kit.fetchRemoteConfig()}export{PrerenderSafeIdGenerator,buildInterfereOtelKit,register};
@@ -0,0 +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 { 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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"}
@@ -2,9 +2,10 @@ import { NextConfig } from "next";
2
2
 
3
3
  //#region src/internal/build/configure-build.d.ts
4
4
  interface InterfereInjectedValues {
5
- readonly __INTERFERE_BUILD_ID__: string | null;
6
5
  readonly __INTERFERE_FORCE_ENABLE__?: boolean;
7
- readonly __INTERFERE_RELEASE_ID__: string | null;
6
+ readonly __INTERFERE_PROXY_MODE__?: boolean;
7
+ readonly __INTERFERE_PUBLIC_KEY__?: string;
8
+ readonly __INTERFERE_RELEASE_SLUG__: string | null;
8
9
  }
9
10
  interface ConfigureBuildInput {
10
11
  readonly existingTurbopack: NextConfig["turbopack"] | undefined;
@@ -1 +1 @@
1
- {"version":3,"file":"configure-build.d.mts","names":[],"sources":["../../../src/internal/build/configure-build.ts"],"mappings":";;;UAKiB,uBAAA;EAAA,SACN,sBAAA;EAAA,SACA,0BAAA;EAAA,SACA,wBAAA;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"}