@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
@@ -1,55 +1 @@
1
- import { isEnabledInEnvironment } from "../env.mjs";
2
- import { isErrorCaptured, markErrorCaptured } from "./dedupe.mjs";
3
- import { buildErrorEnvelope } from "./envelope.mjs";
4
- import { normalizeRequest } from "./normalize-request.mjs";
5
- import { isPluginEnabled } from "./remote-config.mjs";
6
- import { resolveServerCaptureRuntime } from "./runtime.mjs";
7
- import { sendEnvelope } from "./transport.mjs";
8
- import { MECHANISM_TYPE } from "@interfere/types/sdk/errors";
9
- //#region src/internal/server/capture.ts
10
- const ON_REQUEST_ERROR_MECHANISM = {
11
- type: MECHANISM_TYPE.nextjs.onRequestError,
12
- handled: false,
13
- synthetic: false
14
- };
15
- const DEFAULT_REQUEST = {
16
- method: "GET",
17
- path: "/",
18
- headers: new Headers()
19
- };
20
- async function captureError(error, request, context) {
21
- if (!isEnabledInEnvironment()) return;
22
- if (!isPluginEnabled("errors")) return;
23
- const runtime = resolveServerCaptureRuntime();
24
- if (runtime.apiKey === null) return;
25
- const normalizedRequest = normalizeRequest(request);
26
- const envelope = buildErrorEnvelope({
27
- error,
28
- request: normalizedRequest,
29
- context,
30
- runtime
31
- });
32
- try {
33
- await sendEnvelope({
34
- envelope,
35
- runtime,
36
- traceparent: context?.traceparent ?? normalizedRequest?.headers.get("traceparent") ?? void 0
37
- });
38
- } catch {}
39
- }
40
- async function onRequestError(error, request, context) {
41
- if (isErrorCaptured(error)) return;
42
- markErrorCaptured(error);
43
- const normalizedRequest = normalizeRequest(request) ?? DEFAULT_REQUEST;
44
- await captureError(error, normalizedRequest, {
45
- mechanism: ON_REQUEST_ERROR_MECHANISM,
46
- nextjs: {
47
- ...context,
48
- requestMethod: normalizedRequest.method,
49
- requestPath: normalizedRequest.path,
50
- ...error.digest ? { errorDigest: error.digest } : {}
51
- }
52
- });
53
- }
54
- //#endregion
55
- export { captureError, onRequestError };
1
+ import{isEnabledOnServer}from"../env.mjs";import{isPluginEnabled}from"./remote-config.mjs";import{SpanKind,SpanStatusCode,trace}from"@opentelemetry/api";import{MECHANISM_TYPE,isNonErrorException,toException}from"@interfere/types/sdk/errors";const ON_REQUEST_ERROR_MECHANISM={type:MECHANISM_TYPE.nextjs.onRequestError,handled:!1,synthetic:!1},DEFAULT_CAPTURE_ERROR_MECHANISM={type:MECHANISM_TYPE.nextjs.captureError,handled:!0},seen=new WeakSet;function buildAttrs(value,mechanism,context){let attrs={"interfere.exception.mechanism":mechanism.type,"interfere.exception.handled":String(mechanism.handled)},digest=context?.nextjs?.errorDigest;return digest&&(attrs[`interfere.error.digest`]=digest),context?.nextjs?.requestMethod&&(attrs[`http.request.method`]=context.nextjs.requestMethod),context?.nextjs?.requestPath&&(attrs[`url.path`]=context.nextjs.requestPath),isNonErrorException(value)?(attrs[`exception.type`]=value.type,attrs[`exception.message`]=value.value,attrs[`interfere.exception.kind`]=`non-error`,attrs):(attrs[`exception.type`]=value.name,attrs[`exception.message`]=value.message,value.stack&&(attrs[`exception.stacktrace`]=value.stack),attrs)}function recordException({error,mechanism,context}){let value=toException(error),attrs=buildAttrs(value,mechanism,context),tracer=trace.getTracer(`@interfere/next/server`),active=trace.getActiveSpan();if(active){active.addEvent(`exception`,attrs),mechanism.handled||active.setStatus({code:SpanStatusCode.ERROR,message:isNonErrorException(value)?value.value:value.message});return}let span=tracer.startSpan(`interfere.captureError`,{kind:SpanKind.INTERNAL});span.addEvent(`exception`,attrs),mechanism.handled||span.setStatus({code:SpanStatusCode.ERROR,message:isNonErrorException(value)?value.value:value.message}),span.end()}function captureError(error,_request,context){if(isEnabledOnServer()&&isPluginEnabled(`errors`)){if(error instanceof Error){if(seen.has(error))return;seen.add(error)}recordException({error,mechanism:context?.mechanism??DEFAULT_CAPTURE_ERROR_MECHANISM,context})}}function onRequestError(error,_request,context){seen.has(error)||(seen.add(error),isEnabledOnServer()&&isPluginEnabled(`errors`)&&recordException({error,mechanism:ON_REQUEST_ERROR_MECHANISM,context:{mechanism:ON_REQUEST_ERROR_MECHANISM,nextjs:{...context,...error.digest?{errorDigest:error.digest}:{}}}}))}export{captureError,onRequestError};
@@ -1 +1 @@
1
- {"version":3,"file":"capture.mjs","names":[],"sources":["../../../src/internal/server/capture.ts"],"sourcesContent":["import { MECHANISM_TYPE } from \"@interfere/types/sdk/errors\";\nimport type { ErrorMechanism } from \"@interfere/types/sdk/plugins/payload/errors\";\n\nimport { isEnabledInEnvironment } from \"../env.js\";\nimport { isErrorCaptured, markErrorCaptured } from \"./dedupe.js\";\nimport { buildErrorEnvelope } from \"./envelope.js\";\nimport { normalizeRequest, TRACEPARENT_HEADER } from \"./normalize-request.js\";\nimport { isPluginEnabled } from \"./remote-config.js\";\nimport { resolveServerCaptureRuntime } from \"./runtime.js\";\nimport { sendEnvelope } from \"./transport.js\";\nimport type { CaptureErrorContext, OnRequestErrorContext } from \"./types.js\";\n\nconst ON_REQUEST_ERROR_MECHANISM: ErrorMechanism = {\n type: MECHANISM_TYPE.nextjs.onRequestError,\n handled: false,\n synthetic: false,\n};\n\nconst DEFAULT_REQUEST = {\n method: \"GET\",\n path: \"/\",\n headers: new Headers(),\n};\n\nexport async function captureError(\n error: unknown,\n request?: unknown,\n context?: CaptureErrorContext\n): Promise<void> {\n if (!isEnabledInEnvironment()) {\n return;\n }\n\n if (!isPluginEnabled(\"errors\")) {\n return;\n }\n\n const runtime = resolveServerCaptureRuntime();\n if (runtime.apiKey === null) {\n return;\n }\n\n const normalizedRequest = normalizeRequest(request);\n const envelope = buildErrorEnvelope({\n error,\n request: normalizedRequest,\n context,\n runtime,\n });\n\n try {\n await sendEnvelope({\n envelope,\n runtime,\n traceparent:\n context?.traceparent ??\n normalizedRequest?.headers.get(TRACEPARENT_HEADER) ??\n undefined,\n });\n } catch {\n /* best-effort */\n }\n}\n\nexport async function onRequestError(\n error: Error & { digest?: string },\n request: unknown,\n context: OnRequestErrorContext\n): Promise<void> {\n if (isErrorCaptured(error)) {\n return;\n }\n markErrorCaptured(error);\n\n const normalizedRequest = normalizeRequest(request) ?? DEFAULT_REQUEST;\n\n await captureError(error, normalizedRequest, {\n mechanism: ON_REQUEST_ERROR_MECHANISM,\n nextjs: {\n ...context,\n requestMethod: normalizedRequest.method,\n requestPath: normalizedRequest.path,\n ...(error.digest ? { errorDigest: error.digest } : {}),\n },\n });\n}\n"],"mappings":";;;;;;;;;AAYA,MAAM,6BAA6C;CACjD,MAAM,eAAe,OAAO;CAC5B,SAAS;CACT,WAAW;CACZ;AAED,MAAM,kBAAkB;CACtB,QAAQ;CACR,MAAM;CACN,SAAS,IAAI,SAAS;CACvB;AAED,eAAsB,aACpB,OACA,SACA,SACe;AACf,KAAI,CAAC,wBAAwB,CAC3B;AAGF,KAAI,CAAC,gBAAgB,SAAS,CAC5B;CAGF,MAAM,UAAU,6BAA6B;AAC7C,KAAI,QAAQ,WAAW,KACrB;CAGF,MAAM,oBAAoB,iBAAiB,QAAQ;CACnD,MAAM,WAAW,mBAAmB;EAClC;EACA,SAAS;EACT;EACA;EACD,CAAC;AAEF,KAAI;AACF,QAAM,aAAa;GACjB;GACA;GACA,aACE,SAAS,eACT,mBAAmB,QAAQ,IAAA,cAAuB,IAClD,KAAA;GACH,CAAC;SACI;;AAKV,eAAsB,eACpB,OACA,SACA,SACe;AACf,KAAI,gBAAgB,MAAM,CACxB;AAEF,mBAAkB,MAAM;CAExB,MAAM,oBAAoB,iBAAiB,QAAQ,IAAI;AAEvD,OAAM,aAAa,OAAO,mBAAmB;EAC3C,WAAW;EACX,QAAQ;GACN,GAAG;GACH,eAAe,kBAAkB;GACjC,aAAa,kBAAkB;GAC/B,GAAI,MAAM,SAAS,EAAE,aAAa,MAAM,QAAQ,GAAG,EAAE;GACtD;EACF,CAAC"}
1
+ {"version":3,"file":"capture.mjs","names":[],"sources":["../../../src/internal/server/capture.ts"],"sourcesContent":["import {\n isNonErrorException,\n MECHANISM_TYPE,\n type NonErrorException,\n toException,\n} from \"@interfere/types/sdk/errors\";\nimport type { ErrorMechanism } from \"@interfere/types/sdk/plugins/payload/errors\";\n\nimport { SpanKind, SpanStatusCode, trace } from \"@opentelemetry/api\";\n\nimport { isEnabledOnServer } from \"../env.js\";\nimport { isPluginEnabled } from \"./remote-config.js\";\nimport type { CaptureErrorContext, OnRequestErrorContext } from \"./types.js\";\n\nconst TRACER_NAME = \"@interfere/next/server\";\n\nconst ON_REQUEST_ERROR_MECHANISM: ErrorMechanism = {\n type: MECHANISM_TYPE.nextjs.onRequestError,\n handled: false,\n synthetic: false,\n};\n\nconst DEFAULT_CAPTURE_ERROR_MECHANISM: ErrorMechanism = {\n type: MECHANISM_TYPE.nextjs.captureError,\n handled: true,\n};\n\n// Per-process dedupe so a thrown route-handler error captured by both the\n// caller's `try { } catch { captureError(e) }` and Next's own\n// `onRequestError` hook only emits one exception event. WeakSet so GC'd\n// errors don't pin memory.\nconst seen = new WeakSet<Error>();\n\ninterface RecordExceptionInput {\n context?: CaptureErrorContext | undefined;\n error: unknown;\n mechanism: ErrorMechanism;\n}\n\nfunction buildAttrs(\n value: Error | NonErrorException,\n mechanism: ErrorMechanism,\n context: CaptureErrorContext | undefined\n): Record<string, string> {\n const attrs: Record<string, string> = {\n \"interfere.exception.mechanism\": mechanism.type,\n \"interfere.exception.handled\": String(mechanism.handled),\n };\n const digest = context?.nextjs?.errorDigest;\n if (digest) {\n attrs[\"interfere.error.digest\"] = digest;\n }\n if (context?.nextjs?.requestMethod) {\n attrs[\"http.request.method\"] = context.nextjs.requestMethod;\n }\n if (context?.nextjs?.requestPath) {\n attrs[\"url.path\"] = context.nextjs.requestPath;\n }\n if (isNonErrorException(value)) {\n attrs[\"exception.type\"] = value.type;\n attrs[\"exception.message\"] = value.value;\n attrs[\"interfere.exception.kind\"] = \"non-error\";\n return attrs;\n }\n attrs[\"exception.type\"] = value.name;\n attrs[\"exception.message\"] = value.message;\n if (value.stack) {\n attrs[\"exception.stacktrace\"] = value.stack;\n }\n return attrs;\n}\n\nfunction recordException({\n error,\n mechanism,\n context,\n}: RecordExceptionInput): void {\n const value = toException(error);\n const attrs = buildAttrs(value, mechanism, context);\n\n // Prefer the active span (route handler / Next request span). Fall\n // back to a fresh single-event span when no active span is available\n // — Next sometimes calls `onRequestError` from background contexts\n // (background revalidation, failed prerender) where the request span\n // is no longer current.\n const tracer = trace.getTracer(TRACER_NAME);\n const active = trace.getActiveSpan();\n if (active) {\n active.addEvent(\"exception\", attrs);\n if (!mechanism.handled) {\n active.setStatus({\n code: SpanStatusCode.ERROR,\n message: isNonErrorException(value) ? value.value : value.message,\n });\n }\n return;\n }\n\n const span = tracer.startSpan(\"interfere.captureError\", {\n kind: SpanKind.INTERNAL,\n });\n span.addEvent(\"exception\", attrs);\n if (!mechanism.handled) {\n span.setStatus({\n code: SpanStatusCode.ERROR,\n message: isNonErrorException(value) ? value.value : value.message,\n });\n }\n span.end();\n}\n\nexport function captureError(\n error: unknown,\n _request?: unknown,\n context?: CaptureErrorContext\n): void {\n if (!isEnabledOnServer()) {\n return;\n }\n\n if (!isPluginEnabled(\"errors\")) {\n return;\n }\n\n if (error instanceof Error) {\n if (seen.has(error)) {\n return;\n }\n seen.add(error);\n }\n\n recordException({\n error,\n mechanism: context?.mechanism ?? DEFAULT_CAPTURE_ERROR_MECHANISM,\n context,\n });\n}\n\nexport function onRequestError(\n error: Error & { digest?: string },\n _request: unknown,\n context: OnRequestErrorContext\n): void {\n if (seen.has(error)) {\n return;\n }\n seen.add(error);\n\n if (!isEnabledOnServer()) {\n return;\n }\n if (!isPluginEnabled(\"errors\")) {\n return;\n }\n\n recordException({\n error,\n mechanism: ON_REQUEST_ERROR_MECHANISM,\n context: {\n mechanism: ON_REQUEST_ERROR_MECHANISM,\n nextjs: {\n ...context,\n ...(error.digest ? { errorDigest: error.digest } : {}),\n },\n },\n });\n}\n"],"mappings":"iPAcA,MAEM,2BAA6C,CACjD,KAAM,eAAe,OAAO,eAC5B,QAAS,GACT,UAAW,EACb,EAEM,gCAAkD,CACtD,KAAM,eAAe,OAAO,aAC5B,QAAS,EACX,EAMM,KAAO,IAAI,QAQjB,SAAS,WACP,MACA,UACA,QACwB,CACxB,IAAM,MAAgC,CACpC,gCAAiC,UAAU,KAC3C,8BAA+B,OAAO,UAAU,OAAO,CACzD,EACM,OAAS,SAAS,QAAQ,YAqBhC,OApBI,SACF,MAAM,0BAA4B,QAEhC,SAAS,QAAQ,gBACnB,MAAM,uBAAyB,QAAQ,OAAO,eAE5C,SAAS,QAAQ,cACnB,MAAM,YAAc,QAAQ,OAAO,aAEjC,oBAAoB,KAAK,GAC3B,MAAM,kBAAoB,MAAM,KAChC,MAAM,qBAAuB,MAAM,MACnC,MAAM,4BAA8B,YAC7B,QAET,MAAM,kBAAoB,MAAM,KAChC,MAAM,qBAAuB,MAAM,QAC/B,MAAM,QACR,MAAM,wBAA0B,MAAM,OAEjC,MACT,CAEA,SAAS,gBAAgB,CACvB,MACA,UACA,SAC6B,CAC7B,IAAM,MAAQ,YAAY,KAAK,EACzB,MAAQ,WAAW,MAAO,UAAW,OAAO,EAO5C,OAAS,MAAM,UAAU,wBAAW,EACpC,OAAS,MAAM,cAAc,EACnC,GAAI,OAAQ,CACV,OAAO,SAAS,YAAa,KAAK,EAC7B,UAAU,SACb,OAAO,UAAU,CACf,KAAM,eAAe,MACrB,QAAS,oBAAoB,KAAK,EAAI,MAAM,MAAQ,MAAM,OAC5D,CAAC,EAEH,MACF,CAEA,IAAM,KAAO,OAAO,UAAU,yBAA0B,CACtD,KAAM,SAAS,QACjB,CAAC,EACD,KAAK,SAAS,YAAa,KAAK,EAC3B,UAAU,SACb,KAAK,UAAU,CACb,KAAM,eAAe,MACrB,QAAS,oBAAoB,KAAK,EAAI,MAAM,MAAQ,MAAM,OAC5D,CAAC,EAEH,KAAK,IAAI,CACX,CAEA,SAAgB,aACd,MACA,SACA,QACM,CACD,qBAAkB,GAIlB,gBAAgB,QAAQ,EAI7B,IAAI,iBAAiB,MAAO,CAC1B,GAAI,KAAK,IAAI,KAAK,EAChB,OAEF,KAAK,IAAI,KAAK,CAChB,CAEA,gBAAgB,CACd,MACA,UAAW,SAAS,WAAa,gCACjC,OACF,CAAC,CAND,CAOF,CAEA,SAAgB,eACd,MACA,SACA,QACM,CACF,KAAK,IAAI,KAAK,IAGlB,KAAK,IAAI,KAAK,EAET,kBAAkB,GAGlB,gBAAgB,QAAQ,GAI7B,gBAAgB,CACd,MACA,UAAW,2BACX,QAAS,CACP,UAAW,2BACX,OAAQ,CACN,GAAG,QACH,GAAI,MAAM,OAAS,CAAE,YAAa,MAAM,MAAO,EAAI,CAAC,CACtD,CACF,CACF,CAAC,EACH"}
@@ -0,0 +1,19 @@
1
+ //#region src/internal/server/console-bridge.d.ts
2
+ /**
3
+ * Patches `console.{debug,log,info,warn,error}` to additionally emit OTel
4
+ * `LogRecord`s alongside the original output. Every log record carries
5
+ * the active span's context (so trace ↔ log correlation works in
6
+ * dashboards) and any `Error` arg gets unpacked into semconv exception
7
+ * attrs.
8
+ *
9
+ * Returns a disposer that restores the original `console.*` methods.
10
+ *
11
+ * Cycle protection: `emitting` guards against the bridge re-entering
12
+ * itself if a logger backend itself logs to console (which would
13
+ * recursively emit forever). Failures are bounded-rate logged via the
14
+ * original `console.error` so a broken backend doesn't drown the
15
+ * customer's logs in bridge-failure messages.
16
+ */
17
+ declare function bridgeConsoleToOtel(): () => void;
18
+ //#endregion
19
+ export { bridgeConsoleToOtel };
@@ -0,0 +1 @@
1
+ {"version":3,"file":"console-bridge.d.mts","names":[],"sources":["../../../src/internal/server/console-bridge.ts"],"mappings":";;AAgFA;;;;AAAmC;;;;;;;;;;iBAAnB,mBAAA,CAAA"}
@@ -0,0 +1 @@
1
+ import{context,trace}from"@opentelemetry/api";import{logs}from"@opentelemetry/api-logs";const CONSOLE_METHODS=[`debug`,`log`,`info`,`warn`,`error`],SEVERITY={debug:5,log:9,info:9,warn:13,error:17};function stringify(value){if(typeof value==`string`)return value;if(value instanceof Error)return value.stack??`${value.name}: ${value.message}`;try{return JSON.stringify(value)}catch{return String(value)}}function extractException(args){for(let arg of args)if(arg instanceof Error)return arg}function buildExceptionAttributes(args){let exception=extractException(args);if(!exception)return;let attrs={"exception.type":exception.name,"exception.message":exception.message};return exception.stack&&(attrs[`exception.stacktrace`]=exception.stack),attrs}function bridgeConsoleToOtel(){let logger=logs.getLogger(`@interfere/next/console`),emitting=!1,bridgeFailures=0,original={debug:console.debug,log:console.log,info:console.info,warn:console.warn,error:console.error};function emitLog(orig,severity,method,body,activeContext,activeSpan,attributes){if(!emitting){emitting=!0;try{logger.emit({severityNumber:severity,severityText:method.toUpperCase(),body,...activeSpan?{context:activeContext}:{},...attributes?{attributes}:{}})}catch(error){bridgeFailures++,bridgeFailures%100==1&&orig.call(console,`[interfere] console→OTel bridge emission failed (${bridgeFailures} total):`,error)}finally{emitting=!1}}}for(let method of CONSOLE_METHODS){let orig=original[method],severity=SEVERITY[method];console[method]=(...args)=>{orig.apply(console,args);let body=args.map(stringify).join(` `),activeContext=context.active(),activeSpan=trace.getSpan(activeContext),attributes=buildExceptionAttributes(args);queueMicrotask(()=>{emitLog(orig,severity,method,body,activeContext,activeSpan,attributes)})}}return()=>{for(let method of CONSOLE_METHODS)console[method]=original[method]}}export{bridgeConsoleToOtel};
@@ -0,0 +1 @@
1
+ {"version":3,"file":"console-bridge.mjs","names":[],"sources":["../../../src/internal/server/console-bridge.ts"],"sourcesContent":["import { context, trace } from \"@opentelemetry/api\";\nimport { logs, type SeverityNumber } from \"@opentelemetry/api-logs\";\n\nconst ATTR_EXCEPTION_TYPE = \"exception.type\" as const;\nconst ATTR_EXCEPTION_MESSAGE = \"exception.message\" as const;\nconst ATTR_EXCEPTION_STACKTRACE = \"exception.stacktrace\" as const;\n\nconst CONSOLE_METHODS = [\"debug\", \"log\", \"info\", \"warn\", \"error\"] as const;\ntype ConsoleMethod = (typeof CONSOLE_METHODS)[number];\n\nconst SEVERITY: Record<ConsoleMethod, SeverityNumber> = {\n debug: 5,\n log: 9,\n info: 9,\n warn: 13,\n error: 17,\n};\n\n/**\n * Bound at first failure log; subsequent failures only re-log every Nth\n * occurrence so a misconfigured logger backend doesn't itself spam the\n * console with bridge errors at line rate.\n */\nconst BRIDGE_FAILURE_LOG_INTERVAL = 100;\n\nfunction stringify(value: unknown): string {\n if (typeof value === \"string\") {\n return value;\n }\n if (value instanceof Error) {\n return value.stack ?? `${value.name}: ${value.message}`;\n }\n try {\n return JSON.stringify(value);\n } catch {\n return String(value);\n }\n}\n\nfunction extractException(args: unknown[]): Error | undefined {\n for (const arg of args) {\n if (arg instanceof Error) {\n return arg;\n }\n }\n return;\n}\n\nfunction buildExceptionAttributes(\n args: unknown[]\n): Record<string, string> | undefined {\n const exception = extractException(args);\n if (!exception) {\n return;\n }\n const attrs: Record<string, string> = {\n [ATTR_EXCEPTION_TYPE]: exception.name,\n [ATTR_EXCEPTION_MESSAGE]: exception.message,\n };\n if (exception.stack) {\n attrs[ATTR_EXCEPTION_STACKTRACE] = exception.stack;\n }\n return attrs;\n}\n\n/**\n * Patches `console.{debug,log,info,warn,error}` to additionally emit OTel\n * `LogRecord`s alongside the original output. Every log record carries\n * the active span's context (so trace ↔ log correlation works in\n * dashboards) and any `Error` arg gets unpacked into semconv exception\n * attrs.\n *\n * Returns a disposer that restores the original `console.*` methods.\n *\n * Cycle protection: `emitting` guards against the bridge re-entering\n * itself if a logger backend itself logs to console (which would\n * recursively emit forever). Failures are bounded-rate logged via the\n * original `console.error` so a broken backend doesn't drown the\n * customer's logs in bridge-failure messages.\n */\nexport function bridgeConsoleToOtel(): () => void {\n const logger = logs.getLogger(\"@interfere/next/console\");\n let emitting = false;\n let bridgeFailures = 0;\n\n const original: Record<ConsoleMethod, (...args: unknown[]) => void> = {\n debug: console.debug,\n log: console.log,\n info: console.info,\n warn: console.warn,\n error: console.error,\n };\n\n function emitLog(\n orig: (...args: unknown[]) => void,\n severity: SeverityNumber,\n method: ConsoleMethod,\n body: string,\n activeContext: ReturnType<typeof context.active>,\n activeSpan: ReturnType<typeof trace.getSpan>,\n attributes: Record<string, string> | undefined\n ): void {\n if (emitting) {\n return;\n }\n emitting = true;\n try {\n logger.emit({\n severityNumber: severity,\n severityText: method.toUpperCase(),\n body,\n ...(activeSpan ? { context: activeContext } : {}),\n ...(attributes ? { attributes } : {}),\n });\n } catch (error) {\n bridgeFailures++;\n if (bridgeFailures % BRIDGE_FAILURE_LOG_INTERVAL === 1) {\n orig.call(\n console,\n `[interfere] console→OTel bridge emission failed (${bridgeFailures} total):`,\n error\n );\n }\n } finally {\n emitting = false;\n }\n }\n\n for (const method of CONSOLE_METHODS) {\n const orig = original[method];\n const severity = SEVERITY[method];\n console[method] = (...args: unknown[]) => {\n orig.apply(console, args);\n\n const body = args.map(stringify).join(\" \");\n const activeContext = context.active();\n const activeSpan = trace.getSpan(activeContext);\n const attributes = buildExceptionAttributes(args);\n\n // Defer emission via microtask so the synchronous return path\n // out of `console.X` doesn't include the LoggerProvider's batch\n // logic. Customer code's `console.error(...)` call should feel\n // synchronous; the OTel emission rides the next microtask.\n // `queueMicrotask` (not `setTimeout(0)`): macrotask-deferred\n // emissions risk being lost on hard process exit.\n queueMicrotask(() => {\n emitLog(\n orig,\n severity,\n method,\n body,\n activeContext,\n activeSpan,\n attributes\n );\n });\n };\n }\n\n return () => {\n for (const method of CONSOLE_METHODS) {\n console[method] = original[method];\n }\n };\n}\n"],"mappings":"wFAGA,MAIM,gBAAkB,CAAC,QAAS,MAAO,OAAQ,OAAQ,OAAO,EAG1D,SAAkD,CACtD,MAAO,EACP,IAAK,EACL,KAAM,EACN,KAAM,GACN,MAAO,EACT,EASA,SAAS,UAAU,MAAwB,CACzC,GAAI,OAAO,OAAU,SACnB,OAAO,MAET,GAAI,iBAAiB,MACnB,OAAO,MAAM,OAAS,GAAG,MAAM,KAAK,IAAI,MAAM,UAEhD,GAAI,CACF,OAAO,KAAK,UAAU,KAAK,CAC7B,MAAQ,CACN,OAAO,OAAO,KAAK,CACrB,CACF,CAEA,SAAS,iBAAiB,KAAoC,CAC5D,IAAK,IAAM,OAAO,KAChB,GAAI,eAAe,MACjB,OAAO,GAIb,CAEA,SAAS,yBACP,KACoC,CACpC,IAAM,UAAY,iBAAiB,IAAI,EACvC,GAAI,CAAC,UACH,OAEF,IAAM,MAAgC,CACnC,iBAAsB,UAAU,KAChC,oBAAyB,UAAU,OACtC,EAIA,OAHI,UAAU,QACZ,MAAM,wBAA6B,UAAU,OAExC,KACT,CAiBA,SAAgB,qBAAkC,CAChD,IAAM,OAAS,KAAK,UAAU,yBAAyB,EACnD,SAAW,GACX,eAAiB,EAEf,SAAgE,CACpE,MAAO,QAAQ,MACf,IAAK,QAAQ,IACb,KAAM,QAAQ,KACd,KAAM,QAAQ,KACd,MAAO,QAAQ,KACjB,EAEA,SAAS,QACP,KACA,SACA,OACA,KACA,cACA,WACA,WACM,CACF,aAGJ,UAAW,GACX,GAAI,CACF,OAAO,KAAK,CACV,eAAgB,SAChB,aAAc,OAAO,YAAY,EACjC,KACA,GAAI,WAAa,CAAE,QAAS,aAAc,EAAI,CAAC,EAC/C,GAAI,WAAa,CAAE,UAAW,EAAI,CAAC,CACrC,CAAC,CACH,OAAS,MAAO,CACd,iBACI,eAAiB,KAAgC,GACnD,KAAK,KACH,QACA,oDAAoD,eAAe,UACnE,KACF,CAEJ,QAAU,CACR,SAAW,EACb,CApBW,CAqBb,CAEA,IAAK,IAAM,UAAU,gBAAiB,CACpC,IAAM,KAAO,SAAS,QAChB,SAAW,SAAS,QAC1B,QAAQ,SAAW,GAAG,OAAoB,CACxC,KAAK,MAAM,QAAS,IAAI,EAExB,IAAM,KAAO,KAAK,IAAI,SAAS,EAAE,KAAK,GAAG,EACnC,cAAgB,QAAQ,OAAO,EAC/B,WAAa,MAAM,QAAQ,aAAa,EACxC,WAAa,yBAAyB,IAAI,EAQhD,mBAAqB,CACnB,QACE,KACA,SACA,OACA,KACA,cACA,WACA,UACF,CACF,CAAC,CACH,CACF,CAEA,UAAa,CACX,IAAK,IAAM,UAAU,gBACnB,QAAQ,QAAU,SAAS,OAE/B,CACF"}
@@ -0,0 +1,38 @@
1
+ import { IdGenerator } from "@opentelemetry/sdk-trace-base";
2
+
3
+ //#region src/internal/server/id-generator.d.ts
4
+ /**
5
+ * IdGenerator hybrid that uses OTel's default `RandomIdGenerator` whenever
6
+ * available and falls back to a counter-based generator inside Next 16's
7
+ * prerender contexts.
8
+ *
9
+ * Why: Next 16's prerender extension throws synchronously on any
10
+ * `Math.random()` / `crypto.getRandomValues()` call inside a Server
11
+ * Component that hasn't first awaited Request data
12
+ * (`next-prerender-random` / `next-prerender-crypto`). OTel's default
13
+ * generator hits `Math.random()` on every span creation, so spans Next
14
+ * opens around prerendered route renders blow up the build.
15
+ *
16
+ * The hybrid path keeps full 128-bit trace IDs / 64-bit span IDs for the
17
+ * common case (SSR, runtime requests, fluid-compute invocations) and only
18
+ * degrades inside prerender — where the alternative is build failure.
19
+ *
20
+ * Inside prerender, IDs are minted from a per-process random prefix
21
+ * (seeded once at construction time, outside any prerender ALS frame) plus
22
+ * a monotonic counter. Counter widths are masked to keep IDs at their
23
+ * spec-mandated lengths even after wrap.
24
+ */
25
+ declare class PrerenderSafeIdGenerator implements IdGenerator {
26
+ private readonly random;
27
+ private readonly tracePrefix;
28
+ private readonly spanPrefix;
29
+ private traceCounter;
30
+ private spanCounter;
31
+ constructor();
32
+ generateTraceId(): string;
33
+ generateSpanId(): string;
34
+ private fallbackTraceId;
35
+ private fallbackSpanId;
36
+ }
37
+ //#endregion
38
+ export { PrerenderSafeIdGenerator };
@@ -0,0 +1 @@
1
+ {"version":3,"file":"id-generator.d.mts","names":[],"sources":["../../../src/internal/server/id-generator.ts"],"mappings":";;;;;AAoCA;;;;;;;;;;;;;;;;AA0CwB;;;cA1CX,wBAAA,YAAoC,WAAW;EAAA,iBACzC,MAAA;EAAA,iBACA,WAAA;EAAA,iBACA,UAAA;EAAA,QACT,YAAA;EAAA,QACA,WAAA;;EAaR,eAAA,CAAA;EAQA,cAAA,CAAA;EAAA,QAQQ,eAAA;EAAA,QAQA,cAAA;AAAA"}
@@ -0,0 +1 @@
1
+ import{RandomIdGenerator}from"@opentelemetry/sdk-trace-base";import{randomBytes}from"node:crypto";const TRACE_COUNTER_MODULUS=2**32,SPAN_COUNTER_MODULUS=2**16;var PrerenderSafeIdGenerator=class{random=new RandomIdGenerator;tracePrefix;spanPrefix;traceCounter=0;spanCounter=0;constructor(){let seed=randomBytes(36/2);this.tracePrefix=seed.subarray(0,24/2).toString(`hex`),this.spanPrefix=seed.subarray(24/2).toString(`hex`)}generateTraceId(){try{return this.random.generateTraceId()}catch{return this.fallbackTraceId()}}generateSpanId(){try{return this.random.generateSpanId()}catch{return this.fallbackSpanId()}}fallbackTraceId(){return this.traceCounter=(this.traceCounter+1)%TRACE_COUNTER_MODULUS,this.tracePrefix+this.traceCounter.toString(16).padStart(8,`0`)}fallbackSpanId(){return this.spanCounter=(this.spanCounter+1)%SPAN_COUNTER_MODULUS,this.spanPrefix+this.spanCounter.toString(16).padStart(4,`0`)}};export{PrerenderSafeIdGenerator};
@@ -0,0 +1 @@
1
+ {"version":3,"file":"id-generator.mjs","names":[],"sources":["../../../src/internal/server/id-generator.ts"],"sourcesContent":["import { randomBytes } from \"node:crypto\";\nimport {\n type IdGenerator,\n RandomIdGenerator,\n} from \"@opentelemetry/sdk-trace-base\";\n\nconst TRACE_ID_HEX_LEN = 32;\nconst SPAN_ID_HEX_LEN = 16;\nconst TRACE_PREFIX_HEX_LEN = 24;\nconst SPAN_PREFIX_HEX_LEN = 12;\nconst TRACE_COUNTER_HEX_LEN = TRACE_ID_HEX_LEN - TRACE_PREFIX_HEX_LEN;\nconst SPAN_COUNTER_HEX_LEN = SPAN_ID_HEX_LEN - SPAN_PREFIX_HEX_LEN;\nconst TRACE_COUNTER_MODULUS = 2 ** (TRACE_COUNTER_HEX_LEN * 4);\nconst SPAN_COUNTER_MODULUS = 2 ** (SPAN_COUNTER_HEX_LEN * 4);\n\n/**\n * IdGenerator hybrid that uses OTel's default `RandomIdGenerator` whenever\n * available and falls back to a counter-based generator inside Next 16's\n * prerender contexts.\n *\n * Why: Next 16's prerender extension throws synchronously on any\n * `Math.random()` / `crypto.getRandomValues()` call inside a Server\n * Component that hasn't first awaited Request data\n * (`next-prerender-random` / `next-prerender-crypto`). OTel's default\n * generator hits `Math.random()` on every span creation, so spans Next\n * opens around prerendered route renders blow up the build.\n *\n * The hybrid path keeps full 128-bit trace IDs / 64-bit span IDs for the\n * common case (SSR, runtime requests, fluid-compute invocations) and only\n * degrades inside prerender — where the alternative is build failure.\n *\n * Inside prerender, IDs are minted from a per-process random prefix\n * (seeded once at construction time, outside any prerender ALS frame) plus\n * a monotonic counter. Counter widths are masked to keep IDs at their\n * spec-mandated lengths even after wrap.\n */\nexport class PrerenderSafeIdGenerator implements IdGenerator {\n private readonly random = new RandomIdGenerator();\n private readonly tracePrefix: string;\n private readonly spanPrefix: string;\n private traceCounter = 0;\n private spanCounter = 0;\n\n constructor() {\n // Seeded once at `register()` time — module init runs outside any\n // prerender ALS frame, so `randomBytes` is permitted here even if\n // every later call from inside a render is not.\n const seed = randomBytes((TRACE_PREFIX_HEX_LEN + SPAN_PREFIX_HEX_LEN) / 2);\n this.tracePrefix = seed\n .subarray(0, TRACE_PREFIX_HEX_LEN / 2)\n .toString(\"hex\");\n this.spanPrefix = seed.subarray(TRACE_PREFIX_HEX_LEN / 2).toString(\"hex\");\n }\n\n generateTraceId(): string {\n try {\n return this.random.generateTraceId();\n } catch {\n return this.fallbackTraceId();\n }\n }\n\n generateSpanId(): string {\n try {\n return this.random.generateSpanId();\n } catch {\n return this.fallbackSpanId();\n }\n }\n\n private fallbackTraceId(): string {\n this.traceCounter = (this.traceCounter + 1) % TRACE_COUNTER_MODULUS;\n return (\n this.tracePrefix +\n this.traceCounter.toString(16).padStart(TRACE_COUNTER_HEX_LEN, \"0\")\n );\n }\n\n private fallbackSpanId(): string {\n this.spanCounter = (this.spanCounter + 1) % SPAN_COUNTER_MODULUS;\n return (\n this.spanPrefix +\n this.spanCounter.toString(16).padStart(SPAN_COUNTER_HEX_LEN, \"0\")\n );\n }\n}\n"],"mappings":"kGAMA,MAMM,sBAAwB,GAAM,GAC9B,qBAAuB,GAAM,GAuBnC,IAAa,yBAAb,KAA6D,CAC3D,OAA0B,IAAI,kBAC9B,YACA,WACA,aAAuB,EACvB,YAAsB,EAEtB,aAAc,CAIZ,IAAM,KAAO,YAAa,GAA8C,CAAC,EACzE,KAAK,YAAc,KAChB,SAAS,EAAG,GAAuB,CAAC,EACpC,SAAS,KAAK,EACjB,KAAK,WAAa,KAAK,SAAS,GAAuB,CAAC,EAAE,SAAS,KAAK,CAC1E,CAEA,iBAA0B,CACxB,GAAI,CACF,OAAO,KAAK,OAAO,gBAAgB,CACrC,MAAQ,CACN,OAAO,KAAK,gBAAgB,CAC9B,CACF,CAEA,gBAAyB,CACvB,GAAI,CACF,OAAO,KAAK,OAAO,eAAe,CACpC,MAAQ,CACN,OAAO,KAAK,eAAe,CAC7B,CACF,CAEA,iBAAkC,CAEhC,MADA,MAAK,cAAgB,KAAK,aAAe,GAAK,sBAE5C,KAAK,YACL,KAAK,aAAa,SAAS,EAAE,EAAE,SAAS,EAAuB,GAAG,CAEtE,CAEA,gBAAiC,CAE/B,MADA,MAAK,aAAe,KAAK,YAAc,GAAK,qBAE1C,KAAK,WACL,KAAK,YAAY,SAAS,EAAE,EAAE,SAAS,EAAsB,GAAG,CAEpE,CACF"}
@@ -0,0 +1,86 @@
1
+ import { LogRecordProcessor } from "@opentelemetry/sdk-logs";
2
+ import { MetricReader } from "@opentelemetry/sdk-metrics";
3
+ import { SpanProcessor } from "@opentelemetry/sdk-trace-base";
4
+
5
+ //#region src/internal/server/instrumentation-options.d.ts
6
+ /**
7
+ * Per-instrumentation tuning for the server-side `register()`. Mirrors
8
+ * the browser-side `TracingOptions` — same names, same semantics —
9
+ * so a customer running both client + server with the same SDK has
10
+ * one mental model.
11
+ *
12
+ * The shape lives in its own module (rather than alongside
13
+ * `instrumentation.ts`) so the Node entry (`instrumentation.ts`) and the
14
+ * Edge no-op entry (`instrumentation.edge.ts`) can both pull the same
15
+ * type contract — the Edge entry never imports the Node-only OTel
16
+ * implementation, but its `register()` signature must stay byte-for-byte
17
+ * compatible so customer code compiles unchanged when bundled for either
18
+ * runtime.
19
+ *
20
+ * `LogRecordProcessor`, `MetricReader`, and `SpanProcessor` come from
21
+ * the OTel "base" packages (`@opentelemetry/sdk-logs`,
22
+ * `@opentelemetry/sdk-metrics`, `@opentelemetry/sdk-trace-base`),
23
+ * which are edge-safe at the import level. They're also `import type` here
24
+ * so they're erased before bundling — the Edge runtime bundle never sees
25
+ * them at all.
26
+ */
27
+ interface ServerInstrumentationOptions {
28
+ /**
29
+ * @internal
30
+ *
31
+ * Extra log-record processors fanned into the LoggerProvider's
32
+ * processor list. Used by `@interfere/observability` for internal-only
33
+ * dual-write to BetterStack from `interfere/homepage` +
34
+ * `interfere/dashboard`. Customers don't get a fan-out hook on the
35
+ * SDK surface; this is a private bridge for our own dogfood apps.
36
+ */
37
+ _internalAdditionalLogRecordProcessors?: LogRecordProcessor[];
38
+ /**
39
+ * @internal
40
+ *
41
+ * Extra metric readers fanned into the MeterProvider's reader list.
42
+ * See `_internalAdditionalLogRecordProcessors`. Used to keep
43
+ * `http.client.request.duration` (from `UndiciInstrumentation`) and
44
+ * any first-party `metrics.getMeter(...)` counters landing on the
45
+ * BetterStack-fronting OTel collector after the `@vercel/otel` →
46
+ * `@interfere/next` migration removed the default metric reader
47
+ * `registerOTel({ metricReader: "auto" })` used to install.
48
+ */
49
+ _internalAdditionalMetricReaders?: MetricReader[];
50
+ /**
51
+ * @internal
52
+ *
53
+ * Extra span processors fanned into the NodeTracerProvider's processor
54
+ * list. See `_internalAdditionalLogRecordProcessors`.
55
+ */
56
+ _internalAdditionalSpanProcessors?: SpanProcessor[];
57
+ /**
58
+ * `false` disables the `console.*` → OTel `LogRecord` bridge.
59
+ * Defaults to enabled. Customers running their own structured
60
+ * logger (Pino, Winston, etc.) that already emits OTel logs can
61
+ * opt out to avoid double-emit.
62
+ */
63
+ consoleBridge?: boolean;
64
+ /**
65
+ * URL patterns the undici fetch instrumentation skips (no spans
66
+ * created for these). The collector OTLP endpoint is always
67
+ * skipped automatically — without this the SDK would trace its
68
+ * own export requests in an infinite loop.
69
+ */
70
+ ignoreUrls?: (string | RegExp)[];
71
+ /**
72
+ * URL patterns the undici fetch instrumentation injects W3C
73
+ * `traceparent` + `baggage` headers on for cross-process trace
74
+ * correlation. Same-origin requests aren't a concept on the server
75
+ * the way they are in a browser, so the allowlist is the only
76
+ * propagation control.
77
+ */
78
+ propagateContextUrls?: (string | RegExp)[];
79
+ /**
80
+ * Override the OTel `service.name` resource attribute. Defaults to
81
+ * `"interfere-sdk-next-server"`.
82
+ */
83
+ serviceName?: string;
84
+ }
85
+ //#endregion
86
+ export { ServerInstrumentationOptions };
@@ -0,0 +1 @@
1
+ {"version":3,"file":"instrumentation-options.d.mts","names":[],"sources":["../../../src/internal/server/instrumentation-options.ts"],"mappings":";;;;;;;AAyBA;;;;;;;;;;;;;;;;;;;UAAiB,4BAAA;EAmDkB;;;AAKtB;;;;;;EA9CX,sCAAA,GAAyC,kBAAA;;;;;;;;;;;;EAYzC,gCAAA,GAAmC,YAAA;;;;;;;EAOnC,iCAAA,GAAoC,aAAA;;;;;;;EAOpC,aAAA;;;;;;;EAOA,UAAA,aAAuB,MAAA;;;;;;;;EAQvB,oBAAA,aAAiC,MAAA;;;;;EAKjC,WAAA;AAAA"}
@@ -0,0 +1 @@
1
+ export{};
@@ -1 +1 @@
1
- {"version":3,"file":"remote-config.d.mts","names":[],"sources":["../../../src/internal/server/remote-config.ts"],"mappings":";iBAUsB,yBAAA,CAAA,GAA6B,OAAA;AAAA,iBAkCnC,eAAA,CAAgB,MAAA"}
1
+ {"version":3,"file":"remote-config.d.mts","names":[],"sources":["../../../src/internal/server/remote-config.ts"],"mappings":";iBAWsB,yBAAA,CAAA,GAA6B,OAAO;AAAA,iBAoC1C,eAAA,CAAgB,MAAc"}
@@ -1,29 +1 @@
1
- import { isEnabledInEnvironment, readInterfereEnv } from "../env.mjs";
2
- import { API_PATHS } from "@interfere/constants/api";
3
- //#region src/internal/server/remote-config.ts
4
- let cachedConfig = null;
5
- async function fetchAndCacheRemoteConfig() {
6
- if (!isEnabledInEnvironment()) return;
7
- const env = readInterfereEnv();
8
- if (env.apiKey === null) return;
9
- try {
10
- const url = `${env.apiUrl}${API_PATHS.CONFIG}`;
11
- const response = await fetch(url, {
12
- method: "GET",
13
- headers: {
14
- "content-type": "application/json",
15
- "x-api-key": env.apiKey
16
- },
17
- signal: AbortSignal.timeout(1e4)
18
- });
19
- if (!response.ok) return;
20
- const config = await response.json();
21
- if (config?.plugins) cachedConfig = config.plugins;
22
- } catch {}
23
- }
24
- function isPluginEnabled(plugin) {
25
- if (!cachedConfig) return true;
26
- return cachedConfig[plugin] !== false;
27
- }
28
- //#endregion
29
- export { fetchAndCacheRemoteConfig, isPluginEnabled };
1
+ import{isEnabledOnServer,readInterfereEnv}from"../env.mjs";import{withPublicKey}from"../url.mjs";import{API_PATHS}from"@interfere/constants/api";let cachedConfig=null;async function fetchAndCacheRemoteConfig(){if(!isEnabledOnServer())return;let env=readInterfereEnv();if(env.publicKey!==null)try{let url=withPublicKey(`${env.apiUrl}${API_PATHS.CONFIG}`,env.publicKey),response=await fetch(url,{method:`GET`,headers:{"content-type":`application/json`},signal:AbortSignal.timeout(1e4)});if(!response.ok)return;let config=await response.json();config?.plugins&&(cachedConfig=config.plugins)}catch{}}function isPluginEnabled(plugin){return cachedConfig?cachedConfig[plugin]!==!1:!0}export{fetchAndCacheRemoteConfig,isPluginEnabled};
@@ -1 +1 @@
1
- {"version":3,"file":"remote-config.mjs","names":[],"sources":["../../../src/internal/server/remote-config.ts"],"sourcesContent":["import { API_PATHS } from \"@interfere/constants/api\";\nimport type {\n RemoteConfig,\n RemotePluginConfig,\n} from \"@interfere/types/sdk/remote-config\";\n\nimport { isEnabledInEnvironment, readInterfereEnv } from \"../env.js\";\n\nlet cachedConfig: RemotePluginConfig | null = null;\n\nexport async function fetchAndCacheRemoteConfig(): Promise<void> {\n if (!isEnabledInEnvironment()) {\n return;\n }\n\n const env = readInterfereEnv();\n if (env.apiKey === null) {\n return;\n }\n\n try {\n const url = `${env.apiUrl}${API_PATHS.CONFIG}`;\n const response = await fetch(url, {\n method: \"GET\",\n headers: {\n \"content-type\": \"application/json\",\n \"x-api-key\": env.apiKey,\n },\n signal: AbortSignal.timeout(10_000),\n });\n\n if (!response.ok) {\n return;\n }\n\n const config = (await response.json()) as RemoteConfig;\n if (config?.plugins) {\n cachedConfig = config.plugins;\n }\n } catch {\n // Fail silently — all plugins remain enabled\n }\n}\n\nexport function isPluginEnabled(plugin: string): boolean {\n if (!cachedConfig) {\n return true;\n }\n return cachedConfig[plugin as keyof RemotePluginConfig] !== false;\n}\n"],"mappings":";;;AAQA,IAAI,eAA0C;AAE9C,eAAsB,4BAA2C;AAC/D,KAAI,CAAC,wBAAwB,CAC3B;CAGF,MAAM,MAAM,kBAAkB;AAC9B,KAAI,IAAI,WAAW,KACjB;AAGF,KAAI;EACF,MAAM,MAAM,GAAG,IAAI,SAAS,UAAU;EACtC,MAAM,WAAW,MAAM,MAAM,KAAK;GAChC,QAAQ;GACR,SAAS;IACP,gBAAgB;IAChB,aAAa,IAAI;IAClB;GACD,QAAQ,YAAY,QAAQ,IAAO;GACpC,CAAC;AAEF,MAAI,CAAC,SAAS,GACZ;EAGF,MAAM,SAAU,MAAM,SAAS,MAAM;AACrC,MAAI,QAAQ,QACV,gBAAe,OAAO;SAElB;;AAKV,SAAgB,gBAAgB,QAAyB;AACvD,KAAI,CAAC,aACH,QAAO;AAET,QAAO,aAAa,YAAwC"}
1
+ {"version":3,"file":"remote-config.mjs","names":[],"sources":["../../../src/internal/server/remote-config.ts"],"sourcesContent":["import { API_PATHS } from \"@interfere/constants/api\";\nimport type {\n RemoteConfig,\n RemotePluginConfig,\n} from \"@interfere/types/sdk/remote-config\";\n\nimport { isEnabledOnServer, readInterfereEnv } from \"../env.js\";\nimport { withPublicKey } from \"../url.js\";\n\nlet cachedConfig: RemotePluginConfig | null = null;\n\nexport async function fetchAndCacheRemoteConfig(): Promise<void> {\n if (!isEnabledOnServer()) {\n return;\n }\n\n const env = readInterfereEnv();\n if (env.publicKey === null) {\n return;\n }\n\n try {\n const url = withPublicKey(\n `${env.apiUrl}${API_PATHS.CONFIG}`,\n env.publicKey\n );\n const response = await fetch(url, {\n method: \"GET\",\n headers: {\n \"content-type\": \"application/json\",\n },\n signal: AbortSignal.timeout(10_000),\n });\n\n if (!response.ok) {\n return;\n }\n\n const config = (await response.json()) as RemoteConfig;\n if (config?.plugins) {\n cachedConfig = config.plugins;\n }\n } catch {\n // Fail silently — all plugins remain enabled\n }\n}\n\nexport function isPluginEnabled(plugin: string): boolean {\n if (!cachedConfig) {\n return true;\n }\n return cachedConfig[plugin as keyof RemotePluginConfig] !== false;\n}\n"],"mappings":"iJASA,IAAI,aAA0C,KAE9C,eAAsB,2BAA2C,CAC/D,GAAI,CAAC,kBAAkB,EACrB,OAGF,IAAM,IAAM,iBAAiB,EACzB,OAAI,YAAc,KAItB,GAAI,CACF,IAAM,IAAM,cACV,GAAG,IAAI,SAAS,UAAU,SAC1B,IAAI,SACN,EACM,SAAW,MAAM,MAAM,IAAK,CAChC,OAAQ,MACR,QAAS,CACP,eAAgB,kBAClB,EACA,OAAQ,YAAY,QAAQ,GAAM,CACpC,CAAC,EAED,GAAI,CAAC,SAAS,GACZ,OAGF,IAAM,OAAU,MAAM,SAAS,KAAK,EAChC,QAAQ,UACV,aAAe,OAAO,QAE1B,MAAQ,CAER,CACF,CAEA,SAAgB,gBAAgB,OAAyB,CAIvD,OAHK,aAGE,aAAa,UAAwC,GAFnD,EAGX"}
@@ -0,0 +1,32 @@
1
+ //#region src/internal/server/trace-meta.d.ts
2
+ /**
3
+ * Server Component that emits a `<meta name="traceparent">` tag so the
4
+ * client SDK can stitch every browser span onto the server-side trace.
5
+ *
6
+ * Customer usage — drop into the root layout's `<head>`:
7
+ *
8
+ * ```tsx
9
+ * import { TraceMeta } from "@interfere/next/server";
10
+ *
11
+ * export default function RootLayout({ children }) {
12
+ * return (
13
+ * <html>
14
+ * <head>
15
+ * <TraceMeta />
16
+ * </head>
17
+ * <body>{children}</body>
18
+ * </html>
19
+ * );
20
+ * }
21
+ * ```
22
+ *
23
+ * Renders nothing when no OTel span is active (dev without OTel
24
+ * registered, edge runtime where `@interfere/next/instrumentation`'s
25
+ * async `register()` hasn't completed before the layout renders, or
26
+ * unsampled traces). The client SDK's propagation reader handles a
27
+ * missing meta tag the same as no parent — every browser span starts a
28
+ * fresh root, which is at least internally consistent.
29
+ */
30
+ declare function TraceMeta(): import("react/jsx-runtime").JSX.Element | null;
31
+ //#endregion
32
+ export { TraceMeta };
@@ -0,0 +1 @@
1
+ {"version":3,"file":"trace-meta.d.mts","names":[],"sources":["../../../src/internal/server/trace-meta.tsx"],"mappings":";;AA8BA;;;;AAAyB;;;;;;;;;;;;;;;;;;;;;;;iBAAT,SAAA,CAAA,+BAAS,GAAA,CAAA,OAAA"}
@@ -0,0 +1 @@
1
+ import{activeTraceparent}from"./traceparent.mjs";import{jsx}from"react/jsx-runtime";function TraceMeta(){let traceparent=activeTraceparent();return traceparent?jsx(`meta`,{content:traceparent,name:`traceparent`}):null}export{TraceMeta};
@@ -0,0 +1 @@
1
+ {"version":3,"file":"trace-meta.mjs","names":[],"sources":["../../../src/internal/server/trace-meta.tsx"],"sourcesContent":["import { activeTraceparent } from \"./traceparent.js\";\n\n/**\n * Server Component that emits a `<meta name=\"traceparent\">` tag so the\n * client SDK can stitch every browser span onto the server-side trace.\n *\n * Customer usage — drop into the root layout's `<head>`:\n *\n * ```tsx\n * import { TraceMeta } from \"@interfere/next/server\";\n *\n * export default function RootLayout({ children }) {\n * return (\n * <html>\n * <head>\n * <TraceMeta />\n * </head>\n * <body>{children}</body>\n * </html>\n * );\n * }\n * ```\n *\n * Renders nothing when no OTel span is active (dev without OTel\n * registered, edge runtime where `@interfere/next/instrumentation`'s\n * async `register()` hasn't completed before the layout renders, or\n * unsampled traces). The client SDK's propagation reader handles a\n * missing meta tag the same as no parent — every browser span starts a\n * fresh root, which is at least internally consistent.\n */\nexport function TraceMeta() {\n const traceparent = activeTraceparent();\n if (!traceparent) {\n return null;\n }\n return <meta content={traceparent} name=\"traceparent\" />;\n}\n"],"mappings":"oFA8BA,SAAgB,WAAY,CAC1B,IAAM,YAAc,kBAAkB,EAItC,OAHK,YAGE,IAAC,OAAD,CAAM,QAAS,YAAa,KAAK,aAAe,CAAA,EAF9C,IAGX"}
@@ -0,0 +1,16 @@
1
+ //#region src/internal/server/traceparent.d.ts
2
+ /**
3
+ * Build a W3C `traceparent` string from the currently-active OTel
4
+ * span, or `null` if no span is active or the trace is not sampled.
5
+ *
6
+ * Server-side counterpart to the client SDK's
7
+ * `internal/otel/propagation.ts`: both ends of the wire filter
8
+ * unsampled traces. The browser doesn't honor the `sampled` bit when
9
+ * creating child spans, so propagating an unsampled trace_id from the
10
+ * server would orphan every browser span under a trace with no
11
+ * recorded server segments. Returning null lets the browser fall back
12
+ * to its own root, which is at least internally consistent.
13
+ */
14
+ declare function activeTraceparent(): string | null;
15
+ //#endregion
16
+ export { activeTraceparent };
@@ -0,0 +1 @@
1
+ {"version":3,"file":"traceparent.d.mts","names":[],"sources":["../../../src/internal/server/traceparent.ts"],"mappings":";;AAiBA;;;;AAAiC;;;;;;;iBAAjB,iBAAA,CAAA"}
@@ -0,0 +1 @@
1
+ import{TraceFlags,trace}from"@opentelemetry/api";const SAMPLED_BIT=TraceFlags.SAMPLED;function activeTraceparent(){let span=trace.getActiveSpan();if(!span)return null;let ctx=span.spanContext();if((ctx.traceFlags&SAMPLED_BIT)!==SAMPLED_BIT)return null;let flags=ctx.traceFlags.toString(16).padStart(2,`0`);return`00-${ctx.traceId}-${ctx.spanId}-${flags}`}export{activeTraceparent};
@@ -0,0 +1 @@
1
+ {"version":3,"file":"traceparent.mjs","names":[],"sources":["../../../src/internal/server/traceparent.ts"],"sourcesContent":["import { TraceFlags, trace } from \"@opentelemetry/api\";\n\nconst SAMPLED_BIT = TraceFlags.SAMPLED;\nconst W3C_TRACECONTEXT_VERSION = \"00\";\n\n/**\n * Build a W3C `traceparent` string from the currently-active OTel\n * span, or `null` if no span is active or the trace is not sampled.\n *\n * Server-side counterpart to the client SDK's\n * `internal/otel/propagation.ts`: both ends of the wire filter\n * unsampled traces. The browser doesn't honor the `sampled` bit when\n * creating child spans, so propagating an unsampled trace_id from the\n * server would orphan every browser span under a trace with no\n * recorded server segments. Returning null lets the browser fall back\n * to its own root, which is at least internally consistent.\n */\nexport function activeTraceparent(): string | null {\n const span = trace.getActiveSpan();\n if (!span) {\n return null;\n }\n const ctx = span.spanContext();\n // biome-ignore lint/suspicious/noBitwiseOperators: W3C trace_flags is a bitmask; SAMPLED (0x01) must be tested independently of any future reserved flags.\n if ((ctx.traceFlags & SAMPLED_BIT) !== SAMPLED_BIT) {\n return null;\n }\n const flags = ctx.traceFlags.toString(16).padStart(2, \"0\");\n return `${W3C_TRACECONTEXT_VERSION}-${ctx.traceId}-${ctx.spanId}-${flags}`;\n}\n"],"mappings":"iDAEA,MAAM,YAAc,WAAW,QAe/B,SAAgB,mBAAmC,CACjD,IAAM,KAAO,MAAM,cAAc,EACjC,GAAI,CAAC,KACH,OAAO,KAET,IAAM,IAAM,KAAK,YAAY,EAE7B,IAAK,IAAI,WAAa,eAAiB,YACrC,OAAO,KAET,IAAM,MAAQ,IAAI,WAAW,SAAS,EAAE,EAAE,SAAS,EAAG,GAAG,EACzD,MAAO,MAA+B,IAAI,QAAQ,GAAG,IAAI,OAAO,GAAG,OACrE"}
@@ -6,12 +6,6 @@ type OnRequestErrorContext = Omit<NextjsContext, "errorDigest" | "requestMethod"
6
6
  interface CaptureErrorContext {
7
7
  readonly mechanism?: ErrorMechanism;
8
8
  readonly nextjs?: Omit<NextjsContext, "runtime">;
9
- readonly traceparent?: string;
10
- }
11
- interface NormalizedRequest {
12
- readonly headers: Headers;
13
- readonly method: string;
14
- readonly path: string;
15
9
  }
16
10
  //#endregion
17
- export { CaptureErrorContext, NormalizedRequest, OnRequestErrorContext };
11
+ export { CaptureErrorContext, OnRequestErrorContext };
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.mts","names":[],"sources":["../../../src/internal/server/types.ts"],"mappings":";;;;KAGY,qBAAA,GAAwB,IAAA,CAClC,aAAA;AAAA,UAIe,mBAAA;EAAA,SACN,SAAA,GAAY,cAAA;EAAA,SACZ,MAAA,GAAS,IAAA,CAAK,aAAA;EAAA,SACd,WAAA;AAAA;AAAA,UAGM,iBAAA;EAAA,SACN,OAAA,EAAS,OAAA;EAAA,SACT,MAAA;EAAA,SACA,IAAA;AAAA"}
1
+ {"version":3,"file":"types.d.mts","names":[],"sources":["../../../src/internal/server/types.ts"],"mappings":";;;;KAGY,qBAAA,GAAwB,IAAI,CACtC,aAAA;AAAA,UAIe,mBAAA;EAAA,SACN,SAAA,GAAY,cAAA;EAAA,SACZ,MAAA,GAAS,IAAA,CAAK,aAAA;AAAA"}
@@ -1 +1 @@
1
- export {};
1
+ export{};
@@ -0,0 +1,17 @@
1
+ //#region src/internal/setup-warnings.d.ts
2
+ /**
3
+ * Best-effort warning when the customer set `INTERFERE_PUBLIC_KEY` but never
4
+ * created `instrumentation.ts`. Server-side tracing then silently does
5
+ * nothing — that's surprising and there's no other place we get to tell
6
+ * them. Never blocks the build: some customers genuinely don't want
7
+ * server-side tracing.
8
+ */
9
+ declare function warnIfServerInstrumentationMissing(projectDir: string): void;
10
+ /**
11
+ * Reads the customer's installed `next` package version. Returns `null` if
12
+ * Next isn't resolvable from `projectDir` (e.g. running outside a Next app),
13
+ * in which case callers should skip version-conditional behaviour.
14
+ */
15
+ declare function readNextMajorVersion(projectDir: string): number | null;
16
+ //#endregion
17
+ export { readNextMajorVersion, warnIfServerInstrumentationMissing };
@@ -0,0 +1 @@
1
+ {"version":3,"file":"setup-warnings.d.mts","names":[],"sources":["../../src/internal/setup-warnings.ts"],"mappings":";;AA8BA;;;;AAAqE;AAerE;iBAfgB,kCAAA,CAAmC,UAAkB;;;AAed;;;iBAAvC,oBAAA,CAAqB,UAAkB"}
@@ -0,0 +1 @@
1
+ import{log}from"./logger.mjs";import{createRequire}from"node:module";import{existsSync}from"node:fs";import{resolve}from"node:path";const SERVER_INSTRUMENTATION_FILES=[`instrumentation.ts`,`instrumentation.tsx`,`instrumentation.js`,`instrumentation.jsx`,`src/instrumentation.ts`,`src/instrumentation.tsx`,`src/instrumentation.js`,`src/instrumentation.jsx`];function hasServerInstrumentation(projectDir){return SERVER_INSTRUMENTATION_FILES.some(c=>existsSync(resolve(projectDir,c)))}function warnIfServerInstrumentationMissing(projectDir){hasServerInstrumentation(projectDir)||log.warn(`No instrumentation.ts found`,[`Server-side traces will be skipped. To enable, create instrumentation.ts at the project root with:`,` export { register } from '@interfere/next/instrumentation';`])}function readNextMajorVersion(projectDir){try{let pkg=createRequire(`${projectDir}/_`)(`next/package.json`),major=Number.parseInt(pkg.version?.split(`.`)[0]??``,10);return Number.isFinite(major)?major:null}catch{return null}}export{readNextMajorVersion,warnIfServerInstrumentationMissing};
@@ -0,0 +1 @@
1
+ {"version":3,"file":"setup-warnings.mjs","names":[],"sources":["../../src/internal/setup-warnings.ts"],"sourcesContent":["import { existsSync } from \"node:fs\";\nimport { createRequire } from \"node:module\";\nimport { resolve } from \"node:path\";\n\nimport { log } from \"./logger.js\";\n\nconst SERVER_INSTRUMENTATION_FILES = [\n \"instrumentation.ts\",\n \"instrumentation.tsx\",\n \"instrumentation.js\",\n \"instrumentation.jsx\",\n \"src/instrumentation.ts\",\n \"src/instrumentation.tsx\",\n \"src/instrumentation.js\",\n \"src/instrumentation.jsx\",\n] as const;\n\nfunction hasServerInstrumentation(projectDir: string): boolean {\n return SERVER_INSTRUMENTATION_FILES.some((c) =>\n existsSync(resolve(projectDir, c))\n );\n}\n\n/**\n * Best-effort warning when the customer set `INTERFERE_PUBLIC_KEY` but never\n * created `instrumentation.ts`. Server-side tracing then silently does\n * nothing — that's surprising and there's no other place we get to tell\n * them. Never blocks the build: some customers genuinely don't want\n * server-side tracing.\n */\nexport function warnIfServerInstrumentationMissing(projectDir: string): void {\n if (hasServerInstrumentation(projectDir)) {\n return;\n }\n log.warn(\"No instrumentation.ts found\", [\n \"Server-side traces will be skipped. To enable, create instrumentation.ts at the project root with:\",\n \" export { register } from '@interfere/next/instrumentation';\",\n ]);\n}\n\n/**\n * Reads the customer's installed `next` package version. Returns `null` if\n * Next isn't resolvable from `projectDir` (e.g. running outside a Next app),\n * in which case callers should skip version-conditional behaviour.\n */\nexport function readNextMajorVersion(projectDir: string): number | null {\n try {\n const require = createRequire(`${projectDir}/_`);\n const pkg = require(\"next/package.json\") as { version?: string };\n const major = Number.parseInt(pkg.version?.split(\".\")[0] ?? \"\", 10);\n return Number.isFinite(major) ? major : null;\n } catch {\n return null;\n }\n}\n"],"mappings":"oIAMA,MAAM,6BAA+B,CACnC,qBACA,sBACA,qBACA,sBACA,yBACA,0BACA,yBACA,yBACF,EAEA,SAAS,yBAAyB,WAA6B,CAC7D,OAAO,6BAA6B,KAAM,GACxC,WAAW,QAAQ,WAAY,CAAC,CAAC,CACnC,CACF,CASA,SAAgB,mCAAmC,WAA0B,CACvE,yBAAyB,UAAU,GAGvC,IAAI,KAAK,8BAA+B,CACtC,qGACA,+DACF,CAAC,CACH,CAOA,SAAgB,qBAAqB,WAAmC,CACtE,GAAI,CAEF,IAAM,IADU,cAAc,GAAG,WAAW,GAC1B,EAAE,mBAAmB,EACjC,MAAQ,OAAO,SAAS,IAAI,SAAS,MAAM,GAAG,EAAE,IAAM,GAAI,EAAE,EAClE,OAAO,OAAO,SAAS,KAAK,EAAI,MAAQ,IAC1C,MAAQ,CACN,OAAO,IACT,CACF"}
@@ -0,0 +1,4 @@
1
+ //#region src/internal/url.d.ts
2
+ declare function withPublicKey(url: string, publicKey: string): string;
3
+ //#endregion
4
+ export { withPublicKey };
@@ -0,0 +1 @@
1
+ {"version":3,"file":"url.d.mts","names":[],"sources":["../../src/internal/url.ts"],"mappings":";iBAEgB,aAAA,CAAc,GAAA,UAAa,SAAiB"}
@@ -0,0 +1 @@
1
+ function withPublicKey(url,publicKey){let next=new URL(url);return next.searchParams.set(`pk`,publicKey),next.toString()}export{withPublicKey};
@@ -0,0 +1 @@
1
+ {"version":3,"file":"url.mjs","names":[],"sources":["../../src/internal/url.ts"],"sourcesContent":["const PUBLIC_KEY_QUERY = \"pk\";\n\nexport function withPublicKey(url: string, publicKey: string): string {\n const next = new URL(url);\n next.searchParams.set(PUBLIC_KEY_QUERY, publicKey);\n return next.toString();\n}\n"],"mappings":"AAEA,SAAgB,cAAc,IAAa,UAA2B,CACpE,IAAM,KAAO,IAAI,IAAI,GAAG,EAExB,OADA,KAAK,aAAa,IAAI,KAAkB,SAAS,EAC1C,KAAK,SAAS,CACvB"}
@@ -1,5 +1 @@
1
- import { name, version } from "../package.mjs";
2
- //#region src/internal/version.ts
3
- const PRODUCER_VERSION = `${name}@${version}`;
4
- //#endregion
5
- export { PRODUCER_VERSION };
1
+ import{name,version}from"../package.mjs";const PRODUCER_VERSION=`${name}@${version}`;export{PRODUCER_VERSION};
@@ -1 +1 @@
1
- {"version":3,"file":"version.mjs","names":["pkg.name","pkg.version"],"sources":["../../src/internal/version.ts"],"sourcesContent":["import pkg from \"../../package.json\" with { type: \"json\" };\n\nexport const PRODUCER_VERSION = `${pkg.name}@${pkg.version}`;\n"],"mappings":";;AAEA,MAAa,mBAAmB,GAAGA,KAAS,GAAGC"}
1
+ {"version":3,"file":"version.mjs","names":["pkg.name","pkg.version"],"sources":["../../src/internal/version.ts"],"sourcesContent":["import pkg from \"../../package.json\" with { type: \"json\" };\n\nexport const PRODUCER_VERSION = `${pkg.name}@${pkg.version}`;\n"],"mappings":"yCAEA,MAAa,iBAAmB,GAAGA,KAAS,GAAGC"}
package/dist/package.mjs CHANGED
@@ -1,5 +1 @@
1
- //#region package.json
2
- var name = "@interfere/next";
3
- var version = "9.0.2";
4
- //#endregion
5
- export { name, version };
1
+ var name=`@interfere/next`,version=`10.0.1-canary.0`;export{name,version};
@@ -1,3 +1,24 @@
1
- import { InterfereProvider, useInterfere, useSession } from "@interfere/react/provider";
2
- import { ConsentCategory, ConsentState, GateableCategory } from "@interfere/types/sdk/plugins/manifest";
1
+ import { useInterfere, useSession } from "@interfere/react/provider";
2
+ import { PropsWithChildren, ReactNode } from "react";
3
+ import { ConsentCategory, ConsentState, ConsentState as ConsentState$1, GateableCategory } from "@interfere/types/sdk/plugins/manifest";
4
+
5
+ //#region src/provider.d.ts
6
+ interface InterfereProviderProps extends PropsWithChildren {
7
+ consent?: ConsentState$1 | undefined;
8
+ errorBoundary?: boolean;
9
+ }
10
+ /**
11
+ * Next.js wrapper around `@interfere/react`'s provider that resolves the
12
+ * kernel from module scope (set by the matching `init()` call). Customer
13
+ * code never passes the kernel explicitly. Uses `getKernelOrNull()` so the
14
+ * provider is safe to render during SSR/SSG when `init()` hasn't run
15
+ * (`init()` is client-only); the core provider mounts with null-safe
16
+ * accessors and switches to the real kernel on client hydration.
17
+ */
18
+ declare function InterfereProvider({
19
+ children,
20
+ consent,
21
+ errorBoundary
22
+ }: InterfereProviderProps): ReactNode;
23
+ //#endregion
3
24
  export { type ConsentCategory, type ConsentState, type GateableCategory, InterfereProvider, useInterfere, useSession };
@@ -0,0 +1 @@
1
+ {"version":3,"file":"provider.d.mts","names":[],"sources":["../src/provider.tsx"],"mappings":";;;;;UAeU,sBAAA,SAA+B,iBAAiB;EACxD,OAAA,GAAU,cAAA;EACV,aAAA;AAAA;;;;;;;;;iBAWc,iBAAA,CAAA;EACd,QAAA;EACA,OAAA;EACA;AAAA,GACC,sBAAA,GAAyB,SAAA"}
package/dist/provider.mjs CHANGED
@@ -1,3 +1 @@
1
- "use client";
2
- import { InterfereProvider, useInterfere, useSession } from "@interfere/react/provider";
3
- export { InterfereProvider, useInterfere, useSession };
1
+ "use client";import{getKernelOrNull,subscribeToKernel}from"./instrument-client.mjs";import{InterfereProvider as InterfereProvider$1,useInterfere,useSession}from"@interfere/react/provider";import{useSyncExternalStore}from"react";import{jsx}from"react/jsx-runtime";const nullSnapshot=()=>null;function InterfereProvider({children,consent,errorBoundary}){return jsx(InterfereProvider$1,{kernel:useSyncExternalStore(subscribeToKernel,getKernelOrNull,nullSnapshot),...consent===void 0?{}:{consent},...errorBoundary===void 0?{}:{errorBoundary},children})}export{InterfereProvider,useInterfere,useSession};
@@ -0,0 +1 @@
1
+ {"version":3,"file":"provider.mjs","names":["CoreInterfereProvider"],"sources":["../src/provider.tsx"],"sourcesContent":["\"use client\";\n\nimport { InterfereProvider as CoreInterfereProvider } from \"@interfere/react/provider\";\nimport type { ConsentState } from \"@interfere/types/sdk/plugins/manifest\";\n\nimport {\n type PropsWithChildren,\n type ReactNode,\n useSyncExternalStore,\n} from \"react\";\n\nimport { getKernelOrNull, subscribeToKernel } from \"./instrument-client.js\";\n\nconst nullSnapshot = () => null;\n\ninterface InterfereProviderProps extends PropsWithChildren {\n consent?: ConsentState | undefined;\n errorBoundary?: boolean;\n}\n\n/**\n * Next.js wrapper around `@interfere/react`'s provider that resolves the\n * kernel from module scope (set by the matching `init()` call). Customer\n * code never passes the kernel explicitly. Uses `getKernelOrNull()` so the\n * provider is safe to render during SSR/SSG when `init()` hasn't run\n * (`init()` is client-only); the core provider mounts with null-safe\n * accessors and switches to the real kernel on client hydration.\n */\nexport function InterfereProvider({\n children,\n consent,\n errorBoundary,\n}: InterfereProviderProps): ReactNode {\n // Subscribe so the provider re-renders when `init()` resolves on the\n // client (customers commonly fire-and-forget `init()` from\n // `instrumentation-client.ts`, so the kernel may not be available\n // when the provider first mounts). Server renders see `null` via\n // `nullSnapshot` and the core provider mounts with null-safe accessors.\n const kernel = useSyncExternalStore(\n subscribeToKernel,\n getKernelOrNull,\n nullSnapshot\n );\n return (\n <CoreInterfereProvider\n kernel={kernel}\n {...(consent === undefined ? {} : { consent })}\n {...(errorBoundary === undefined ? {} : { errorBoundary })}\n >\n {children}\n </CoreInterfereProvider>\n );\n}\n\n// biome-ignore lint/performance/noBarrelFile: Next.js provider entrypoint re-exports the React SDK hooks for one-line customer setup.\nexport { useInterfere, useSession } from \"@interfere/react/provider\";\nexport type {\n ConsentCategory,\n ConsentState,\n GateableCategory,\n} from \"@interfere/types/sdk/plugins/manifest\";\n"],"mappings":"uQAaA,MAAM,iBAAqB,KAe3B,SAAgB,kBAAkB,CAChC,SACA,QACA,eACoC,CAWpC,OACE,IAACA,oBAAD,CACE,OAPW,qBACb,kBACA,gBACA,YAIe,EACb,GAAK,UAAY,IAAA,GAAY,CAAC,EAAI,CAAE,OAAQ,EAC5C,GAAK,gBAAkB,IAAA,GAAY,CAAC,EAAI,CAAE,aAAc,EAEvD,QACoB,CAAA,CAE3B"}
@@ -1,7 +1,12 @@
1
1
  //#region src/route-handler.d.ts
2
+ /**
3
+ * Customers consume this module via `export * from "@interfere/next/route-handler"`
4
+ * so any HTTP method we add later (PATCH, DELETE, …) is picked up
5
+ * without a customer file change. Do NOT add non-method exports here —
6
+ * `route-handler.lint.test.ts` will fail the build if you do.
7
+ */
2
8
  declare function GET(request: Request): Promise<Response>;
3
9
  declare function POST(request: Request): Promise<Response>;
4
- declare function PUT(request: Request): Promise<Response>;
5
10
  declare function OPTIONS(): Response;
6
11
  //#endregion
7
- export { GET, OPTIONS, POST, PUT };
12
+ export { GET, OPTIONS, POST };
@@ -1 +1 @@
1
- {"version":3,"file":"route-handler.d.mts","names":[],"sources":["../src/route-handler.ts"],"mappings":";iBAMsB,GAAA,CAAI,OAAA,EAAS,OAAA,GAAU,OAAA,CAAQ,QAAA;AAAA,iBAOrC,IAAA,CAAK,OAAA,EAAS,OAAA,GAAU,OAAA,CAAQ,QAAA;AAAA,iBAOhC,GAAA,CAAI,OAAA,EAAS,OAAA,GAAU,OAAA,CAAQ,QAAA;AAAA,iBAc/B,OAAA,CAAA,GAAW,QAAA"}
1
+ {"version":3,"file":"route-handler.d.mts","names":[],"sources":["../src/route-handler.ts"],"mappings":";;AAaA;;;;;iBAAsB,GAAA,CAAI,OAAA,EAAS,OAAA,GAAU,OAAA,CAAQ,QAAA;AAAA,iBAOrC,IAAA,CAAK,OAAA,EAAS,OAAA,GAAU,OAAA,CAAQ,QAAA;AAAA,iBAchC,OAAA,CAAA,GAAW,QAAQ"}