@interfere/next 0.1.0-alpha.9 → 0.2.0-alpha.4

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 (242) hide show
  1. package/README.md +70 -277
  2. package/dist/_virtual/_rolldown/runtime.mjs +13 -0
  3. package/dist/config.d.mts +11 -0
  4. package/dist/config.d.mts.map +1 -0
  5. package/dist/config.mjs +107 -0
  6. package/dist/config.mjs.map +1 -0
  7. package/dist/instrument-client.d.mts +2 -0
  8. package/dist/instrument-client.mjs +2 -0
  9. package/dist/internal/build/configure-build.d.mts +22 -0
  10. package/dist/internal/build/configure-build.d.mts.map +1 -0
  11. package/dist/internal/build/configure-build.mjs +87 -0
  12. package/dist/internal/build/configure-build.mjs.map +1 -0
  13. package/dist/internal/build/injected.d.mts +12 -0
  14. package/dist/internal/build/injected.d.mts.map +1 -0
  15. package/dist/internal/build/injected.mjs +9 -0
  16. package/dist/internal/build/injected.mjs.map +1 -0
  17. package/dist/internal/build/release/destinations/vercel.d.mts +6 -0
  18. package/dist/internal/build/release/destinations/vercel.d.mts.map +1 -0
  19. package/dist/internal/build/release/destinations/vercel.mjs +25 -0
  20. package/dist/internal/build/release/destinations/vercel.mjs.map +1 -0
  21. package/dist/internal/build/release/git.d.mts +4 -0
  22. package/dist/internal/build/release/git.d.mts.map +1 -0
  23. package/dist/internal/build/release/git.mjs +21 -0
  24. package/dist/internal/build/release/git.mjs.map +1 -0
  25. package/dist/internal/build/release/index.d.mts +7 -0
  26. package/dist/internal/build/release/index.d.mts.map +1 -0
  27. package/dist/internal/build/release/index.mjs +24 -0
  28. package/dist/internal/build/release/index.mjs.map +1 -0
  29. package/dist/internal/build/release/sources/github.d.mts +6 -0
  30. package/dist/internal/build/release/sources/github.d.mts.map +1 -0
  31. package/dist/internal/build/release/sources/github.mjs +15 -0
  32. package/dist/internal/build/release/sources/github.mjs.map +1 -0
  33. package/dist/internal/build/release/types.d.mts +11 -0
  34. package/dist/internal/build/release/types.d.mts.map +1 -0
  35. package/dist/internal/build/release/types.mjs +1 -0
  36. package/dist/internal/build/source-maps/discover.d.mts +14 -0
  37. package/dist/internal/build/source-maps/discover.d.mts.map +1 -0
  38. package/dist/internal/build/source-maps/discover.mjs +61 -0
  39. package/dist/internal/build/source-maps/discover.mjs.map +1 -0
  40. package/dist/internal/build/source-maps/index.d.mts +23 -0
  41. package/dist/internal/build/source-maps/index.d.mts.map +1 -0
  42. package/dist/internal/build/source-maps/index.mjs +33 -0
  43. package/dist/internal/build/source-maps/index.mjs.map +1 -0
  44. package/dist/internal/build/value-injection-loader.d.mts +10 -0
  45. package/dist/internal/build/value-injection-loader.d.mts.map +1 -0
  46. package/dist/internal/build/value-injection-loader.mjs +24 -0
  47. package/dist/internal/build/value-injection-loader.mjs.map +1 -0
  48. package/dist/internal/env.d.mts +16 -0
  49. package/dist/internal/env.d.mts.map +1 -0
  50. package/dist/internal/env.mjs +19 -0
  51. package/dist/internal/env.mjs.map +1 -0
  52. package/dist/internal/logger.d.mts +8 -0
  53. package/dist/internal/logger.d.mts.map +1 -0
  54. package/dist/internal/logger.mjs +44 -0
  55. package/dist/internal/logger.mjs.map +1 -0
  56. package/dist/internal/route/cors.d.mts +4 -0
  57. package/dist/internal/route/cors.d.mts.map +1 -0
  58. package/dist/internal/route/cors.mjs +15 -0
  59. package/dist/internal/route/cors.mjs.map +1 -0
  60. package/dist/internal/route/handle-get.d.mts +4 -0
  61. package/dist/internal/route/handle-get.d.mts.map +1 -0
  62. package/dist/internal/route/handle-get.mjs +15 -0
  63. package/dist/internal/route/handle-get.mjs.map +1 -0
  64. package/dist/internal/route/handle-post.d.mts +4 -0
  65. package/dist/internal/route/handle-post.d.mts.map +1 -0
  66. package/dist/internal/route/handle-post.mjs +105 -0
  67. package/dist/internal/route/handle-post.mjs.map +1 -0
  68. package/dist/internal/route/sw-script.d.mts +4 -0
  69. package/dist/internal/route/sw-script.d.mts.map +1 -0
  70. package/dist/internal/route/sw-script.mjs +32 -0
  71. package/dist/internal/route/sw-script.mjs.map +1 -0
  72. package/dist/internal/server/capture.d.mts +9 -0
  73. package/dist/internal/server/capture.d.mts.map +1 -0
  74. package/dist/internal/server/capture.mjs +46 -0
  75. package/dist/internal/server/capture.mjs.map +1 -0
  76. package/dist/internal/server/dedupe.d.mts +5 -0
  77. package/dist/internal/server/dedupe.d.mts.map +1 -0
  78. package/dist/internal/server/dedupe.mjs +11 -0
  79. package/dist/internal/server/dedupe.mjs.map +1 -0
  80. package/dist/internal/server/envelope.d.mts +14 -0
  81. package/dist/internal/server/envelope.d.mts.map +1 -0
  82. package/dist/internal/server/envelope.mjs +41 -0
  83. package/dist/internal/server/envelope.mjs.map +1 -0
  84. package/dist/internal/server/mechanisms.d.mts +7 -0
  85. package/dist/internal/server/mechanisms.d.mts.map +1 -0
  86. package/dist/internal/server/mechanisms.mjs +12 -0
  87. package/dist/internal/server/mechanisms.mjs.map +1 -0
  88. package/dist/internal/server/normalize-request.d.mts +7 -0
  89. package/dist/internal/server/normalize-request.d.mts.map +1 -0
  90. package/dist/internal/server/normalize-request.mjs +50 -0
  91. package/dist/internal/server/normalize-request.mjs.map +1 -0
  92. package/dist/internal/server/runtime.d.mts +14 -0
  93. package/dist/internal/server/runtime.d.mts.map +1 -0
  94. package/dist/internal/server/runtime.mjs +18 -0
  95. package/dist/internal/server/runtime.mjs.map +1 -0
  96. package/dist/internal/server/session.d.mts +11 -0
  97. package/dist/internal/server/session.d.mts.map +1 -0
  98. package/dist/internal/server/session.mjs +15 -0
  99. package/dist/internal/server/session.mjs.map +1 -0
  100. package/dist/internal/server/transport.d.mts +12 -0
  101. package/dist/internal/server/transport.d.mts.map +1 -0
  102. package/dist/internal/server/transport.mjs +17 -0
  103. package/dist/internal/server/transport.mjs.map +1 -0
  104. package/dist/internal/server/types.d.mts +17 -0
  105. package/dist/internal/server/types.d.mts.map +1 -0
  106. package/dist/internal/server/types.mjs +1 -0
  107. package/dist/provider.d.mts +2 -0
  108. package/dist/provider.mjs +3 -0
  109. package/dist/route-handler.d.mts +7 -0
  110. package/dist/route-handler.d.mts.map +1 -0
  111. package/dist/route-handler.mjs +18 -0
  112. package/dist/route-handler.mjs.map +1 -0
  113. package/dist/server.d.mts +8 -0
  114. package/dist/server.d.mts.map +1 -0
  115. package/dist/server.mjs +6 -0
  116. package/dist/server.mjs.map +1 -0
  117. package/package.json +60 -73
  118. package/LICENSE +0 -21
  119. package/dist/build/env-config.d.mts +0 -7
  120. package/dist/build/env-config.d.mts.map +0 -1
  121. package/dist/build/env-config.mjs +0 -17
  122. package/dist/build/env-config.mjs.map +0 -1
  123. package/dist/build/loaders/value-injection-loader.d.mts +0 -28
  124. package/dist/build/loaders/value-injection-loader.d.mts.map +0 -1
  125. package/dist/build/loaders/value-injection-loader.mjs +0 -44
  126. package/dist/build/loaders/value-injection-loader.mjs.map +0 -1
  127. package/dist/build/logger.d.mts +0 -11
  128. package/dist/build/logger.d.mts.map +0 -1
  129. package/dist/build/logger.mjs +0 -155
  130. package/dist/build/logger.mjs.map +0 -1
  131. package/dist/build/release-program.d.mts +0 -19
  132. package/dist/build/release-program.d.mts.map +0 -1
  133. package/dist/build/release-program.mjs +0 -92
  134. package/dist/build/release-program.mjs.map +0 -1
  135. package/dist/build/secret-key.d.mts +0 -10
  136. package/dist/build/secret-key.d.mts.map +0 -1
  137. package/dist/build/secret-key.mjs +0 -16
  138. package/dist/build/secret-key.mjs.map +0 -1
  139. package/dist/build/services/config.service.d.mts +0 -9
  140. package/dist/build/services/config.service.d.mts.map +0 -1
  141. package/dist/build/services/config.service.mjs +0 -8
  142. package/dist/build/services/config.service.mjs.map +0 -1
  143. package/dist/build/services/instrumentation-detection.service.d.mts +0 -22
  144. package/dist/build/services/instrumentation-detection.service.d.mts.map +0 -1
  145. package/dist/build/services/instrumentation-detection.service.mjs +0 -60
  146. package/dist/build/services/instrumentation-detection.service.mjs.map +0 -1
  147. package/dist/build/services/preflight.service.d.mts +0 -19
  148. package/dist/build/services/preflight.service.d.mts.map +0 -1
  149. package/dist/build/services/preflight.service.mjs +0 -76
  150. package/dist/build/services/preflight.service.mjs.map +0 -1
  151. package/dist/build/services/release-identity.service.d.mts +0 -22
  152. package/dist/build/services/release-identity.service.d.mts.map +0 -1
  153. package/dist/build/services/release-identity.service.mjs +0 -48
  154. package/dist/build/services/release-identity.service.mjs.map +0 -1
  155. package/dist/build/services/source-map.service.d.mts +0 -24
  156. package/dist/build/services/source-map.service.d.mts.map +0 -1
  157. package/dist/build/services/source-map.service.mjs +0 -58
  158. package/dist/build/services/source-map.service.mjs.map +0 -1
  159. package/dist/build/source-maps/api.d.mts +0 -35
  160. package/dist/build/source-maps/api.d.mts.map +0 -1
  161. package/dist/build/source-maps/api.mjs +0 -61
  162. package/dist/build/source-maps/api.mjs.map +0 -1
  163. package/dist/build/source-maps/client.d.mts +0 -73
  164. package/dist/build/source-maps/client.d.mts.map +0 -1
  165. package/dist/build/source-maps/client.mjs +0 -228
  166. package/dist/build/source-maps/client.mjs.map +0 -1
  167. package/dist/build/source-maps/errors.d.mts +0 -109
  168. package/dist/build/source-maps/errors.d.mts.map +0 -1
  169. package/dist/build/source-maps/errors.mjs +0 -22
  170. package/dist/build/source-maps/errors.mjs.map +0 -1
  171. package/dist/build/source-maps/files.d.mts +0 -35
  172. package/dist/build/source-maps/files.d.mts.map +0 -1
  173. package/dist/build/source-maps/files.mjs +0 -222
  174. package/dist/build/source-maps/files.mjs.map +0 -1
  175. package/dist/build/source-maps/providers/deployment/detector.d.mts +0 -26
  176. package/dist/build/source-maps/providers/deployment/detector.d.mts.map +0 -1
  177. package/dist/build/source-maps/providers/deployment/detector.mjs +0 -22
  178. package/dist/build/source-maps/providers/deployment/detector.mjs.map +0 -1
  179. package/dist/build/source-maps/providers/deployment/types.d.mts +0 -12
  180. package/dist/build/source-maps/providers/deployment/types.d.mts.map +0 -1
  181. package/dist/build/source-maps/providers/deployment/types.mjs +0 -3
  182. package/dist/build/source-maps/providers/deployment/vercel.d.mts +0 -6
  183. package/dist/build/source-maps/providers/deployment/vercel.d.mts.map +0 -1
  184. package/dist/build/source-maps/providers/deployment/vercel.mjs +0 -44
  185. package/dist/build/source-maps/providers/deployment/vercel.mjs.map +0 -1
  186. package/dist/build/source-maps/providers/source-control/detector.d.mts +0 -15
  187. package/dist/build/source-maps/providers/source-control/detector.d.mts.map +0 -1
  188. package/dist/build/source-maps/providers/source-control/detector.mjs +0 -22
  189. package/dist/build/source-maps/providers/source-control/detector.mjs.map +0 -1
  190. package/dist/build/source-maps/providers/source-control/git.d.mts +0 -6
  191. package/dist/build/source-maps/providers/source-control/git.d.mts.map +0 -1
  192. package/dist/build/source-maps/providers/source-control/git.mjs +0 -50
  193. package/dist/build/source-maps/providers/source-control/git.mjs.map +0 -1
  194. package/dist/build/source-maps/providers/source-control/types.d.mts +0 -12
  195. package/dist/build/source-maps/providers/source-control/types.d.mts.map +0 -1
  196. package/dist/build/source-maps/providers/source-control/types.mjs +0 -3
  197. package/dist/build/with-interfere.d.mts +0 -70
  198. package/dist/build/with-interfere.d.mts.map +0 -1
  199. package/dist/build/with-interfere.mjs +0 -154
  200. package/dist/build/with-interfere.mjs.map +0 -1
  201. package/dist/client/auto-init.d.mts +0 -92
  202. package/dist/client/auto-init.d.mts.map +0 -1
  203. package/dist/client/auto-init.mjs +0 -121
  204. package/dist/client/auto-init.mjs.map +0 -1
  205. package/dist/client/client.d.mts +0 -3
  206. package/dist/client/client.mjs +0 -5
  207. package/dist/client/provider.d.mts +0 -22
  208. package/dist/client/provider.d.mts.map +0 -1
  209. package/dist/client/provider.mjs +0 -50
  210. package/dist/client/provider.mjs.map +0 -1
  211. package/dist/lib/env.d.mts +0 -12
  212. package/dist/lib/env.d.mts.map +0 -1
  213. package/dist/lib/env.mjs +0 -17
  214. package/dist/lib/env.mjs.map +0 -1
  215. package/dist/lib/test-utils/make-next-request.d.mts +0 -6
  216. package/dist/lib/test-utils/make-next-request.d.mts.map +0 -1
  217. package/dist/lib/test-utils/make-next-request.mjs +0 -12
  218. package/dist/lib/test-utils/make-next-request.mjs.map +0 -1
  219. package/dist/lib/types.d.mts +0 -22
  220. package/dist/lib/types.d.mts.map +0 -1
  221. package/dist/lib/types.mjs +0 -7
  222. package/dist/lib/types.mjs.map +0 -1
  223. package/dist/server/middleware.d.mts +0 -11
  224. package/dist/server/middleware.d.mts.map +0 -1
  225. package/dist/server/middleware.mjs +0 -85
  226. package/dist/server/middleware.mjs.map +0 -1
  227. package/dist/server/proxy.d.mts +0 -6
  228. package/dist/server/proxy.d.mts.map +0 -1
  229. package/dist/server/proxy.mjs +0 -30
  230. package/dist/server/proxy.mjs.map +0 -1
  231. package/dist/server/route-handler.d.mts +0 -9
  232. package/dist/server/route-handler.d.mts.map +0 -1
  233. package/dist/server/route-handler.mjs +0 -172
  234. package/dist/server/route-handler.mjs.map +0 -1
  235. package/dist/server/services/config.service.d.mts +0 -21
  236. package/dist/server/services/config.service.d.mts.map +0 -1
  237. package/dist/server/services/config.service.mjs +0 -43
  238. package/dist/server/services/config.service.mjs.map +0 -1
  239. package/dist/server/services/error-tracking.service.d.mts +0 -19
  240. package/dist/server/services/error-tracking.service.d.mts.map +0 -1
  241. package/dist/server/services/error-tracking.service.mjs +0 -31
  242. package/dist/server/services/error-tracking.service.mjs.map +0 -1
package/README.md CHANGED
@@ -1,56 +1,80 @@
1
- # @interfere/next
2
-
3
- Official Next.js SDK for Interfere error monitoring and analytics.
4
-
5
- ## Installation
1
+ <p align="center">
2
+ <a href="https://interfere.com">
3
+ <picture>
4
+ <source media="(prefers-color-scheme: dark)" srcset="https://qyzkf4cgb8ydxtq1.public.blob.vercel-storage.com/v2/header/logo-dark.png">
5
+ <img src="https://qyzkf4cgb8ydxtq1.public.blob.vercel-storage.com/v2/header/logo-light.png" height="64">
6
+ </picture>
7
+ </a>
8
+ <h1 align="center">@interfere/next</h1>
9
+ </p>
10
+
11
+ <p align="center">
12
+ <a href="https://www.npmjs.com/package/@interfere/next"><img src="https://img.shields.io/npm/v/@interfere/next.svg" /></a>
13
+ <a href="https://github.com/interfere-inc/interfere/blob/main/LICENSE"><img src="https://img.shields.io/npm/l/@interfere/next.svg" /></a>
14
+ <a href="https://www.npmjs.com/package/@interfere/next"><img src="https://img.shields.io/npm/dm/@interfere/next.svg" /></a>
15
+ </p>
16
+
17
+ <p align="center">
18
+ Next.js SDK for <a href="https://interfere.com">Interfere</a> — error tracking, session replay, and analytics for modern product teams.
19
+ </p>
20
+
21
+ <p align="center">
22
+ <a href="https://interfere.com/docs">Documentation</a>
23
+ ·
24
+ <a href="https://github.com/interfere-inc/interfere/issues/new">Report a Bug</a>
25
+ ·
26
+ <a href="mailto:support@interfere.com">Get Help</a>
27
+ </p>
28
+
29
+ ---
30
+
31
+ ## Getting Started
32
+
33
+ ### Prerequisites
34
+
35
+ - Next.js `>=16`
36
+ - React `>=19`
37
+ - Node.js `>=20`
38
+
39
+ ### Installation
6
40
 
7
41
  ```bash
8
42
  npm install @interfere/next
9
- # or
10
- yarn add @interfere/next
11
- # or
12
- pnpm add @interfere/next
13
43
  ```
14
44
 
15
- ## Quick Start
45
+ ### Quick Start
16
46
 
17
- ### 1. Initialize the SDK
47
+ **1. Wrap your Next.js config**
18
48
 
19
- Create a file to initialize Interfere (e.g., `lib/interfere.ts`):
49
+ ```ts
50
+ // next.config.ts
51
+ import { withInterfere } from "@interfere/next/config";
52
+ import type { NextConfig } from "next";
20
53
 
21
- ```typescript
22
- import { init } from '@interfere/next';
54
+ const config: NextConfig = {};
23
55
 
24
- export const interfere = init({
25
- project: process.env.NEXT_PUBLIC_INTERFERE_PROJECT_ID!,
26
- options: {
27
- env: process.env.NODE_ENV as 'development' | 'preview' | 'production',
28
- debug: process.env.NODE_ENV === 'development',
29
- },
30
- });
56
+ export default withInterfere(config);
31
57
  ```
32
58
 
33
- ### 2. Add the Proxy Route
34
-
35
- The SDK sends events through a server-side proxy route to keep your API credentials secure. Create `app/api/interfere/[[...path]]/route.ts`:
59
+ **2. Wire instrumentation**
36
60
 
37
- ```typescript
38
- export { GET, OPTIONS, POST } from '@interfere/next/route-handler';
61
+ ```ts
62
+ // instrumentation.ts
63
+ export { onRequestError } from "@interfere/next/server";
39
64
  ```
40
65
 
41
- This route proxies client-side events to Interfere's ingest API using your `INTERFERE_SECRET_KEY` environment variable. Add the key to your `.env.local`:
66
+ **3. Mount the ingest route**
42
67
 
43
- ```bash
44
- INTERFERE_SECRET_KEY=if_sk_xxx
68
+ ```ts
69
+ // app/api/interfere/[[...path]]/route.ts
70
+ export { GET, POST, OPTIONS } from "@interfere/next/route-handler";
45
71
  ```
46
72
 
47
- ### 3. Add Error Boundary (App Directory)
48
-
49
- In your root layout (`app/layout.tsx`):
73
+ **4. Add the provider**
50
74
 
51
75
  ```tsx
52
- import { InterfereProvider, InterfereErrorBoundary } from '@interfere/next';
53
- import { interfere } from '@/lib/interfere';
76
+ // app/layout.tsx
77
+ import { InterfereProvider } from "@interfere/next/provider";
54
78
 
55
79
  export default function RootLayout({
56
80
  children,
@@ -60,258 +84,27 @@ export default function RootLayout({
60
84
  return (
61
85
  <html lang="en">
62
86
  <body>
63
- <InterfereProvider>
64
- <InterfereErrorBoundary>
65
- {children}
66
- </InterfereErrorBoundary>
67
- </InterfereProvider>
68
- </body>
69
- </html>
70
- );
71
- }
72
- ```
73
-
74
- ### 4. Add Error Handler (App Directory)
75
-
76
- Create `app/error.tsx`:
77
-
78
- ```tsx
79
- 'use client';
80
-
81
- import { useEffect } from 'react';
82
- import { captureErrorBoundaryError } from '@interfere/next';
83
-
84
- export default function Error({
85
- error,
86
- reset,
87
- }: {
88
- error: Error & { digest?: string };
89
- reset: () => void;
90
- }) {
91
- useEffect(() => {
92
- captureErrorBoundaryError(error, {
93
- componentStack: error.stack || '',
94
- });
95
- }, [error]);
96
-
97
- return (
98
- <div>
99
- <h2>Something went wrong!</h2>
100
- <button onClick={() => reset()}>Try again</button>
101
- </div>
102
- );
103
- }
104
- ```
105
-
106
- ### 5. Add Global Error Handler
107
-
108
- Create `app/global-error.tsx`:
109
-
110
- ```tsx
111
- 'use client';
112
-
113
- import { createInterfereErrorHandler } from '@interfere/next';
114
-
115
- const errorHandler = createInterfereErrorHandler();
116
-
117
- export default function GlobalError({
118
- error,
119
- reset,
120
- }: {
121
- error: Error & { digest?: string };
122
- reset: () => void;
123
- }) {
124
- errorHandler(error, { digest: error.digest });
125
-
126
- return (
127
- <html>
128
- <body>
129
- <h2>Something went wrong!</h2>
130
- <button onClick={() => reset()}>Try again</button>
87
+ <InterfereProvider>{children}</InterfereProvider>
131
88
  </body>
132
89
  </html>
133
90
  );
134
91
  }
135
92
  ```
136
93
 
137
- ## API Routes
138
-
139
- ### Automatic Error Capture
140
-
141
- Wrap your API route handlers:
142
-
143
- ```typescript
144
- // app/api/users/route.ts
145
- import { withInterfereApiRoute } from '@interfere/next';
146
-
147
- export const GET = withInterfereApiRoute(async (request) => {
148
- // Your API logic here
149
- const users = await fetchUsers();
150
- return Response.json(users);
151
- });
152
- ```
153
-
154
- ### Manual Error Capture
155
-
156
- ```typescript
157
- // app/api/webhook/route.ts
158
- import { captureServerError } from '@interfere/next';
159
-
160
- export async function POST(request: Request) {
161
- try {
162
- const body = await request.json();
163
- // Process webhook
164
- } catch (error) {
165
- captureServerError(error, request, {
166
- pathname: '/api/webhook',
167
- type: 'webhook_error',
168
- });
169
- return Response.json({ error: 'Webhook failed' }, { status: 500 });
170
- }
171
- }
172
- ```
173
-
174
- ## Middleware
175
-
176
- Wrap your middleware to capture errors:
177
-
178
- ```typescript
179
- // middleware.ts
180
- import { withInterfereMiddleware } from '@interfere/next';
181
- import { NextResponse } from 'next/server';
182
-
183
- export default withInterfereMiddleware(async (request) => {
184
- // Your middleware logic
185
- return NextResponse.next();
186
- });
187
-
188
- export const config = {
189
- matcher: '/api/:path*',
190
- };
191
- ```
192
-
193
- ## Server Components
194
-
195
- Wrap async server components:
196
-
197
- ```typescript
198
- // app/dashboard/page.tsx
199
- import { withInterfereServerComponent } from '@interfere/next';
200
-
201
- async function DashboardPage() {
202
- const data = await fetchDashboardData();
203
- return <Dashboard data={data} />;
204
- }
205
-
206
- export default withInterfereServerComponent(DashboardPage, 'DashboardPage');
207
- ```
208
-
209
- ## Custom Event Capture
210
-
211
- Capture custom events and errors:
212
-
213
- ```typescript
214
- import { capture, captureServerError } from '@interfere/next';
215
-
216
- // Capture custom events
217
- capture('custom', {
218
- action: 'user_signup',
219
- userId: user.id,
220
- plan: 'premium',
221
- });
222
-
223
- // Capture handled errors
224
- try {
225
- await riskyOperation();
226
- } catch (error) {
227
- captureServerError(error, undefined, {
228
- operation: 'risky_operation',
229
- context: { userId: user.id },
230
- });
231
- }
232
- ```
233
-
234
- ## React Hook
94
+ ### Environment Variables
235
95
 
236
- Use the `useInterfere` hook in client components:
96
+ | Variable | Required | Description |
97
+ | --- | --- | --- |
98
+ | `INTERFERE_API_KEY` | Yes | Your project API key |
237
99
 
238
- ```tsx
239
- 'use client';
240
-
241
- import { useInterfere } from '@interfere/next';
242
-
243
- export function Button() {
244
- const { capture } = useInterfere();
245
-
246
- const handleClick = () => {
247
- capture('ui_event', {
248
- action: 'button_click',
249
- label: 'cta_button',
250
- });
251
- };
252
-
253
- return <button onClick={handleClick}>Click me</button>;
254
- }
255
- ```
256
-
257
- ## Configuration Options
258
-
259
- ```typescript
260
- init({
261
- project: 'if_proj_xxx', // Your project ID
262
- options: {
263
- env: 'production', // 'development' | 'preview' | 'production'
264
- flushInterval: 5000, // Flush interval in ms (client-side only)
265
- debug: false, // Enable debug logging
266
- sessionId: 'custom-session-id', // Optional custom session ID
267
- },
268
- });
269
- ```
270
-
271
- ## Event Types
100
+ ## What's Included
272
101
 
273
- The SDK automatically captures these event types:
274
-
275
- - `error` - Runtime errors (client, server, and edge); origin is indicated by `errorSource` in the payload (`client` | `server` | `edge`).
276
- - `ui_event` - User interface events
277
- - `custom` - Custom application events
278
- - `rage_click` - rage clicks
279
-
280
- ## Best Practices
281
-
282
- 1. **Initialize Early**: Initialize Interfere as early as possible in your application lifecycle.
283
-
284
- 2. **Use Error Boundaries**: Always wrap your app with `InterfereErrorBoundary` to catch React errors.
285
-
286
- 3. **Wrap Async Functions**: Use `withErrorCapture` or specific wrappers for automatic error tracking.
287
-
288
- 4. **Add Context**: Include relevant context when capturing errors manually:
289
- ```typescript
290
- captureServerError(error, request, {
291
- userId: session.userId,
292
- action: 'update_profile',
293
- metadata: { ... },
294
- });
295
- ```
296
-
297
- 5. **Environment Variables**: Store your project ID in environment variables:
298
- ```bash
299
- NEXT_PUBLIC_INTERFERE_PROJECT_ID=if_proj_xxx
300
- ```
301
-
302
- ## TypeScript
303
-
304
- The SDK is fully typed. Import types as needed:
305
-
306
- ```typescript
307
- import type {
308
- Config,
309
- InitConfig,
310
- EventType,
311
- Envelope,
312
- } from '@interfere/next';
313
- ```
102
+ - **Error tracking** automatic capture of server and client errors with rich stack traces
103
+ - **Session replay** — full visual playback of user sessions
104
+ - **Source maps** automatic upload during production builds
105
+ - **Release tracking** links builds to Git commits and deployments
106
+ - **Server capture** — `captureError()` for manual server-side error reporting
314
107
 
315
108
  ## License
316
109
 
317
- MIT
110
+ MIT
@@ -0,0 +1,13 @@
1
+ //#region \0rolldown/runtime.js
2
+ var __defProp = Object.defineProperty;
3
+ var __exportAll = (all, no_symbols) => {
4
+ let target = {};
5
+ for (var name in all) __defProp(target, name, {
6
+ get: all[name],
7
+ enumerable: true
8
+ });
9
+ if (!no_symbols) __defProp(target, Symbol.toStringTag, { value: "Module" });
10
+ return target;
11
+ };
12
+ //#endregion
13
+ export { __exportAll };
@@ -0,0 +1,11 @@
1
+ import { Envelope } from "@interfere/types/sdk/envelope";
2
+ import { NextConfig } from "next";
3
+
4
+ //#region src/config.d.ts
5
+ interface InterfereConfig extends Partial<Pick<Envelope, "buildId" | "releaseId">> {}
6
+ type NextConfigWithInterfere = NextConfig & {
7
+ interfere?: InterfereConfig;
8
+ };
9
+ declare function withInterfere(nextConfig?: NextConfigWithInterfere): NextConfig;
10
+ //#endregion
11
+ export { InterfereConfig, NextConfigWithInterfere, withInterfere };
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config.d.mts","names":[],"sources":["../src/config.ts"],"mappings":";;;;UAeiB,eAAA,SACP,OAAA,CAAQ,IAAA,CAAK,QAAA;AAAA,KAEX,uBAAA,GAA0B,UAAA;EACpC,SAAA,GAAY,eAAA;AAAA;AAAA,iBAUE,aAAA,CACd,UAAA,GAAY,uBAAA,GACX,UAAA"}
@@ -0,0 +1,107 @@
1
+ import { configureBuild } from "./internal/build/configure-build.mjs";
2
+ import { buildInjectedValues } from "./internal/build/injected.mjs";
3
+ import { log } from "./internal/logger.mjs";
4
+ import { runGitCommand } from "./internal/build/release/git.mjs";
5
+ import { readInterfereEnv } from "./internal/env.mjs";
6
+ import { releaseDestinationIdEnvKeys, releaseSourceIdEnvKeys } from "@interfere/types/integrations";
7
+ import { parseEnvValue, readFirstEnvValue } from "@interfere/types/sdk/env";
8
+ //#region src/config.ts
9
+ function withInterfere(nextConfig = {}) {
10
+ const { interfere, env: userEnv, webpack, turbopack, compiler, productionBrowserSourceMaps, ...rest } = nextConfig;
11
+ const config = resolveBuildConfig(interfere);
12
+ const build = configureBuild({
13
+ existingWebpack: webpack,
14
+ existingTurbopack: turbopack,
15
+ projectDir: process.cwd(),
16
+ values: buildInjectedValues(config)
17
+ });
18
+ if (config.apiKey !== null && !build.webpack && !build.turbopack) throw new Error("[Interfere] 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. See: https://interfere.com/docs/nextjs/setup");
19
+ const existingHook = compiler?.runAfterProductionCompile;
20
+ return {
21
+ ...rest,
22
+ env: mergeEnvConfig(userEnv, config),
23
+ compiler: {
24
+ ...compiler ?? {},
25
+ async runAfterProductionCompile(context) {
26
+ if (existingHook) await existingHook(context);
27
+ await runBuildReleasePipeline(context, config);
28
+ }
29
+ },
30
+ webpack: build.webpack,
31
+ turbopack: build.turbopack,
32
+ productionBrowserSourceMaps: config.apiKey !== null ? true : productionBrowserSourceMaps
33
+ };
34
+ }
35
+ function resolveBuildConfig(interfere) {
36
+ const { apiKey, apiUrl } = readInterfereEnv();
37
+ const buildId = parseEnvValue(interfere?.buildId) ?? readFirstEnvValue(process.env, releaseSourceIdEnvKeys) ?? runGitCommand("git rev-parse HEAD");
38
+ return {
39
+ apiKey,
40
+ apiUrl,
41
+ buildId,
42
+ releaseId: parseEnvValue(interfere?.releaseId) ?? readFirstEnvValue(process.env, releaseDestinationIdEnvKeys) ?? buildId
43
+ };
44
+ }
45
+ function mergeEnvConfig(userEnv, config) {
46
+ const merged = {};
47
+ if (config.buildId !== null) merged.NEXT_PUBLIC_INTERFERE_BUILD_ID = config.buildId;
48
+ if (config.releaseId !== null) merged.NEXT_PUBLIC_INTERFERE_RELEASE_ID = config.releaseId;
49
+ return {
50
+ ...merged,
51
+ ...userEnv
52
+ };
53
+ }
54
+ async function runBuildReleasePipeline(context, config) {
55
+ const { apiKey, apiUrl, buildId } = config;
56
+ if (apiKey === null) throw new Error("[Interfere] INTERFERE_API_KEY is not set. withInterfere() requires an API key to upload source maps during production builds. Set the INTERFERE_API_KEY environment variable, or remove withInterfere() from your Next.js config. See: https://interfere.com/docs/nextjs/setup");
57
+ if (buildId === null) {
58
+ log.error("Build ID missing", [
59
+ "Could not resolve a build ID from config, environment variables, or git.",
60
+ "Source maps will not be uploaded and errors will have unresolved stack traces.",
61
+ "Set INTERFERE_BUILD_ID, or ensure git is available in your build environment."
62
+ ]);
63
+ return;
64
+ }
65
+ const { createRelease } = await import("./internal/build/release/index.mjs");
66
+ const { runSourceMapPipeline } = await import("./internal/build/source-maps/index.mjs");
67
+ const client = {
68
+ async createRelease() {
69
+ const release = await createRelease(apiKey, apiUrl, buildId);
70
+ return {
71
+ slug: release.destination.slug,
72
+ orgSlug: release.org.slug,
73
+ buildId: release.build.hash ?? buildId
74
+ };
75
+ },
76
+ async uploadSourceMaps(releaseSlug, body) {
77
+ const url = `${apiUrl}/v1/releases/${releaseSlug}/source-maps`;
78
+ const response = await fetch(url, {
79
+ method: "POST",
80
+ headers: { "x-api-key": apiKey },
81
+ body
82
+ });
83
+ if (!response.ok) {
84
+ const text = await response.text().catch(() => "");
85
+ throw new Error(`Source map upload failed: ${response.status} ${response.statusText} ${text}`);
86
+ }
87
+ }
88
+ };
89
+ try {
90
+ const result = await runSourceMapPipeline(context.projectDir, context.distDir, client);
91
+ if (!result.ready) {
92
+ log.warn("Skipping", ["No source maps found"]);
93
+ return;
94
+ }
95
+ log.info("Completed", [
96
+ `https://interfere.com/~/${result.orgSlug}`,
97
+ `Release: ${result.releaseSlug}`,
98
+ `Build: ${result.buildId}`,
99
+ `Artifacts: ${result.fileCount} source maps`
100
+ ]);
101
+ } catch (error) {
102
+ log.error("Error", [error instanceof Error ? error.message : String(error)]);
103
+ throw error;
104
+ }
105
+ }
106
+ //#endregion
107
+ export { withInterfere };
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config.mjs","names":[],"sources":["../src/config.ts"],"sourcesContent":["import {\n releaseDestinationIdEnvKeys,\n releaseSourceIdEnvKeys,\n} from \"@interfere/types/integrations\";\nimport { parseEnvValue, readFirstEnvValue } from \"@interfere/types/sdk/env\";\nimport type { Envelope } from \"@interfere/types/sdk/envelope\";\n\nimport type { NextConfig } from \"next\";\n\nimport { configureBuild } from \"./internal/build/configure-build.js\";\nimport { buildInjectedValues } from \"./internal/build/injected.js\";\nimport { runGitCommand } from \"./internal/build/release/git.js\";\nimport { readInterfereEnv } from \"./internal/env.js\";\nimport { log } from \"./internal/logger.js\";\n\nexport interface InterfereConfig\n extends Partial<Pick<Envelope, \"buildId\" | \"releaseId\">> {}\n\nexport type NextConfigWithInterfere = NextConfig & {\n interfere?: InterfereConfig;\n};\n\ninterface ResolvedBuildConfig {\n readonly apiKey: string | null;\n readonly apiUrl: string;\n readonly buildId: string | null;\n readonly releaseId: string | null;\n}\n\nexport function withInterfere(\n nextConfig: NextConfigWithInterfere = {}\n): NextConfig {\n const {\n interfere,\n env: userEnv,\n webpack,\n turbopack,\n compiler,\n productionBrowserSourceMaps,\n ...rest\n } = nextConfig;\n\n const config = resolveBuildConfig(interfere);\n const build = configureBuild({\n existingWebpack: webpack,\n existingTurbopack: turbopack,\n projectDir: process.cwd(),\n values: buildInjectedValues(config),\n });\n\n if (config.apiKey !== null && !build.webpack && !build.turbopack) {\n throw new Error(\n \"[Interfere] 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 \"See: https://interfere.com/docs/nextjs/setup\"\n );\n }\n\n const existingHook = (compiler as NextCompilerWithProductionHook | undefined)\n ?.runAfterProductionCompile;\n\n return {\n ...rest,\n env: mergeEnvConfig(userEnv, config),\n compiler: {\n ...(compiler ?? {}),\n async runAfterProductionCompile(context: ProductionCompileContext) {\n if (existingHook) {\n await existingHook(context);\n }\n\n await runBuildReleasePipeline(context, config);\n },\n } as NextConfig[\"compiler\"],\n webpack: build.webpack,\n turbopack: build.turbopack,\n productionBrowserSourceMaps:\n config.apiKey !== null ? true : productionBrowserSourceMaps,\n };\n}\n\nfunction resolveBuildConfig(interfere?: InterfereConfig): ResolvedBuildConfig {\n const { apiKey, apiUrl } = readInterfereEnv();\n\n const buildId =\n parseEnvValue(interfere?.buildId) ??\n readFirstEnvValue(process.env, releaseSourceIdEnvKeys) ??\n runGitCommand(\"git rev-parse HEAD\");\n const releaseId =\n parseEnvValue(interfere?.releaseId) ??\n readFirstEnvValue(process.env, releaseDestinationIdEnvKeys) ??\n buildId;\n\n return { apiKey, apiUrl, buildId, releaseId };\n}\n\nfunction mergeEnvConfig(\n userEnv: NextConfig[\"env\"] | undefined,\n config: ResolvedBuildConfig\n): NextConfig[\"env\"] {\n const merged: Record<string, string> = {};\n\n if (config.buildId !== null) {\n merged.NEXT_PUBLIC_INTERFERE_BUILD_ID = config.buildId;\n }\n\n if (config.releaseId !== null) {\n merged.NEXT_PUBLIC_INTERFERE_RELEASE_ID = config.releaseId;\n }\n\n return { ...merged, ...userEnv };\n}\n\ninterface 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, apiUrl, buildId } = config;\n\n if (apiKey === null) {\n throw new Error(\n \"[Interfere] INTERFERE_API_KEY is 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://interfere.com/docs/nextjs/setup\"\n );\n }\n\n if (buildId === null) {\n log.error(\"Build ID missing\", [\n \"Could not resolve a build ID from config, environment variables, or git.\",\n \"Source maps will not be uploaded and errors will have unresolved stack traces.\",\n \"Set INTERFERE_BUILD_ID, or ensure git is available in your build environment.\",\n ]);\n return;\n }\n\n const { createRelease } = await import(\"./internal/build/release/index.js\");\n const { runSourceMapPipeline } = await import(\n \"./internal/build/source-maps/index.js\"\n );\n\n const client: import(\"./internal/build/source-maps/index.js\").BuildClient = {\n async createRelease() {\n const release = await createRelease(apiKey, apiUrl, buildId);\n return {\n slug: release.destination.slug,\n orgSlug: release.org.slug,\n buildId: release.build.hash ?? buildId,\n };\n },\n async uploadSourceMaps(releaseSlug, body) {\n const url = `${apiUrl}/v1/releases/${releaseSlug}/source-maps`;\n const response = await fetch(url, {\n method: \"POST\",\n headers: { \"x-api-key\": apiKey },\n body,\n });\n\n if (!response.ok) {\n const text = await response.text().catch(() => \"\");\n throw new Error(\n `Source map upload failed: ${response.status} ${response.statusText} ${text}`\n );\n }\n },\n };\n\n try {\n const result = await runSourceMapPipeline(\n context.projectDir,\n context.distDir,\n client\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.orgSlug}`,\n `Release: ${result.releaseSlug}`,\n `Build: ${result.buildId}`,\n `Artifacts: ${result.fileCount} source maps`,\n ]);\n } catch (error) {\n log.error(\"Error\", [\n error instanceof Error ? error.message : String(error),\n ]);\n throw error;\n }\n}\n"],"mappings":";;;;;;;;AA6BA,SAAgB,cACd,aAAsC,EAAE,EAC5B;CACZ,MAAM,EACJ,WACA,KAAK,SACL,SACA,WACA,UACA,6BACA,GAAG,SACD;CAEJ,MAAM,SAAS,mBAAmB,UAAU;CAC5C,MAAM,QAAQ,eAAe;EAC3B,iBAAiB;EACjB,mBAAmB;EACnB,YAAY,QAAQ,KAAK;EACzB,QAAQ,oBAAoB,OAAO;EACpC,CAAC;AAEF,KAAI,OAAO,WAAW,QAAQ,CAAC,MAAM,WAAW,CAAC,MAAM,UACrD,OAAM,IAAI,MACR,mNAGD;CAGH,MAAM,eAAgB,UAClB;AAEJ,QAAO;EACL,GAAG;EACH,KAAK,eAAe,SAAS,OAAO;EACpC,UAAU;GACR,GAAI,YAAY,EAAE;GAClB,MAAM,0BAA0B,SAAmC;AACjE,QAAI,aACF,OAAM,aAAa,QAAQ;AAG7B,UAAM,wBAAwB,SAAS,OAAO;;GAEjD;EACD,SAAS,MAAM;EACf,WAAW,MAAM;EACjB,6BACE,OAAO,WAAW,OAAO,OAAO;EACnC;;AAGH,SAAS,mBAAmB,WAAkD;CAC5E,MAAM,EAAE,QAAQ,WAAW,kBAAkB;CAE7C,MAAM,UACJ,cAAc,WAAW,QAAQ,IACjC,kBAAkB,QAAQ,KAAK,uBAAuB,IACtD,cAAc,qBAAqB;AAMrC,QAAO;EAAE;EAAQ;EAAQ;EAAS,WAJhC,cAAc,WAAW,UAAU,IACnC,kBAAkB,QAAQ,KAAK,4BAA4B,IAC3D;EAE2C;;AAG/C,SAAS,eACP,SACA,QACmB;CACnB,MAAM,SAAiC,EAAE;AAEzC,KAAI,OAAO,YAAY,KACrB,QAAO,iCAAiC,OAAO;AAGjD,KAAI,OAAO,cAAc,KACvB,QAAO,mCAAmC,OAAO;AAGnD,QAAO;EAAE,GAAG;EAAQ,GAAG;EAAS;;AAclC,eAAe,wBACb,SACA,QACe;CACf,MAAM,EAAE,QAAQ,QAAQ,YAAY;AAEpC,KAAI,WAAW,KACb,OAAM,IAAI,MACR,iRAID;AAGH,KAAI,YAAY,MAAM;AACpB,MAAI,MAAM,oBAAoB;GAC5B;GACA;GACA;GACD,CAAC;AACF;;CAGF,MAAM,EAAE,kBAAkB,MAAM,OAAO;CACvC,MAAM,EAAE,yBAAyB,MAAM,OACrC;CAGF,MAAM,SAAsE;EAC1E,MAAM,gBAAgB;GACpB,MAAM,UAAU,MAAM,cAAc,QAAQ,QAAQ,QAAQ;AAC5D,UAAO;IACL,MAAM,QAAQ,YAAY;IAC1B,SAAS,QAAQ,IAAI;IACrB,SAAS,QAAQ,MAAM,QAAQ;IAChC;;EAEH,MAAM,iBAAiB,aAAa,MAAM;GACxC,MAAM,MAAM,GAAG,OAAO,eAAe,YAAY;GACjD,MAAM,WAAW,MAAM,MAAM,KAAK;IAChC,QAAQ;IACR,SAAS,EAAE,aAAa,QAAQ;IAChC;IACD,CAAC;AAEF,OAAI,CAAC,SAAS,IAAI;IAChB,MAAM,OAAO,MAAM,SAAS,MAAM,CAAC,YAAY,GAAG;AAClD,UAAM,IAAI,MACR,6BAA6B,SAAS,OAAO,GAAG,SAAS,WAAW,GAAG,OACxE;;;EAGN;AAED,KAAI;EACF,MAAM,SAAS,MAAM,qBACnB,QAAQ,YACR,QAAQ,SACR,OACD;AAED,MAAI,CAAC,OAAO,OAAO;AACjB,OAAI,KAAK,YAAY,CAAC,uBAAuB,CAAC;AAC9C;;AAGF,MAAI,KAAK,aAAa;GACpB,2BAA2B,OAAO;GAClC,YAAY,OAAO;GACnB,UAAU,OAAO;GACjB,cAAc,OAAO,UAAU;GAChC,CAAC;UACK,OAAO;AACd,MAAI,MAAM,SAAS,CACjB,iBAAiB,QAAQ,MAAM,UAAU,OAAO,MAAM,CACvD,CAAC;AACF,QAAM"}
@@ -0,0 +1,2 @@
1
+ import { init } from "@interfere/react/internal/client";
2
+ export { init };
@@ -0,0 +1,2 @@
1
+ import { init } from "@interfere/react/internal/client";
2
+ export { init };
@@ -0,0 +1,22 @@
1
+ import { InterfereInjectedValues } from "./injected.mjs";
2
+ import { NextConfig } from "next";
3
+
4
+ //#region src/internal/build/configure-build.d.ts
5
+ interface ConfigureBuildInput {
6
+ readonly existingWebpack: NextConfig["webpack"] | undefined;
7
+ readonly existingTurbopack: NextConfig["turbopack"] | undefined;
8
+ readonly projectDir: string;
9
+ readonly values: InterfereInjectedValues;
10
+ }
11
+ interface ConfigureBuildOutput {
12
+ readonly webpack: NextConfig["webpack"] | undefined;
13
+ readonly turbopack: NextConfig["turbopack"] | undefined;
14
+ }
15
+ declare function configureBuild({
16
+ existingWebpack,
17
+ existingTurbopack,
18
+ projectDir,
19
+ values
20
+ }: ConfigureBuildInput): ConfigureBuildOutput;
21
+ //#endregion
22
+ export { configureBuild };
@@ -0,0 +1 @@
1
+ {"version":3,"file":"configure-build.d.mts","names":[],"sources":["../../../src/internal/build/configure-build.ts"],"mappings":";;;;UAyBU,mBAAA;EAAA,SACC,eAAA,EAAiB,UAAA;EAAA,SACjB,iBAAA,EAAmB,UAAA;EAAA,SACnB,UAAA;EAAA,SACA,MAAA,EAAQ,uBAAA;AAAA;AAAA,UAGT,oBAAA;EAAA,SACC,OAAA,EAAS,UAAA;EAAA,SACT,SAAA,EAAW,UAAA;AAAA;AAAA,iBAGN,cAAA,CAAA;EACd,eAAA;EACA,iBAAA;EACA,UAAA;EACA;AAAA,GACC,mBAAA,GAAsB,oBAAA"}
@@ -0,0 +1,87 @@
1
+ import { existsSync } from "node:fs";
2
+ import { basename, dirname, join, normalize, resolve } from "node:path";
3
+ import { fileURLToPath } from "node:url";
4
+ //#region src/internal/build/configure-build.ts
5
+ const INSTRUMENTATION_CLIENT_FILES = [
6
+ "instrumentation-client.ts",
7
+ "instrumentation-client.tsx",
8
+ "instrumentation-client.js",
9
+ "instrumentation-client.jsx",
10
+ "src/instrumentation-client.ts",
11
+ "src/instrumentation-client.tsx",
12
+ "src/instrumentation-client.js",
13
+ "src/instrumentation-client.jsx"
14
+ ];
15
+ const LOADER_FILE_CANDIDATES = [
16
+ "value-injection-loader.ts",
17
+ "value-injection-loader.js",
18
+ "value-injection-loader.mjs",
19
+ "value-injection-loader.cjs"
20
+ ];
21
+ function configureBuild({ existingWebpack, existingTurbopack, projectDir, values }) {
22
+ const instrumentationClientPath = resolveInstrumentationClientPath(projectDir);
23
+ return {
24
+ webpack: buildWebpackHook(existingWebpack, instrumentationClientPath, values),
25
+ turbopack: buildTurbopackConfig(existingTurbopack, instrumentationClientPath, values)
26
+ };
27
+ }
28
+ function hasInjectedMetadata(metadata) {
29
+ return metadata.__INTERFERE_BUILD_ID__ !== null || metadata.__INTERFERE_RELEASE_ID__ !== null;
30
+ }
31
+ function buildWebpackHook(existingWebpack, instrumentationClientPath, values) {
32
+ if (!(instrumentationClientPath && hasInjectedMetadata(values))) return existingWebpack;
33
+ const normalizedPath = normalize(instrumentationClientPath);
34
+ const loaderPath = resolveLoaderPath();
35
+ return (webpackConfig, options) => {
36
+ const outputConfig = existingWebpack ? existingWebpack(webpackConfig, options) : webpackConfig;
37
+ const mutableConfig = outputConfig;
38
+ const injectionRule = {
39
+ test: (resource) => Boolean(resource) && normalize(resource) === normalizedPath,
40
+ use: [{
41
+ loader: loaderPath,
42
+ options: { values }
43
+ }]
44
+ };
45
+ mutableConfig.module ??= {};
46
+ mutableConfig.module.rules ??= [];
47
+ mutableConfig.module.rules.push(injectionRule);
48
+ return outputConfig;
49
+ };
50
+ }
51
+ function buildTurbopackConfig(existingTurbopack, instrumentationClientPath, values) {
52
+ if (!(instrumentationClientPath && hasInjectedMetadata(values))) return existingTurbopack;
53
+ const baseConfig = existingTurbopack ?? {};
54
+ const ruleKey = `**/${basename(instrumentationClientPath)}`;
55
+ const existingRule = baseConfig.rules?.[ruleKey] ?? {};
56
+ const existingLoaders = Array.isArray(existingRule.loaders) ? existingRule.loaders : [];
57
+ return {
58
+ ...baseConfig,
59
+ rules: {
60
+ ...baseConfig.rules,
61
+ [ruleKey]: {
62
+ ...existingRule,
63
+ loaders: [...existingLoaders, {
64
+ loader: resolveLoaderPath(),
65
+ options: { serializedValues: JSON.stringify(values) }
66
+ }]
67
+ }
68
+ }
69
+ };
70
+ }
71
+ function resolveInstrumentationClientPath(projectDir) {
72
+ for (const candidate of INSTRUMENTATION_CLIENT_FILES) {
73
+ const filePath = resolve(projectDir, candidate);
74
+ if (existsSync(filePath)) return filePath;
75
+ }
76
+ return null;
77
+ }
78
+ function resolveLoaderPath() {
79
+ const directory = resolve(dirname(fileURLToPath(import.meta.url)));
80
+ for (const candidate of LOADER_FILE_CANDIDATES) {
81
+ const filePath = join(directory, candidate);
82
+ if (existsSync(filePath)) return filePath;
83
+ }
84
+ return join(directory, "value-injection-loader.js");
85
+ }
86
+ //#endregion
87
+ export { configureBuild };