@interfere/next 0.0.15-alpha.8 → 0.1.0-alpha.11

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 (146) hide show
  1. package/LICENSE +1 -1
  2. package/README.md +36 -8
  3. package/dist/_virtual/_rolldown/runtime.mjs +7 -0
  4. package/dist/build/env-config.d.mts +3 -1
  5. package/dist/build/env-config.d.mts.map +1 -1
  6. package/dist/build/env-config.mjs +9 -1
  7. package/dist/build/env-config.mjs.map +1 -1
  8. package/dist/build/exchange-surface.d.mts +9 -0
  9. package/dist/build/exchange-surface.d.mts.map +1 -0
  10. package/dist/build/exchange-surface.mjs +36 -0
  11. package/dist/build/exchange-surface.mjs.map +1 -0
  12. package/dist/build/loaders/value-injection-loader.d.mts +22 -0
  13. package/dist/build/loaders/value-injection-loader.d.mts.map +1 -0
  14. package/dist/build/loaders/value-injection-loader.mjs +35 -0
  15. package/dist/build/loaders/value-injection-loader.mjs.map +1 -0
  16. package/dist/build/logger.d.mts +2 -2
  17. package/dist/build/logger.d.mts.map +1 -1
  18. package/dist/build/logger.mjs +10 -12
  19. package/dist/build/logger.mjs.map +1 -1
  20. package/dist/build/nextjs-version.d.mts +40 -0
  21. package/dist/build/nextjs-version.d.mts.map +1 -0
  22. package/dist/build/nextjs-version.mjs +66 -0
  23. package/dist/build/nextjs-version.mjs.map +1 -0
  24. package/dist/build/release-program.d.mts +5 -3
  25. package/dist/build/release-program.d.mts.map +1 -1
  26. package/dist/build/release-program.mjs +11 -12
  27. package/dist/build/release-program.mjs.map +1 -1
  28. package/dist/build/services/config.service.d.mts.map +1 -1
  29. package/dist/build/services/config.service.mjs.map +1 -1
  30. package/dist/build/services/instrumentation-detection.service.d.mts +19 -0
  31. package/dist/build/services/instrumentation-detection.service.d.mts.map +1 -0
  32. package/dist/build/services/instrumentation-detection.service.mjs +77 -0
  33. package/dist/build/services/instrumentation-detection.service.mjs.map +1 -0
  34. package/dist/build/services/preflight.service.d.mts +2 -3
  35. package/dist/build/services/preflight.service.d.mts.map +1 -1
  36. package/dist/build/services/preflight.service.mjs +28 -37
  37. package/dist/build/services/preflight.service.mjs.map +1 -1
  38. package/dist/build/services/release-api.service.d.mts +11 -0
  39. package/dist/build/services/release-api.service.d.mts.map +1 -0
  40. package/dist/build/services/release-api.service.mjs +9 -0
  41. package/dist/build/services/release-api.service.mjs.map +1 -0
  42. package/dist/build/services/release-identity.service.d.mts +4 -3
  43. package/dist/build/services/release-identity.service.d.mts.map +1 -1
  44. package/dist/build/services/release-identity.service.mjs +28 -15
  45. package/dist/build/services/release-identity.service.mjs.map +1 -1
  46. package/dist/build/services/source-map-failure-cleanup.service.d.mts +11 -0
  47. package/dist/build/services/source-map-failure-cleanup.service.d.mts.map +1 -0
  48. package/dist/build/services/source-map-failure-cleanup.service.mjs +9 -0
  49. package/dist/build/services/source-map-failure-cleanup.service.mjs.map +1 -0
  50. package/dist/build/services/source-map.service.d.mts +4 -8
  51. package/dist/build/services/source-map.service.d.mts.map +1 -1
  52. package/dist/build/services/source-map.service.mjs +2 -4
  53. package/dist/build/services/source-map.service.mjs.map +1 -1
  54. package/dist/build/source-maps/api.d.mts +25 -16
  55. package/dist/build/source-maps/api.d.mts.map +1 -1
  56. package/dist/build/source-maps/api.mjs +11 -8
  57. package/dist/build/source-maps/api.mjs.map +1 -1
  58. package/dist/build/source-maps/client.d.mts +11 -2
  59. package/dist/build/source-maps/client.d.mts.map +1 -1
  60. package/dist/build/source-maps/client.mjs +25 -14
  61. package/dist/build/source-maps/client.mjs.map +1 -1
  62. package/dist/build/source-maps/errors.d.mts +118 -106
  63. package/dist/build/source-maps/errors.d.mts.map +1 -1
  64. package/dist/build/source-maps/errors.mjs +42 -18
  65. package/dist/build/source-maps/errors.mjs.map +1 -1
  66. package/dist/build/source-maps/files.d.mts +1 -1
  67. package/dist/build/source-maps/files.d.mts.map +1 -1
  68. package/dist/build/source-maps/files.mjs +13 -15
  69. package/dist/build/source-maps/files.mjs.map +1 -1
  70. package/dist/build/source-maps/providers/deployment/detector.d.mts +8 -17
  71. package/dist/build/source-maps/providers/deployment/detector.d.mts.map +1 -1
  72. package/dist/build/source-maps/providers/deployment/detector.mjs +11 -13
  73. package/dist/build/source-maps/providers/deployment/detector.mjs.map +1 -1
  74. package/dist/build/source-maps/providers/deployment/types.d.mts +2 -2
  75. package/dist/build/source-maps/providers/deployment/types.d.mts.map +1 -1
  76. package/dist/build/source-maps/providers/deployment/vercel.d.mts.map +1 -1
  77. package/dist/build/source-maps/providers/deployment/vercel.mjs +8 -19
  78. package/dist/build/source-maps/providers/deployment/vercel.mjs.map +1 -1
  79. package/dist/build/source-maps/providers/source-control/detector.d.mts +6 -5
  80. package/dist/build/source-maps/providers/source-control/detector.d.mts.map +1 -1
  81. package/dist/build/source-maps/providers/source-control/detector.mjs +11 -13
  82. package/dist/build/source-maps/providers/source-control/detector.mjs.map +1 -1
  83. package/dist/build/source-maps/providers/source-control/git.d.mts.map +1 -1
  84. package/dist/build/source-maps/providers/source-control/git.mjs +5 -8
  85. package/dist/build/source-maps/providers/source-control/git.mjs.map +1 -1
  86. package/dist/build/source-maps/providers/source-control/types.d.mts +5 -3
  87. package/dist/build/source-maps/providers/source-control/types.d.mts.map +1 -1
  88. package/dist/build/with-interfere.d.mts +25 -3
  89. package/dist/build/with-interfere.d.mts.map +1 -1
  90. package/dist/build/with-interfere.mjs +131 -24
  91. package/dist/build/with-interfere.mjs.map +1 -1
  92. package/dist/client/auto-init.d.mts +91 -0
  93. package/dist/client/auto-init.d.mts.map +1 -0
  94. package/dist/client/auto-init.mjs +121 -0
  95. package/dist/client/auto-init.mjs.map +1 -0
  96. package/dist/client/provider.d.mts +3 -3
  97. package/dist/client/provider.d.mts.map +1 -1
  98. package/dist/client/provider.mjs +21 -8
  99. package/dist/client/provider.mjs.map +1 -1
  100. package/dist/lib/env.d.mts.map +1 -1
  101. package/dist/lib/types.d.mts +6 -6
  102. package/dist/lib/types.d.mts.map +1 -1
  103. package/dist/lib/types.mjs.map +1 -1
  104. package/dist/server/auto-init.d.mts +88 -0
  105. package/dist/server/auto-init.d.mts.map +1 -0
  106. package/dist/server/auto-init.mjs +101 -0
  107. package/dist/server/auto-init.mjs.map +1 -0
  108. package/dist/server/middleware.d.mts.map +1 -1
  109. package/dist/server/middleware.mjs +20 -13
  110. package/dist/server/middleware.mjs.map +1 -1
  111. package/dist/server/on-request-error.d.mts +27 -0
  112. package/dist/server/on-request-error.d.mts.map +1 -0
  113. package/dist/server/on-request-error.mjs +74 -0
  114. package/dist/server/on-request-error.mjs.map +1 -0
  115. package/dist/server/proxy.d.mts.map +1 -1
  116. package/dist/server/proxy.mjs +4 -5
  117. package/dist/server/proxy.mjs.map +1 -1
  118. package/dist/server/route-handler.d.mts +31 -1
  119. package/dist/server/route-handler.d.mts.map +1 -1
  120. package/dist/server/route-handler.mjs +78 -79
  121. package/dist/server/route-handler.mjs.map +1 -1
  122. package/dist/server/sdk.d.mts +96 -0
  123. package/dist/server/sdk.d.mts.map +1 -0
  124. package/dist/server/sdk.mjs +152 -0
  125. package/dist/server/sdk.mjs.map +1 -0
  126. package/dist/server/services/config.service.d.mts +33 -6
  127. package/dist/server/services/config.service.d.mts.map +1 -1
  128. package/dist/server/services/config.service.mjs +54 -30
  129. package/dist/server/services/config.service.mjs.map +1 -1
  130. package/dist/server/services/error-tracking.service.d.mts +3 -3
  131. package/dist/server/services/error-tracking.service.d.mts.map +1 -1
  132. package/dist/server/services/error-tracking.service.mjs +5 -3
  133. package/dist/server/services/error-tracking.service.mjs.map +1 -1
  134. package/dist/server/session-context.d.mts +60 -0
  135. package/dist/server/session-context.d.mts.map +1 -0
  136. package/dist/server/session-context.mjs +62 -0
  137. package/dist/server/session-context.mjs.map +1 -0
  138. package/package.json +58 -34
  139. package/dist/build/secret-key.d.mts +0 -10
  140. package/dist/build/secret-key.d.mts.map +0 -1
  141. package/dist/build/secret-key.mjs +0 -16
  142. package/dist/build/secret-key.mjs.map +0 -1
  143. package/dist/lib/test-utils/make-next-request.d.mts +0 -6
  144. package/dist/lib/test-utils/make-next-request.d.mts.map +0 -1
  145. package/dist/lib/test-utils/make-next-request.mjs +0 -12
  146. package/dist/lib/test-utils/make-next-request.mjs.map +0 -1
package/LICENSE CHANGED
@@ -1,6 +1,6 @@
1
1
  MIT License
2
2
 
3
- Copyright (c) 2025 Interfere, Inc.
3
+ Copyright (c) 2026 Interfere, Inc.
4
4
 
5
5
  Permission is hereby granted, free of charge, to any person obtaining a copy
6
6
  of this software and associated documentation files (the "Software"), to deal
package/README.md CHANGED
@@ -9,12 +9,40 @@ npm install @interfere/next
9
9
  # or
10
10
  yarn add @interfere/next
11
11
  # or
12
- pnpm add @interfere/next
12
+ bun add @interfere/next
13
13
  ```
14
14
 
15
15
  ## Quick Start
16
16
 
17
- ### 1. Initialize the SDK
17
+ ### 1. Server-Side Error Tracking (Recommended)
18
+
19
+ The recommended way to capture server-side errors in Next.js 15+ is via the `onRequestError` hook in `instrumentation.ts`. This captures errors from React Server Components, SSR, API routes, Server Actions, and more.
20
+
21
+ Create `instrumentation.ts` in your project root (or `src/` directory):
22
+
23
+ ```typescript
24
+ import { captureRequestError } from '@interfere/next/server/on-request-error';
25
+
26
+ export async function register() {
27
+ if (process.env.NEXT_RUNTIME === 'nodejs') {
28
+ const { autoInitServer } = await import('@interfere/next/server/auto-init');
29
+ autoInitServer();
30
+ }
31
+ }
32
+
33
+ export async function onRequestError(error, request, context) {
34
+ await captureRequestError({ error, request, context });
35
+ }
36
+ ```
37
+
38
+ The `onRequestError` hook provides rich context including:
39
+ - **routerKind**: "App Router" or "Pages Router"
40
+ - **routePath**: The route file path (e.g., `/app/api/users/route`)
41
+ - **routeType**: "render", "route", "action", "middleware", or "proxy"
42
+ - **renderSource**: For render errors - "react-server-components", "server-rendering", etc.
43
+ - **error.digest**: Unique error identifier for deduplication
44
+
45
+ ### 2. Initialize the Client SDK
18
46
 
19
47
  Create a file to initialize Interfere (e.g., `lib/interfere.ts`):
20
48
 
@@ -30,7 +58,7 @@ export const interfere = init({
30
58
  });
31
59
  ```
32
60
 
33
- ### 2. Add the Proxy Route
61
+ ### 3. Add the Proxy Route
34
62
 
35
63
  The SDK sends events through a server-side proxy route to keep your API credentials secure. Create `app/api/interfere/[[...path]]/route.ts`:
36
64
 
@@ -38,13 +66,13 @@ The SDK sends events through a server-side proxy route to keep your API credenti
38
66
  export { GET, OPTIONS, POST } from '@interfere/next/route-handler';
39
67
  ```
40
68
 
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`:
69
+ This route proxies client-side events to Interfere's ingest API using your `INTERFERE_API_KEY` environment variable. Add the key to your `.env.local`:
42
70
 
43
71
  ```bash
44
- INTERFERE_SECRET_KEY=if_sk_xxx
72
+ INTERFERE_API_KEY=ak_xxx
45
73
  ```
46
74
 
47
- ### 3. Add Error Boundary (App Directory)
75
+ ### 4. Add Error Boundary (App Directory)
48
76
 
49
77
  In your root layout (`app/layout.tsx`):
50
78
 
@@ -71,7 +99,7 @@ export default function RootLayout({
71
99
  }
72
100
  ```
73
101
 
74
- ### 4. Add Error Handler (App Directory)
102
+ ### 5. Add Error Handler (App Directory)
75
103
 
76
104
  Create `app/error.tsx`:
77
105
 
@@ -103,7 +131,7 @@ export default function Error({
103
131
  }
104
132
  ```
105
133
 
106
- ### 5. Add Global Error Handler
134
+ ### 6. Add Global Error Handler
107
135
 
108
136
  Create `app/global-error.tsx`:
109
137
 
@@ -0,0 +1,7 @@
1
+ import { createRequire } from "node:module";
2
+
3
+ //#region \0rolldown/runtime.js
4
+ var __require = /* @__PURE__ */ createRequire(import.meta.url);
5
+
6
+ //#endregion
7
+ export { __require };
@@ -2,6 +2,8 @@ import { NonEmptyString } from "../lib/types.mjs";
2
2
 
3
3
  //#region src/build/env-config.d.ts
4
4
  declare function resolveApiUrl(): string;
5
+ declare function normalizeApiKey(raw: string | undefined): NonEmptyString | null;
5
6
  declare function normalizeSecretKey(raw: string | undefined): NonEmptyString | null;
7
+ declare function normalizeSurfaceSlug(raw: string | undefined): NonEmptyString | null;
6
8
  //#endregion
7
- export { normalizeSecretKey, resolveApiUrl };
9
+ export { normalizeApiKey, normalizeSecretKey, normalizeSurfaceSlug, resolveApiUrl };
@@ -1 +1 @@
1
- {"version":3,"file":"env-config.d.mts","names":[],"sources":["../../src/build/env-config.ts"],"sourcesContent":[],"mappings":";;;iBAGgB,aAAA,CAAA;iBAWA,kBAAA,2BAEb"}
1
+ {"version":3,"file":"env-config.d.mts","names":[],"sources":["../../src/build/env-config.ts"],"mappings":";;;iBAGgB,aAAA,CAAA;AAAA,iBAWA,eAAA,CACd,GAAA,uBACC,cAAA;AAAA,iBAWa,kBAAA,CACd,GAAA,uBACC,cAAA;AAAA,iBAWa,oBAAA,CACd,GAAA,uBACC,cAAA"}
@@ -8,10 +8,18 @@ function resolveApiUrl() {
8
8
  if (trimmed.length > 0) return trimmed;
9
9
  return API_URL;
10
10
  }
11
+ function normalizeApiKey(raw) {
12
+ if (typeof raw !== "string") return null;
13
+ return toNonEmptyString(raw.trim().replace(/^['"]|['"]$/g, ""));
14
+ }
11
15
  function normalizeSecretKey(raw) {
12
16
  if (typeof raw !== "string") return null;
13
17
  return toNonEmptyString(raw.trim().replace(/^['"]|['"]$/g, ""));
14
18
  }
19
+ function normalizeSurfaceSlug(raw) {
20
+ if (typeof raw !== "string") return null;
21
+ return toNonEmptyString(raw.trim());
22
+ }
15
23
 
16
24
  //#endregion
17
- export { normalizeSecretKey, resolveApiUrl };
25
+ export { normalizeApiKey, normalizeSecretKey, normalizeSurfaceSlug, resolveApiUrl };
@@ -1 +1 @@
1
- {"version":3,"file":"env-config.mjs","names":[],"sources":["../../src/build/env-config.ts"],"sourcesContent":["import { API_URL } from \"@interfere/constants/api\";\nimport { type NonEmptyString, toNonEmptyString } from \"../lib/types.js\";\n\nexport function resolveApiUrl(): string {\n const raw = process.env.INTERFERE_API_URL;\n const trimmed = typeof raw === \"string\" ? raw.trim() : \"\";\n\n if (trimmed.length > 0) {\n return trimmed;\n }\n\n return API_URL;\n}\n\nexport function normalizeSecretKey(\n raw: string | undefined\n): NonEmptyString | null {\n if (typeof raw !== \"string\") {\n return null;\n }\n\n const trimmed = raw.trim();\n const cleaned = trimmed.replace(/^['\"]|['\"]$/g, \"\");\n\n return toNonEmptyString(cleaned);\n}\n\n\n"],"mappings":";;;;AAGA,SAAgB,gBAAwB;CACtC,MAAM,MAAM,QAAQ,IAAI;CACxB,MAAM,UAAU,OAAO,QAAQ,WAAW,IAAI,MAAM,GAAG;AAEvD,KAAI,QAAQ,SAAS,EACnB,QAAO;AAGT,QAAO;;AAGT,SAAgB,mBACd,KACuB;AACvB,KAAI,OAAO,QAAQ,SACjB,QAAO;AAMT,QAAO,iBAHS,IAAI,MAAM,CACF,QAAQ,gBAAgB,GAAG,CAEnB"}
1
+ {"version":3,"file":"env-config.mjs","names":[],"sources":["../../src/build/env-config.ts"],"sourcesContent":["import { API_URL } from \"@interfere/constants/api\";\nimport { type NonEmptyString, toNonEmptyString } from \"../lib/types.js\";\n\nexport function resolveApiUrl(): string {\n const raw = process.env.INTERFERE_API_URL;\n const trimmed = typeof raw === \"string\" ? raw.trim() : \"\";\n\n if (trimmed.length > 0) {\n return trimmed;\n }\n\n return API_URL;\n}\n\nexport function normalizeApiKey(\n raw: string | undefined\n): NonEmptyString | null {\n if (typeof raw !== \"string\") {\n return null;\n }\n\n const trimmed = raw.trim();\n const cleaned = trimmed.replace(/^['\"]|['\"]$/g, \"\");\n\n return toNonEmptyString(cleaned);\n}\n\nexport function normalizeSecretKey(\n raw: string | undefined\n): NonEmptyString | null {\n if (typeof raw !== \"string\") {\n return null;\n }\n\n const trimmed = raw.trim();\n const cleaned = trimmed.replace(/^['\"]|['\"]$/g, \"\");\n\n return toNonEmptyString(cleaned);\n}\n\nexport function normalizeSurfaceSlug(\n raw: string | undefined\n): NonEmptyString | null {\n if (typeof raw !== \"string\") {\n return null;\n }\n\n return toNonEmptyString(raw.trim());\n}\n\n"],"mappings":";;;;AAGA,SAAgB,gBAAwB;CACtC,MAAM,MAAM,QAAQ,IAAI;CACxB,MAAM,UAAU,OAAO,QAAQ,WAAW,IAAI,MAAM,GAAG;AAEvD,KAAI,QAAQ,SAAS,EACnB,QAAO;AAGT,QAAO;;AAGT,SAAgB,gBACd,KACuB;AACvB,KAAI,OAAO,QAAQ,SACjB,QAAO;AAMT,QAAO,iBAHS,IAAI,MAAM,CACF,QAAQ,gBAAgB,GAAG,CAEnB;;AAGlC,SAAgB,mBACd,KACuB;AACvB,KAAI,OAAO,QAAQ,SACjB,QAAO;AAMT,QAAO,iBAHS,IAAI,MAAM,CACF,QAAQ,gBAAgB,GAAG,CAEnB;;AAGlC,SAAgB,qBACd,KACuB;AACvB,KAAI,OAAO,QAAQ,SACjB,QAAO;AAGT,QAAO,iBAAiB,IAAI,MAAM,CAAC"}
@@ -0,0 +1,9 @@
1
+ //#region src/build/exchange-surface.d.ts
2
+ /**
3
+ * Build-time only: call auth exchange with API key (no surface slug) and return
4
+ * the surface slug from the response. Used to infer surface from key so we can
5
+ * bundle it and avoid runtime lookup.
6
+ */
7
+ declare function fetchSurfaceSlugFromExchange(apiUrl: string, apiKey: string): Promise<string | null>;
8
+ //#endregion
9
+ export { fetchSurfaceSlugFromExchange };
@@ -0,0 +1 @@
1
+ {"version":3,"file":"exchange-surface.d.mts","names":[],"sources":["../../src/build/exchange-surface.ts"],"mappings":";;AAKA;;;;iBAAsB,4BAAA,CACpB,MAAA,UACA,MAAA,WACC,OAAA"}
@@ -0,0 +1,36 @@
1
+ //#region src/build/exchange-surface.ts
2
+ /**
3
+ * Build-time only: call auth exchange with API key (no surface slug) and return
4
+ * the surface slug from the response. Used to infer surface from key so we can
5
+ * bundle it and avoid runtime lookup.
6
+ */
7
+ async function fetchSurfaceSlugFromExchange(apiUrl, apiKey) {
8
+ const url = `${apiUrl.replace(/\/$/, "")}/auth/exchange`;
9
+ const safePrefix = apiKey.length >= 5 ? `${apiKey.slice(0, 5)}...` : "(key set)";
10
+ if (process.env.NODE_ENV === "development" || process.env.DEBUG) console.info(`[Interfere] Sending auth/exchange with INTERFERE_API_KEY (${safePrefix}) to ${url}`);
11
+ const res = await fetch(url, {
12
+ method: "POST",
13
+ headers: {
14
+ "x-api-key": apiKey,
15
+ "Content-Type": "application/json"
16
+ },
17
+ body: "{}"
18
+ });
19
+ if (!res.ok) {
20
+ let hint = "";
21
+ try {
22
+ const body = await res.json();
23
+ if (body?.message) hint = ` Server: ${body.message}`;
24
+ else if (body?.code) hint = ` Server code: ${body.code}`;
25
+ } catch {}
26
+ const keyPrefix = apiKey.startsWith("ak_") ? "ak_..." : "key (not ak_...)";
27
+ const envMismatchHint = res.status === 401 ? "\n For 401: the key is being sent. If Clerk reports 'Not Found', the key was created in a different Clerk instance – use a key from the same environment as this API (sandbox key with sandbox API URL)." : "";
28
+ console.error(`[Interfere] auth/exchange returned ${res.status}.${hint}${envMismatchHint}\n INTERFERE_API_KEY is being sent (format: ${keyPrefix}). INTERFERE_API_URL: ${apiUrl}`);
29
+ return null;
30
+ }
31
+ const slug = (await res.json())?.surfaceSlug;
32
+ return typeof slug === "string" && slug.length > 0 ? slug : null;
33
+ }
34
+
35
+ //#endregion
36
+ export { fetchSurfaceSlugFromExchange };
@@ -0,0 +1 @@
1
+ {"version":3,"file":"exchange-surface.mjs","names":[],"sources":["../../src/build/exchange-surface.ts"],"sourcesContent":["/**\n * Build-time only: call auth exchange with API key (no surface slug) and return\n * the surface slug from the response. Used to infer surface from key so we can\n * bundle it and avoid runtime lookup.\n */\nexport async function fetchSurfaceSlugFromExchange(\n apiUrl: string,\n apiKey: string\n): Promise<string | null> {\n const url = `${apiUrl.replace(/\\/$/, \"\")}/auth/exchange`;\n const safePrefix =\n apiKey.length >= 5 ? `${apiKey.slice(0, 5)}...` : \"(key set)\";\n if (process.env.NODE_ENV === \"development\" || process.env.DEBUG) {\n console.info(\n `[Interfere] Sending auth/exchange with INTERFERE_API_KEY (${safePrefix}) to ${url}`\n );\n }\n const res = await fetch(url, {\n method: \"POST\",\n headers: {\n \"x-api-key\": apiKey,\n \"Content-Type\": \"application/json\",\n },\n body: \"{}\",\n });\n\n if (!res.ok) {\n let hint = \"\";\n try {\n const body = (await res.json()) as { message?: string; code?: string };\n if (body?.message) {\n hint = ` Server: ${body.message}`;\n } else if (body?.code) {\n hint = ` Server code: ${body.code}`;\n }\n } catch {\n // ignore non-JSON body\n }\n const keyPrefix = apiKey.startsWith(\"ak_\") ? \"ak_...\" : \"key (not ak_...)\";\n const envMismatchHint =\n res.status === 401\n ? \"\\n For 401: the key is being sent. If Clerk reports 'Not Found', the key was created in a different Clerk instance – use a key from the same environment as this API (sandbox key with sandbox API URL).\"\n : \"\";\n console.error(\n `[Interfere] auth/exchange returned ${res.status}.${hint}${envMismatchHint}\\n` +\n ` INTERFERE_API_KEY is being sent (format: ${keyPrefix}). INTERFERE_API_URL: ${apiUrl}`\n );\n return null;\n }\n\n const data = (await res.json()) as { surfaceSlug?: string };\n const slug = data?.surfaceSlug;\n return typeof slug === \"string\" && slug.length > 0 ? slug : null;\n}\n"],"mappings":";;;;;;AAKA,eAAsB,6BACpB,QACA,QACwB;CACxB,MAAM,MAAM,GAAG,OAAO,QAAQ,OAAO,GAAG,CAAC;CACzC,MAAM,aACJ,OAAO,UAAU,IAAI,GAAG,OAAO,MAAM,GAAG,EAAE,CAAC,OAAO;AACpD,KAAI,QAAQ,IAAI,aAAa,iBAAiB,QAAQ,IAAI,MACxD,SAAQ,KACN,6DAA6D,WAAW,OAAO,MAChF;CAEH,MAAM,MAAM,MAAM,MAAM,KAAK;EAC3B,QAAQ;EACR,SAAS;GACP,aAAa;GACb,gBAAgB;GACjB;EACD,MAAM;EACP,CAAC;AAEF,KAAI,CAAC,IAAI,IAAI;EACX,IAAI,OAAO;AACX,MAAI;GACF,MAAM,OAAQ,MAAM,IAAI,MAAM;AAC9B,OAAI,MAAM,QACR,QAAO,YAAY,KAAK;YACf,MAAM,KACf,QAAO,iBAAiB,KAAK;UAEzB;EAGR,MAAM,YAAY,OAAO,WAAW,MAAM,GAAG,WAAW;EACxD,MAAM,kBACJ,IAAI,WAAW,MACX,8MACA;AACN,UAAQ,MACN,sCAAsC,IAAI,OAAO,GAAG,OAAO,gBAAgB,+CAC3B,UAAU,wBAAwB,SACnF;AACD,SAAO;;CAIT,MAAM,QADQ,MAAM,IAAI,MAAM,GACX;AACnB,QAAO,OAAO,SAAS,YAAY,KAAK,SAAS,IAAI,OAAO"}
@@ -0,0 +1,22 @@
1
+ import { LoaderContext } from "webpack";
2
+
3
+ //#region src/build/loaders/value-injection-loader.d.ts
4
+ interface ValueInjectionLoaderOptions {
5
+ /** Key-value pairs to inject into globalThis (used by webpack) */
6
+ values?: Record<string, unknown>;
7
+ /** Serialized JSON string of values (used by turbopack to preserve null values) */
8
+ serializedValues?: string;
9
+ }
10
+ /**
11
+ * Webpack/Turbopack loader that injects build-time values into globalThis.
12
+ *
13
+ * This loader prepends code that sets values on globalThis, making them
14
+ * available at runtime without requiring environment variables.
15
+ *
16
+ * Supports two input formats:
17
+ * - `values`: Direct object with key-value pairs (webpack)
18
+ * - `serializedValues`: JSON-serialized string of values (turbopack)
19
+ */
20
+ declare function valueInjectionLoader(this: LoaderContext<ValueInjectionLoaderOptions>, userCode: string): string;
21
+ //#endregion
22
+ export { ValueInjectionLoaderOptions, valueInjectionLoader as default };
@@ -0,0 +1 @@
1
+ {"version":3,"file":"value-injection-loader.d.mts","names":[],"sources":["../../../src/build/loaders/value-injection-loader.ts"],"mappings":";;;UAEiB,2BAAA;;EAEf,MAAA,GAAS,MAAA;EAFiC;EAI1C,gBAAA;AAAA;;;;;;AACD;;;;;iBAYuB,oBAAA,CACtB,IAAA,EAAM,aAAA,CAAc,2BAAA,GACpB,QAAA"}
@@ -0,0 +1,35 @@
1
+ //#region src/build/loaders/value-injection-loader.ts
2
+ /**
3
+ * Webpack/Turbopack loader that injects build-time values into globalThis.
4
+ *
5
+ * This loader prepends code that sets values on globalThis, making them
6
+ * available at runtime without requiring environment variables.
7
+ *
8
+ * Supports two input formats:
9
+ * - `values`: Direct object with key-value pairs (webpack)
10
+ * - `serializedValues`: JSON-serialized string of values (turbopack)
11
+ */
12
+ function valueInjectionLoader(userCode) {
13
+ const options = this.getOptions();
14
+ let values = {};
15
+ if (options.serializedValues) try {
16
+ values = JSON.parse(options.serializedValues);
17
+ } catch {
18
+ values = {};
19
+ }
20
+ else if (options.values) values = options.values;
21
+ const injectionLines = [];
22
+ for (const [key, value] of Object.entries(values)) {
23
+ if (value === void 0) continue;
24
+ const serialized = JSON.stringify(value);
25
+ injectionLines.push(`globalThis["${escapeKey(key)}"] = ${serialized};`);
26
+ }
27
+ if (injectionLines.length === 0) return userCode;
28
+ return `${injectionLines.join("\n")}\n${userCode}`;
29
+ }
30
+ function escapeKey(key) {
31
+ return key.replace(/\\/g, "\\\\").replace(/"/g, "\\\"");
32
+ }
33
+
34
+ //#endregion
35
+ export { valueInjectionLoader as default };
@@ -0,0 +1 @@
1
+ {"version":3,"file":"value-injection-loader.mjs","names":[],"sources":["../../../src/build/loaders/value-injection-loader.ts"],"sourcesContent":["import type { LoaderContext } from \"webpack\";\n\nexport interface ValueInjectionLoaderOptions {\n /** Key-value pairs to inject into globalThis (used by webpack) */\n values?: Record<string, unknown>;\n /** Serialized JSON string of values (used by turbopack to preserve null values) */\n serializedValues?: string;\n}\n\n/**\n * Webpack/Turbopack loader that injects build-time values into globalThis.\n * \n * This loader prepends code that sets values on globalThis, making them\n * available at runtime without requiring environment variables.\n * \n * Supports two input formats:\n * - `values`: Direct object with key-value pairs (webpack)\n * - `serializedValues`: JSON-serialized string of values (turbopack)\n */\nexport default function valueInjectionLoader(\n this: LoaderContext<ValueInjectionLoaderOptions>,\n userCode: string\n): string {\n const options = this.getOptions();\n \n let values: Record<string, unknown> = {};\n if (options.serializedValues) {\n try {\n values = JSON.parse(options.serializedValues);\n } catch {\n values = {};\n }\n } else if (options.values) {\n values = options.values;\n }\n\n const injectionLines: string[] = [];\n\n for (const [key, value] of Object.entries(values)) {\n if (value === undefined) {\n continue;\n }\n\n const serialized = JSON.stringify(value);\n injectionLines.push(`globalThis[\"${escapeKey(key)}\"] = ${serialized};`);\n }\n\n if (injectionLines.length === 0) {\n return userCode;\n }\n\n const injectionCode = injectionLines.join(\"\\n\");\n return `${injectionCode}\\n${userCode}`;\n}\n\nfunction escapeKey(key: string): string {\n return key.replace(/\\\\/g, \"\\\\\\\\\").replace(/\"/g, '\\\\\"');\n}\n"],"mappings":";;;;;;;;;;;AAmBA,SAAwB,qBAEtB,UACQ;CACR,MAAM,UAAU,KAAK,YAAY;CAEjC,IAAI,SAAkC,EAAE;AACxC,KAAI,QAAQ,iBACV,KAAI;AACF,WAAS,KAAK,MAAM,QAAQ,iBAAiB;SACvC;AACN,WAAS,EAAE;;UAEJ,QAAQ,OACjB,UAAS,QAAQ;CAGnB,MAAM,iBAA2B,EAAE;AAEnC,MAAK,MAAM,CAAC,KAAK,UAAU,OAAO,QAAQ,OAAO,EAAE;AACjD,MAAI,UAAU,OACZ;EAGF,MAAM,aAAa,KAAK,UAAU,MAAM;AACxC,iBAAe,KAAK,eAAe,UAAU,IAAI,CAAC,OAAO,WAAW,GAAG;;AAGzE,KAAI,eAAe,WAAW,EAC5B,QAAO;AAIT,QAAO,GADe,eAAe,KAAK,KAAK,CACvB,IAAI;;AAG9B,SAAS,UAAU,KAAqB;AACtC,QAAO,IAAI,QAAQ,OAAO,OAAO,CAAC,QAAQ,MAAM,OAAM"}
@@ -5,7 +5,7 @@ declare const nextBuildLogger: Logger.Logger<unknown, void>;
5
5
  declare function logBuildResult(level: LogLevel.Literal, title: string, lines: string[]): Effect.Effect<void, never, never>;
6
6
  declare function setBuildLogTitle(level: LogLevel.Literal, title: string): Effect.Effect<void, never, never>;
7
7
  declare function appendBuildLogLine(line: string): Effect.Effect<void, never, never>;
8
- declare function flushBuildLog(): Effect.Effect<void, never, never>;
9
- declare function withBufferedBuildLog(level: LogLevel.Literal, title: string, use: (log: (line: string) => ReturnType<typeof appendBuildLogLine>) => Effect.Effect<unknown, unknown, unknown>): Effect.Effect<unknown, unknown, unknown>;
8
+ declare const flushBuildLog: () => Effect.Effect<void, never, never>;
9
+ declare function withBufferedBuildLog<A, E, R>(level: LogLevel.Literal, title: string, use: (log: (line: string) => ReturnType<typeof appendBuildLogLine>) => Effect.Effect<A, E, R>): Effect.Effect<A, E, R>;
10
10
  //#endregion
11
11
  export { appendBuildLogLine, flushBuildLog, logBuildResult, nextBuildLogger, setBuildLogTitle, withBufferedBuildLog };
@@ -1 +1 @@
1
- {"version":3,"file":"logger.d.mts","names":[],"sources":["../../src/build/logger.ts"],"sourcesContent":[],"mappings":";;;cA+CM,iBAAe,MAAA,CAAA;AAAf,iBA0HU,cAAA,CA1HK,KAAA,EA0HiB,QAAA,CAAS,OA1H1B,EAAA,KAAA,EAAA,MAAA,EAAA,KAAA,EAAA,MAAA,EAAA,CAAA,EA0HiE,MAAA,CAAA,MA1HjE,CAAA,IAAA,EAAA,KAAA,EAAA,KAAA,CAAA;AA0HL,iBAyCA,gBAAA,CAzC+B,KAAA,EA0CtC,QAAA,CAAS,OA1CoE,EAAA,KAAA,EAAA,MAAA,CAAA,EA2CvE,MAAA,CAAA,MA3CuE,CAAA,IAAA,EAAA,KAAA,EAAA,KAAA,CAAA;AAyCtE,iBAUA,kBAAA,CATE,IAAA,EAAA,MACH,CAAA,EAQgC,MAAA,CAAA,MARhC,CAAA,IAAA,EAAA,KAAA,EAAA,KAAA,CAAA;AAQC,iBAWA,aAAA,CAAA,CAX+B,EAWlB,MAAA,CAAA,MAXkB,CAAA,IAAA,EAAA,KAAA,EAAA,KAAA,CAAA;AAW/B,iBAmBA,oBAAA,CAnBa,KAAA,EAoBpB,QAAA,CAAS,OApBW,EAAA,KAAA,EAAA,MAAA,EAAA,GAAA,EAAA,CAAA,GAAA,EAAA,CAAA,IAAA,EAAA,MAAA,EAAA,GAuBF,UAvBE,CAAA,OAuBgB,kBAvBhB,CAAA,EAAA,GAwBtB,MAAA,CAAO,MAxBe,CAAA,OAAA,EAAA,OAAA,EAAA,OAAA,CAAA,CAAA,EAwBkB,MAAA,CAAA,MAxBlB,CAAA,OAAA,EAAA,OAAA,EAAA,OAAA,CAAA"}
1
+ {"version":3,"file":"logger.d.mts","names":[],"sources":["../../src/build/logger.ts"],"mappings":";;;cA+CM,eAAA,EAAe,MAAA,CAAA,MAAA;AAAA,iBA0HL,cAAA,CAAe,KAAA,EAAO,QAAA,CAAS,OAAA,EAAS,KAAA,UAAe,KAAA,aAAe,MAAA,CAAA,MAAA;AAAA,iBAyCtE,gBAAA,CACd,KAAA,EAAO,QAAA,CAAS,OAAA,EAChB,KAAA,WAAa,MAAA,CAAA,MAAA;AAAA,iBAQC,kBAAA,CAAmB,IAAA,WAAY,MAAA,CAAA,MAAA;AAAA,cAWlC,aAAA,QAAa,MAAA,CAAA,MAAA;AAAA,iBAiBV,oBAAA,SAAA,CACd,KAAA,EAAO,QAAA,CAAS,OAAA,EAChB,KAAA,UACA,GAAA,GACE,GAAA,GAAM,IAAA,aAAiB,UAAA,QAAkB,kBAAA,MACtC,MAAA,CAAO,MAAA,CAAO,CAAA,EAAG,CAAA,EAAG,CAAA,IACxB,MAAA,CAAO,MAAA,CAAO,CAAA,EAAG,CAAA,EAAG,CAAA"}
@@ -125,18 +125,16 @@ function appendBuildLogLine(line) {
125
125
  buildLogState.lines.push(trimmed);
126
126
  });
127
127
  }
128
- function flushBuildLog() {
129
- return Effect.gen(function* () {
130
- if (!buildLogState.title || buildLogState.lines.length === 0) return;
131
- const level = buildLogState.level;
132
- const title = buildLogState.title;
133
- const lines = [...buildLogState.lines];
134
- buildLogState.level = "Info";
135
- buildLogState.title = null;
136
- buildLogState.lines = [];
137
- yield* logBuildResult(level, title, lines);
138
- });
139
- }
128
+ const flushBuildLog = Effect.fn("flushBuildLog")(function* () {
129
+ if (!buildLogState.title || buildLogState.lines.length === 0) return;
130
+ const level = buildLogState.level;
131
+ const title = buildLogState.title;
132
+ const lines = [...buildLogState.lines];
133
+ buildLogState.level = "Info";
134
+ buildLogState.title = null;
135
+ buildLogState.lines = [];
136
+ yield* logBuildResult(level, title, lines);
137
+ });
140
138
  function withBufferedBuildLog(level, title, use) {
141
139
  return Effect.acquireUseRelease(setBuildLogTitle(level, title), () => use((line) => appendBuildLogLine(line)), (_, _exit) => flushBuildLog());
142
140
  }
@@ -1 +1 @@
1
- {"version":3,"file":"logger.mjs","names":["prefixes: Record<LogLevel.Literal, string>","textStyles: Record<LogLevel.Literal, ChalkInstance>","logMethods: Partial<Record<LogLevel.Literal, keyof Console>>","buildLogState: BuildLogState"],"sources":["../../src/build/logger.ts"],"sourcesContent":["import { InterfereLogger } from \"@interfere/effect-utils/observability\";\nimport chalk, { type ChalkInstance } from \"chalk\";\nimport { Cause, Effect, Logger, LogLevel } from \"effect\";\n\nconst buildConsole = globalThis.console;\n\nconst prefixes: Record<LogLevel.Literal, string> = {\n Info: chalk.cyan.bold(\" \"),\n Debug: chalk.gray.bold(\" \"),\n All: chalk.gray.bold(\" \"),\n Trace: chalk.magenta.bold(\" \"),\n Warning: chalk.yellow.bold(\"⚠\"),\n Error: chalk.red.bold(\"⨯\"),\n Fatal: chalk.red.bold(\"⨯\"),\n None: chalk.white.bold(\" \"),\n} as const;\n\nconst textStyles: Record<LogLevel.Literal, ChalkInstance> = {\n Info: chalk.cyan.bold,\n Debug: chalk.gray.bold,\n All: chalk.gray.bold,\n Trace: chalk.magenta.bold,\n Warning: chalk.yellow.bold,\n Error: chalk.red.bold,\n Fatal: chalk.red.bold,\n None: chalk.white.bold,\n}\n\nconst logMethods: Partial<Record<LogLevel.Literal, keyof Console>> = {\n Warning: \"warn\",\n Error: \"error\",\n};\n\nfunction tagForLevel(level: LogLevel.Literal) {\n switch (level) {\n case \"Error\":\n case \"Fatal\":\n return \"[error]\";\n case \"Warning\":\n return \"[warn]\";\n case \"Debug\":\n return \"[debug]\";\n default:\n return \"\";\n }\n}\n\nconst nextBuildLogger = Logger.make<unknown, void>(\n ({ logLevel, message, cause }) => {\n if (!shouldLog(logLevel._tag)) {\n return;\n }\n\n const renderedMessage = coerceToArray(message)\n .map(formatValue)\n .filter(Boolean)\n .join(\" \")\n .trim();\n\n if (renderedMessage.length > 0) {\n levelLog(logLevel._tag, renderedMessage);\n } else {\n levelLog(logLevel._tag);\n }\n\n if (!Cause.isEmpty(cause)) {\n levelLog(\n logLevel._tag,\n `${chalk.dim(\"details\")} ${Cause.pretty(cause, {\n renderErrorCause: true,\n })}`\n );\n }\n }\n);\n\n\n\nfunction systemLog(level: LogLevel.Literal, ...message: string[]) {\n if (!shouldLog(level)) {\n return;\n }\n\n const consoleMethod = logMethods[level] ?? \"log\";\n\n const consoleFn = buildConsole[consoleMethod];\n if (typeof consoleFn !== \"function\") {\n return;\n }\n\n const invoke = (...args: unknown[]) =>\n Reflect.apply(consoleFn, buildConsole, args);\n\n if (message.length === 0) {\n invoke(\"\");\n return;\n }\n\n if (message.length === 1) {\n invoke(` ${message[0]}`);\n return;\n }\n\n invoke(` `, ...message);\n}\n\nfunction coerceToArray(value: unknown): string[] {\n if (Array.isArray(value)) {\n return value.map(formatValue);\n }\n\n return [formatValue(value)];\n}\n\nfunction formatValue(value: unknown): string {\n if (typeof value === \"string\") {\n return value;\n }\n\n if (value instanceof Error) {\n return value.stack ?? value.message;\n }\n\n if (value === null || value === undefined) {\n return \"\";\n }\n\n try {\n return JSON.stringify(value);\n } catch {\n return String(value);\n }\n}\n\nexport { nextBuildLogger };\n\nfunction levelLog(level: LogLevel.Literal, ...message: string[]) {\n if (!shouldLog(level)) {\n return;\n }\n\n const consoleMethod = logMethods[level] ?? \"log\";\n const prefix = prefixes[level] ?? prefixes.Info;\n const tag = tagForLevel(level);\n\n const consoleFn = buildConsole[consoleMethod];\n\n if (typeof consoleFn !== \"function\") {\n return;\n }\n\n const invoke = (...args: unknown[]) =>\n Reflect.apply(consoleFn, buildConsole, args);\n\n if (message.length === 0) {\n invoke(\"\");\n return;\n }\n\n const tagPart = tag ? ` ${tag}` : \"\";\n\n if (message.length === 1) {\n invoke(` ${prefix}${tagPart} ${message[0]}`);\n return;\n }\n\n invoke(` ${prefix}${tagPart}`, ...message);\n}\n\nexport function logBuildResult(level: LogLevel.Literal, title: string, lines: string[]) {\n if (!shouldLog(level)) {\n return Effect.void;\n }\n\n return Effect.sync(() => {\n systemLog(level, `❖ ${chalk.white(\"Interfere →\")} ${textStyles[level](title)}`);\n\n if (lines.length === 0) {\n return;\n }\n\n const prefix = prefixes[level] ?? prefixes.Info;\n const tag = tagForLevel(level);\n const tagPart = tag ? `${tag} ` : \"\";\n const consoleMethod = logMethods[level] ?? \"log\";\n const consoleFn = buildConsole[consoleMethod];\n\n if (typeof consoleFn !== \"function\") {\n return;\n }\n\n const invoke = (...args: unknown[]) =>\n Reflect.apply(consoleFn, buildConsole, args);\n\n if (lines.length === 1) {\n // Single line - connector plus tag after the connector\n const connector = \"└\";\n invoke(` ${prefix} ${connector} ${tagPart}${lines[0]}`);\n return;\n }\n\n // Multi-line - tree structure with connectors and tag after connector\n lines.forEach((line, index) => {\n const isLast = index === lines.length - 1;\n const connector = isLast ? \"└\" : \"├\";\n invoke(` ${prefix} ${connector} ${tagPart}${line}`);\n });\n });\n}\n\nexport function setBuildLogTitle(\n level: LogLevel.Literal,\n title: string\n) {\n return Effect.sync(() => {\n buildLogState.level = level;\n buildLogState.title = title;\n });\n}\n\nexport function appendBuildLogLine(line: string) {\n return Effect.sync(() => {\n const trimmed = line.trim();\n if (trimmed.length === 0) {\n return;\n }\n\n buildLogState.lines.push(trimmed);\n });\n}\n\nexport function flushBuildLog() {\n return Effect.gen(function* () {\n if (!buildLogState.title || buildLogState.lines.length === 0) {\n return;\n }\n\n const level = buildLogState.level;\n const title = buildLogState.title;\n const lines = [...buildLogState.lines];\n\n // Reset state before logging in case logging itself fails\n buildLogState.level = \"Info\";\n buildLogState.title = null;\n buildLogState.lines = [];\n\n yield* logBuildResult(level, title, lines);\n });\n}\n\nexport function withBufferedBuildLog(\n level: LogLevel.Literal,\n title: string,\n use: (\n log: (line: string) => ReturnType<typeof appendBuildLogLine>\n ) => Effect.Effect<unknown, unknown, unknown>\n) {\n return Effect.acquireUseRelease(\n setBuildLogTitle(level, title),\n () => use((line) => appendBuildLogLine(line)),\n (_, _exit) => flushBuildLog()\n );\n}\n\ntype BuildLogState = {\n level: LogLevel.Literal;\n title: string | null;\n lines: string[];\n};\n\nconst buildLogState: BuildLogState = {\n level: \"Info\",\n title: null,\n lines: [],\n};\n\nfunction shouldLog(level: LogLevel.Literal) {\n const debugEnabled = process.env.INTERFERE_PLUGIN_DEBUG === \"1\";\n const minLevel = debugEnabled ? LogLevel.Debug : InterfereLogger.minimumLevel();\n const currentLevel = LogLevel.fromLiteral(level);\n return LogLevel.greaterThanEqual(currentLevel, minLevel);\n}\n\n"],"mappings":";;;;;AAIA,MAAM,eAAe,WAAW;AAEhC,MAAMA,WAA6C;CACjD,MAAM,MAAM,KAAK,KAAK,IAAI;CAC1B,OAAO,MAAM,KAAK,KAAK,IAAI;CAC3B,KAAK,MAAM,KAAK,KAAK,IAAI;CACzB,OAAO,MAAM,QAAQ,KAAK,IAAI;CAC9B,SAAS,MAAM,OAAO,KAAK,IAAI;CAC/B,OAAO,MAAM,IAAI,KAAK,IAAI;CAC1B,OAAO,MAAM,IAAI,KAAK,IAAI;CAC1B,MAAM,MAAM,MAAM,KAAK,IAAI;CAC5B;AAED,MAAMC,aAAsD;CAC1D,MAAM,MAAM,KAAK;CACjB,OAAO,MAAM,KAAK;CAClB,KAAK,MAAM,KAAK;CAChB,OAAO,MAAM,QAAQ;CACrB,SAAS,MAAM,OAAO;CACtB,OAAO,MAAM,IAAI;CACjB,OAAO,MAAM,IAAI;CACjB,MAAM,MAAM,MAAM;CACnB;AAED,MAAMC,aAA+D;CACnE,SAAS;CACT,OAAO;CACR;AAED,SAAS,YAAY,OAAyB;AAC5C,SAAQ,OAAR;EACE,KAAK;EACL,KAAK,QACH,QAAO;EACT,KAAK,UACH,QAAO;EACT,KAAK,QACH,QAAO;EACT,QACE,QAAO;;;AAIb,MAAM,kBAAkB,OAAO,MAC5B,EAAE,UAAU,SAAS,YAAY;AAChC,KAAI,CAAC,UAAU,SAAS,KAAK,CAC3B;CAGF,MAAM,kBAAkB,cAAc,QAAQ,CAC3C,IAAI,YAAY,CAChB,OAAO,QAAQ,CACf,KAAK,IAAI,CACT,MAAM;AAET,KAAI,gBAAgB,SAAS,EAC3B,UAAS,SAAS,MAAM,gBAAgB;KAExC,UAAS,SAAS,KAAK;AAGzB,KAAI,CAAC,MAAM,QAAQ,MAAM,CACvB,UACE,SAAS,MACT,GAAG,MAAM,IAAI,UAAU,CAAC,GAAG,MAAM,OAAO,OAAO,EAC7C,kBAAkB,MACnB,CAAC,GACH;EAGN;AAID,SAAS,UAAU,OAAyB,GAAG,SAAmB;AAChE,KAAI,CAAC,UAAU,MAAM,CACnB;CAKF,MAAM,YAAY,aAFI,WAAW,UAAU;AAG3C,KAAI,OAAO,cAAc,WACvB;CAGF,MAAM,UAAU,GAAG,SACjB,QAAQ,MAAM,WAAW,cAAc,KAAK;AAE9C,KAAI,QAAQ,WAAW,GAAG;AACxB,SAAO,GAAG;AACV;;AAGF,KAAI,QAAQ,WAAW,GAAG;AACxB,SAAO,IAAI,QAAQ,KAAK;AACxB;;AAGF,QAAO,KAAK,GAAG,QAAQ;;AAGzB,SAAS,cAAc,OAA0B;AAC/C,KAAI,MAAM,QAAQ,MAAM,CACtB,QAAO,MAAM,IAAI,YAAY;AAG/B,QAAO,CAAC,YAAY,MAAM,CAAC;;AAG7B,SAAS,YAAY,OAAwB;AAC3C,KAAI,OAAO,UAAU,SACnB,QAAO;AAGT,KAAI,iBAAiB,MACnB,QAAO,MAAM,SAAS,MAAM;AAG9B,KAAI,UAAU,QAAQ,UAAU,OAC9B,QAAO;AAGT,KAAI;AACF,SAAO,KAAK,UAAU,MAAM;SACtB;AACN,SAAO,OAAO,MAAM;;;AAMxB,SAAS,SAAS,OAAyB,GAAG,SAAmB;AAC/D,KAAI,CAAC,UAAU,MAAM,CACnB;CAGF,MAAM,gBAAgB,WAAW,UAAU;CAC3C,MAAM,SAAS,SAAS,UAAU,SAAS;CAC3C,MAAM,MAAM,YAAY,MAAM;CAE9B,MAAM,YAAY,aAAa;AAE/B,KAAI,OAAO,cAAc,WACvB;CAGF,MAAM,UAAU,GAAG,SACjB,QAAQ,MAAM,WAAW,cAAc,KAAK;AAE9C,KAAI,QAAQ,WAAW,GAAG;AACxB,SAAO,GAAG;AACV;;CAGF,MAAM,UAAU,MAAM,IAAI,QAAQ;AAElC,KAAI,QAAQ,WAAW,GAAG;AACxB,SAAO,IAAI,SAAS,QAAQ,GAAG,QAAQ,KAAK;AAC5C;;AAGF,QAAO,IAAI,SAAS,WAAW,GAAG,QAAQ;;AAG5C,SAAgB,eAAe,OAAyB,OAAe,OAAiB;AACtF,KAAI,CAAC,UAAU,MAAM,CACnB,QAAO,OAAO;AAGhB,QAAO,OAAO,WAAW;AACvB,YAAU,OAAO,KAAK,MAAM,MAAM,cAAc,CAAC,GAAG,WAAW,OAAO,MAAM,GAAG;AAE/E,MAAI,MAAM,WAAW,EACnB;EAGF,MAAM,SAAS,SAAS,UAAU,SAAS;EAC3C,MAAM,MAAM,YAAY,MAAM;EAC9B,MAAM,UAAU,MAAM,GAAG,IAAI,KAAK;EAElC,MAAM,YAAY,aADI,WAAW,UAAU;AAG3C,MAAI,OAAO,cAAc,WACvB;EAGF,MAAM,UAAU,GAAG,SACjB,QAAQ,MAAM,WAAW,cAAc,KAAK;AAE9C,MAAI,MAAM,WAAW,GAAG;AAGtB,UAAO,IAAI,OAAO,KAAgB,UAAU,MAAM,KAAK;AACvD;;AAIF,QAAM,SAAS,MAAM,UAAU;AAG7B,UAAO,IAAI,OAAO,GAFH,UAAU,MAAM,SAAS,IACb,MAAM,IACF,GAAG,UAAU,OAAO;IACnD;GACF;;AAGJ,SAAgB,iBACd,OACA,OACA;AACA,QAAO,OAAO,WAAW;AACvB,gBAAc,QAAQ;AACtB,gBAAc,QAAQ;GACtB;;AAGJ,SAAgB,mBAAmB,MAAc;AAC/C,QAAO,OAAO,WAAW;EACvB,MAAM,UAAU,KAAK,MAAM;AAC3B,MAAI,QAAQ,WAAW,EACrB;AAGF,gBAAc,MAAM,KAAK,QAAQ;GACjC;;AAGJ,SAAgB,gBAAgB;AAC9B,QAAO,OAAO,IAAI,aAAa;AAC7B,MAAI,CAAC,cAAc,SAAS,cAAc,MAAM,WAAW,EACzD;EAGF,MAAM,QAAQ,cAAc;EAC5B,MAAM,QAAQ,cAAc;EAC5B,MAAM,QAAQ,CAAC,GAAG,cAAc,MAAM;AAGtC,gBAAc,QAAQ;AACtB,gBAAc,QAAQ;AACtB,gBAAc,QAAQ,EAAE;AAExB,SAAO,eAAe,OAAO,OAAO,MAAM;GAC1C;;AAGJ,SAAgB,qBACd,OACA,OACA,KAGA;AACA,QAAO,OAAO,kBACZ,iBAAiB,OAAO,MAAM,QACxB,KAAK,SAAS,mBAAmB,KAAK,CAAC,GAC5C,GAAG,UAAU,eAAe,CAC9B;;AASH,MAAMC,gBAA+B;CACnC,OAAO;CACP,OAAO;CACP,OAAO,EAAE;CACV;AAED,SAAS,UAAU,OAAyB;CAE1C,MAAM,WADe,QAAQ,IAAI,2BAA2B,MAC5B,SAAS,QAAQ,gBAAgB,cAAc;CAC/E,MAAM,eAAe,SAAS,YAAY,MAAM;AAChD,QAAO,SAAS,iBAAiB,cAAc,SAAS"}
1
+ {"version":3,"file":"logger.mjs","names":[],"sources":["../../src/build/logger.ts"],"sourcesContent":["import { InterfereLogger } from \"@interfere/effect-utils/observability\";\nimport chalk, { type ChalkInstance } from \"chalk\";\nimport { Cause, Effect, Logger, LogLevel } from \"effect\";\n\nconst buildConsole = globalThis.console;\n\nconst prefixes: Record<LogLevel.Literal, string> = {\n Info: chalk.cyan.bold(\" \"),\n Debug: chalk.gray.bold(\" \"),\n All: chalk.gray.bold(\" \"),\n Trace: chalk.magenta.bold(\" \"),\n Warning: chalk.yellow.bold(\"⚠\"),\n Error: chalk.red.bold(\"⨯\"),\n Fatal: chalk.red.bold(\"⨯\"),\n None: chalk.white.bold(\" \"),\n} as const;\n\nconst textStyles: Record<LogLevel.Literal, ChalkInstance> = {\n Info: chalk.cyan.bold,\n Debug: chalk.gray.bold,\n All: chalk.gray.bold,\n Trace: chalk.magenta.bold,\n Warning: chalk.yellow.bold,\n Error: chalk.red.bold,\n Fatal: chalk.red.bold,\n None: chalk.white.bold,\n}\n\nconst logMethods: Partial<Record<LogLevel.Literal, keyof Console>> = {\n Warning: \"warn\",\n Error: \"error\",\n};\n\nfunction tagForLevel(level: LogLevel.Literal) {\n switch (level) {\n case \"Error\":\n case \"Fatal\":\n return \"[error]\";\n case \"Warning\":\n return \"[warn]\";\n case \"Debug\":\n return \"[debug]\";\n default:\n return \"\";\n }\n}\n\nconst nextBuildLogger = Logger.make<unknown, void>(\n ({ logLevel, message, cause }) => {\n if (!shouldLog(logLevel._tag)) {\n return;\n }\n\n const renderedMessage = coerceToArray(message)\n .map(formatValue)\n .filter(Boolean)\n .join(\" \")\n .trim();\n\n if (renderedMessage.length > 0) {\n levelLog(logLevel._tag, renderedMessage);\n } else {\n levelLog(logLevel._tag);\n }\n\n if (!Cause.isEmpty(cause)) {\n levelLog(\n logLevel._tag,\n `${chalk.dim(\"details\")} ${Cause.pretty(cause, {\n renderErrorCause: true,\n })}`\n );\n }\n }\n);\n\n\n\nfunction systemLog(level: LogLevel.Literal, ...message: string[]) {\n if (!shouldLog(level)) {\n return;\n }\n\n const consoleMethod = logMethods[level] ?? \"log\";\n\n const consoleFn = buildConsole[consoleMethod];\n if (typeof consoleFn !== \"function\") {\n return;\n }\n\n const invoke = (...args: unknown[]) =>\n Reflect.apply(consoleFn, buildConsole, args);\n\n if (message.length === 0) {\n invoke(\"\");\n return;\n }\n\n if (message.length === 1) {\n invoke(` ${message[0]}`);\n return;\n }\n\n invoke(` `, ...message);\n}\n\nfunction coerceToArray(value: unknown): string[] {\n if (Array.isArray(value)) {\n return value.map(formatValue);\n }\n\n return [formatValue(value)];\n}\n\nfunction formatValue(value: unknown): string {\n if (typeof value === \"string\") {\n return value;\n }\n\n if (value instanceof Error) {\n return value.stack ?? value.message;\n }\n\n if (value === null || value === undefined) {\n return \"\";\n }\n\n try {\n return JSON.stringify(value);\n } catch {\n return String(value);\n }\n}\n\nexport { nextBuildLogger };\n\nfunction levelLog(level: LogLevel.Literal, ...message: string[]) {\n if (!shouldLog(level)) {\n return;\n }\n\n const consoleMethod = logMethods[level] ?? \"log\";\n const prefix = prefixes[level] ?? prefixes.Info;\n const tag = tagForLevel(level);\n\n const consoleFn = buildConsole[consoleMethod];\n\n if (typeof consoleFn !== \"function\") {\n return;\n }\n\n const invoke = (...args: unknown[]) =>\n Reflect.apply(consoleFn, buildConsole, args);\n\n if (message.length === 0) {\n invoke(\"\");\n return;\n }\n\n const tagPart = tag ? ` ${tag}` : \"\";\n\n if (message.length === 1) {\n invoke(` ${prefix}${tagPart} ${message[0]}`);\n return;\n }\n\n invoke(` ${prefix}${tagPart}`, ...message);\n}\n\nexport function logBuildResult(level: LogLevel.Literal, title: string, lines: string[]) {\n if (!shouldLog(level)) {\n return Effect.void;\n }\n\n return Effect.sync(() => {\n systemLog(level, `❖ ${chalk.white(\"Interfere →\")} ${textStyles[level](title)}`);\n\n if (lines.length === 0) {\n return;\n }\n\n const prefix = prefixes[level] ?? prefixes.Info;\n const tag = tagForLevel(level);\n const tagPart = tag ? `${tag} ` : \"\";\n const consoleMethod = logMethods[level] ?? \"log\";\n const consoleFn = buildConsole[consoleMethod];\n\n if (typeof consoleFn !== \"function\") {\n return;\n }\n\n const invoke = (...args: unknown[]) =>\n Reflect.apply(consoleFn, buildConsole, args);\n\n if (lines.length === 1) {\n // Single line - connector plus tag after the connector\n const connector = \"└\";\n invoke(` ${prefix} ${connector} ${tagPart}${lines[0]}`);\n return;\n }\n\n // Multi-line - tree structure with connectors and tag after connector\n lines.forEach((line, index) => {\n const isLast = index === lines.length - 1;\n const connector = isLast ? \"└\" : \"├\";\n invoke(` ${prefix} ${connector} ${tagPart}${line}`);\n });\n });\n}\n\nexport function setBuildLogTitle(\n level: LogLevel.Literal,\n title: string\n) {\n return Effect.sync(() => {\n buildLogState.level = level;\n buildLogState.title = title;\n });\n}\n\nexport function appendBuildLogLine(line: string) {\n return Effect.sync(() => {\n const trimmed = line.trim();\n if (trimmed.length === 0) {\n return;\n }\n\n buildLogState.lines.push(trimmed);\n });\n}\n\nexport const flushBuildLog = Effect.fn(\"flushBuildLog\")(function* () {\n if (!buildLogState.title || buildLogState.lines.length === 0) {\n return;\n }\n\n const level = buildLogState.level;\n const title = buildLogState.title;\n const lines = [...buildLogState.lines];\n\n // Reset state before logging in case logging itself fails\n buildLogState.level = \"Info\";\n buildLogState.title = null;\n buildLogState.lines = [];\n\n yield* logBuildResult(level, title, lines);\n });\n\nexport function withBufferedBuildLog<A, E, R>(\n level: LogLevel.Literal,\n title: string,\n use: (\n log: (line: string) => ReturnType<typeof appendBuildLogLine>\n ) => Effect.Effect<A, E, R>\n): Effect.Effect<A, E, R> {\n return Effect.acquireUseRelease(\n setBuildLogTitle(level, title),\n () => use((line) => appendBuildLogLine(line)),\n (_, _exit) => flushBuildLog()\n );\n}\n\ntype BuildLogState = {\n level: LogLevel.Literal;\n title: string | null;\n lines: string[];\n};\n\nconst buildLogState: BuildLogState = {\n level: \"Info\",\n title: null,\n lines: [],\n};\n\nfunction shouldLog(level: LogLevel.Literal) {\n const debugEnabled = process.env.INTERFERE_PLUGIN_DEBUG === \"1\";\n const minLevel = debugEnabled ? LogLevel.Debug : InterfereLogger.minimumLevel();\n const currentLevel = LogLevel.fromLiteral(level);\n return LogLevel.greaterThanEqual(currentLevel, minLevel);\n}\n\n"],"mappings":"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"}
@@ -0,0 +1,40 @@
1
+ //#region src/build/nextjs-version.d.ts
2
+ /**
3
+ * Parsed semver version components
4
+ */
5
+ type ParsedSemver = {
6
+ major: number | undefined;
7
+ minor: number | undefined;
8
+ patch: number | undefined;
9
+ prerelease: string | undefined;
10
+ };
11
+ /**
12
+ * Parses a semver version string into its components
13
+ *
14
+ * @param version - version string to parse (e.g., "15.0.0-canary.124")
15
+ * @returns parsed version components
16
+ */
17
+ declare function parseSemver(version: string): ParsedSemver;
18
+ /**
19
+ * Determines if a Next.js version requires the experimental.instrumentationHook option.
20
+ *
21
+ * - Next.js 16+: Never requires the hook (instrumentation is fully stable)
22
+ * - Next.js 14 and below: Always requires the hook
23
+ * - Next.js 15 stable releases (15.0.0+): Doesn't require the hook
24
+ * - Next.js 15 prereleases:
25
+ * - rc.0 requires it, other RCs don't
26
+ * - Canary versions before canary.124 require it
27
+ * - Other prereleases (alpha, beta) require it
28
+ *
29
+ * @param version - version string to check
30
+ * @returns true if the version requires the instrumentationHook option to be set
31
+ */
32
+ declare function requiresInstrumentationHook(version: string): boolean;
33
+ /**
34
+ * Attempts to detect the installed Next.js version.
35
+ *
36
+ * @returns The Next.js version string, or undefined if it cannot be determined
37
+ */
38
+ declare function detectNextJsVersion(): string | undefined;
39
+ //#endregion
40
+ export { ParsedSemver, detectNextJsVersion, parseSemver, requiresInstrumentationHook };
@@ -0,0 +1 @@
1
+ {"version":3,"file":"nextjs-version.d.mts","names":[],"sources":["../../src/build/nextjs-version.ts"],"mappings":";;AAGA;;KAAY,YAAA;EACV,KAAA;EACA,KAAA;EACA,KAAA;EACA,UAAA;AAAA;;;AASF;;;;iBAAgB,WAAA,CAAY,OAAA,WAAkB,YAAA;AAoC9C;;;;;AAoDA;;;;;;;;;AApDA,iBAAgB,2BAAA,CAA4B,OAAA;;;;;;iBAoD5B,mBAAA,CAAA"}
@@ -0,0 +1,66 @@
1
+ import { __require } from "../_virtual/_rolldown/runtime.mjs";
2
+
3
+ //#region src/build/nextjs-version.ts
4
+ /**
5
+ * Parses a semver version string into its components
6
+ *
7
+ * @param version - version string to parse (e.g., "15.0.0-canary.124")
8
+ * @returns parsed version components
9
+ */
10
+ function parseSemver(version) {
11
+ const match = version.match(/^(\d+)\.(\d+)\.(\d+)(?:-(.+))?$/);
12
+ if (!match) return {
13
+ major: void 0,
14
+ minor: void 0,
15
+ patch: void 0,
16
+ prerelease: void 0
17
+ };
18
+ const [, majorStr, minorStr, patchStr, prerelease] = match;
19
+ return {
20
+ major: majorStr ? Number.parseInt(majorStr, 10) : void 0,
21
+ minor: minorStr ? Number.parseInt(minorStr, 10) : void 0,
22
+ patch: patchStr ? Number.parseInt(patchStr, 10) : void 0,
23
+ prerelease
24
+ };
25
+ }
26
+ /**
27
+ * Determines if a Next.js version requires the experimental.instrumentationHook option.
28
+ *
29
+ * - Next.js 16+: Never requires the hook (instrumentation is fully stable)
30
+ * - Next.js 14 and below: Always requires the hook
31
+ * - Next.js 15 stable releases (15.0.0+): Doesn't require the hook
32
+ * - Next.js 15 prereleases:
33
+ * - rc.0 requires it, other RCs don't
34
+ * - Canary versions before canary.124 require it
35
+ * - Other prereleases (alpha, beta) require it
36
+ *
37
+ * @param version - version string to check
38
+ * @returns true if the version requires the instrumentationHook option to be set
39
+ */
40
+ function requiresInstrumentationHook(version) {
41
+ if (!version) return true;
42
+ const { major, minor, patch, prerelease } = parseSemver(version);
43
+ if (major === void 0 || minor === void 0 || patch === void 0) return true;
44
+ if (major >= 16) return false;
45
+ if (major < 15) return true;
46
+ if (!prerelease) return false;
47
+ if (minor > 0 || patch > 0) return false;
48
+ if (prerelease.startsWith("rc.")) return Number.parseInt(prerelease.split(".")[1] ?? "0", 10) === 0;
49
+ if (prerelease.startsWith("canary.")) return Number.parseInt(prerelease.split(".")[1] ?? "0", 10) < 124;
50
+ return true;
51
+ }
52
+ /**
53
+ * Attempts to detect the installed Next.js version.
54
+ *
55
+ * @returns The Next.js version string, or undefined if it cannot be determined
56
+ */
57
+ function detectNextJsVersion() {
58
+ try {
59
+ return __require("next/package.json").version;
60
+ } catch {
61
+ return;
62
+ }
63
+ }
64
+
65
+ //#endregion
66
+ export { detectNextJsVersion, parseSemver, requiresInstrumentationHook };
@@ -0,0 +1 @@
1
+ {"version":3,"file":"nextjs-version.mjs","names":[],"sources":["../../src/build/nextjs-version.ts"],"sourcesContent":["/**\n * Parsed semver version components\n */\nexport type ParsedSemver = {\n major: number | undefined;\n minor: number | undefined;\n patch: number | undefined;\n prerelease: string | undefined;\n};\n\n/**\n * Parses a semver version string into its components\n *\n * @param version - version string to parse (e.g., \"15.0.0-canary.124\")\n * @returns parsed version components\n */\nexport function parseSemver(version: string): ParsedSemver {\n const match = version.match(/^(\\d+)\\.(\\d+)\\.(\\d+)(?:-(.+))?$/);\n\n if (!match) {\n return {\n major: undefined,\n minor: undefined,\n patch: undefined,\n prerelease: undefined,\n };\n }\n\n const [, majorStr, minorStr, patchStr, prerelease] = match;\n\n return {\n major: majorStr ? Number.parseInt(majorStr, 10) : undefined,\n minor: minorStr ? Number.parseInt(minorStr, 10) : undefined,\n patch: patchStr ? Number.parseInt(patchStr, 10) : undefined,\n prerelease,\n };\n}\n\n/**\n * Determines if a Next.js version requires the experimental.instrumentationHook option.\n *\n * - Next.js 16+: Never requires the hook (instrumentation is fully stable)\n * - Next.js 14 and below: Always requires the hook\n * - Next.js 15 stable releases (15.0.0+): Doesn't require the hook\n * - Next.js 15 prereleases:\n * - rc.0 requires it, other RCs don't\n * - Canary versions before canary.124 require it\n * - Other prereleases (alpha, beta) require it\n *\n * @param version - version string to check\n * @returns true if the version requires the instrumentationHook option to be set\n */\nexport function requiresInstrumentationHook(version: string): boolean {\n if (!version) {\n return true; // Default to requiring it if version cannot be determined\n }\n\n const { major, minor, patch, prerelease } = parseSemver(version);\n\n if (major === undefined || minor === undefined || patch === undefined) {\n return true; // Default to requiring it if parsing fails\n }\n\n // Next.js 16+ never requires the hook\n if (major >= 16) {\n return false;\n }\n\n // Next.js 14 and below always require the hook\n if (major < 15) {\n return true;\n }\n\n // At this point, we know it's Next.js 15.x.y\n // Stable releases (15.0.0+) don't require the hook\n if (!prerelease) {\n return false;\n }\n\n // Next.js 15.x.y with x > 0 or y > 0 don't require the hook\n if (minor > 0 || patch > 0) {\n return false;\n }\n\n // Check specific prerelease versions that don't require the hook\n if (prerelease.startsWith(\"rc.\")) {\n const rcNumber = Number.parseInt(prerelease.split(\".\")[1] ?? \"0\", 10);\n return rcNumber === 0; // Only rc.0 requires the hook\n }\n\n if (prerelease.startsWith(\"canary.\")) {\n const canaryNumber = Number.parseInt(prerelease.split(\".\")[1] ?? \"0\", 10);\n return canaryNumber < 124; // canary.124+ doesn't require the hook\n }\n\n // All other 15.0.0 prerelease versions (alpha, beta, etc.) require the hook\n return true;\n}\n\n/**\n * Attempts to detect the installed Next.js version.\n *\n * @returns The Next.js version string, or undefined if it cannot be determined\n */\nexport function detectNextJsVersion(): string | undefined {\n try {\n // Dynamic require to get the Next.js version from node_modules\n // eslint-disable-next-line @typescript-eslint/no-require-imports\n const nextPackageJson = require(\"next/package.json\") as { version: string };\n return nextPackageJson.version;\n } catch {\n return undefined;\n }\n}\n\n"],"mappings":";;;;;;;;;AAgBA,SAAgB,YAAY,SAA+B;CACzD,MAAM,QAAQ,QAAQ,MAAM,kCAAkC;AAE9D,KAAI,CAAC,MACH,QAAO;EACL,OAAO;EACP,OAAO;EACP,OAAO;EACP,YAAY;EACb;CAGH,MAAM,GAAG,UAAU,UAAU,UAAU,cAAc;AAErD,QAAO;EACL,OAAO,WAAW,OAAO,SAAS,UAAU,GAAG,GAAG;EAClD,OAAO,WAAW,OAAO,SAAS,UAAU,GAAG,GAAG;EAClD,OAAO,WAAW,OAAO,SAAS,UAAU,GAAG,GAAG;EAClD;EACD;;;;;;;;;;;;;;;;AAiBH,SAAgB,4BAA4B,SAA0B;AACpE,KAAI,CAAC,QACH,QAAO;CAGT,MAAM,EAAE,OAAO,OAAO,OAAO,eAAe,YAAY,QAAQ;AAEhE,KAAI,UAAU,UAAa,UAAU,UAAa,UAAU,OAC1D,QAAO;AAIT,KAAI,SAAS,GACX,QAAO;AAIT,KAAI,QAAQ,GACV,QAAO;AAKT,KAAI,CAAC,WACH,QAAO;AAIT,KAAI,QAAQ,KAAK,QAAQ,EACvB,QAAO;AAIT,KAAI,WAAW,WAAW,MAAM,CAE9B,QADiB,OAAO,SAAS,WAAW,MAAM,IAAI,CAAC,MAAM,KAAK,GAAG,KACjD;AAGtB,KAAI,WAAW,WAAW,UAAU,CAElC,QADqB,OAAO,SAAS,WAAW,MAAM,IAAI,CAAC,MAAM,KAAK,GAAG,GACnD;AAIxB,QAAO;;;;;;;AAQT,SAAgB,sBAA0C;AACxD,KAAI;AAIF,mBADgC,oBAAoB,CAC7B;SACjB;AACN"}
@@ -1,19 +1,21 @@
1
1
  import { PreflightConfig } from "../lib/types.mjs";
2
+ import { FileDeleteError, FileGlobError, MissingBuildIdError, MissingReleaseIdError } from "./source-maps/errors.mjs";
2
3
  import { ConfigService } from "./services/config.service.mjs";
3
4
  import { ReleaseIdentityService } from "./services/release-identity.service.mjs";
5
+ import { ReleaseApiService } from "./services/release-api.service.mjs";
4
6
  import { SourceMapService } from "./services/source-map.service.mjs";
7
+ import { SourceMapFailureCleanupService } from "./services/source-map-failure-cleanup.service.mjs";
5
8
  import { Effect, Layer } from "effect";
6
9
 
7
10
  //#region src/build/release-program.d.ts
8
-
9
11
  /**
10
12
  * The main release upload program.
11
13
  * This is a single Effect that orchestrates the entire release process.
12
14
  */
13
- declare const releaseProgram: Effect.Effect<unknown, unknown, unknown>;
15
+ declare const releaseProgram: Effect.Effect<void, MissingBuildIdError | MissingReleaseIdError | FileGlobError | FileDeleteError, ConfigService | ReleaseApiService | ReleaseIdentityService | SourceMapFailureCleanupService | SourceMapService>;
14
16
  /**
15
17
  * Create the layer stack for the release program
16
18
  */
17
- declare const createReleaseLayers: (config: PreflightConfig) => Layer.Layer<ConfigService | SourceMapService | ReleaseIdentityService, never, never>;
19
+ declare const createReleaseLayers: (config: PreflightConfig) => Layer.Layer<ConfigService | ReleaseApiService | ReleaseIdentityService | SourceMapFailureCleanupService | SourceMapService, never, never>;
18
20
  //#endregion
19
21
  export { createReleaseLayers, releaseProgram };
@@ -1 +1 @@
1
- {"version":3,"file":"release-program.d.mts","names":[],"sources":["../../src/build/release-program.ts"],"sourcesContent":[],"mappings":";;;;;;;;;;AAuBA;AA6IA;AAA4C,cA7I/B,cA6I+B,EA7IjB,MAAA,CAAA,MA6IiB,CAAA,OAAA,EAAA,OAAA,EAAA,OAAA,CAAA;;;;AAAe,cAA9C,mBAA8C,EAAA,CAAA,MAAA,EAAf,eAAe,EAAA,GAAA,KAAA,CAAA,KAAA,CAAA,aAAA,GAAA,gBAAA,GAAA,sBAAA,EAAA,KAAA,EAAA,KAAA,CAAA"}
1
+ {"version":3,"file":"release-program.d.mts","names":[],"sources":["../../src/build/release-program.ts"],"mappings":";;;;;;;;;;;;;AA6BA;cAAa,cAAA,EAAc,MAAA,CAAA,MAAA,OAsI1B,mBAAA,GAtI0B,qBAAA,GAAA,aAAA,GAAA,eAAA,EAAA,aAAA,GAAA,iBAAA,GAAA,sBAAA,GAAA,8BAAA,GAAA,gBAAA;;;;cA2Id,mBAAA,GAAuB,MAAA,EAAQ,eAAA,KAAe,KAAA,CAAA,KAAA,CAAA,aAAA,GAAA,iBAAA,GAAA,sBAAA,GAAA,8BAAA,GAAA,gBAAA"}
@@ -2,9 +2,9 @@ import { resolveApiUrl } from "./env-config.mjs";
2
2
  import { logBuildResult, withBufferedBuildLog } from "./logger.mjs";
3
3
  import { ConfigService, ConfigServiceLive } from "./services/config.service.mjs";
4
4
  import { ReleaseIdentityService, ReleaseIdentityServiceLive } from "./services/release-identity.service.mjs";
5
- import { createRelease } from "./source-maps/api.mjs";
6
- import { maybeCleanupAfterFailure } from "./source-maps/files.mjs";
5
+ import { ReleaseApiService, ReleaseApiServiceLive } from "./services/release-api.service.mjs";
7
6
  import { SourceMapService, SourceMapServiceLive } from "./services/source-map.service.mjs";
7
+ import { SourceMapFailureCleanupService, SourceMapFailureCleanupServiceLive } from "./services/source-map-failure-cleanup.service.mjs";
8
8
  import { Effect, Layer } from "effect";
9
9
 
10
10
  //#region src/build/release-program.ts
@@ -23,8 +23,8 @@ const releaseProgram = Effect.gen(function* () {
23
23
  return;
24
24
  }
25
25
  const sourceMapService = yield* SourceMapService;
26
- if (!config.secretKey) {
27
- yield* logBuildResult("Warning", "Skipping Release", ["Missing secret key. Please set the `INTERFERE_SECRET_KEY` environment variable."]);
26
+ if (!config.apiKey) {
27
+ yield* logBuildResult("Warning", "Skipping Release", ["Missing API key. Please set the `INTERFERE_API_KEY` environment variable."]);
28
28
  return;
29
29
  }
30
30
  yield* Effect.logDebug("Getting release identity");
@@ -49,13 +49,11 @@ const releaseProgram = Effect.gen(function* () {
49
49
  }
50
50
  yield* Effect.logDebug("Creating release");
51
51
  const createStart = Date.now();
52
- const releaseResponse = yield* createRelease(config, {
52
+ const releaseResponse = yield* (yield* ReleaseApiService).createRelease(config, {
53
53
  environment: config.environment,
54
54
  sourceId: identity.buildId,
55
- sourceType: identity.sourceControl.type,
56
- sourceMetadata: identity.sourceControl.metadata,
57
- destinationType: identity.deployment.type,
58
- destinationMetadata: identity.deployment.metadata
55
+ sourceMetadata: identity.sourceControl?.metadata,
56
+ destinationMetadata: identity.deployment?.metadata
59
57
  });
60
58
  yield* Effect.logDebug(`Release created in ${Date.now() - createStart}ms`);
61
59
  yield* Effect.logDebug("Reading source maps");
@@ -73,10 +71,11 @@ const releaseProgram = Effect.gen(function* () {
73
71
  const cleanupStart = Date.now();
74
72
  yield* sourceMapService.cleanup(sourceMapFiles, !!config.debug);
75
73
  yield* Effect.logDebug(`Cleanup completed in ${Date.now() - cleanupStart}ms`);
76
- }).pipe(Effect.catchIf((error) => error._tag !== "MissingBuildIdError" && error._tag !== "MissingReleaseIdError", (error) => withBufferedBuildLog("Error", "Failed to upload source maps", (log) => Effect.gen(function* () {
74
+ }).pipe(Effect.catchIf((error) => error._tag !== "MissingBuildIdError" && error._tag !== "MissingReleaseIdError", (error) => withBufferedBuildLog("Error", "Failed to upload source maps", Effect.fn("handleUploadError")(function* (log) {
77
75
  const config = yield* ConfigService;
76
+ const failureCleanup = yield* SourceMapFailureCleanupService;
78
77
  yield* log(String(error));
79
- if (config.environment === "production" && config.cleanupSourceMaps !== false) yield* maybeCleanupAfterFailure(!!config.debug);
78
+ if (config.environment === "production" && config.cleanupSourceMaps !== false) yield* failureCleanup.maybeCleanupAfterFailure(!!config.debug);
80
79
  }))), Effect.withSpan("interfere.release"));
81
80
  /**
82
81
  * Create the layer stack for the release program
@@ -85,7 +84,7 @@ const createReleaseLayers = (config) => {
85
84
  const configLayer = ConfigServiceLive(config);
86
85
  const identityLayer = ReleaseIdentityServiceLive;
87
86
  const sourceMapLayer = SourceMapServiceLive.pipe(Layer.provide(configLayer));
88
- return Layer.mergeAll(configLayer, identityLayer, sourceMapLayer);
87
+ return Layer.mergeAll(configLayer, identityLayer, sourceMapLayer, ReleaseApiServiceLive, SourceMapFailureCleanupServiceLive);
89
88
  };
90
89
 
91
90
  //#endregion