@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.
- package/LICENSE +1 -1
- package/README.md +36 -8
- package/dist/_virtual/_rolldown/runtime.mjs +7 -0
- package/dist/build/env-config.d.mts +3 -1
- package/dist/build/env-config.d.mts.map +1 -1
- package/dist/build/env-config.mjs +9 -1
- package/dist/build/env-config.mjs.map +1 -1
- package/dist/build/exchange-surface.d.mts +9 -0
- package/dist/build/exchange-surface.d.mts.map +1 -0
- package/dist/build/exchange-surface.mjs +36 -0
- package/dist/build/exchange-surface.mjs.map +1 -0
- package/dist/build/loaders/value-injection-loader.d.mts +22 -0
- package/dist/build/loaders/value-injection-loader.d.mts.map +1 -0
- package/dist/build/loaders/value-injection-loader.mjs +35 -0
- package/dist/build/loaders/value-injection-loader.mjs.map +1 -0
- package/dist/build/logger.d.mts +2 -2
- package/dist/build/logger.d.mts.map +1 -1
- package/dist/build/logger.mjs +10 -12
- package/dist/build/logger.mjs.map +1 -1
- package/dist/build/nextjs-version.d.mts +40 -0
- package/dist/build/nextjs-version.d.mts.map +1 -0
- package/dist/build/nextjs-version.mjs +66 -0
- package/dist/build/nextjs-version.mjs.map +1 -0
- package/dist/build/release-program.d.mts +5 -3
- package/dist/build/release-program.d.mts.map +1 -1
- package/dist/build/release-program.mjs +11 -12
- package/dist/build/release-program.mjs.map +1 -1
- package/dist/build/services/config.service.d.mts.map +1 -1
- package/dist/build/services/config.service.mjs.map +1 -1
- package/dist/build/services/instrumentation-detection.service.d.mts +19 -0
- package/dist/build/services/instrumentation-detection.service.d.mts.map +1 -0
- package/dist/build/services/instrumentation-detection.service.mjs +77 -0
- package/dist/build/services/instrumentation-detection.service.mjs.map +1 -0
- package/dist/build/services/preflight.service.d.mts +2 -3
- package/dist/build/services/preflight.service.d.mts.map +1 -1
- package/dist/build/services/preflight.service.mjs +28 -37
- package/dist/build/services/preflight.service.mjs.map +1 -1
- package/dist/build/services/release-api.service.d.mts +11 -0
- package/dist/build/services/release-api.service.d.mts.map +1 -0
- package/dist/build/services/release-api.service.mjs +9 -0
- package/dist/build/services/release-api.service.mjs.map +1 -0
- package/dist/build/services/release-identity.service.d.mts +4 -3
- package/dist/build/services/release-identity.service.d.mts.map +1 -1
- package/dist/build/services/release-identity.service.mjs +28 -15
- package/dist/build/services/release-identity.service.mjs.map +1 -1
- package/dist/build/services/source-map-failure-cleanup.service.d.mts +11 -0
- package/dist/build/services/source-map-failure-cleanup.service.d.mts.map +1 -0
- package/dist/build/services/source-map-failure-cleanup.service.mjs +9 -0
- package/dist/build/services/source-map-failure-cleanup.service.mjs.map +1 -0
- package/dist/build/services/source-map.service.d.mts +4 -8
- package/dist/build/services/source-map.service.d.mts.map +1 -1
- package/dist/build/services/source-map.service.mjs +2 -4
- package/dist/build/services/source-map.service.mjs.map +1 -1
- package/dist/build/source-maps/api.d.mts +25 -16
- package/dist/build/source-maps/api.d.mts.map +1 -1
- package/dist/build/source-maps/api.mjs +11 -8
- package/dist/build/source-maps/api.mjs.map +1 -1
- package/dist/build/source-maps/client.d.mts +11 -2
- package/dist/build/source-maps/client.d.mts.map +1 -1
- package/dist/build/source-maps/client.mjs +25 -14
- package/dist/build/source-maps/client.mjs.map +1 -1
- package/dist/build/source-maps/errors.d.mts +118 -106
- package/dist/build/source-maps/errors.d.mts.map +1 -1
- package/dist/build/source-maps/errors.mjs +42 -18
- package/dist/build/source-maps/errors.mjs.map +1 -1
- package/dist/build/source-maps/files.d.mts +1 -1
- package/dist/build/source-maps/files.d.mts.map +1 -1
- package/dist/build/source-maps/files.mjs +13 -15
- package/dist/build/source-maps/files.mjs.map +1 -1
- package/dist/build/source-maps/providers/deployment/detector.d.mts +8 -17
- package/dist/build/source-maps/providers/deployment/detector.d.mts.map +1 -1
- package/dist/build/source-maps/providers/deployment/detector.mjs +11 -13
- package/dist/build/source-maps/providers/deployment/detector.mjs.map +1 -1
- package/dist/build/source-maps/providers/deployment/types.d.mts +2 -2
- package/dist/build/source-maps/providers/deployment/types.d.mts.map +1 -1
- package/dist/build/source-maps/providers/deployment/vercel.d.mts.map +1 -1
- package/dist/build/source-maps/providers/deployment/vercel.mjs +8 -19
- package/dist/build/source-maps/providers/deployment/vercel.mjs.map +1 -1
- package/dist/build/source-maps/providers/source-control/detector.d.mts +6 -5
- package/dist/build/source-maps/providers/source-control/detector.d.mts.map +1 -1
- package/dist/build/source-maps/providers/source-control/detector.mjs +11 -13
- package/dist/build/source-maps/providers/source-control/detector.mjs.map +1 -1
- package/dist/build/source-maps/providers/source-control/git.d.mts.map +1 -1
- package/dist/build/source-maps/providers/source-control/git.mjs +5 -8
- package/dist/build/source-maps/providers/source-control/git.mjs.map +1 -1
- package/dist/build/source-maps/providers/source-control/types.d.mts +5 -3
- package/dist/build/source-maps/providers/source-control/types.d.mts.map +1 -1
- package/dist/build/with-interfere.d.mts +25 -3
- package/dist/build/with-interfere.d.mts.map +1 -1
- package/dist/build/with-interfere.mjs +131 -24
- package/dist/build/with-interfere.mjs.map +1 -1
- package/dist/client/auto-init.d.mts +91 -0
- package/dist/client/auto-init.d.mts.map +1 -0
- package/dist/client/auto-init.mjs +121 -0
- package/dist/client/auto-init.mjs.map +1 -0
- package/dist/client/provider.d.mts +3 -3
- package/dist/client/provider.d.mts.map +1 -1
- package/dist/client/provider.mjs +21 -8
- package/dist/client/provider.mjs.map +1 -1
- package/dist/lib/env.d.mts.map +1 -1
- package/dist/lib/types.d.mts +6 -6
- package/dist/lib/types.d.mts.map +1 -1
- package/dist/lib/types.mjs.map +1 -1
- package/dist/server/auto-init.d.mts +88 -0
- package/dist/server/auto-init.d.mts.map +1 -0
- package/dist/server/auto-init.mjs +101 -0
- package/dist/server/auto-init.mjs.map +1 -0
- package/dist/server/middleware.d.mts.map +1 -1
- package/dist/server/middleware.mjs +20 -13
- package/dist/server/middleware.mjs.map +1 -1
- package/dist/server/on-request-error.d.mts +27 -0
- package/dist/server/on-request-error.d.mts.map +1 -0
- package/dist/server/on-request-error.mjs +74 -0
- package/dist/server/on-request-error.mjs.map +1 -0
- package/dist/server/proxy.d.mts.map +1 -1
- package/dist/server/proxy.mjs +4 -5
- package/dist/server/proxy.mjs.map +1 -1
- package/dist/server/route-handler.d.mts +31 -1
- package/dist/server/route-handler.d.mts.map +1 -1
- package/dist/server/route-handler.mjs +78 -79
- package/dist/server/route-handler.mjs.map +1 -1
- package/dist/server/sdk.d.mts +96 -0
- package/dist/server/sdk.d.mts.map +1 -0
- package/dist/server/sdk.mjs +152 -0
- package/dist/server/sdk.mjs.map +1 -0
- package/dist/server/services/config.service.d.mts +33 -6
- package/dist/server/services/config.service.d.mts.map +1 -1
- package/dist/server/services/config.service.mjs +54 -30
- package/dist/server/services/config.service.mjs.map +1 -1
- package/dist/server/services/error-tracking.service.d.mts +3 -3
- package/dist/server/services/error-tracking.service.d.mts.map +1 -1
- package/dist/server/services/error-tracking.service.mjs +5 -3
- package/dist/server/services/error-tracking.service.mjs.map +1 -1
- package/dist/server/session-context.d.mts +60 -0
- package/dist/server/session-context.d.mts.map +1 -0
- package/dist/server/session-context.mjs +62 -0
- package/dist/server/session-context.mjs.map +1 -0
- package/package.json +58 -34
- package/dist/build/secret-key.d.mts +0 -10
- package/dist/build/secret-key.d.mts.map +0 -1
- package/dist/build/secret-key.mjs +0 -16
- package/dist/build/secret-key.mjs.map +0 -1
- package/dist/lib/test-utils/make-next-request.d.mts +0 -6
- package/dist/lib/test-utils/make-next-request.d.mts.map +0 -1
- package/dist/lib/test-utils/make-next-request.mjs +0 -12
- package/dist/lib/test-utils/make-next-request.mjs.map +0 -1
package/LICENSE
CHANGED
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
|
-
|
|
12
|
+
bun add @interfere/next
|
|
13
13
|
```
|
|
14
14
|
|
|
15
15
|
## Quick Start
|
|
16
16
|
|
|
17
|
-
### 1.
|
|
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
|
-
###
|
|
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 `
|
|
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
|
-
|
|
72
|
+
INTERFERE_API_KEY=ak_xxx
|
|
45
73
|
```
|
|
46
74
|
|
|
47
|
-
###
|
|
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
|
-
###
|
|
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
|
-
###
|
|
134
|
+
### 6. Add Global Error Handler
|
|
107
135
|
|
|
108
136
|
Create `app/global-error.tsx`:
|
|
109
137
|
|
|
@@ -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"],"
|
|
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"}
|
package/dist/build/logger.d.mts
CHANGED
|
@@ -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
|
|
9
|
-
declare function withBufferedBuildLog(level: LogLevel.Literal, title: string, use: (log: (line: string) => ReturnType<typeof appendBuildLogLine>) => Effect.Effect<
|
|
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"],"
|
|
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"}
|
package/dist/build/logger.mjs
CHANGED
|
@@ -125,18 +125,16 @@ function appendBuildLogLine(line) {
|
|
|
125
125
|
buildLogState.lines.push(trimmed);
|
|
126
126
|
});
|
|
127
127
|
}
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
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<
|
|
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 |
|
|
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"],"
|
|
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 {
|
|
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.
|
|
27
|
-
yield* logBuildResult("Warning", "Skipping Release", ["Missing
|
|
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
|
-
|
|
56
|
-
|
|
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",
|
|
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
|