@interfere/next 0.0.15-alpha.8 → 0.1.0-alpha.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 (214) hide show
  1. package/README.md +57 -266
  2. package/dist/config.d.mts +11 -0
  3. package/dist/config.d.mts.map +1 -0
  4. package/dist/config.mjs +105 -0
  5. package/dist/config.mjs.map +1 -0
  6. package/dist/internal/build/configure-build.d.mts +22 -0
  7. package/dist/internal/build/configure-build.d.mts.map +1 -0
  8. package/dist/internal/build/configure-build.mjs +87 -0
  9. package/dist/internal/build/configure-build.mjs.map +1 -0
  10. package/dist/internal/build/injected.d.mts +11 -0
  11. package/dist/internal/build/injected.d.mts.map +1 -0
  12. package/dist/internal/build/injected.mjs +9 -0
  13. package/dist/internal/build/injected.mjs.map +1 -0
  14. package/dist/internal/build/logger.d.mts +8 -0
  15. package/dist/internal/build/logger.d.mts.map +1 -0
  16. package/dist/internal/build/logger.mjs +44 -0
  17. package/dist/internal/build/logger.mjs.map +1 -0
  18. package/dist/internal/build/release.d.mts +9 -0
  19. package/dist/internal/build/release.d.mts.map +1 -0
  20. package/dist/internal/build/release.mjs +66 -0
  21. package/dist/internal/build/release.mjs.map +1 -0
  22. package/dist/internal/build/source-maps/discover.d.mts +14 -0
  23. package/dist/internal/build/source-maps/discover.d.mts.map +1 -0
  24. package/dist/internal/build/source-maps/discover.mjs +59 -0
  25. package/dist/internal/build/source-maps/discover.mjs.map +1 -0
  26. package/dist/internal/build/source-maps/index.d.mts +23 -0
  27. package/dist/internal/build/source-maps/index.d.mts.map +1 -0
  28. package/dist/internal/build/source-maps/index.mjs +33 -0
  29. package/dist/internal/build/source-maps/index.mjs.map +1 -0
  30. package/dist/internal/build/value-injection-loader.d.mts +10 -0
  31. package/dist/internal/build/value-injection-loader.d.mts.map +1 -0
  32. package/dist/internal/build/value-injection-loader.mjs +24 -0
  33. package/dist/internal/build/value-injection-loader.mjs.map +1 -0
  34. package/dist/internal/env.d.mts +15 -0
  35. package/dist/internal/env.d.mts.map +1 -0
  36. package/dist/internal/env.mjs +19 -0
  37. package/dist/internal/env.mjs.map +1 -0
  38. package/dist/internal/route/cors.d.mts +4 -0
  39. package/dist/internal/route/cors.d.mts.map +1 -0
  40. package/dist/internal/route/cors.mjs +15 -0
  41. package/dist/internal/route/cors.mjs.map +1 -0
  42. package/dist/internal/route/handle-get.d.mts +4 -0
  43. package/dist/internal/route/handle-get.d.mts.map +1 -0
  44. package/dist/internal/route/handle-get.mjs +15 -0
  45. package/dist/internal/route/handle-get.mjs.map +1 -0
  46. package/dist/internal/route/handle-post.d.mts +4 -0
  47. package/dist/internal/route/handle-post.d.mts.map +1 -0
  48. package/dist/internal/route/handle-post.mjs +105 -0
  49. package/dist/internal/route/handle-post.mjs.map +1 -0
  50. package/dist/internal/route/sw-script.d.mts +4 -0
  51. package/dist/internal/route/sw-script.d.mts.map +1 -0
  52. package/dist/internal/route/sw-script.mjs +16 -0
  53. package/dist/internal/route/sw-script.mjs.map +1 -0
  54. package/dist/internal/server/capture.d.mts +9 -0
  55. package/dist/internal/server/capture.d.mts.map +1 -0
  56. package/dist/internal/server/capture.mjs +46 -0
  57. package/dist/internal/server/capture.mjs.map +1 -0
  58. package/dist/internal/server/dedupe.d.mts +5 -0
  59. package/dist/internal/server/dedupe.d.mts.map +1 -0
  60. package/dist/internal/server/dedupe.mjs +11 -0
  61. package/dist/internal/server/dedupe.mjs.map +1 -0
  62. package/dist/internal/server/envelope.d.mts +14 -0
  63. package/dist/internal/server/envelope.d.mts.map +1 -0
  64. package/dist/internal/server/envelope.mjs +41 -0
  65. package/dist/internal/server/envelope.mjs.map +1 -0
  66. package/dist/internal/server/mechanisms.d.mts +7 -0
  67. package/dist/internal/server/mechanisms.d.mts.map +1 -0
  68. package/dist/internal/server/mechanisms.mjs +12 -0
  69. package/dist/internal/server/mechanisms.mjs.map +1 -0
  70. package/dist/internal/server/normalize-request.d.mts +7 -0
  71. package/dist/internal/server/normalize-request.d.mts.map +1 -0
  72. package/dist/internal/server/normalize-request.mjs +50 -0
  73. package/dist/internal/server/normalize-request.mjs.map +1 -0
  74. package/dist/internal/server/runtime.d.mts +14 -0
  75. package/dist/internal/server/runtime.d.mts.map +1 -0
  76. package/dist/internal/server/runtime.mjs +17 -0
  77. package/dist/internal/server/runtime.mjs.map +1 -0
  78. package/dist/internal/server/session.d.mts +11 -0
  79. package/dist/internal/server/session.d.mts.map +1 -0
  80. package/dist/internal/server/session.mjs +15 -0
  81. package/dist/internal/server/session.mjs.map +1 -0
  82. package/dist/internal/server/transport.d.mts +12 -0
  83. package/dist/internal/server/transport.d.mts.map +1 -0
  84. package/dist/internal/server/transport.mjs +17 -0
  85. package/dist/internal/server/transport.mjs.map +1 -0
  86. package/dist/internal/server/types.d.mts +17 -0
  87. package/dist/internal/server/types.d.mts.map +1 -0
  88. package/dist/internal/server/types.mjs +1 -0
  89. package/dist/provider.d.mts +13 -0
  90. package/dist/provider.d.mts.map +1 -0
  91. package/dist/provider.mjs +16 -0
  92. package/dist/provider.mjs.map +1 -0
  93. package/dist/route-handler.d.mts +7 -0
  94. package/dist/route-handler.d.mts.map +1 -0
  95. package/dist/route-handler.mjs +18 -0
  96. package/dist/route-handler.mjs.map +1 -0
  97. package/dist/server.d.mts +8 -0
  98. package/dist/server.d.mts.map +1 -0
  99. package/dist/server.mjs +6 -0
  100. package/dist/server.mjs.map +1 -0
  101. package/package.json +59 -72
  102. package/LICENSE +0 -21
  103. package/dist/build/env-config.d.mts +0 -7
  104. package/dist/build/env-config.d.mts.map +0 -1
  105. package/dist/build/env-config.mjs +0 -17
  106. package/dist/build/env-config.mjs.map +0 -1
  107. package/dist/build/logger.d.mts +0 -11
  108. package/dist/build/logger.d.mts.map +0 -1
  109. package/dist/build/logger.mjs +0 -155
  110. package/dist/build/logger.mjs.map +0 -1
  111. package/dist/build/release-program.d.mts +0 -19
  112. package/dist/build/release-program.d.mts.map +0 -1
  113. package/dist/build/release-program.mjs +0 -92
  114. package/dist/build/release-program.mjs.map +0 -1
  115. package/dist/build/secret-key.d.mts +0 -10
  116. package/dist/build/secret-key.d.mts.map +0 -1
  117. package/dist/build/secret-key.mjs +0 -16
  118. package/dist/build/secret-key.mjs.map +0 -1
  119. package/dist/build/services/config.service.d.mts +0 -9
  120. package/dist/build/services/config.service.d.mts.map +0 -1
  121. package/dist/build/services/config.service.mjs +0 -8
  122. package/dist/build/services/config.service.mjs.map +0 -1
  123. package/dist/build/services/preflight.service.d.mts +0 -19
  124. package/dist/build/services/preflight.service.d.mts.map +0 -1
  125. package/dist/build/services/preflight.service.mjs +0 -76
  126. package/dist/build/services/preflight.service.mjs.map +0 -1
  127. package/dist/build/services/release-identity.service.d.mts +0 -22
  128. package/dist/build/services/release-identity.service.d.mts.map +0 -1
  129. package/dist/build/services/release-identity.service.mjs +0 -48
  130. package/dist/build/services/release-identity.service.mjs.map +0 -1
  131. package/dist/build/services/source-map.service.d.mts +0 -24
  132. package/dist/build/services/source-map.service.d.mts.map +0 -1
  133. package/dist/build/services/source-map.service.mjs +0 -58
  134. package/dist/build/services/source-map.service.mjs.map +0 -1
  135. package/dist/build/source-maps/api.d.mts +0 -35
  136. package/dist/build/source-maps/api.d.mts.map +0 -1
  137. package/dist/build/source-maps/api.mjs +0 -61
  138. package/dist/build/source-maps/api.mjs.map +0 -1
  139. package/dist/build/source-maps/client.d.mts +0 -73
  140. package/dist/build/source-maps/client.d.mts.map +0 -1
  141. package/dist/build/source-maps/client.mjs +0 -228
  142. package/dist/build/source-maps/client.mjs.map +0 -1
  143. package/dist/build/source-maps/errors.d.mts +0 -109
  144. package/dist/build/source-maps/errors.d.mts.map +0 -1
  145. package/dist/build/source-maps/errors.mjs +0 -22
  146. package/dist/build/source-maps/errors.mjs.map +0 -1
  147. package/dist/build/source-maps/files.d.mts +0 -35
  148. package/dist/build/source-maps/files.d.mts.map +0 -1
  149. package/dist/build/source-maps/files.mjs +0 -222
  150. package/dist/build/source-maps/files.mjs.map +0 -1
  151. package/dist/build/source-maps/providers/deployment/detector.d.mts +0 -26
  152. package/dist/build/source-maps/providers/deployment/detector.d.mts.map +0 -1
  153. package/dist/build/source-maps/providers/deployment/detector.mjs +0 -22
  154. package/dist/build/source-maps/providers/deployment/detector.mjs.map +0 -1
  155. package/dist/build/source-maps/providers/deployment/types.d.mts +0 -12
  156. package/dist/build/source-maps/providers/deployment/types.d.mts.map +0 -1
  157. package/dist/build/source-maps/providers/deployment/types.mjs +0 -3
  158. package/dist/build/source-maps/providers/deployment/vercel.d.mts +0 -6
  159. package/dist/build/source-maps/providers/deployment/vercel.d.mts.map +0 -1
  160. package/dist/build/source-maps/providers/deployment/vercel.mjs +0 -44
  161. package/dist/build/source-maps/providers/deployment/vercel.mjs.map +0 -1
  162. package/dist/build/source-maps/providers/source-control/detector.d.mts +0 -15
  163. package/dist/build/source-maps/providers/source-control/detector.d.mts.map +0 -1
  164. package/dist/build/source-maps/providers/source-control/detector.mjs +0 -22
  165. package/dist/build/source-maps/providers/source-control/detector.mjs.map +0 -1
  166. package/dist/build/source-maps/providers/source-control/git.d.mts +0 -6
  167. package/dist/build/source-maps/providers/source-control/git.d.mts.map +0 -1
  168. package/dist/build/source-maps/providers/source-control/git.mjs +0 -50
  169. package/dist/build/source-maps/providers/source-control/git.mjs.map +0 -1
  170. package/dist/build/source-maps/providers/source-control/types.d.mts +0 -12
  171. package/dist/build/source-maps/providers/source-control/types.d.mts.map +0 -1
  172. package/dist/build/source-maps/providers/source-control/types.mjs +0 -3
  173. package/dist/build/with-interfere.d.mts +0 -48
  174. package/dist/build/with-interfere.d.mts.map +0 -1
  175. package/dist/build/with-interfere.mjs +0 -75
  176. package/dist/build/with-interfere.mjs.map +0 -1
  177. package/dist/client/client.d.mts +0 -3
  178. package/dist/client/client.mjs +0 -5
  179. package/dist/client/provider.d.mts +0 -22
  180. package/dist/client/provider.d.mts.map +0 -1
  181. package/dist/client/provider.mjs +0 -37
  182. package/dist/client/provider.mjs.map +0 -1
  183. package/dist/lib/env.d.mts +0 -12
  184. package/dist/lib/env.d.mts.map +0 -1
  185. package/dist/lib/env.mjs +0 -17
  186. package/dist/lib/env.mjs.map +0 -1
  187. package/dist/lib/test-utils/make-next-request.d.mts +0 -6
  188. package/dist/lib/test-utils/make-next-request.d.mts.map +0 -1
  189. package/dist/lib/test-utils/make-next-request.mjs +0 -12
  190. package/dist/lib/test-utils/make-next-request.mjs.map +0 -1
  191. package/dist/lib/types.d.mts +0 -22
  192. package/dist/lib/types.d.mts.map +0 -1
  193. package/dist/lib/types.mjs +0 -7
  194. package/dist/lib/types.mjs.map +0 -1
  195. package/dist/server/middleware.d.mts +0 -11
  196. package/dist/server/middleware.d.mts.map +0 -1
  197. package/dist/server/middleware.mjs +0 -85
  198. package/dist/server/middleware.mjs.map +0 -1
  199. package/dist/server/proxy.d.mts +0 -6
  200. package/dist/server/proxy.d.mts.map +0 -1
  201. package/dist/server/proxy.mjs +0 -30
  202. package/dist/server/proxy.mjs.map +0 -1
  203. package/dist/server/route-handler.d.mts +0 -9
  204. package/dist/server/route-handler.d.mts.map +0 -1
  205. package/dist/server/route-handler.mjs +0 -172
  206. package/dist/server/route-handler.mjs.map +0 -1
  207. package/dist/server/services/config.service.d.mts +0 -21
  208. package/dist/server/services/config.service.d.mts.map +0 -1
  209. package/dist/server/services/config.service.mjs +0 -43
  210. package/dist/server/services/config.service.mjs.map +0 -1
  211. package/dist/server/services/error-tracking.service.d.mts +0 -19
  212. package/dist/server/services/error-tracking.service.d.mts.map +0 -1
  213. package/dist/server/services/error-tracking.service.mjs +0 -31
  214. package/dist/server/services/error-tracking.service.mjs.map +0 -1
package/README.md CHANGED
@@ -1,317 +1,108 @@
1
1
  # @interfere/next
2
2
 
3
- Official Next.js SDK for Interfere error monitoring and analytics.
3
+ Next.js SDK v2 for Interfere (`next >= 15`, `react >= 19`).
4
4
 
5
- ## Installation
5
+ ## Install
6
6
 
7
7
  ```bash
8
- npm install @interfere/next
9
- # or
10
- yarn add @interfere/next
11
- # or
12
- pnpm add @interfere/next
8
+ bun add @interfere/next
13
9
  ```
14
10
 
15
11
  ## Quick Start
16
12
 
17
- ### 1. Initialize the SDK
13
+ 1. Wrap your Next config.
18
14
 
19
- Create a file to initialize Interfere (e.g., `lib/interfere.ts`):
15
+ ```ts
16
+ // next.config.ts
17
+ import { withInterfere } from "@interfere/next/config";
18
+ import type { NextConfig } from "next";
20
19
 
21
- ```typescript
22
- import { init } from '@interfere/next';
20
+ const config: NextConfig = {};
23
21
 
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
- });
22
+ export default withInterfere(config);
31
23
  ```
32
24
 
33
- ### 2. Add the Proxy Route
25
+ 2. Wire Next instrumentation.
34
26
 
35
- The SDK sends events through a server-side proxy route to keep your API credentials secure. Create `app/api/interfere/[[...path]]/route.ts`:
36
-
37
- ```typescript
38
- export { GET, OPTIONS, POST } from '@interfere/next/route-handler';
39
- ```
40
-
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`:
42
-
43
- ```bash
44
- INTERFERE_SECRET_KEY=if_sk_xxx
27
+ ```ts
28
+ // instrumentation.ts
29
+ export { onRequestError } from "@interfere/next/server";
45
30
  ```
46
31
 
47
- ### 3. Add Error Boundary (App Directory)
32
+ 3. Mount the ingest route.
48
33
 
49
- In your root layout (`app/layout.tsx`):
34
+ ```ts
35
+ // app/api/interfere/[[...path]]/route.ts
36
+ import {
37
+ GET as handleGet,
38
+ OPTIONS as handleOptions,
39
+ POST as handlePost,
40
+ } from "@interfere/next/route-handler";
50
41
 
51
- ```tsx
52
- import { InterfereProvider, InterfereErrorBoundary } from '@interfere/next';
53
- import { interfere } from '@/lib/interfere';
54
-
55
- export default function RootLayout({
56
- children,
57
- }: {
58
- children: React.ReactNode;
59
- }) {
60
- return (
61
- <html lang="en">
62
- <body>
63
- <InterfereProvider>
64
- <InterfereErrorBoundary>
65
- {children}
66
- </InterfereErrorBoundary>
67
- </InterfereProvider>
68
- </body>
69
- </html>
70
- );
42
+ export function GET(request: Request): Response {
43
+ return handleGet(request);
71
44
  }
72
- ```
73
-
74
- ### 4. Add Error Handler (App Directory)
75
45
 
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]);
46
+ export function POST(request: Request): Promise<Response> {
47
+ return handlePost(request);
48
+ }
96
49
 
97
- return (
98
- <div>
99
- <h2>Something went wrong!</h2>
100
- <button onClick={() => reset()}>Try again</button>
101
- </div>
102
- );
50
+ export function OPTIONS(): Response {
51
+ return handleOptions();
103
52
  }
104
53
  ```
105
54
 
106
- ### 5. Add Global Error Handler
107
-
108
- Create `app/global-error.tsx`:
55
+ 4. Add the provider in your app layout.
109
56
 
110
57
  ```tsx
111
- 'use client';
112
-
113
- import { createInterfereErrorHandler } from '@interfere/next';
58
+ import { InterfereProvider } from "@interfere/next/provider";
114
59
 
115
- const errorHandler = createInterfereErrorHandler();
116
-
117
- export default function GlobalError({
118
- error,
119
- reset,
60
+ export default function RootLayout({
61
+ children,
120
62
  }: {
121
- error: Error & { digest?: string };
122
- reset: () => void;
63
+ children: React.ReactNode;
123
64
  }) {
124
- errorHandler(error, { digest: error.digest });
125
-
126
65
  return (
127
- <html>
66
+ <html lang="en">
128
67
  <body>
129
- <h2>Something went wrong!</h2>
130
- <button onClick={() => reset()}>Try again</button>
68
+ <InterfereProvider>{children}</InterfereProvider>
131
69
  </body>
132
70
  </html>
133
71
  );
134
72
  }
135
73
  ```
136
74
 
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
75
+ ## Manual Server Capture
155
76
 
156
- ```typescript
157
- // app/api/webhook/route.ts
158
- import { captureServerError } from '@interfere/next';
77
+ ```ts
78
+ import { captureError } from "@interfere/next/server";
159
79
 
160
- export async function POST(request: Request) {
80
+ export async function GET(request: Request): Promise<Response> {
161
81
  try {
162
- const body = await request.json();
163
- // Process webhook
82
+ throw new Error("boom");
164
83
  } catch (error) {
165
- captureServerError(error, request, {
166
- pathname: '/api/webhook',
167
- type: 'webhook_error',
168
- });
169
- return Response.json({ error: 'Webhook failed' }, { status: 500 });
84
+ await captureError(error, request);
85
+ throw error;
170
86
  }
171
87
  }
172
88
  ```
173
89
 
174
- ## Middleware
90
+ ## Required Env
175
91
 
176
- Wrap your middleware to capture errors:
92
+ - `INTERFERE_API_KEY`
177
93
 
178
- ```typescript
179
- // middleware.ts
180
- import { withInterfereMiddleware } from '@interfere/next';
181
- import { NextResponse } from 'next/server';
94
+ Optional:
182
95
 
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
235
-
236
- Use the `useInterfere` hook in client components:
237
-
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
272
-
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
- ```
96
+ - `INTERFERE_API_URL`
314
97
 
315
- ## License
98
+ ## Migration Notes (from `@interfere/next`)
316
99
 
317
- MIT
100
+ - Legacy package remains frozen at `@interfere/next`.
101
+ - `@interfere/next` exposes only:
102
+ - `@interfere/next/config`
103
+ - `@interfere/next/provider`
104
+ - `@interfere/next/server`
105
+ - `@interfere/next/route-handler`
106
+ - No `middleware` wrapper exports.
107
+ - No `server/auto-init` export.
108
+ - Preferred instrumentation wiring is a single re-export from `./server`.
@@ -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":";;;;UAmBiB,eAAA,SACP,OAAA,CAAQ,IAAA,CAAK,QAAA;AAAA,KAEX,uBAAA,GAA0B,UAAA;EACpC,SAAA,GAAY,eAAA;AAAA;AAAA,iBAGE,aAAA,CACd,UAAA,GAAY,uBAAA,GACX,UAAA"}
@@ -0,0 +1,105 @@
1
+ import { configureBuild } from "./internal/build/configure-build.mjs";
2
+ import { buildInjectedValues } from "./internal/build/injected.mjs";
3
+ import { buildLog } from "./internal/build/logger.mjs";
4
+ import { createRelease, runGitCommand } from "./internal/build/release.mjs";
5
+ import { runSourceMapPipeline } from "./internal/build/source-maps/index.mjs";
6
+ import { readInterfereEnv } from "./internal/env.mjs";
7
+ import { releaseDestinationIdEnvKeys, releaseSourceIdEnvKeys } from "@interfere/types/integrations";
8
+ import { parseEnvValue, readFirstEnvValue } from "@interfere/types/sdk/env";
9
+ //#region src/config.ts
10
+ function withInterfere(nextConfig = {}) {
11
+ const { interfere, env: userEnv, webpack, turbopack, compiler, productionBrowserSourceMaps, ...rest } = nextConfig;
12
+ const metadata = resolveBuildMetadata(interfere);
13
+ const injectedValues = buildInjectedValues(metadata);
14
+ const hasApiKey = readInterfereEnv().apiKey !== null;
15
+ const build = configureBuild({
16
+ existingWebpack: webpack,
17
+ existingTurbopack: turbopack,
18
+ projectDir: process.cwd(),
19
+ values: injectedValues
20
+ });
21
+ return {
22
+ ...rest,
23
+ env: mergeEnvConfig(userEnv, metadata),
24
+ compiler: buildCompilerConfig(compiler, hasApiKey, metadata),
25
+ webpack: build.webpack,
26
+ turbopack: build.turbopack,
27
+ productionBrowserSourceMaps: hasApiKey ? true : productionBrowserSourceMaps
28
+ };
29
+ }
30
+ function resolveBuildMetadata(config) {
31
+ const buildId = parseEnvValue(config?.buildId) ?? readFirstEnvValue(process.env, releaseSourceIdEnvKeys) ?? runGitCommand("git rev-parse HEAD");
32
+ return {
33
+ buildId,
34
+ releaseId: parseEnvValue(config?.releaseId) ?? readFirstEnvValue(process.env, releaseDestinationIdEnvKeys) ?? buildId
35
+ };
36
+ }
37
+ function mergeEnvConfig(userEnv, metadata) {
38
+ const merged = {};
39
+ if (metadata.buildId !== null) merged.NEXT_PUBLIC_INTERFERE_BUILD_ID = metadata.buildId;
40
+ if (metadata.releaseId !== null) merged.NEXT_PUBLIC_INTERFERE_RELEASE_ID = metadata.releaseId;
41
+ return {
42
+ ...merged,
43
+ ...userEnv
44
+ };
45
+ }
46
+ function buildCompilerConfig(existingCompiler, enabled, metadata) {
47
+ const compiler = existingCompiler;
48
+ const existingHook = compiler?.runAfterProductionCompile;
49
+ if (!(existingHook || enabled)) return existingCompiler;
50
+ return {
51
+ ...compiler ?? {},
52
+ async runAfterProductionCompile(context) {
53
+ if (existingHook) await existingHook(context);
54
+ if (enabled) await runBuildReleasePipeline(context, metadata);
55
+ }
56
+ };
57
+ }
58
+ async function runBuildReleasePipeline(context, metadata) {
59
+ const env = readInterfereEnv();
60
+ const apiKey = env.apiKey;
61
+ if (apiKey === null) {
62
+ buildLog.warn("Skipping", ["Missing INTERFERE_API_KEY."]);
63
+ return;
64
+ }
65
+ const client = {
66
+ async createRelease() {
67
+ const release = await createRelease(apiKey, env.apiUrl, metadata.buildId);
68
+ return {
69
+ slug: release.destination.slug,
70
+ orgSlug: release.org.slug,
71
+ buildId: release.build.hash
72
+ };
73
+ },
74
+ async uploadSourceMaps(releaseSlug, body) {
75
+ const url = `${env.apiUrl}/v1/releases/${releaseSlug}/source-maps`;
76
+ const response = await fetch(url, {
77
+ method: "POST",
78
+ headers: { "x-api-key": apiKey },
79
+ body
80
+ });
81
+ if (!response.ok) {
82
+ const text = await response.text().catch(() => "");
83
+ throw new Error(`Source map upload failed: ${response.status} ${response.statusText} ${text}`);
84
+ }
85
+ }
86
+ };
87
+ try {
88
+ const result = await runSourceMapPipeline(context.projectDir, context.distDir, client);
89
+ if (!result.ready) {
90
+ buildLog.warn("Skipping", ["No source maps found"]);
91
+ return;
92
+ }
93
+ buildLog.info("Completed", [
94
+ `https://interfere.com/~/${result.orgSlug}`,
95
+ `Release: ${result.releaseSlug}`,
96
+ `Build: ${result.buildId ?? "unknown"}`,
97
+ `Artifacts: ${result.fileCount} source maps`
98
+ ]);
99
+ } catch (error) {
100
+ buildLog.error("Error", [error instanceof Error ? error.message : String(error)]);
101
+ throw error;
102
+ }
103
+ }
104
+ //#endregion
105
+ 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 {\n buildInjectedValues,\n type InterfereBuildMetadata,\n} from \"./internal/build/injected.js\";\nimport { buildLog } from \"./internal/build/logger.js\";\nimport { createRelease, runGitCommand } from \"./internal/build/release.js\";\nimport { runSourceMapPipeline } from \"./internal/build/source-maps/index.js\";\nimport { readInterfereEnv } from \"./internal/env.js\";\n\nexport interface InterfereConfig\n extends Partial<Pick<Envelope, \"buildId\" | \"releaseId\">> {}\n\nexport type NextConfigWithInterfere = NextConfig & {\n interfere?: InterfereConfig;\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 const metadata = resolveBuildMetadata(interfere);\n const injectedValues = buildInjectedValues(metadata);\n const hasApiKey = readInterfereEnv().apiKey !== null;\n const build = configureBuild({\n existingWebpack: webpack,\n existingTurbopack: turbopack,\n projectDir: process.cwd(),\n values: injectedValues,\n });\n\n return {\n ...rest,\n env: mergeEnvConfig(userEnv, metadata),\n compiler: buildCompilerConfig(compiler, hasApiKey, metadata),\n webpack: build.webpack,\n turbopack: build.turbopack,\n productionBrowserSourceMaps: hasApiKey ? true : productionBrowserSourceMaps,\n };\n}\n\nfunction resolveBuildMetadata(\n config?: InterfereConfig\n): InterfereBuildMetadata {\n const buildId =\n parseEnvValue(config?.buildId) ??\n readFirstEnvValue(process.env, releaseSourceIdEnvKeys) ??\n runGitCommand(\"git rev-parse HEAD\");\n const releaseId =\n parseEnvValue(config?.releaseId) ??\n readFirstEnvValue(process.env, releaseDestinationIdEnvKeys) ??\n buildId;\n\n return {\n buildId,\n releaseId,\n };\n}\n\nfunction mergeEnvConfig(\n userEnv: NextConfig[\"env\"] | undefined,\n metadata: InterfereBuildMetadata\n): NextConfig[\"env\"] {\n const merged: Record<string, string> = {};\n\n if (metadata.buildId !== null) {\n merged.NEXT_PUBLIC_INTERFERE_BUILD_ID = metadata.buildId;\n }\n\n if (metadata.releaseId !== null) {\n merged.NEXT_PUBLIC_INTERFERE_RELEASE_ID = metadata.releaseId;\n }\n\n return {\n ...merged,\n ...userEnv,\n };\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\nfunction buildCompilerConfig(\n existingCompiler: NextConfig[\"compiler\"] | undefined,\n enabled: boolean,\n metadata: InterfereBuildMetadata\n): NextConfig[\"compiler\"] | undefined {\n const compiler = existingCompiler as\n | NextCompilerWithProductionHook\n | undefined;\n const existingHook = compiler?.runAfterProductionCompile;\n\n if (!(existingHook || enabled)) {\n return existingCompiler;\n }\n\n return {\n ...(compiler ?? {}),\n async runAfterProductionCompile(context: ProductionCompileContext) {\n if (existingHook) {\n await existingHook(context);\n }\n\n if (enabled) {\n await runBuildReleasePipeline(context, metadata);\n }\n },\n } as NextConfig[\"compiler\"];\n}\n\nasync function runBuildReleasePipeline(\n context: ProductionCompileContext,\n metadata: InterfereBuildMetadata\n): Promise<void> {\n const env = readInterfereEnv();\n const apiKey = env.apiKey;\n\n if (apiKey === null) {\n buildLog.warn(\"Skipping\", [\"Missing INTERFERE_API_KEY.\"]);\n return;\n }\n\n const client: import(\"./internal/build/source-maps/index.js\").BuildClient = {\n async createRelease() {\n const release = await createRelease(apiKey, env.apiUrl, metadata.buildId);\n return {\n slug: release.destination.slug,\n orgSlug: release.org.slug,\n buildId: release.build.hash,\n };\n },\n async uploadSourceMaps(releaseSlug, body) {\n const url = `${env.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 buildLog.warn(\"Skipping\", [\"No source maps found\"]);\n return;\n }\n\n buildLog.info(\"Completed\", [\n `https://interfere.com/~/${result.orgSlug}`,\n `Release: ${result.releaseSlug}`,\n `Build: ${result.buildId ?? \"unknown\"}`,\n `Artifacts: ${result.fileCount} source maps`,\n ]);\n } catch (error) {\n buildLog.error(\"Error\", [\n error instanceof Error ? error.message : String(error),\n ]);\n throw error;\n }\n}\n"],"mappings":";;;;;;;;;AA0BA,SAAgB,cACd,aAAsC,EAAE,EAC5B;CACZ,MAAM,EACJ,WACA,KAAK,SACL,SACA,WACA,UACA,6BACA,GAAG,SACD;CACJ,MAAM,WAAW,qBAAqB,UAAU;CAChD,MAAM,iBAAiB,oBAAoB,SAAS;CACpD,MAAM,YAAY,kBAAkB,CAAC,WAAW;CAChD,MAAM,QAAQ,eAAe;EAC3B,iBAAiB;EACjB,mBAAmB;EACnB,YAAY,QAAQ,KAAK;EACzB,QAAQ;EACT,CAAC;AAEF,QAAO;EACL,GAAG;EACH,KAAK,eAAe,SAAS,SAAS;EACtC,UAAU,oBAAoB,UAAU,WAAW,SAAS;EAC5D,SAAS,MAAM;EACf,WAAW,MAAM;EACjB,6BAA6B,YAAY,OAAO;EACjD;;AAGH,SAAS,qBACP,QACwB;CACxB,MAAM,UACJ,cAAc,QAAQ,QAAQ,IAC9B,kBAAkB,QAAQ,KAAK,uBAAuB,IACtD,cAAc,qBAAqB;AAMrC,QAAO;EACL;EACA,WANA,cAAc,QAAQ,UAAU,IAChC,kBAAkB,QAAQ,KAAK,4BAA4B,IAC3D;EAKD;;AAGH,SAAS,eACP,SACA,UACmB;CACnB,MAAM,SAAiC,EAAE;AAEzC,KAAI,SAAS,YAAY,KACvB,QAAO,iCAAiC,SAAS;AAGnD,KAAI,SAAS,cAAc,KACzB,QAAO,mCAAmC,SAAS;AAGrD,QAAO;EACL,GAAG;EACH,GAAG;EACJ;;AAcH,SAAS,oBACP,kBACA,SACA,UACoC;CACpC,MAAM,WAAW;CAGjB,MAAM,eAAe,UAAU;AAE/B,KAAI,EAAE,gBAAgB,SACpB,QAAO;AAGT,QAAO;EACL,GAAI,YAAY,EAAE;EAClB,MAAM,0BAA0B,SAAmC;AACjE,OAAI,aACF,OAAM,aAAa,QAAQ;AAG7B,OAAI,QACF,OAAM,wBAAwB,SAAS,SAAS;;EAGrD;;AAGH,eAAe,wBACb,SACA,UACe;CACf,MAAM,MAAM,kBAAkB;CAC9B,MAAM,SAAS,IAAI;AAEnB,KAAI,WAAW,MAAM;AACnB,WAAS,KAAK,YAAY,CAAC,6BAA6B,CAAC;AACzD;;CAGF,MAAM,SAAsE;EAC1E,MAAM,gBAAgB;GACpB,MAAM,UAAU,MAAM,cAAc,QAAQ,IAAI,QAAQ,SAAS,QAAQ;AACzE,UAAO;IACL,MAAM,QAAQ,YAAY;IAC1B,SAAS,QAAQ,IAAI;IACrB,SAAS,QAAQ,MAAM;IACxB;;EAEH,MAAM,iBAAiB,aAAa,MAAM;GACxC,MAAM,MAAM,GAAG,IAAI,OAAO,eAAe,YAAY;GACrD,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,YAAS,KAAK,YAAY,CAAC,uBAAuB,CAAC;AACnD;;AAGF,WAAS,KAAK,aAAa;GACzB,2BAA2B,OAAO;GAClC,YAAY,OAAO;GACnB,UAAU,OAAO,WAAW;GAC5B,cAAc,OAAO,UAAU;GAChC,CAAC;UACK,OAAO;AACd,WAAS,MAAM,SAAS,CACtB,iBAAiB,QAAQ,MAAM,UAAU,OAAO,MAAM,CACvD,CAAC;AACF,QAAM"}
@@ -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 };
@@ -0,0 +1 @@
1
+ {"version":3,"file":"configure-build.mjs","names":[],"sources":["../../../src/internal/build/configure-build.ts"],"sourcesContent":["import { existsSync } from \"node:fs\";\nimport { basename, dirname, join, normalize, resolve } from \"node:path\";\nimport { fileURLToPath } from \"node:url\";\nimport type { NextConfig } from \"next\";\n\nimport type { InterfereInjectedValues } from \"./injected.js\";\n\nconst INSTRUMENTATION_CLIENT_FILES = [\n \"instrumentation-client.ts\",\n \"instrumentation-client.tsx\",\n \"instrumentation-client.js\",\n \"instrumentation-client.jsx\",\n \"src/instrumentation-client.ts\",\n \"src/instrumentation-client.tsx\",\n \"src/instrumentation-client.js\",\n \"src/instrumentation-client.jsx\",\n] as const;\n\nconst LOADER_FILE_CANDIDATES = [\n \"value-injection-loader.ts\",\n \"value-injection-loader.js\",\n \"value-injection-loader.mjs\",\n \"value-injection-loader.cjs\",\n] as const;\n\ninterface ConfigureBuildInput {\n readonly existingWebpack: NextConfig[\"webpack\"] | undefined;\n readonly existingTurbopack: NextConfig[\"turbopack\"] | undefined;\n readonly projectDir: string;\n readonly values: InterfereInjectedValues;\n}\n\ninterface ConfigureBuildOutput {\n readonly webpack: NextConfig[\"webpack\"] | undefined;\n readonly turbopack: NextConfig[\"turbopack\"] | undefined;\n}\n\nexport function configureBuild({\n existingWebpack,\n existingTurbopack,\n projectDir,\n values,\n}: ConfigureBuildInput): ConfigureBuildOutput {\n const instrumentationClientPath = resolveInstrumentationClientPath(projectDir);\n\n return {\n webpack: buildWebpackHook(existingWebpack, instrumentationClientPath, values),\n turbopack: buildTurbopackConfig(\n existingTurbopack,\n instrumentationClientPath,\n values\n ),\n };\n}\n\nfunction hasInjectedMetadata(metadata: InterfereInjectedValues): boolean {\n return (\n metadata.__INTERFERE_BUILD_ID__ !== null ||\n metadata.__INTERFERE_RELEASE_ID__ !== null\n );\n}\n\nfunction buildWebpackHook(\n existingWebpack: NextConfig[\"webpack\"] | undefined,\n instrumentationClientPath: string | null,\n values: InterfereInjectedValues\n): NextConfig[\"webpack\"] | undefined {\n if (!(instrumentationClientPath && hasInjectedMetadata(values))) {\n return existingWebpack;\n }\n\n const normalizedPath = normalize(instrumentationClientPath);\n const loaderPath = resolveLoaderPath();\n\n return (webpackConfig, options) => {\n const outputConfig = existingWebpack\n ? existingWebpack(webpackConfig, options)\n : webpackConfig;\n const mutableConfig = outputConfig as {\n module?: { rules?: unknown[] };\n };\n\n const injectionRule = {\n test: (resource: string): boolean =>\n Boolean(resource) && normalize(resource) === normalizedPath,\n use: [\n {\n loader: loaderPath,\n options: { values },\n },\n ],\n };\n\n mutableConfig.module ??= {};\n mutableConfig.module.rules ??= [];\n mutableConfig.module.rules.push(injectionRule);\n\n return outputConfig;\n };\n}\n\nfunction buildTurbopackConfig(\n existingTurbopack: NextConfig[\"turbopack\"] | undefined,\n instrumentationClientPath: string | null,\n values: InterfereInjectedValues\n): NextConfig[\"turbopack\"] | undefined {\n if (!(instrumentationClientPath && hasInjectedMetadata(values))) {\n return existingTurbopack;\n }\n\n const baseConfig = (existingTurbopack ?? {}) as {\n rules?: Record<string, unknown>;\n };\n const ruleKey = `**/${basename(instrumentationClientPath)}`;\n const existingRule = (baseConfig.rules?.[ruleKey] ?? {}) as {\n loaders?: unknown[];\n };\n const existingLoaders = Array.isArray(existingRule.loaders)\n ? existingRule.loaders\n : [];\n\n return {\n ...baseConfig,\n rules: {\n ...baseConfig.rules,\n [ruleKey]: {\n ...existingRule,\n loaders: [\n ...existingLoaders,\n {\n loader: resolveLoaderPath(),\n options: {\n serializedValues: JSON.stringify(values),\n },\n },\n ],\n },\n },\n } as NextConfig[\"turbopack\"];\n}\n\nfunction resolveInstrumentationClientPath(projectDir: string): string | null {\n for (const candidate of INSTRUMENTATION_CLIENT_FILES) {\n const filePath = resolve(projectDir, candidate);\n if (existsSync(filePath)) {\n return filePath;\n }\n }\n\n return null;\n}\n\nfunction resolveLoaderPath(): string {\n const directory = resolve(dirname(fileURLToPath(import.meta.url)));\n\n for (const candidate of LOADER_FILE_CANDIDATES) {\n const filePath = join(directory, candidate);\n if (existsSync(filePath)) {\n return filePath;\n }\n }\n\n return join(directory, \"value-injection-loader.js\");\n}\n"],"mappings":";;;;AAOA,MAAM,+BAA+B;CACnC;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACD;AAED,MAAM,yBAAyB;CAC7B;CACA;CACA;CACA;CACD;AAcD,SAAgB,eAAe,EAC7B,iBACA,mBACA,YACA,UAC4C;CAC5C,MAAM,4BAA4B,iCAAiC,WAAW;AAE9E,QAAO;EACL,SAAS,iBAAiB,iBAAiB,2BAA2B,OAAO;EAC7E,WAAW,qBACT,mBACA,2BACA,OACD;EACF;;AAGH,SAAS,oBAAoB,UAA4C;AACvE,QACE,SAAS,2BAA2B,QACpC,SAAS,6BAA6B;;AAI1C,SAAS,iBACP,iBACA,2BACA,QACmC;AACnC,KAAI,EAAE,6BAA6B,oBAAoB,OAAO,EAC5D,QAAO;CAGT,MAAM,iBAAiB,UAAU,0BAA0B;CAC3D,MAAM,aAAa,mBAAmB;AAEtC,SAAQ,eAAe,YAAY;EACjC,MAAM,eAAe,kBACjB,gBAAgB,eAAe,QAAQ,GACvC;EACJ,MAAM,gBAAgB;EAItB,MAAM,gBAAgB;GACpB,OAAO,aACL,QAAQ,SAAS,IAAI,UAAU,SAAS,KAAK;GAC/C,KAAK,CACH;IACE,QAAQ;IACR,SAAS,EAAE,QAAQ;IACpB,CACF;GACF;AAED,gBAAc,WAAW,EAAE;AAC3B,gBAAc,OAAO,UAAU,EAAE;AACjC,gBAAc,OAAO,MAAM,KAAK,cAAc;AAE9C,SAAO;;;AAIX,SAAS,qBACP,mBACA,2BACA,QACqC;AACrC,KAAI,EAAE,6BAA6B,oBAAoB,OAAO,EAC5D,QAAO;CAGT,MAAM,aAAc,qBAAqB,EAAE;CAG3C,MAAM,UAAU,MAAM,SAAS,0BAA0B;CACzD,MAAM,eAAgB,WAAW,QAAQ,YAAY,EAAE;CAGvD,MAAM,kBAAkB,MAAM,QAAQ,aAAa,QAAQ,GACvD,aAAa,UACb,EAAE;AAEN,QAAO;EACL,GAAG;EACH,OAAO;GACL,GAAG,WAAW;IACb,UAAU;IACT,GAAG;IACH,SAAS,CACP,GAAG,iBACH;KACE,QAAQ,mBAAmB;KAC3B,SAAS,EACP,kBAAkB,KAAK,UAAU,OAAO,EACzC;KACF,CACF;IACF;GACF;EACF;;AAGH,SAAS,iCAAiC,YAAmC;AAC3E,MAAK,MAAM,aAAa,8BAA8B;EACpD,MAAM,WAAW,QAAQ,YAAY,UAAU;AAC/C,MAAI,WAAW,SAAS,CACtB,QAAO;;AAIX,QAAO;;AAGT,SAAS,oBAA4B;CACnC,MAAM,YAAY,QAAQ,QAAQ,cAAc,OAAO,KAAK,IAAI,CAAC,CAAC;AAElE,MAAK,MAAM,aAAa,wBAAwB;EAC9C,MAAM,WAAW,KAAK,WAAW,UAAU;AAC3C,MAAI,WAAW,SAAS,CACtB,QAAO;;AAIX,QAAO,KAAK,WAAW,4BAA4B"}
@@ -0,0 +1,11 @@
1
+ import { Envelope } from "@interfere/types/sdk/envelope";
2
+
3
+ //#region src/internal/build/injected.d.ts
4
+ type InterfereBuildMetadata = Pick<Envelope, "buildId" | "releaseId">;
5
+ interface InterfereInjectedValues {
6
+ readonly __INTERFERE_BUILD_ID__: Envelope["buildId"];
7
+ readonly __INTERFERE_RELEASE_ID__: Envelope["releaseId"];
8
+ }
9
+ declare function buildInjectedValues(metadata: InterfereBuildMetadata): InterfereInjectedValues;
10
+ //#endregion
11
+ export { InterfereBuildMetadata, InterfereInjectedValues, buildInjectedValues };
@@ -0,0 +1 @@
1
+ {"version":3,"file":"injected.d.mts","names":[],"sources":["../../../src/internal/build/injected.ts"],"mappings":";;;KAEY,sBAAA,GAAyB,IAAA,CAAK,QAAA;AAAA,UAEzB,uBAAA;EAAA,SACN,sBAAA,EAAwB,QAAA;EAAA,SACxB,wBAAA,EAA0B,QAAA;AAAA;AAAA,iBAGrB,mBAAA,CACd,QAAA,EAAU,sBAAA,GACT,uBAAA"}
@@ -0,0 +1,9 @@
1
+ //#region src/internal/build/injected.ts
2
+ function buildInjectedValues(metadata) {
3
+ return {
4
+ __INTERFERE_BUILD_ID__: metadata.buildId,
5
+ __INTERFERE_RELEASE_ID__: metadata.releaseId
6
+ };
7
+ }
8
+ //#endregion
9
+ export { buildInjectedValues };
@@ -0,0 +1 @@
1
+ {"version":3,"file":"injected.mjs","names":[],"sources":["../../../src/internal/build/injected.ts"],"sourcesContent":["import type { Envelope } from \"@interfere/types/sdk/envelope\";\n\nexport type InterfereBuildMetadata = Pick<Envelope, \"buildId\" | \"releaseId\">;\n\nexport interface InterfereInjectedValues {\n readonly __INTERFERE_BUILD_ID__: Envelope[\"buildId\"];\n readonly __INTERFERE_RELEASE_ID__: Envelope[\"releaseId\"];\n}\n\nexport function buildInjectedValues(\n metadata: InterfereBuildMetadata\n): InterfereInjectedValues {\n return {\n __INTERFERE_BUILD_ID__: metadata.buildId,\n __INTERFERE_RELEASE_ID__: metadata.releaseId,\n };\n}\n"],"mappings":";AASA,SAAgB,oBACd,UACyB;AACzB,QAAO;EACL,wBAAwB,SAAS;EACjC,0BAA0B,SAAS;EACpC"}