@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
package/README.md CHANGED
@@ -97,9 +97,14 @@ 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. |
101
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. |
102
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
+
103
108
  ## Custom Route Prefix
104
109
 
105
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.
package/dist/config.d.mts CHANGED
@@ -22,6 +22,7 @@ interface ResolvedBuildConfig {
22
22
  * into the bundle; never exposed via env.
23
23
  */
24
24
  readonly buildId: string | null;
25
+ readonly publicKey: string | null;
25
26
  /**
26
27
  * Deterministically derived from the leading 16 hex of the commit SHA, so
27
28
  * the build step and the collector arrive at the same
@@ -1 +1 @@
1
- {"version":3,"file":"config.d.mts","names":[],"sources":["../src/config.ts"],"mappings":";;;;UAgBiB,uBAAA,SAAgC,UAAA;;AAAjD;;;;;EAOE,SAAA;IAAA,SAAuB,OAAA;EAAA;AAAA;AAAA,UAGR,mBAAA;EAAA,SACN,MAAA;EAAA,SACA,MAAA;EAcwB;;;;;EAAA,SARxB,OAAA;EAQwB;;AAGnC;;;;;EAHmC,SAAxB,WAAA,EAAa,WAAA;AAAA;AAAA,iBAGR,aAAA,CACd,UAAA,GAAY,uBAAA,GACX,UAAA;AAAA,UAwIc,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,110 +1 @@
1
- import { configureBuild } from "./internal/build/configure-build.mjs";
2
- import { readInterfereEnv } from "./internal/env.mjs";
3
- import { FatalError, log } from "./internal/logger.mjs";
4
- import { resolveReleaseSlug } from "./internal/release-slug.mjs";
5
- import { readNextMajorVersion, warnIfServerInstrumentationMissing } from "./internal/setup-warnings.mjs";
6
- import { omitUndefined } from "@interfere/helpers/omit-undefined";
7
- //#region src/config.ts
8
- const NEXT_INSTRUMENTATION_HOOK_FLAG_LAST_MAJOR = 14;
9
- function withInterfere(nextConfig = {}) {
10
- const { interfere, env: userEnv, webpack, turbopack, compiler, productionBrowserSourceMaps, ...rest } = nextConfig;
11
- 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."]);
12
- const projectDir = process.cwd();
13
- const config = resolveBuildConfig();
14
- const forceEnable = !!process.env["NEXT_PUBLIC_INTERFERE_FORCE_ENABLE"];
15
- const build = configureBuild({
16
- existingWebpack: webpack,
17
- existingTurbopack: turbopack,
18
- projectDir,
19
- values: {
20
- __INTERFERE_RELEASE_SLUG__: forceEnable ? "rel_local" : config.releaseSlug,
21
- ...forceEnable && { __INTERFERE_FORCE_ENABLE__: true }
22
- }
23
- });
24
- 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."]);
25
- if (config.apiKey !== null) warnIfServerInstrumentationMissing(projectDir);
26
- const nextMajor = readNextMajorVersion(projectDir);
27
- const needsInstrumentationHookFlag = nextMajor === null || nextMajor <= NEXT_INSTRUMENTATION_HOOK_FLAG_LAST_MAJOR;
28
- const existingHook = compiler?.runAfterProductionCompile;
29
- const browserSourceMaps = config.apiKey === null ? productionBrowserSourceMaps : true;
30
- if (config.apiKey !== null && productionBrowserSourceMaps === false) log.warn("Forcing productionBrowserSourceMaps", ["withInterfere() requires production source maps to symbolicate errors.", "Your `productionBrowserSourceMaps: false` was overridden to `true`."]);
31
- return {
32
- ...rest,
33
- ...userEnv ? { env: userEnv } : {},
34
- compiler: {
35
- ...omitUndefined(compiler ?? {}),
36
- async runAfterProductionCompile(context) {
37
- if (existingHook) await existingHook(context);
38
- try {
39
- await runBuildReleasePipeline(context, config);
40
- } catch (error) {
41
- if (error instanceof FatalError) throw error;
42
- const message = error instanceof Error ? error.message : String(error);
43
- log.warn("Skipping release pipeline", [
44
- "Interfere encountered an unexpected error.",
45
- "Build will continue, but this release's data will be ingested, but ignored as evidence when generating insights.",
46
- `Error: ${message}`
47
- ]);
48
- }
49
- }
50
- },
51
- ...omitUndefined({
52
- productionBrowserSourceMaps: browserSourceMaps,
53
- turbopack: build.turbopack,
54
- webpack: build.webpack
55
- }),
56
- ...needsInstrumentationHookFlag ? { experimental: {
57
- ...rest.experimental ?? {},
58
- instrumentationHook: true
59
- } } : {}
60
- };
61
- }
62
- function resolveBuildConfig() {
63
- const { apiKey, apiUrl } = readInterfereEnv();
64
- const { commitSha, slug } = resolveReleaseSlug();
65
- return {
66
- apiKey: apiKey ?? null,
67
- apiUrl,
68
- buildId: commitSha,
69
- releaseSlug: slug
70
- };
71
- }
72
- async function runBuildReleasePipeline(context, config) {
73
- const { apiKey, buildId, releaseSlug } = config;
74
- if (!apiKey) return log.fatal("API key not set", [
75
- "withInterfere() requires an API key to upload source maps during production builds.",
76
- "Set the INTERFERE_API_KEY environment variable, or remove withInterfere() from your Next.js config.",
77
- "See: https://support.interfere.com/docs/guides/next-js"
78
- ]);
79
- 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."]);
80
- const { runBuildPipeline } = await import("./internal/build/pipeline.mjs");
81
- try {
82
- const result = await runBuildPipeline(context, {
83
- ...config,
84
- apiKey,
85
- buildId,
86
- releaseSlug
87
- });
88
- if (!result.ready) {
89
- log.warn("Skipping", ["No source maps found"]);
90
- return;
91
- }
92
- log.info("Completed", [
93
- `https://interfere.com/~/${result.config?.org.slug}/surfaces/${result.config?.surface.slug}`,
94
- `Release: ${result.release?.destination.slug ?? "Unknown"}`,
95
- `Build: ${result.buildId}`,
96
- `Artifacts: ${result.fileCount} source maps`
97
- ]);
98
- } catch (error) {
99
- const message = error instanceof Error ? error.message : String(error);
100
- log.warn("Skipping release pipeline", [
101
- "Interfere failed to process this release.",
102
- "Events from this release will be ingested, but ignored as evidence when generating insights.",
103
- "Please check https://status.interfere.com for any outages, or contact support@interfere.com if the problem persists.",
104
- `Error: ${message}`
105
- ]);
106
- return;
107
- }
108
- }
109
- //#endregion
110
- 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 type { ReleaseSlug } 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 /**\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 sandbox/preview\n // DB seeds `rel_local` as preflight-confirmed (see ENG-1353); prod\n // collectors silently drop force-enabled batches by header (ENG-1356).\n const releaseSlug = forceEnable ? \"rel_local\" : config.releaseSlug;\n const build = configureBuild({\n existingWebpack: webpack,\n existingTurbopack: turbopack,\n projectDir,\n values: {\n __INTERFERE_RELEASE_SLUG__: releaseSlug,\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 if (config.apiKey !== 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 } = readInterfereEnv();\n const { commitSha, slug } = resolveReleaseSlug();\n\n return {\n apiKey: apiKey ?? null,\n apiUrl,\n buildId: commitSha,\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 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 && 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
+ {"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,17 +1,14 @@
1
1
  import { capture, span } from "@interfere/react/api";
2
- import * as _$_interfere_types_sdk_plugins_manifest0 from "@interfere/types/sdk/plugins/manifest";
3
- import { ConsentCategory, ConsentState, GateableCategory } from "@interfere/types/sdk/plugins/manifest";
4
- import * as _$_interfere_react_internal_kernel0 from "@interfere/react/internal/kernel";
5
2
  import { Kernel, KernelInternalOptions, KernelOptions } from "@interfere/react/internal/kernel";
6
- import * as _$_interfere_types_sdk_identify0 from "@interfere/types/sdk/identify";
3
+ import { ConsentCategory, ConsentState, GateableCategory } from "@interfere/types/sdk/plugins/manifest";
7
4
 
8
5
  //#region src/instrument-client.d.ts
9
6
  declare const close: () => Promise<void>, consent: {
10
- get(): _$_interfere_types_sdk_plugins_manifest0.ConsentState | null;
11
- set(value?: _$_interfere_types_sdk_plugins_manifest0.ConsentState): void;
12
- }, getKernel: () => _$_interfere_react_internal_kernel0.Kernel, getKernelOrNull: () => _$_interfere_react_internal_kernel0.Kernel | null, identity: {
13
- get(): _$_interfere_types_sdk_identify0.IdentifyParams | null;
14
- set(params: _$_interfere_types_sdk_identify0.IdentifyParams): Promise<void>;
15
- }, init: (opts?: _$_interfere_react_internal_kernel0.KernelOptions) => Promise<_$_interfere_react_internal_kernel0.Kernel | null>, subscribeToKernel: (listener: () => void) => () => void;
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;
16
13
  //#endregion
17
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":";;;;;;;;cAuBE,KAAA,QAAK,OAAA,QAAA,OAAA;WAAA,wCAAA,CAAA,YAAA;;0DAEI,MAAA,EAAA,eAAA,QAAA,mCAAA,CACM,MAAA,SAAA,QAAA;WAAA,gCAAA,CAAA,cAAA;;YAEX,IAAA,uCAAA,aAAA,KAAA,OAAA,CAAA,mCAAA,CAAA,MAAA,UAAA,iBAAA,GACa,QAAA"}
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,9 +1 @@
1
- import { PRODUCER_VERSION } from "./internal/version.mjs";
2
- import { createWrapperSingleton } from "@interfere/react/internal/wrapper-singleton";
3
- import { capture, span } from "@interfere/react/api";
4
- const { close, consent, getKernel, getKernelOrNull, identity, init, subscribeToKernel } = createWrapperSingleton({
5
- producerVersion: PRODUCER_VERSION,
6
- initEntryName: "instrumentation-client"
7
- });
8
- //#endregion
9
- export { capture, close, consent, getKernel, getKernelOrNull, identity, init, span, subscribeToKernel };
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 { 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":";;;AAsBA,MAAa,EACX,OACA,SACA,WACA,iBACA,UACA,MACA,sBAZc,uBAAuB;CACrC,iBAAiB;CACjB,eAAe;CAChB,CAUG"}
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"}
@@ -1,22 +1 @@
1
- import { init } from "./instrument-client.mjs";
2
- //#region src/instrumentation-client.ts
3
- /**
4
- * Side-effect entry for Next.js 15.3+ which auto-loads `instrumentation-client.ts`
5
- * on every page load. Customer's `instrumentation-client.ts` becomes:
6
- *
7
- * ```ts
8
- * import "@interfere/next/instrumentation-client";
9
- * ```
10
- *
11
- * That single import boots the kernel with sensible defaults. Customers who
12
- * need overrides can call `init({...})` from `@interfere/next` directly —
13
- * `init()` is idempotent so the side-effect call here turns into a no-op.
14
- *
15
- * The `.catch` surfaces sync boot errors in dev — production swallows them
16
- * (a misconfigured SDK shouldn't take the customer's app down).
17
- */
18
- init().catch((error) => {
19
- if (process.env["NODE_ENV"] !== "production") console.warn("[interfere] init() threw during boot", error);
20
- });
21
- //#endregion
22
- export {};
1
+ import{init}from"./instrument-client.mjs";init().catch(error=>{process.env.NODE_ENV!==`production`&&console.warn(`[interfere] init() threw during boot`,error)});export{};
@@ -1 +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":";;;;;;;;;;;;;;;;;AAiBA,MAAM,CAAC,OAAO,UAAmB;CAC/B,IAAI,QAAQ,IAAI,gBAAgB,cAC9B,QAAQ,KAAK,wCAAwC,MAAM;EAE7D"}
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"}
@@ -22,7 +22,7 @@ import { SpanProcessor } from "@opentelemetry/sdk-trace-base";
22
22
  * The standalone `register()` builds the kit internally and wires it
23
23
  * into private providers, so customer DX stays a one-liner export.
24
24
  *
25
- * Returns `null` when `INTERFERE_API_KEY` is unset — callers can spread
25
+ * Returns `null` when `INTERFERE_PUBLIC_KEY` is unset — callers can spread
26
26
  * `kit?.spanProcessors ?? []` without a no-op guard.
27
27
  */
28
28
  interface InterfereOtelKit {
@@ -85,7 +85,7 @@ interface InterfereOtelKit {
85
85
  * the OTel primitives the SDK contributes so a host bootstrap (Vercel,
86
86
  * DataDog, custom) can compose them in.
87
87
  *
88
- * Returns `null` when `INTERFERE_API_KEY` isn't set, so callers can
88
+ * Returns `null` when `INTERFERE_PUBLIC_KEY` isn't set, so callers can
89
89
  * unconditionally spread `kit?.spanProcessors ?? []` in dev where the
90
90
  * SDK isn't configured.
91
91
  */
@@ -126,7 +126,7 @@ declare function buildInterfereOtelKit(opts?: ServerInstrumentationOptions): Int
126
126
  * Idempotent — repeat calls (e.g. HMR) short-circuit on the
127
127
  * module-scoped `registered` flag.
128
128
  *
129
- * Bails silently when `INTERFERE_API_KEY` is unset so dev runs without
129
+ * Bails silently when `INTERFERE_PUBLIC_KEY` is unset so dev runs without
130
130
  * the SDK configured don't crash.
131
131
  */
132
132
  declare function register(opts?: ServerInstrumentationOptions): Promise<void>;
@@ -1 +1 @@
1
- {"version":3,"file":"instrumentation.d.mts","names":[],"sources":["../src/instrumentation.ts"],"mappings":";;;;;;;;;;AAoFA;;;;;;;;;;;;;;;;;UAAiB,gBAAA;EAqCf;;;;;;;;EA5BA,mBAAA;EA4CA;;;;AAYF;EAlDE,iBAAA,QAAyB,OAAA;;;;;;;;AA0M3B;;;;;;;;;;;;;EArLE,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,gBAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBAsJmB,QAAA,CACpB,IAAA,GAAM,4BAAA,GACL,OAAA"}
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"}
@@ -28,7 +28,7 @@ declare function register(_opts?: ServerInstrumentationOptions): Promise<void>;
28
28
  * Edge stub for the kit factory. Returns `null` so callers spreading
29
29
  * `kit?.spanProcessors ?? []` into a host bootstrap behave as if the
30
30
  * SDK is unconfigured — same shape as the Node entry returns when
31
- * `INTERFERE_API_KEY` is unset.
31
+ * `INTERFERE_PUBLIC_KEY` is unset.
32
32
  */
33
33
  declare function buildInterfereOtelKit(_opts?: ServerInstrumentationOptions): null;
34
34
  //#endregion
@@ -1 +1 @@
1
- {"version":3,"file":"instrumentation.edge.d.mts","names":[],"sources":["../src/instrumentation.edge.ts"],"mappings":";;;;;AA0BA;;;;;;;;;AAYA;;;;;;;;;;;iBAZsB,QAAA,CACpB,KAAA,GAAO,4BAAA,GACN,OAAA;;;;;;;iBAUa,qBAAA,CACd,KAAA,GAAO,4BAAA"}
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"}
@@ -1,34 +1 @@
1
- //#region src/instrumentation.edge.ts
2
- /**
3
- * Edge-runtime entry for `@interfere/next/instrumentation`. Selected by
4
- * `package.json`'s `edge-light` / `workerd` / `worker` export conditions
5
- * — Next.js + Vercel pick this bundle when compiling
6
- * `instrumentation.ts` for the Edge runtime.
7
- *
8
- * The Node entry (`instrumentation.ts`) is built around
9
- * `NodeTracerProvider`, `AsyncLocalStorageContextManager`, undici
10
- * instrumentation, and a console→OTel bridge — none of which work in
11
- * the Edge runtime. Pulling that import graph into an Edge bundle would
12
- * (a) trip Next's `node:*`-in-edge warnings (release-slug derivation
13
- * uses `node:child_process` + `node:crypto`) and (b) crash on module
14
- * load if the Edge bundle were ever actually invoked.
15
- *
16
- * Both `register()` and `buildInterfereOtelKit()` are exported as
17
- * no-op stubs so customer TypeScript code compiles unchanged
18
- * regardless of which runtime the file ends up in. Edge-runtime
19
- * tracing (middleware spans, edge route handlers) needs an
20
- * `@opentelemetry/sdk-trace-base`-based pipeline with a fetch-based
21
- * exporter — tracked separately.
22
- */
23
- async function register(_opts = {}) {}
24
- /**
25
- * Edge stub for the kit factory. Returns `null` so callers spreading
26
- * `kit?.spanProcessors ?? []` into a host bootstrap behave as if the
27
- * SDK is unconfigured — same shape as the Node entry returns when
28
- * `INTERFERE_API_KEY` is unset.
29
- */
30
- function buildInterfereOtelKit(_opts = {}) {
31
- return null;
32
- }
33
- //#endregion
34
- export { buildInterfereOtelKit, register };
1
+ async function register(_opts={}){}function buildInterfereOtelKit(_opts={}){return null}export{buildInterfereOtelKit,register};
@@ -1 +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_API_KEY` is unset.\n */\nexport function buildInterfereOtelKit(\n _opts: ServerInstrumentationOptions = {}\n): null {\n return null;\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;AA0BA,eAAsB,SACpB,QAAsC,EAAE,EACzB;;;;;;;AAUjB,SAAgB,sBACd,QAAsC,EAAE,EAClC;CACN,OAAO"}
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"}
@@ -1,165 +1 @@
1
- import { readInterfereEnv } from "./internal/env.mjs";
2
- import { resolveReleaseSlug } from "./internal/release-slug.mjs";
3
- import { PRODUCER_VERSION } from "./internal/version.mjs";
4
- import { bridgeConsoleToOtel } from "./internal/server/console-bridge.mjs";
5
- import { PrerenderSafeIdGenerator } from "./internal/server/id-generator.mjs";
6
- import { fetchAndCacheRemoteConfig } from "./internal/server/remote-config.mjs";
7
- import { metrics, propagation } from "@opentelemetry/api";
8
- import { BaggageSpanProcessor } from "@opentelemetry/baggage-span-processor";
9
- import { AsyncLocalStorageContextManager } from "@opentelemetry/context-async-hooks";
10
- import { CompositePropagator, W3CBaggagePropagator, W3CTraceContextPropagator } from "@opentelemetry/core";
11
- import { OTLPLogExporter } from "@opentelemetry/exporter-logs-otlp-http";
12
- import { AggregationTemporalityPreference, OTLPMetricExporter } from "@opentelemetry/exporter-metrics-otlp-http";
13
- import { OTLPTraceExporter } from "@opentelemetry/exporter-trace-otlp-http";
14
- import { registerInstrumentations } from "@opentelemetry/instrumentation";
15
- import { UndiciInstrumentation } from "@opentelemetry/instrumentation-undici";
16
- import { resourceFromAttributes } from "@opentelemetry/resources";
17
- import { BatchLogRecordProcessor, LoggerProvider } from "@opentelemetry/sdk-logs";
18
- import { MeterProvider, PeriodicExportingMetricReader } from "@opentelemetry/sdk-metrics";
19
- import { BatchSpanProcessor } from "@opentelemetry/sdk-trace-base";
20
- import { NodeTracerProvider } from "@opentelemetry/sdk-trace-node";
21
- //#region src/instrumentation.ts
22
- const DEFAULT_SERVICE_NAME = "interfere-sdk-next-server";
23
- const SERVICE_NAMESPACE = "interfere";
24
- let registered = false;
25
- function matchesAny(url, patterns) {
26
- for (const pattern of patterns) if (pattern instanceof RegExp ? pattern.test(url) : url.includes(pattern)) return true;
27
- return false;
28
- }
29
- /**
30
- * Pure factory — no global registration, no provider construction. Returns
31
- * the OTel primitives the SDK contributes so a host bootstrap (Vercel,
32
- * DataDog, custom) can compose them in.
33
- *
34
- * Returns `null` when `INTERFERE_API_KEY` isn't set, so callers can
35
- * unconditionally spread `kit?.spanProcessors ?? []` in dev where the
36
- * SDK isn't configured.
37
- */
38
- function buildInterfereOtelKit(opts = {}) {
39
- const env = readInterfereEnv();
40
- if (!env.apiKey) return null;
41
- const { slug: releaseSlug } = resolveReleaseSlug();
42
- if (!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.");
43
- const sinkUrl = `${env.apiUrl}/v2/sink`;
44
- const ignoreUrls = [sinkUrl, ...opts.ignoreUrls ?? []];
45
- const propagateContextUrls = opts.propagateContextUrls ?? [];
46
- const exporterHeaders = {
47
- "x-api-key": env.apiKey,
48
- "x-interfere-producer-version": PRODUCER_VERSION
49
- };
50
- return {
51
- resourceAttributes: {
52
- "service.name": opts.serviceName ?? DEFAULT_SERVICE_NAME,
53
- "service.namespace": SERVICE_NAMESPACE,
54
- "deployment.environment.name": env.nodeEnvironment ?? "unknown",
55
- "telemetry.sdk.language": "nodejs",
56
- "interfere.sdk.name": "@interfere/next",
57
- "interfere.sdk.version": PRODUCER_VERSION,
58
- ...releaseSlug ? { "release.slug": releaseSlug } : {}
59
- },
60
- spanProcessors: [
61
- new BaggageSpanProcessor(() => true),
62
- new BatchSpanProcessor(new OTLPTraceExporter({
63
- url: sinkUrl,
64
- headers: exporterHeaders
65
- })),
66
- ...opts._internalAdditionalSpanProcessors ?? []
67
- ],
68
- logRecordProcessors: [new BatchLogRecordProcessor(new OTLPLogExporter({
69
- url: sinkUrl,
70
- headers: exporterHeaders
71
- })), ...opts._internalAdditionalLogRecordProcessors ?? []],
72
- metricReaders: [new PeriodicExportingMetricReader({
73
- exporter: new OTLPMetricExporter({
74
- url: sinkUrl,
75
- headers: exporterHeaders,
76
- temporalityPreference: AggregationTemporalityPreference.DELTA
77
- }),
78
- exportIntervalMillis: 3e4
79
- }), ...opts._internalAdditionalMetricReaders ?? []],
80
- propagators: [new W3CBaggagePropagator()],
81
- instrumentations: [new UndiciInstrumentation({
82
- ignoreRequestHook: (req) => {
83
- return matchesAny(`${req.origin}${req.path}`, ignoreUrls);
84
- },
85
- requestHook: (span, req) => {
86
- if (matchesAny(`${req.origin}${req.path}`, propagateContextUrls)) span.setAttribute("interfere.propagated", true);
87
- }
88
- })],
89
- enableConsoleBridge: () => bridgeConsoleToOtel(),
90
- fetchRemoteConfig: () => fetchAndCacheRemoteConfig()
91
- };
92
- }
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_API_KEY` is unset so dev runs without
130
- * the SDK configured don't crash.
131
- */
132
- async function register(opts = {}) {
133
- if (registered) return;
134
- const kit = buildInterfereOtelKit(opts);
135
- if (!kit) return;
136
- const resource = resourceFromAttributes(kit.resourceAttributes);
137
- const tracerProvider = new NodeTracerProvider({
138
- resource,
139
- spanProcessors: kit.spanProcessors,
140
- idGenerator: new PrerenderSafeIdGenerator()
141
- });
142
- if (propagation.fields().length === 0) propagation.setGlobalPropagator(new CompositePropagator({ propagators: [new W3CTraceContextPropagator(), ...kit.propagators] }));
143
- tracerProvider.register({ contextManager: new AsyncLocalStorageContextManager().enable() });
144
- const loggerProvider = new LoggerProvider({
145
- resource,
146
- processors: kit.logRecordProcessors
147
- });
148
- const { logs: logsApi } = await import("@opentelemetry/api-logs");
149
- logsApi.setGlobalLoggerProvider(loggerProvider);
150
- const meterProvider = new MeterProvider({
151
- resource,
152
- readers: kit.metricReaders
153
- });
154
- metrics.setGlobalMeterProvider(meterProvider);
155
- registerInstrumentations({
156
- tracerProvider,
157
- meterProvider,
158
- instrumentations: kit.instrumentations
159
- });
160
- if (opts.consoleBridge !== false) kit.enableConsoleBridge();
161
- registered = true;
162
- await kit.fetchRemoteConfig();
163
- }
164
- //#endregion
165
- export { PrerenderSafeIdGenerator, buildInterfereOtelKit, register };
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};