@interfere/vite 0.1.2 → 10.0.1-canary.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +112 -30
- package/dist/handler.d.mts +2 -0
- package/dist/handler.mjs +1 -0
- package/dist/init.d.mts +10 -3
- package/dist/init.d.mts.map +1 -1
- package/dist/init.mjs +1 -11
- package/dist/init.mjs.map +1 -1
- package/dist/internal/build/pipeline.d.mts +64 -0
- package/dist/internal/build/pipeline.d.mts.map +1 -0
- package/dist/internal/build/pipeline.mjs +1 -0
- package/dist/internal/build/pipeline.mjs.map +1 -0
- package/dist/internal/build/source-maps.d.mts +56 -0
- package/dist/internal/build/source-maps.d.mts.map +1 -0
- package/dist/internal/build/source-maps.mjs +1 -0
- package/dist/internal/build/source-maps.mjs.map +1 -0
- package/dist/internal/release-slug.d.mts +10 -0
- package/dist/internal/release-slug.d.mts.map +1 -0
- package/dist/internal/release-slug.mjs +1 -0
- package/dist/internal/release-slug.mjs.map +1 -0
- package/dist/internal/route/handle.d.mts +20 -0
- package/dist/internal/route/handle.d.mts.map +1 -0
- package/dist/internal/route/handle.mjs +1 -0
- package/dist/internal/route/handle.mjs.map +1 -0
- package/dist/internal/route/proxy.d.mts +33 -0
- package/dist/internal/route/proxy.d.mts.map +1 -0
- package/dist/internal/route/proxy.mjs +1 -0
- package/dist/internal/route/proxy.mjs.map +1 -0
- package/dist/internal/server/capture.d.mts +6 -0
- package/dist/internal/server/capture.d.mts.map +1 -0
- package/dist/internal/server/capture.mjs +1 -0
- package/dist/internal/server/capture.mjs.map +1 -0
- package/dist/internal/server/console-bridge.d.mts +23 -0
- package/dist/internal/server/console-bridge.d.mts.map +1 -0
- package/dist/internal/server/console-bridge.mjs +1 -0
- package/dist/internal/server/console-bridge.mjs.map +1 -0
- package/dist/internal/server/env.d.mts +22 -0
- package/dist/internal/server/env.d.mts.map +1 -0
- package/dist/internal/server/env.mjs +1 -0
- package/dist/internal/server/env.mjs.map +1 -0
- package/dist/internal/server/instrumentation-options.d.mts +44 -0
- package/dist/internal/server/instrumentation-options.d.mts.map +1 -0
- package/dist/internal/server/instrumentation-options.mjs +1 -0
- package/dist/internal/server/register.d.mts +30 -0
- package/dist/internal/server/register.d.mts.map +1 -0
- package/dist/internal/server/register.mjs +1 -0
- package/dist/internal/server/register.mjs.map +1 -0
- package/dist/internal/server/remote-config.d.mts +5 -0
- package/dist/internal/server/remote-config.d.mts.map +1 -0
- package/dist/internal/server/remote-config.mjs +1 -0
- package/dist/internal/server/remote-config.mjs.map +1 -0
- package/dist/internal/server/trace-meta.d.mts +34 -0
- package/dist/internal/server/trace-meta.d.mts.map +1 -0
- package/dist/internal/server/trace-meta.mjs +1 -0
- package/dist/internal/server/trace-meta.mjs.map +1 -0
- package/dist/internal/server/traceparent.d.mts +17 -0
- package/dist/internal/server/traceparent.d.mts.map +1 -0
- package/dist/internal/server/traceparent.mjs +1 -0
- package/dist/internal/server/traceparent.mjs.map +1 -0
- package/dist/internal/server/types.d.mts +17 -0
- package/dist/internal/server/types.d.mts.map +1 -0
- package/dist/internal/server/types.mjs +1 -0
- package/dist/internal/server/url.d.mts +4 -0
- package/dist/internal/server/url.d.mts.map +1 -0
- package/dist/internal/server/url.mjs +1 -0
- package/dist/internal/server/url.mjs.map +1 -0
- package/dist/package.mjs +1 -5
- package/dist/plugin.d.mts +35 -3
- package/dist/plugin.d.mts.map +1 -1
- package/dist/plugin.mjs +3 -34
- package/dist/plugin.mjs.map +1 -1
- package/dist/provider.d.mts +20 -0
- package/dist/provider.d.mts.map +1 -0
- package/dist/provider.mjs +1 -0
- package/dist/provider.mjs.map +1 -0
- package/dist/server.d.mts +6 -0
- package/dist/server.mjs +1 -0
- package/dist/version.mjs +1 -5
- package/dist/version.mjs.map +1 -1
- package/dist/vite-env.d.mts +1 -0
- package/package.json +63 -18
package/README.md
CHANGED
|
@@ -2,20 +2,20 @@
|
|
|
2
2
|
<a href="https://interfere.com">
|
|
3
3
|
<picture>
|
|
4
4
|
<source media="(prefers-color-scheme: dark)" srcset="https://qyzkf4cgb8ydxtq1.public.blob.vercel-storage.com/v2/header/logo-dark.png">
|
|
5
|
-
<img src="https://qyzkf4cgb8ydxtq1.public.blob.vercel-storage.com/v2/header/logo-light.png" height="64">
|
|
5
|
+
<img src="https://qyzkf4cgb8ydxtq1.public.blob.vercel-storage.com/v2/header/logo-light.png" height="64" alt="Interfere">
|
|
6
6
|
</picture>
|
|
7
7
|
</a>
|
|
8
8
|
<h1 align="center">@interfere/vite</h1>
|
|
9
9
|
</p>
|
|
10
10
|
|
|
11
11
|
<p align="center">
|
|
12
|
-
<a href="https://www.npmjs.com/package/@interfere/vite"><img src="https://img.shields.io/npm/v/@interfere/vite.svg" /></a>
|
|
13
|
-
<a href="https://github.com/interfere-inc/interfere/blob/main/LICENSE"><img src="https://img.shields.io/npm/l/@interfere/vite.svg" /></a>
|
|
14
|
-
<a href="https://www.npmjs.com/package/@interfere/vite"><img src="https://img.shields.io/npm/dm/@interfere/vite.svg" /></a>
|
|
12
|
+
<a href="https://www.npmjs.com/package/@interfere/vite"><img src="https://img.shields.io/npm/v/@interfere/vite.svg" alt="npm version" /></a>
|
|
13
|
+
<a href="https://github.com/interfere-inc/interfere/blob/main/LICENSE"><img src="https://img.shields.io/npm/l/@interfere/vite.svg" alt="License" /></a>
|
|
14
|
+
<a href="https://www.npmjs.com/package/@interfere/vite"><img src="https://img.shields.io/npm/dm/@interfere/vite.svg" alt="npm downloads" /></a>
|
|
15
15
|
</p>
|
|
16
16
|
|
|
17
17
|
<p align="center">
|
|
18
|
-
Vite
|
|
18
|
+
Vite SDK for <a href="https://interfere.com">Interfere</a> — error tracking, session replay, and analytics for React apps shipped with Vite or TanStack Start.
|
|
19
19
|
</p>
|
|
20
20
|
|
|
21
21
|
<p align="center">
|
|
@@ -36,15 +36,14 @@
|
|
|
36
36
|
|
|
37
37
|
- Vite `>=5`
|
|
38
38
|
- React `>=19`
|
|
39
|
-
- [`@interfere/react`](https://www.npmjs.com/package/@interfere/react) for the React provider and hooks
|
|
40
39
|
|
|
41
40
|
### Installation
|
|
42
41
|
|
|
43
42
|
```bash
|
|
44
|
-
npm install @interfere/vite
|
|
43
|
+
npm install @interfere/vite
|
|
45
44
|
```
|
|
46
45
|
|
|
47
|
-
### Quick Start
|
|
46
|
+
### Quick Start (vanilla Vite SPA)
|
|
48
47
|
|
|
49
48
|
**1. Add the Vite plugin**
|
|
50
49
|
|
|
@@ -59,26 +58,27 @@ export default defineConfig({
|
|
|
59
58
|
});
|
|
60
59
|
```
|
|
61
60
|
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
**2. Initialize the client**
|
|
61
|
+
**2. Initialize the SDK**
|
|
65
62
|
|
|
66
63
|
```ts
|
|
67
64
|
// src/main.tsx
|
|
68
65
|
import { init } from "@interfere/vite/init";
|
|
69
66
|
|
|
67
|
+
import { createRoot } from "react-dom/client";
|
|
68
|
+
import { App } from "./app";
|
|
69
|
+
|
|
70
70
|
init();
|
|
71
|
-
```
|
|
72
71
|
|
|
73
|
-
|
|
72
|
+
createRoot(document.getElementById("root")!).render(<App />);
|
|
73
|
+
```
|
|
74
74
|
|
|
75
|
-
**3. Add the
|
|
75
|
+
**3. Add the provider**
|
|
76
76
|
|
|
77
77
|
```tsx
|
|
78
|
-
// src/
|
|
79
|
-
import { InterfereProvider } from "@interfere/
|
|
78
|
+
// src/app.tsx
|
|
79
|
+
import { InterfereProvider } from "@interfere/vite/provider";
|
|
80
80
|
|
|
81
|
-
function App() {
|
|
81
|
+
export function App() {
|
|
82
82
|
return (
|
|
83
83
|
<InterfereProvider>
|
|
84
84
|
<YourApp />
|
|
@@ -87,38 +87,120 @@ function App() {
|
|
|
87
87
|
}
|
|
88
88
|
```
|
|
89
89
|
|
|
90
|
-
|
|
90
|
+
That's it. The provider auto-resolves the kernel created by `init()`; you don't have to wire `useSyncExternalStore` yourself.
|
|
91
|
+
|
|
92
|
+
### Quick Start (TanStack Start + Nitro)
|
|
93
|
+
|
|
94
|
+
TanStack Start runs through Nitro, so the SDK mirrors the Next.js shape: browser events go to a same-origin proxy route, and the server forwards the SDK's public-key-authenticated requests.
|
|
95
|
+
|
|
96
|
+
Use the same browser imports — call `init()` from the file that boots your router, and put `<InterfereProvider>` in `__root.tsx`:
|
|
97
|
+
|
|
98
|
+
```ts
|
|
99
|
+
// src/router.tsx
|
|
100
|
+
import { init } from "@interfere/vite/init";
|
|
101
|
+
import { createRouter } from "@tanstack/react-router";
|
|
102
|
+
import { routeTree } from "./routeTree.gen";
|
|
103
|
+
|
|
104
|
+
if (typeof window !== "undefined") {
|
|
105
|
+
init();
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
export const getRouter = () =>
|
|
109
|
+
createRouter({ routeTree, scrollRestoration: true });
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
```tsx
|
|
113
|
+
// src/routes/__root.tsx
|
|
114
|
+
import { InterfereProvider } from "@interfere/vite/provider";
|
|
115
|
+
import { Outlet } from "@tanstack/react-router";
|
|
116
|
+
|
|
117
|
+
function RootComponent() {
|
|
118
|
+
return (
|
|
119
|
+
<InterfereProvider>
|
|
120
|
+
<Outlet />
|
|
121
|
+
</InterfereProvider>
|
|
122
|
+
);
|
|
123
|
+
}
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
The browser guard matters for TanStack Start because prerender can evaluate the router import graph on the server, while the Interfere kernel uses browser-only APIs.
|
|
127
|
+
|
|
128
|
+
Then mount the proxy handler and server instrumentation in a catch-all route:
|
|
129
|
+
|
|
130
|
+
```tsx
|
|
131
|
+
// src/routes/api/interfere/$.tsx
|
|
132
|
+
import { handle } from "@interfere/vite/handler";
|
|
133
|
+
import { register } from "@interfere/vite/server";
|
|
134
|
+
|
|
135
|
+
import { createFileRoute } from "@tanstack/react-router";
|
|
136
|
+
|
|
137
|
+
if (typeof window === "undefined") {
|
|
138
|
+
register().catch((error: unknown) => {
|
|
139
|
+
console.warn("[interfere] register() threw during boot", error);
|
|
140
|
+
});
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
export const Route = createFileRoute("/api/interfere/$")({
|
|
144
|
+
server: {
|
|
145
|
+
handlers: {
|
|
146
|
+
GET: ({ request }) => handle(request),
|
|
147
|
+
POST: ({ request }) => handle(request),
|
|
148
|
+
OPTIONS: ({ request }) => handle(request),
|
|
149
|
+
},
|
|
150
|
+
},
|
|
151
|
+
});
|
|
152
|
+
```
|
|
153
|
+
|
|
154
|
+
## First-Time Setup
|
|
155
|
+
|
|
156
|
+
The SDK splits its credentials by concern: a **public key** travels with the browser bundle (it's not a secret), and an **API key** stays server-side (CI / Infisical / `.env.local`).
|
|
157
|
+
|
|
158
|
+
1. **Install** `@interfere/vite` and add the plugin (above).
|
|
159
|
+
2. **Public key** — copy the dashboard's `interfere_pk_*` value into `.env.local` as `VITE_INTERFERE_PUBLIC_KEY=...`. Public by design; safe to commit to a public repo.
|
|
160
|
+
3. **API key** — create an Interfere API key and put the `interfere_ak_*` value in `.env.local` as `INTERFERE_API_KEY=...`. This key is what the build pipeline uses to publish release metadata. **Server-side; never commit.**
|
|
161
|
+
4. **First build** — run `bun run build`. The plugin's `closeBundle` hook publishes release metadata and preflight-confirms the release. After this the commit's slug is accepted at ingest.
|
|
162
|
+
5. **Dev cycle** — `bun run dev` then exercises the bundle in your browser. Events flow with the commit's preflight-confirmed slug (the build did the work). New commit? Re-run `bun run build` so the new commit's slug is preflighted.
|
|
163
|
+
|
|
164
|
+
For **Vercel preview / production**, set `INTERFERE_API_KEY` in Infisical at your sandbox's path (or directly as a Vercel env var). Each preview build runs the same `bun run build` flow in CI; no local-vs-preview divergence.
|
|
165
|
+
|
|
166
|
+
## Environment Variables
|
|
91
167
|
|
|
92
168
|
| Variable | Required | Description |
|
|
93
169
|
| --- | --- | --- |
|
|
94
|
-
| `VITE_INTERFERE_PUBLIC_KEY` | Yes |
|
|
95
|
-
| `
|
|
170
|
+
| `VITE_INTERFERE_PUBLIC_KEY` | Yes | Surface public key in the `interfere_pk_*` format. Stamped into the page by the plugin at build time for both direct and proxy mode. |
|
|
171
|
+
| `INTERFERE_API_KEY` | Yes for release metadata | Interfere API key in the `interfere_ak_*` format. Used by the plugin at build time. Without it, release metadata is not published and the collector rejects events as `COLLECTOR_RELEASE_PREFLIGHT_UNCONFIRMED`. |
|
|
172
|
+
| `INTERFERE_API_URL` | No | Override the collector URL the build pipeline targets. Defaults to `https://in.interfere.com`. |
|
|
173
|
+
| `VITE_INTERFERE_API_URL` | No | Override the collector URL the browser kernel targets in direct mode. Proxy mode uses `INTERFERE_API_URL` server-side. |
|
|
174
|
+
| `VITE_INTERFERE_COMMIT_SHA` | No | Override the auto-detected commit SHA used to derive the release slug. Defaults to `git rev-parse HEAD`. |
|
|
175
|
+
| `VITE_INTERFERE_FORCE_ENABLE` | No | `"1"` / `"true"` flips the SDK into force-enable mode so `vite dev` (which sets `NODE_ENV=development`) emits events. Production collectors silently 202-drop force-enabled batches; safe to ship by mistake but useless. Use only in dev. |
|
|
96
176
|
|
|
97
177
|
## Plugin Options
|
|
98
178
|
|
|
99
179
|
```ts
|
|
100
180
|
interfere({
|
|
101
|
-
|
|
102
|
-
releaseId: "v1.2.3",
|
|
181
|
+
commitSha: "abcd0000abcd0000abcd0000abcd0000abcd0000",
|
|
103
182
|
});
|
|
104
183
|
```
|
|
105
184
|
|
|
106
185
|
| Option | Default | Description |
|
|
107
186
|
| --- | --- | --- |
|
|
108
|
-
| `
|
|
109
|
-
| `
|
|
187
|
+
| `commitSha` | `VITE_INTERFERE_COMMIT_SHA` → `git rev-parse HEAD` | Commit SHA used to derive the deterministic release slug. |
|
|
188
|
+
| `mode` | `"auto"` | `"auto"` detects TanStack Start / Nitro and uses proxy mode; vanilla Vite uses direct mode. Override with `"direct"` or `"proxy"` when needed. |
|
|
189
|
+
| `sourceMaps` | auto | `false` disables build-time release metadata publishing. By default the pipeline runs when `INTERFERE_API_KEY` and a commit SHA are available. |
|
|
190
|
+
|
|
191
|
+
## Migrating From 0.x
|
|
192
|
+
|
|
193
|
+
Upgrade all `@interfere/*` SDK packages together. Keep the env var names, but replace old `int_pub_*` values with the dashboard's new `interfere_pk_*` public key, and replace old `ak_*` build keys with the `interfere_ak_*` Interfere API key.
|
|
110
194
|
|
|
111
195
|
## Identity Management
|
|
112
196
|
|
|
113
197
|
Link sessions to your authenticated users with `identity.set()`:
|
|
114
198
|
|
|
115
199
|
```tsx
|
|
116
|
-
import { useInterfere } from "@interfere/
|
|
200
|
+
import { useInterfere } from "@interfere/vite/provider";
|
|
117
201
|
|
|
118
202
|
function useInterfereIdentity() {
|
|
119
203
|
const { identity } = useInterfere();
|
|
120
|
-
|
|
121
|
-
// Clerk, Auth0, etc.
|
|
122
204
|
const { user } = useAuthProvider();
|
|
123
205
|
|
|
124
206
|
useEffect(() => {
|
|
@@ -163,7 +245,7 @@ Identity is automatically cleared when the SDK is closed or the session rotates.
|
|
|
163
245
|
By default, all SDK features are active. To gate features behind user consent, pass a `consent` prop to the provider:
|
|
164
246
|
|
|
165
247
|
```tsx
|
|
166
|
-
import { InterfereProvider } from "@interfere/
|
|
248
|
+
import { InterfereProvider } from "@interfere/vite/provider";
|
|
167
249
|
|
|
168
250
|
function App() {
|
|
169
251
|
return (
|
|
@@ -198,7 +280,7 @@ consent.get(); // current state, or null if no
|
|
|
198
280
|
|
|
199
281
|
### Initial consent via init
|
|
200
282
|
|
|
201
|
-
To set consent before React renders (avoiding any window where non-consented plugins might load), pass it to `init()`:
|
|
283
|
+
To set consent before React renders (avoiding any window where non-consented plugins might load), pass it to `init()` directly instead of using `auto`:
|
|
202
284
|
|
|
203
285
|
```ts
|
|
204
286
|
import { init } from "@interfere/vite/init";
|
|
@@ -210,7 +292,7 @@ The provider's `consent` prop will then keep it in sync as the user updates thei
|
|
|
210
292
|
|
|
211
293
|
## What's Included
|
|
212
294
|
|
|
213
|
-
- **Build metadata injection** —
|
|
295
|
+
- **Build metadata injection** — automatic Git SHA-derived release slug
|
|
214
296
|
- **Error tracking** — automatic capture of uncaught errors and unhandled rejections
|
|
215
297
|
- **Session replay** — full visual playback of user sessions
|
|
216
298
|
- **Page analytics** — SPA-aware pageviews and UI interaction events
|
package/dist/handler.mjs
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{handle}from"./internal/route/handle.mjs";export{handle};
|
package/dist/init.d.mts
CHANGED
|
@@ -1,7 +1,14 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { capture, span } from "@interfere/react/api";
|
|
2
|
+
import { Kernel, KernelOptions } from "@interfere/react/internal/kernel";
|
|
2
3
|
import { ConsentCategory, ConsentState, GateableCategory } from "@interfere/types/sdk/plugins/manifest";
|
|
3
4
|
|
|
4
5
|
//#region src/init.d.ts
|
|
5
|
-
declare
|
|
6
|
+
declare const close: () => Promise<void>, consent: {
|
|
7
|
+
get(): import("@interfere/types/sdk/plugins/manifest").ConsentState | null;
|
|
8
|
+
set(value?: import("@interfere/types/sdk/plugins/manifest").ConsentState): void;
|
|
9
|
+
}, getKernel: () => import("@interfere/react/internal/kernel").Kernel, getKernelOrNull: () => import("@interfere/react/internal/kernel").Kernel | null, identity: {
|
|
10
|
+
get(): import("@interfere/types/sdk/identify").IdentifyParams | null;
|
|
11
|
+
set(params: import("@interfere/types/sdk/identify").IdentifyParams): Promise<void>;
|
|
12
|
+
}, init: (opts?: import("@interfere/react/internal/kernel").KernelOptions) => Promise<import("@interfere/react/internal/kernel").Kernel | null>, subscribeToKernel: (listener: () => void) => () => void;
|
|
6
13
|
//#endregion
|
|
7
|
-
export { type
|
|
14
|
+
export { type ConsentCategory, type ConsentState, type GateableCategory, type Kernel, type KernelOptions, capture, close, consent, getKernel, getKernelOrNull, identity, init, span, subscribeToKernel };
|
package/dist/init.d.mts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"init.d.mts","names":[],"sources":["../src/init.ts"],"mappings":"
|
|
1
|
+
{"version":3,"file":"init.d.mts","names":[],"sources":["../src/init.ts"],"mappings":";;;;;cAmBE,KAAA,QAAK,OAAA,QAAA,OAAA;;;iEAEI,MAAA,EAAA,eAAA,mDACM,MAAA,SAAA,QAAA;;;YAEX,IAAA,8CAAA,aAAA,KAAA,OAAA,4CAAA,MAAA,UAAA,iBAAA,GACa,QAAA"}
|
package/dist/init.mjs
CHANGED
|
@@ -1,11 +1 @@
|
|
|
1
|
-
import
|
|
2
|
-
import { consent, init as init$1 } from "@interfere/react/internal/client";
|
|
3
|
-
//#region src/init.ts
|
|
4
|
-
function init(opts) {
|
|
5
|
-
init$1({
|
|
6
|
-
...opts,
|
|
7
|
-
_wrapperVersions: [PRODUCER_VERSION, ...opts?._wrapperVersions ?? []]
|
|
8
|
-
});
|
|
9
|
-
}
|
|
10
|
-
//#endregion
|
|
11
|
-
export { consent, init };
|
|
1
|
+
import{PRODUCER_VERSION}from"./version.mjs";import{createWrapperSingleton}from"@interfere/react/internal/wrapper-singleton";import{capture,span}from"@interfere/react/api";const{close,consent,getKernel,getKernelOrNull,identity,init,subscribeToKernel}=createWrapperSingleton({producerVersion:PRODUCER_VERSION,initEntryName:`Vite`});export{capture,close,consent,getKernel,getKernelOrNull,identity,init,span,subscribeToKernel};
|
package/dist/init.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"init.mjs","names":[],"sources":["../src/init.ts"],"sourcesContent":["import {
|
|
1
|
+
{"version":3,"file":"init.mjs","names":[],"sources":["../src/init.ts"],"sourcesContent":["import { createWrapperSingleton } from \"@interfere/react/internal/wrapper-singleton\";\n\nimport { PRODUCER_VERSION } from \"./version.js\";\n\n// biome-ignore lint/performance/noBarrelFile: customer-facing one-import surface — `@interfere/vite/init` re-exports the runtime helpers so callers don't have to also import `@interfere/react/api`.\nexport { capture, span } from \"@interfere/react/api\";\nexport type { Kernel, KernelOptions } from \"@interfere/react/internal/kernel\";\nexport type {\n ConsentCategory,\n ConsentState,\n GateableCategory,\n} from \"@interfere/types/sdk/plugins/manifest\";\n\nconst wrapper = createWrapperSingleton({\n producerVersion: PRODUCER_VERSION,\n initEntryName: \"Vite\",\n});\n\nexport const {\n close,\n consent,\n getKernel,\n getKernelOrNull,\n identity,\n init,\n subscribeToKernel,\n} = wrapper;\n"],"mappings":"2KAkBA,KAAa,CACX,MACA,QACA,UACA,gBACA,SACA,KACA,mBAZc,uBAAuB,CACrC,gBAAiB,iBACjB,cAAe,MACjB,CAUI"}
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import { DiscoveryResult } from "./source-maps.mjs";
|
|
2
|
+
import { ReleaseSlug } from "@interfere/types/releases/slug";
|
|
3
|
+
import { HTTPClient, Interfere } from "@interfere/sdk";
|
|
4
|
+
import { ReleasesConfigResponse } from "@interfere/sdk/models/releases-config-response.js";
|
|
5
|
+
import { ManifestBundler } from "@interfere/types/data/source-maps";
|
|
6
|
+
import { CreateReleaseResponse } from "@interfere/types/releases/definition";
|
|
7
|
+
|
|
8
|
+
//#region src/internal/build/pipeline.d.ts
|
|
9
|
+
interface BuildTiming {
|
|
10
|
+
cleanup: number;
|
|
11
|
+
createRelease: number;
|
|
12
|
+
fileCount: number;
|
|
13
|
+
preflight: number;
|
|
14
|
+
total: number;
|
|
15
|
+
totalBytes: number;
|
|
16
|
+
upload: number;
|
|
17
|
+
}
|
|
18
|
+
type ReleasePipelineFailure = {
|
|
19
|
+
kind: "missing_source_provider";
|
|
20
|
+
config: ReleasesConfigResponse;
|
|
21
|
+
} | {
|
|
22
|
+
kind: "missing_destination_provider";
|
|
23
|
+
config: ReleasesConfigResponse;
|
|
24
|
+
};
|
|
25
|
+
type ReleasePipelineResult = {
|
|
26
|
+
ok: true;
|
|
27
|
+
data: ReleasePipelineSuccess;
|
|
28
|
+
} | {
|
|
29
|
+
ok: false;
|
|
30
|
+
failure: ReleasePipelineFailure;
|
|
31
|
+
};
|
|
32
|
+
interface ReleasePipelineSuccess {
|
|
33
|
+
buildId: string;
|
|
34
|
+
cleanupFailures: {
|
|
35
|
+
absolute: string;
|
|
36
|
+
code: string | undefined;
|
|
37
|
+
message: string;
|
|
38
|
+
}[];
|
|
39
|
+
config: ReleasesConfigResponse;
|
|
40
|
+
fileCount: number;
|
|
41
|
+
release: CreateReleaseResponse;
|
|
42
|
+
releaseSlug: ReleaseSlug;
|
|
43
|
+
timing: BuildTiming;
|
|
44
|
+
}
|
|
45
|
+
interface ReleasePipelineInput {
|
|
46
|
+
apiKey: string;
|
|
47
|
+
apiUrl: string;
|
|
48
|
+
buildId: string;
|
|
49
|
+
bundler: ManifestBundler;
|
|
50
|
+
discovery: DiscoveryResult;
|
|
51
|
+
producerVersion: string;
|
|
52
|
+
releaseSlug: ReleaseSlug;
|
|
53
|
+
releasesConfig: ReleasesConfigResponse;
|
|
54
|
+
}
|
|
55
|
+
declare function createSdkClient(opts: {
|
|
56
|
+
apiKey: string;
|
|
57
|
+
apiUrl: string;
|
|
58
|
+
}): {
|
|
59
|
+
httpClient: HTTPClient;
|
|
60
|
+
sdk: Interfere;
|
|
61
|
+
};
|
|
62
|
+
declare function runReleasePipeline(input: ReleasePipelineInput): Promise<ReleasePipelineResult>;
|
|
63
|
+
//#endregion
|
|
64
|
+
export { BuildTiming, ReleasePipelineFailure, ReleasePipelineInput, ReleasePipelineResult, ReleasePipelineSuccess, createSdkClient, runReleasePipeline };
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pipeline.d.mts","names":[],"sources":["../../../src/internal/build/pipeline.ts"],"mappings":";;;;;;;;UA2BiB,WAAA;EACf,OAAA;EACA,aAAA;EACA,SAAA;EACA,SAAA;EACA,KAAA;EACA,UAAA;EACA,MAAA;AAAA;AAAA,KAGU,sBAAA;EACN,IAAA;EAAiC,MAAA,EAAQ,sBAAA;AAAA;EACzC,IAAA;EAAsC,MAAA,EAAQ,sBAAsB;AAAA;AAAA,KAE9D,qBAAA;EACN,EAAA;EAAU,IAAA,EAAM,sBAAA;AAAA;EAChB,EAAA;EAAW,OAAA,EAAS,sBAAsB;AAAA;AAAA,UAE/B,sBAAA;EACf,OAAA;EACA,eAAA;IACE,QAAA;IACA,IAAA;IACA,OAAA;EAAA;EAEF,MAAA,EAAQ,sBAAA;EACR,SAAA;EACA,OAAA,EAAS,qBAAA;EACT,WAAA,EAAa,WAAA;EACb,MAAA,EAAQ,WAAA;AAAA;AAAA,UAGO,oBAAA;EACf,MAAA;EACA,MAAA;EACA,OAAA;EACA,OAAA,EAAS,eAAA;EACT,SAAA,EAAW,eAAA;EACX,eAAA;EACA,WAAA,EAAa,WAAA;EACb,cAAA,EAAgB,sBAAA;AAAA;AAAA,iBA2BF,eAAA,CAAgB,IAAA;EAAQ,MAAA;EAAgB,MAAA;AAAA;EACtD,UAAA,EAAY,UAAA;EACZ,GAAA,EAAK,SAAS;AAAA;AAAA,iBAwCM,kBAAA,CACpB,KAAA,EAAO,oBAAA,GACN,OAAA,CAAQ,qBAAA"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{cleanupSourceMaps,uploadSourceMaps}from"./source-maps.mjs";import{parseEnvValue}from"@interfere/types/sdk/env";import{releaseSlugSchema}from"@interfere/types/releases/slug";import{execSync}from"node:child_process";import{HTTPClient,Interfere}from"@interfere/sdk";const sources={github:resolveGithubSource},destinations={vercel:resolveVercelDestination};async function timed(fn){let start=performance.now();return[await fn(),Math.round(performance.now()-start)]}function createSdkClient(opts){let httpClient=new HTTPClient;return httpClient.addHook(`beforeRequest`,request=>{let next=new Request(request);return next.headers.set(`Authorization`,`Bearer ${opts.apiKey}`),next}),{httpClient,sdk:new Interfere({serverURL:opts.apiUrl,httpClient})}}function resolveReleaseRequest(buildId,releaseSlug,producerVersion,config){return config.surface.sourceProvider?config.surface.destinationProvider?{ok:!0,request:{source:sources[config.surface.sourceProvider](),destination:destinations[config.surface.destinationProvider](),buildId,slug:releaseSlug,producerVersion}}:{ok:!1,reason:`missing_destination_provider`}:{ok:!1,reason:`missing_source_provider`}}async function runReleasePipeline(input){let{apiKey,apiUrl,bundler,discovery,releasesConfig}=input,releaseRequest=resolveReleaseRequest(input.buildId,input.releaseSlug,input.producerVersion,releasesConfig);if(!releaseRequest.ok)return{ok:!1,failure:{kind:releaseRequest.reason,config:releasesConfig}};let start=performance.now(),{httpClient,sdk}=createSdkClient({apiKey,apiUrl}),[release,createReleaseMs]=await timed(()=>sdk.releases.create(releaseRequest.request)),releaseSlug=releaseSlugSchema.parse(release.destination.slug),buildId=release.build.hash??input.buildId,[{totalBytes},uploadMs]=await timed(()=>uploadSourceMaps({apiUrl,bundler,discovered:discovery,httpClient,releaseSlug})),[,preflightMs]=await timed(()=>sdk.releases.preflight({releaseSlug})),[{failures},cleanupMs]=await timed(()=>cleanupSourceMaps(discovery.files));return{ok:!0,data:{buildId,cleanupFailures:failures,config:releasesConfig,fileCount:discovery.files.length,release:{...release,destination:{...release.destination,slug:releaseSlug}},releaseSlug,timing:{createRelease:createReleaseMs,upload:uploadMs,preflight:preflightMs,cleanup:cleanupMs,total:Math.round(performance.now()-start),fileCount:discovery.files.length,totalBytes}}}}function runGitCommand(command){try{let output=execSync(command,{encoding:`utf8`,stdio:[`ignore`,`pipe`,`ignore`]}).trim();return output.length>0?output:null}catch{return null}}function resolveGithubSource(){return{provider:`github`,branch:parseEnvValue(process.env.VERCEL_GIT_COMMIT_REF)??parseEnvValue(process.env.GITHUB_REF_NAME)??parseEnvValue(process.env.GITHUB_HEAD_REF)??runGitCommand(`git rev-parse --abbrev-ref HEAD`)??`unknown`,commitMessage:parseEnvValue(process.env.VERCEL_GIT_COMMIT_MESSAGE)??runGitCommand(`git log -1 --pretty=%B`)??``,commitSha:parseEnvValue(process.env.VERCEL_GIT_COMMIT_SHA)??parseEnvValue(process.env.GITHUB_SHA)??runGitCommand(`git rev-parse HEAD`)}}function resolveVercelDestination(){let environment=parseEnvValue(process.env.VERCEL_ENV??process.env.VERCEL_TARGET_ENV),deploymentId=parseEnvValue(process.env.VERCEL_DEPLOYMENT_ID);return{provider:`vercel`,destinationReleaseId:deploymentId,environment,deploymentId,deploymentUrl:resolveDeploymentUrl(),environmentName:environment,environmentTarget:environment}}function resolveDeploymentUrl(){let deploymentUrl=parseEnvValue(process.env.VERCEL_URL);return deploymentUrl===null?null:deploymentUrl.startsWith(`https://`)||deploymentUrl.startsWith(`http://`)?deploymentUrl:`https://${deploymentUrl}`}export{createSdkClient,runReleasePipeline};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pipeline.mjs","names":[],"sources":["../../../src/internal/build/pipeline.ts"],"sourcesContent":["import { execSync } from \"node:child_process\";\n\nimport { HTTPClient, Interfere } from \"@interfere/sdk\";\nimport type { ReleasesConfigResponse } from \"@interfere/sdk/models/releases-config-response.js\";\nimport type { ManifestBundler } from \"@interfere/types/data/source-maps\";\nimport type {\n DestinationProvider,\n ReleaseDestinationMetadata,\n ReleaseSourceMetadata,\n SourceProvider,\n} from \"@interfere/types/integrations\";\nimport type {\n CreateReleaseRequest,\n CreateReleaseResponse,\n} from \"@interfere/types/releases/definition\";\nimport {\n type ReleaseSlug,\n releaseSlugSchema,\n} from \"@interfere/types/releases/slug\";\nimport { parseEnvValue } from \"@interfere/types/sdk/env\";\n\nimport {\n cleanupSourceMaps,\n type DiscoveryResult,\n uploadSourceMaps,\n} from \"./source-maps.js\";\n\nexport interface BuildTiming {\n cleanup: number;\n createRelease: number;\n fileCount: number;\n preflight: number;\n total: number;\n totalBytes: number;\n upload: number;\n}\n\nexport type ReleasePipelineFailure =\n | { kind: \"missing_source_provider\"; config: ReleasesConfigResponse }\n | { kind: \"missing_destination_provider\"; config: ReleasesConfigResponse };\n\nexport type ReleasePipelineResult =\n | { ok: true; data: ReleasePipelineSuccess }\n | { ok: false; failure: ReleasePipelineFailure };\n\nexport interface ReleasePipelineSuccess {\n buildId: string;\n cleanupFailures: {\n absolute: string;\n code: string | undefined;\n message: string;\n }[];\n config: ReleasesConfigResponse;\n fileCount: number;\n release: CreateReleaseResponse;\n releaseSlug: ReleaseSlug;\n timing: BuildTiming;\n}\n\nexport interface ReleasePipelineInput {\n apiKey: string;\n apiUrl: string;\n buildId: string;\n bundler: ManifestBundler;\n discovery: DiscoveryResult;\n producerVersion: string;\n releaseSlug: ReleaseSlug;\n releasesConfig: ReleasesConfigResponse;\n}\n\ntype ResolveReleaseRequestResult =\n | { ok: true; request: CreateReleaseRequest }\n | {\n ok: false;\n reason: \"missing_source_provider\" | \"missing_destination_provider\";\n };\n\nconst sources: Record<SourceProvider, () => ReleaseSourceMetadata> = {\n github: resolveGithubSource,\n};\n\nconst destinations: Record<\n DestinationProvider,\n () => ReleaseDestinationMetadata\n> = {\n vercel: resolveVercelDestination,\n};\n\nasync function timed<T>(fn: () => Promise<T>): Promise<[T, number]> {\n const start = performance.now();\n const result = await fn();\n return [result, Math.round(performance.now() - start)];\n}\n\nexport function createSdkClient(opts: { apiKey: string; apiUrl: string }): {\n httpClient: HTTPClient;\n sdk: Interfere;\n} {\n const httpClient = new HTTPClient();\n httpClient.addHook(\"beforeRequest\", (request) => {\n const next = new Request(request);\n next.headers.set(\"Authorization\", `Bearer ${opts.apiKey}`);\n return next;\n });\n return {\n httpClient,\n sdk: new Interfere({ serverURL: opts.apiUrl, httpClient }),\n };\n}\n\nfunction resolveReleaseRequest(\n buildId: string,\n releaseSlug: ReleaseSlug,\n producerVersion: string,\n config: ReleasesConfigResponse\n): ResolveReleaseRequestResult {\n if (!config.surface.sourceProvider) {\n return { ok: false, reason: \"missing_source_provider\" };\n }\n\n if (!config.surface.destinationProvider) {\n return { ok: false, reason: \"missing_destination_provider\" };\n }\n\n return {\n ok: true,\n request: {\n source: sources[config.surface.sourceProvider](),\n destination: destinations[config.surface.destinationProvider](),\n buildId,\n slug: releaseSlug,\n producerVersion,\n },\n };\n}\n\nexport async function runReleasePipeline(\n input: ReleasePipelineInput\n): Promise<ReleasePipelineResult> {\n const { apiKey, apiUrl, bundler, discovery, releasesConfig } = input;\n const releaseRequest = resolveReleaseRequest(\n input.buildId,\n input.releaseSlug,\n input.producerVersion,\n releasesConfig\n );\n\n if (!releaseRequest.ok) {\n return {\n ok: false,\n failure: { kind: releaseRequest.reason, config: releasesConfig },\n };\n }\n\n const start = performance.now();\n const { httpClient, sdk } = createSdkClient({ apiKey, apiUrl });\n const [release, createReleaseMs] = await timed(() =>\n sdk.releases.create(releaseRequest.request)\n );\n const releaseSlug = releaseSlugSchema.parse(release.destination.slug);\n const buildId = release.build.hash ?? input.buildId;\n const [{ totalBytes }, uploadMs] = await timed(() =>\n uploadSourceMaps({\n apiUrl,\n bundler,\n discovered: discovery,\n httpClient,\n releaseSlug,\n })\n );\n const [, preflightMs] = await timed(() =>\n sdk.releases.preflight({ releaseSlug })\n );\n const [{ failures }, cleanupMs] = await timed(() =>\n cleanupSourceMaps(discovery.files)\n );\n\n return {\n ok: true,\n data: {\n buildId,\n cleanupFailures: failures,\n config: releasesConfig,\n fileCount: discovery.files.length,\n release: {\n ...release,\n destination: { ...release.destination, slug: releaseSlug },\n },\n releaseSlug,\n timing: {\n createRelease: createReleaseMs,\n upload: uploadMs,\n preflight: preflightMs,\n cleanup: cleanupMs,\n total: Math.round(performance.now() - start),\n fileCount: discovery.files.length,\n totalBytes,\n },\n },\n };\n}\n\nfunction runGitCommand(command: string): string | null {\n try {\n const output = execSync(command, {\n encoding: \"utf8\",\n stdio: [\"ignore\", \"pipe\", \"ignore\"],\n }).trim();\n return output.length > 0 ? output : null;\n } catch {\n return null;\n }\n}\n\nfunction resolveGithubSource(): ReleaseSourceMetadata {\n return {\n provider: \"github\",\n branch:\n parseEnvValue(process.env[\"VERCEL_GIT_COMMIT_REF\"]) ??\n parseEnvValue(process.env[\"GITHUB_REF_NAME\"]) ??\n parseEnvValue(process.env[\"GITHUB_HEAD_REF\"]) ??\n runGitCommand(\"git rev-parse --abbrev-ref HEAD\") ??\n \"unknown\",\n commitMessage:\n parseEnvValue(process.env[\"VERCEL_GIT_COMMIT_MESSAGE\"]) ??\n runGitCommand(\"git log -1 --pretty=%B\") ??\n \"\",\n commitSha:\n parseEnvValue(process.env[\"VERCEL_GIT_COMMIT_SHA\"]) ??\n parseEnvValue(process.env[\"GITHUB_SHA\"]) ??\n runGitCommand(\"git rev-parse HEAD\"),\n };\n}\n\nfunction resolveVercelDestination(): ReleaseDestinationMetadata {\n const environment = parseEnvValue(\n process.env[\"VERCEL_ENV\"] ?? process.env[\"VERCEL_TARGET_ENV\"]\n );\n const deploymentId = parseEnvValue(process.env[\"VERCEL_DEPLOYMENT_ID\"]);\n\n return {\n provider: \"vercel\",\n destinationReleaseId: deploymentId,\n environment,\n deploymentId,\n deploymentUrl: resolveDeploymentUrl(),\n environmentName: environment,\n environmentTarget: environment,\n };\n}\n\nfunction resolveDeploymentUrl(): string | null {\n const deploymentUrl = parseEnvValue(process.env[\"VERCEL_URL\"]);\n if (deploymentUrl === null) {\n return null;\n }\n if (\n deploymentUrl.startsWith(\"https://\") ||\n deploymentUrl.startsWith(\"http://\")\n ) {\n return deploymentUrl;\n }\n return `https://${deploymentUrl}`;\n}\n"],"mappings":"8QA6EA,MAAM,QAA+D,CACnE,OAAQ,mBACV,EAEM,aAGF,CACF,OAAQ,wBACV,EAEA,eAAe,MAAS,GAA4C,CAClE,IAAM,MAAQ,YAAY,IAAI,EAE9B,MAAO,CAAC,MADa,GAAG,EACR,KAAK,MAAM,YAAY,IAAI,EAAI,KAAK,CAAC,CACvD,CAEA,SAAgB,gBAAgB,KAG9B,CACA,IAAM,WAAa,IAAI,WAMvB,OALA,WAAW,QAAQ,gBAAkB,SAAY,CAC/C,IAAM,KAAO,IAAI,QAAQ,OAAO,EAEhC,OADA,KAAK,QAAQ,IAAI,gBAAiB,UAAU,KAAK,QAAQ,EAClD,IACT,CAAC,EACM,CACL,WACA,IAAK,IAAI,UAAU,CAAE,UAAW,KAAK,OAAQ,UAAW,CAAC,CAC3D,CACF,CAEA,SAAS,sBACP,QACA,YACA,gBACA,OAC6B,CAS7B,OARK,OAAO,QAAQ,eAIf,OAAO,QAAQ,oBAIb,CACL,GAAI,GACJ,QAAS,CACP,OAAQ,QAAQ,OAAO,QAAQ,gBAAgB,EAC/C,YAAa,aAAa,OAAO,QAAQ,qBAAqB,EAC9D,QACA,KAAM,YACN,eACF,CACF,EAZS,CAAE,GAAI,GAAO,OAAQ,8BAA+B,EAJpD,CAAE,GAAI,GAAO,OAAQ,yBAA0B,CAiB1D,CAEA,eAAsB,mBACpB,MACgC,CAChC,GAAM,CAAE,OAAQ,OAAQ,QAAS,UAAW,gBAAmB,MACzD,eAAiB,sBACrB,MAAM,QACN,MAAM,YACN,MAAM,gBACN,cACF,EAEA,GAAI,CAAC,eAAe,GAClB,MAAO,CACL,GAAI,GACJ,QAAS,CAAE,KAAM,eAAe,OAAQ,OAAQ,cAAe,CACjE,EAGF,IAAM,MAAQ,YAAY,IAAI,EACxB,CAAE,WAAY,KAAQ,gBAAgB,CAAE,OAAQ,MAAO,CAAC,EACxD,CAAC,QAAS,iBAAmB,MAAM,UACvC,IAAI,SAAS,OAAO,eAAe,OAAO,CAC5C,EACM,YAAc,kBAAkB,MAAM,QAAQ,YAAY,IAAI,EAC9D,QAAU,QAAQ,MAAM,MAAQ,MAAM,QACtC,CAAC,CAAE,YAAc,UAAY,MAAM,UACvC,iBAAiB,CACf,OACA,QACA,WAAY,UACZ,WACA,WACF,CAAC,CACH,EACM,EAAG,aAAe,MAAM,UAC5B,IAAI,SAAS,UAAU,CAAE,WAAY,CAAC,CACxC,EACM,CAAC,CAAE,UAAY,WAAa,MAAM,UACtC,kBAAkB,UAAU,KAAK,CACnC,EAEA,MAAO,CACL,GAAI,GACJ,KAAM,CACJ,QACA,gBAAiB,SACjB,OAAQ,eACR,UAAW,UAAU,MAAM,OAC3B,QAAS,CACP,GAAG,QACH,YAAa,CAAE,GAAG,QAAQ,YAAa,KAAM,WAAY,CAC3D,EACA,YACA,OAAQ,CACN,cAAe,gBACf,OAAQ,SACR,UAAW,YACX,QAAS,UACT,MAAO,KAAK,MAAM,YAAY,IAAI,EAAI,KAAK,EAC3C,UAAW,UAAU,MAAM,OAC3B,UACF,CACF,CACF,CACF,CAEA,SAAS,cAAc,QAAgC,CACrD,GAAI,CACF,IAAM,OAAS,SAAS,QAAS,CAC/B,SAAU,OACV,MAAO,CAAC,SAAU,OAAQ,QAAQ,CACpC,CAAC,EAAE,KAAK,EACR,OAAO,OAAO,OAAS,EAAI,OAAS,IACtC,MAAQ,CACN,OAAO,IACT,CACF,CAEA,SAAS,qBAA6C,CACpD,MAAO,CACL,SAAU,SACV,OACE,cAAc,QAAQ,IAAI,qBAAwB,GAClD,cAAc,QAAQ,IAAI,eAAkB,GAC5C,cAAc,QAAQ,IAAI,eAAkB,GAC5C,cAAc,iCAAiC,GAC/C,UACF,cACE,cAAc,QAAQ,IAAI,yBAA4B,GACtD,cAAc,wBAAwB,GACtC,GACF,UACE,cAAc,QAAQ,IAAI,qBAAwB,GAClD,cAAc,QAAQ,IAAI,UAAa,GACvC,cAAc,oBAAoB,CACtC,CACF,CAEA,SAAS,0BAAuD,CAC9D,IAAM,YAAc,cAClB,QAAQ,IAAI,YAAiB,QAAQ,IAAI,iBAC3C,EACM,aAAe,cAAc,QAAQ,IAAI,oBAAuB,EAEtE,MAAO,CACL,SAAU,SACV,qBAAsB,aACtB,YACA,aACA,cAAe,qBAAqB,EACpC,gBAAiB,YACjB,kBAAmB,WACrB,CACF,CAEA,SAAS,sBAAsC,CAC7C,IAAM,cAAgB,cAAc,QAAQ,IAAI,UAAa,EAU7D,OATI,gBAAkB,KACb,KAGP,cAAc,WAAW,UAAU,GACnC,cAAc,WAAW,SAAS,EAE3B,cAEF,WAAW,eACpB"}
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import { ReleaseSlug } from "@interfere/types/releases/slug";
|
|
2
|
+
import { HTTPClient } from "@interfere/sdk";
|
|
3
|
+
import { ManifestBundler } from "@interfere/types/data/source-maps";
|
|
4
|
+
|
|
5
|
+
//#region src/internal/build/source-maps.d.ts
|
|
6
|
+
interface SourceMapFile {
|
|
7
|
+
readonly absolute: string;
|
|
8
|
+
readonly chunkUrl: string;
|
|
9
|
+
readonly content: string;
|
|
10
|
+
readonly debugId: string;
|
|
11
|
+
readonly hash: string;
|
|
12
|
+
readonly path: string;
|
|
13
|
+
}
|
|
14
|
+
interface DiscoveryResult {
|
|
15
|
+
readonly files: SourceMapFile[];
|
|
16
|
+
readonly sourceFileCount: number;
|
|
17
|
+
}
|
|
18
|
+
interface PublicPathRewrite {
|
|
19
|
+
from: string;
|
|
20
|
+
to: string;
|
|
21
|
+
}
|
|
22
|
+
interface DiscoverByPairingOptions {
|
|
23
|
+
distDir: string;
|
|
24
|
+
projectDir: string;
|
|
25
|
+
publicPathRewrites: readonly PublicPathRewrite[];
|
|
26
|
+
subtrees: readonly string[];
|
|
27
|
+
}
|
|
28
|
+
interface CleanupFailure {
|
|
29
|
+
readonly absolute: string;
|
|
30
|
+
readonly code: string | undefined;
|
|
31
|
+
readonly message: string;
|
|
32
|
+
}
|
|
33
|
+
interface UploadParams {
|
|
34
|
+
apiUrl: string;
|
|
35
|
+
bundler: ManifestBundler;
|
|
36
|
+
discovered: DiscoveryResult;
|
|
37
|
+
httpClient: HTTPClient;
|
|
38
|
+
releaseSlug: ReleaseSlug;
|
|
39
|
+
}
|
|
40
|
+
interface UploadResult {
|
|
41
|
+
fileCount: number;
|
|
42
|
+
totalBytes: number;
|
|
43
|
+
}
|
|
44
|
+
declare function discoverByPairing(opts: DiscoverByPairingOptions): Promise<DiscoveryResult>;
|
|
45
|
+
declare function cleanupSourceMaps(files: readonly SourceMapFile[]): Promise<{
|
|
46
|
+
failures: CleanupFailure[];
|
|
47
|
+
}>;
|
|
48
|
+
declare function uploadSourceMaps({
|
|
49
|
+
apiUrl,
|
|
50
|
+
bundler,
|
|
51
|
+
discovered,
|
|
52
|
+
httpClient,
|
|
53
|
+
releaseSlug
|
|
54
|
+
}: UploadParams): Promise<UploadResult>;
|
|
55
|
+
//#endregion
|
|
56
|
+
export { CleanupFailure, DiscoverByPairingOptions, DiscoveryResult, SourceMapFile, UploadResult, cleanupSourceMaps, discoverByPairing, uploadSourceMaps };
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"source-maps.d.mts","names":[],"sources":["../../../src/internal/build/source-maps.ts"],"mappings":";;;;;UAqBiB,aAAA;EAAA,SACN,QAAA;EAAA,SACA,QAAA;EAAA,SACA,OAAA;EAAA,SACA,OAAA;EAAA,SACA,IAAA;EAAA,SACA,IAAA;AAAA;AAAA,UAGM,eAAA;EAAA,SACN,KAAA,EAAO,aAAa;EAAA,SACpB,eAAA;AAAA;AAAA,UAGD,iBAAA;EACR,IAAA;EACA,EAAE;AAAA;AAAA,UAGa,wBAAA;EACf,OAAA;EACA,UAAA;EACA,kBAAA,WAA6B,iBAAiB;EAC9C,QAAA;AAAA;AAAA,UAGe,cAAA;EAAA,SACN,QAAA;EAAA,SACA,IAAA;EAAA,SACA,OAAA;AAAA;AAAA,UAGD,YAAA;EACR,MAAA;EACA,OAAA,EAAS,eAAA;EACT,UAAA,EAAY,eAAA;EACZ,UAAA,EAAY,UAAA;EACZ,WAAA,EAAa,WAAA;AAAA;AAAA,UAGE,YAAA;EACf,SAAA;EACA,UAAU;AAAA;AAAA,iBA+EU,iBAAA,CACpB,IAAA,EAAM,wBAAA,GACL,OAAA,CAAQ,eAAA;AAAA,iBA6FW,iBAAA,CACpB,KAAA,WAAgB,aAAA,KACf,OAAA;EAAU,QAAA,EAAU,cAAA;AAAA;AAAA,iBAyBD,gBAAA,CAAA;EACpB,MAAA;EACA,OAAA;EACA,UAAA;EACA,UAAA;EACA;AAAA,GACC,YAAA,GAAe,OAAA,CAAQ,YAAA"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{isAbsolute,join,relative,resolve}from"node:path";import{createHash,randomUUID}from"node:crypto";import{readFile,readdir,unlink,writeFile}from"node:fs/promises";const LEADING_DOT_SLASH_RE=/^(\.\/)+/,SOURCEMAPPING_RE=/\/\/[#@]\s*sourceMappingURL=(\S+)\s*$/,SPEC_LAST_DEBUG_ID_RE=/\/\/# debugId=([a-fA-F0-9-]+)(?![\s\S]*\/\/# debugId=)/m,SCRIPT_SUFFIXES=[`.js`,`.mjs`,`.cjs`];function normalizeDistDir(distDir){return distDir.replaceAll(`\\`,`/`).replace(LEADING_DOT_SLASH_RE,``)}function resolveDistDir(projectDir,distDir){return isAbsolute(distDir)?distDir:resolve(projectDir,distDir)}async function walkDistTrees(absDistDir,suffixes,subtrees){return(await Promise.all(subtrees.map(async subtree=>{let root=subtree===`.`?absDistDir:join(absDistDir,subtree),entries=await readdir(root,{recursive:!0}).catch(()=>[]),out=[];for(let entry of entries)typeof entry==`string`&&suffixes.some(suffix=>entry.endsWith(suffix))&&out.push(join(root,entry));return out}))).flat()}function toPublicPath(rel,rewrites){let normalized=rel.replaceAll(`\\`,`/`);for(let{from,to}of rewrites){let prefix=from.endsWith(`/`)?from:`${from}/`;if(normalized.startsWith(prefix))return`${to}${normalized.slice(prefix.length)}`}return normalized}function readDebugIdFromJs(content){return SPEC_LAST_DEBUG_ID_RE.exec(content)?.[1]??null}function injectDebugIdIntoJs(content,debugId){let debugIdComment=`//# debugId=${debugId}`;if(SPEC_LAST_DEBUG_ID_RE.test(content))return content.replace(SPEC_LAST_DEBUG_ID_RE,debugIdComment);let match=SOURCEMAPPING_RE.exec(content);return match?`${content.slice(0,match.index).trimEnd()}\n${debugIdComment}\n${match[0]}`:`${content}\n${debugIdComment}`}function injectDebugIdIntoMap(content,debugId){let json=JSON.parse(content);return json.debugId=debugId,JSON.stringify(json)}async function discoverByPairing(opts){let absDistDir=resolveDistDir(opts.projectDir,normalizeDistDir(opts.distDir)),jsPaths=await walkDistTrees(absDistDir,SCRIPT_SUFFIXES,opts.subtrees),pairs=new Map;for(let jsAbs of jsPaths){let content=await readFile(jsAbs,`utf8`),match=SOURCEMAPPING_RE.exec(content);if(!match?.[1])continue;let mapAbs=`${jsAbs.slice(0,jsAbs.lastIndexOf(`/`)+1)}${decodeURIComponent(match[1])}`,jsPublic=toPublicPath(relative(absDistDir,jsAbs),opts.publicPathRewrites),mapPublic=toPublicPath(relative(absDistDir,mapAbs),opts.publicPathRewrites);pairs.set(mapPublic,{existingDebugId:readDebugIdFromJs(content),jsAbs,jsContent:content,jsPublic,mapAbs})}return{files:(await Promise.all(Array.from(pairs.entries(),async([mapPublic,pair])=>{let mapContent=await readFile(pair.mapAbs,`utf8`).catch(()=>null);if(mapContent===null)return null;let debugId=pair.existingDebugId??randomUUID();pair.existingDebugId||await writeFile(pair.jsAbs,injectDebugIdIntoJs(pair.jsContent,debugId),`utf8`);let finalMap=JSON.parse(mapContent).debugId===debugId?mapContent:injectDebugIdIntoMap(mapContent,debugId);return finalMap!==mapContent&&await writeFile(pair.mapAbs,finalMap,`utf8`),{absolute:pair.mapAbs,path:mapPublic,content:finalMap,hash:createHash(`sha256`).update(finalMap).digest(`hex`),debugId,chunkUrl:pair.jsPublic}}))).filter(file=>file!==null),sourceFileCount:pairs.size}}async function cleanupSourceMaps(files){let results=await Promise.allSettled(files.map(file=>unlink(file.absolute))),failures=[];for(let[index,result]of results.entries()){if(result.status!==`rejected`)continue;let error=result.reason;if(error.code===`ENOENT`)continue;let file=files[index];failures.push({absolute:file?.absolute??`<unknown>`,code:error.code,message:error.message??String(error)})}return{failures}}async function uploadSourceMaps({apiUrl,bundler,discovered,httpClient,releaseSlug}){let filesByPath=new Map(discovered.files.map(file=>[file.path,file])),signRequest={files:discovered.files.map(file=>({path:file.path,sizeBytes:byteLengthOf(file.content),...extractRichness(file.content)}))},signResponse=await postJson(httpClient,new URL(`/v1/releases/${encodeURIComponent(releaseSlug)}/source-maps/sign`,apiUrl),signRequest),totalBytes=0;await mapWithConcurrency(signResponse.uploads,12,async upload=>{let file=filesByPath.get(upload.path);if(!file)throw Error(`Sign response referenced unknown path "${upload.path}"`);totalBytes+=byteLengthOf(file.content),await putToR2(upload.presignedUrl,file.content)});let completeRequest={files:discovered.files.map(file=>({path:file.path,hash:file.hash,debugId:file.debugId,chunkUrl:file.chunkUrl})),sourceFileCount:discovered.sourceFileCount,bundler};return{fileCount:(await postJson(httpClient,new URL(`/v1/releases/${encodeURIComponent(releaseSlug)}/source-maps/complete`,apiUrl),completeRequest)).fileCount,totalBytes}}function byteLengthOf(content){return new TextEncoder().encode(content).byteLength}const EMPTY_RICHNESS={hasSourcesContent:!1,hasNames:!1,hasFile:!1,mappingsPresent:!1};function leafRichness(map){let sourcesContent=map.sourcesContent,names=map.names,file=map.file,mappings=map.mappings;return{hasSourcesContent:Array.isArray(sourcesContent)&&sourcesContent.length>0,hasNames:Array.isArray(names)&&names.length>0,hasFile:typeof file==`string`&&file.length>0,mappingsPresent:typeof mappings==`string`&&mappings.length>0}}function extractRichness(content){let parsed;try{parsed=JSON.parse(content)}catch{return EMPTY_RICHNESS}if(!(parsed&&typeof parsed==`object`))return EMPTY_RICHNESS;let top=parsed,sections=top.sections;if(!Array.isArray(sections))return leafRichness(top);let merged={hasSourcesContent:!1,hasNames:!1,hasFile:typeof top.file==`string`&&top.file.length>0,mappingsPresent:!1};for(let section of sections){let inner=section?.map;if(!(inner&&typeof inner==`object`))continue;let richness=leafRichness(inner);merged.hasSourcesContent||=richness.hasSourcesContent,merged.hasNames||=richness.hasNames,merged.mappingsPresent||=richness.mappingsPresent}return merged}async function postJson(httpClient,url,body){let response=await httpClient.request(new Request(url,{method:`POST`,headers:{"content-type":`application/json`,accept:`application/json`},body:JSON.stringify(body)}));if(!response.ok){let detail=await response.text().catch(()=>``);throw Error(`Source-map API request failed: POST ${url.pathname} -> ${response.status} ${detail}`)}return await response.json()}async function putToR2(presignedUrl,content){let response=await fetch(presignedUrl,{method:`PUT`,headers:{"content-type":`application/json`},body:content});if(!response.ok){let detail=await response.text().catch(()=>``);throw Error(`Release metadata file upload failed: ${response.status} ${detail}`)}}async function mapWithConcurrency(items,concurrency,fn){let cursor=0;async function worker(){for(;;){let index=cursor++;if(index>=items.length)return;let item=items[index];if(item===void 0)return;await fn(item,index)}}await Promise.all(Array.from({length:Math.min(concurrency,items.length)},()=>worker()))}export{cleanupSourceMaps,discoverByPairing,uploadSourceMaps};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"source-maps.mjs","names":[],"sources":["../../../src/internal/build/source-maps.ts"],"sourcesContent":["import { createHash, randomUUID } from \"node:crypto\";\nimport { readdir, readFile, unlink, writeFile } from \"node:fs/promises\";\nimport { isAbsolute, join, relative, resolve } from \"node:path\";\n\nimport type { HTTPClient } from \"@interfere/sdk\";\nimport type {\n CompleteSourceMapsRequest,\n CompleteSourceMapsResponse,\n ManifestBundler,\n SignSourceMapsRequest,\n SignSourceMapsResponse,\n} from \"@interfere/types/data/source-maps\";\nimport type { ReleaseSlug } from \"@interfere/types/releases/slug\";\n\nconst LEADING_DOT_SLASH_RE = /^(\\.\\/)+/;\nconst PUT_CONCURRENCY = 12;\nconst SOURCEMAPPING_RE = /\\/\\/[#@]\\s*sourceMappingURL=(\\S+)\\s*$/;\nconst SPEC_LAST_DEBUG_ID_RE =\n /\\/\\/# debugId=([a-fA-F0-9-]+)(?![\\s\\S]*\\/\\/# debugId=)/m;\nconst SCRIPT_SUFFIXES = [\".js\", \".mjs\", \".cjs\"] as const;\n\nexport interface SourceMapFile {\n readonly absolute: string;\n readonly chunkUrl: string;\n readonly content: string;\n readonly debugId: string;\n readonly hash: string;\n readonly path: string;\n}\n\nexport interface DiscoveryResult {\n readonly files: SourceMapFile[];\n readonly sourceFileCount: number;\n}\n\ninterface PublicPathRewrite {\n from: string;\n to: string;\n}\n\nexport interface DiscoverByPairingOptions {\n distDir: string;\n projectDir: string;\n publicPathRewrites: readonly PublicPathRewrite[];\n subtrees: readonly string[];\n}\n\nexport interface CleanupFailure {\n readonly absolute: string;\n readonly code: string | undefined;\n readonly message: string;\n}\n\ninterface UploadParams {\n apiUrl: string;\n bundler: ManifestBundler;\n discovered: DiscoveryResult;\n httpClient: HTTPClient;\n releaseSlug: ReleaseSlug;\n}\n\nexport interface UploadResult {\n fileCount: number;\n totalBytes: number;\n}\n\nfunction normalizeDistDir(distDir: string): string {\n return distDir.replaceAll(\"\\\\\", \"/\").replace(LEADING_DOT_SLASH_RE, \"\");\n}\n\nfunction resolveDistDir(projectDir: string, distDir: string): string {\n return isAbsolute(distDir) ? distDir : resolve(projectDir, distDir);\n}\n\nasync function walkDistTrees(\n absDistDir: string,\n suffixes: readonly string[],\n subtrees: readonly string[]\n): Promise<string[]> {\n const results = await Promise.all(\n subtrees.map(async (subtree) => {\n const root = subtree === \".\" ? absDistDir : join(absDistDir, subtree);\n const entries = await readdir(root, { recursive: true }).catch(\n () => [] as string[]\n );\n const out: string[] = [];\n for (const entry of entries) {\n if (\n typeof entry === \"string\" &&\n suffixes.some((suffix) => entry.endsWith(suffix))\n ) {\n out.push(join(root, entry));\n }\n }\n return out;\n })\n );\n\n return results.flat();\n}\n\nfunction toPublicPath(\n rel: string,\n rewrites: readonly PublicPathRewrite[]\n): string {\n const normalized = rel.replaceAll(\"\\\\\", \"/\");\n for (const { from, to } of rewrites) {\n const prefix = from.endsWith(\"/\") ? from : `${from}/`;\n if (normalized.startsWith(prefix)) {\n return `${to}${normalized.slice(prefix.length)}`;\n }\n }\n return normalized;\n}\n\nfunction readDebugIdFromJs(content: string): string | null {\n const match = SPEC_LAST_DEBUG_ID_RE.exec(content);\n return match?.[1] ?? null;\n}\n\nfunction injectDebugIdIntoJs(content: string, debugId: string): string {\n const debugIdComment = `//# debugId=${debugId}`;\n\n if (SPEC_LAST_DEBUG_ID_RE.test(content)) {\n return content.replace(SPEC_LAST_DEBUG_ID_RE, debugIdComment);\n }\n\n const match = SOURCEMAPPING_RE.exec(content);\n if (match) {\n const before = content.slice(0, match.index).trimEnd();\n return `${before}\\n${debugIdComment}\\n${match[0]}`;\n }\n\n return `${content}\\n${debugIdComment}`;\n}\n\nfunction injectDebugIdIntoMap(content: string, debugId: string): string {\n const json = JSON.parse(content) as Record<string, unknown>;\n json[\"debugId\"] = debugId;\n return JSON.stringify(json);\n}\n\nexport async function discoverByPairing(\n opts: DiscoverByPairingOptions\n): Promise<DiscoveryResult> {\n const absDistDir = resolveDistDir(\n opts.projectDir,\n normalizeDistDir(opts.distDir)\n );\n const jsPaths = await walkDistTrees(\n absDistDir,\n SCRIPT_SUFFIXES,\n opts.subtrees\n );\n const pairs = new Map<\n string,\n {\n existingDebugId: string | null;\n jsAbs: string;\n jsContent: string;\n jsPublic: string;\n mapAbs: string;\n }\n >();\n\n for (const jsAbs of jsPaths) {\n const content = await readFile(jsAbs, \"utf8\");\n const match = SOURCEMAPPING_RE.exec(content);\n if (!match?.[1]) {\n continue;\n }\n\n const jsDir = jsAbs.slice(0, jsAbs.lastIndexOf(\"/\") + 1);\n const mapAbs = `${jsDir}${decodeURIComponent(match[1])}`;\n const jsPublic = toPublicPath(\n relative(absDistDir, jsAbs),\n opts.publicPathRewrites\n );\n const mapPublic = toPublicPath(\n relative(absDistDir, mapAbs),\n opts.publicPathRewrites\n );\n\n pairs.set(mapPublic, {\n existingDebugId: readDebugIdFromJs(content),\n jsAbs,\n jsContent: content,\n jsPublic,\n mapAbs,\n });\n }\n\n const files = await Promise.all(\n Array.from(\n pairs.entries(),\n async ([mapPublic, pair]): Promise<SourceMapFile | null> => {\n const mapContent = await readFile(pair.mapAbs, \"utf8\").catch(\n () => null\n );\n if (mapContent === null) {\n return null;\n }\n\n const debugId = pair.existingDebugId ?? randomUUID();\n if (!pair.existingDebugId) {\n await writeFile(\n pair.jsAbs,\n injectDebugIdIntoJs(pair.jsContent, debugId),\n \"utf8\"\n );\n }\n\n const mapJson = JSON.parse(mapContent) as Record<string, unknown>;\n const finalMap =\n mapJson[\"debugId\"] === debugId\n ? mapContent\n : injectDebugIdIntoMap(mapContent, debugId);\n if (finalMap !== mapContent) {\n await writeFile(pair.mapAbs, finalMap, \"utf8\");\n }\n\n return {\n absolute: pair.mapAbs,\n path: mapPublic,\n content: finalMap,\n hash: createHash(\"sha256\").update(finalMap).digest(\"hex\"),\n debugId,\n chunkUrl: pair.jsPublic,\n };\n }\n )\n );\n\n const loaded = files.filter((file): file is SourceMapFile => file !== null);\n return { files: loaded, sourceFileCount: pairs.size };\n}\n\nexport async function cleanupSourceMaps(\n files: readonly SourceMapFile[]\n): Promise<{ failures: CleanupFailure[] }> {\n const results = await Promise.allSettled(\n files.map((file) => unlink(file.absolute))\n );\n const failures: CleanupFailure[] = [];\n\n for (const [index, result] of results.entries()) {\n if (result.status !== \"rejected\") {\n continue;\n }\n const error = result.reason as NodeJS.ErrnoException;\n if (error.code === \"ENOENT\") {\n continue;\n }\n const file = files[index];\n failures.push({\n absolute: file?.absolute ?? \"<unknown>\",\n code: error.code,\n message: error.message ?? String(error),\n });\n }\n\n return { failures };\n}\n\nexport async function uploadSourceMaps({\n apiUrl,\n bundler,\n discovered,\n httpClient,\n releaseSlug,\n}: UploadParams): Promise<UploadResult> {\n const filesByPath = new Map(discovered.files.map((file) => [file.path, file]));\n const signRequest = {\n files: discovered.files.map((file) => ({\n path: file.path,\n sizeBytes: byteLengthOf(file.content),\n ...extractRichness(file.content),\n })),\n } satisfies SignSourceMapsRequest;\n\n const signResponse = await postJson<SignSourceMapsResponse>(\n httpClient,\n new URL(\n `/v1/releases/${encodeURIComponent(releaseSlug)}/source-maps/sign`,\n apiUrl\n ),\n signRequest\n );\n\n let totalBytes = 0;\n await mapWithConcurrency(\n signResponse.uploads,\n PUT_CONCURRENCY,\n async (upload) => {\n const file = filesByPath.get(upload.path);\n if (!file) {\n throw new Error(\n `Sign response referenced unknown path \"${upload.path}\"`\n );\n }\n\n totalBytes += byteLengthOf(file.content);\n await putToR2(upload.presignedUrl, file.content);\n }\n );\n\n const completeRequest = {\n files: discovered.files.map((file) => ({\n path: file.path,\n hash: file.hash,\n debugId: file.debugId,\n chunkUrl: file.chunkUrl,\n })),\n sourceFileCount: discovered.sourceFileCount,\n bundler,\n } satisfies CompleteSourceMapsRequest;\n\n const completeResponse = await postJson<CompleteSourceMapsResponse>(\n httpClient,\n new URL(\n `/v1/releases/${encodeURIComponent(releaseSlug)}/source-maps/complete`,\n apiUrl\n ),\n completeRequest\n );\n\n return {\n fileCount: completeResponse.fileCount,\n totalBytes,\n };\n}\n\nfunction byteLengthOf(content: string) {\n return new TextEncoder().encode(content).byteLength;\n}\n\ninterface SourceMapRichness {\n hasFile: boolean;\n hasNames: boolean;\n hasSourcesContent: boolean;\n mappingsPresent: boolean;\n}\n\nconst EMPTY_RICHNESS: SourceMapRichness = {\n hasSourcesContent: false,\n hasNames: false,\n hasFile: false,\n mappingsPresent: false,\n};\n\nfunction leafRichness(map: Record<string, unknown>): SourceMapRichness {\n const sourcesContent = map[\"sourcesContent\"];\n const names = map[\"names\"];\n const file = map[\"file\"];\n const mappings = map[\"mappings\"];\n\n return {\n hasSourcesContent:\n Array.isArray(sourcesContent) && sourcesContent.length > 0,\n hasNames: Array.isArray(names) && names.length > 0,\n hasFile: typeof file === \"string\" && file.length > 0,\n mappingsPresent: typeof mappings === \"string\" && mappings.length > 0,\n };\n}\n\nfunction extractRichness(content: string): SourceMapRichness {\n let parsed: unknown;\n try {\n parsed = JSON.parse(content);\n } catch {\n return EMPTY_RICHNESS;\n }\n\n if (!(parsed && typeof parsed === \"object\")) {\n return EMPTY_RICHNESS;\n }\n\n const top = parsed as Record<string, unknown>;\n const sections = top[\"sections\"];\n if (!Array.isArray(sections)) {\n return leafRichness(top);\n }\n\n const merged: SourceMapRichness = {\n hasSourcesContent: false,\n hasNames: false,\n hasFile:\n typeof top[\"file\"] === \"string\" && (top[\"file\"] as string).length > 0,\n mappingsPresent: false,\n };\n\n for (const section of sections) {\n const inner = (section as { map?: unknown } | null)?.map;\n if (!(inner && typeof inner === \"object\")) {\n continue;\n }\n const richness = leafRichness(inner as Record<string, unknown>);\n merged.hasSourcesContent ||= richness.hasSourcesContent;\n merged.hasNames ||= richness.hasNames;\n merged.mappingsPresent ||= richness.mappingsPresent;\n }\n\n return merged;\n}\n\nasync function postJson<T>(\n httpClient: HTTPClient,\n url: URL,\n body: unknown\n): Promise<T> {\n const response = await httpClient.request(\n new Request(url, {\n method: \"POST\",\n headers: {\n \"content-type\": \"application/json\",\n accept: \"application/json\",\n },\n body: JSON.stringify(body),\n })\n );\n\n if (!response.ok) {\n const detail = await response.text().catch(() => \"\");\n throw new Error(\n `Source-map API request failed: POST ${url.pathname} -> ${response.status} ${detail}`\n );\n }\n\n return (await response.json()) as T;\n}\n\nasync function putToR2(presignedUrl: string, content: string) {\n const response = await fetch(presignedUrl, {\n method: \"PUT\",\n headers: { \"content-type\": \"application/json\" },\n body: content,\n });\n\n if (!response.ok) {\n const detail = await response.text().catch(() => \"\");\n throw new Error(\n `Release metadata file upload failed: ${response.status} ${detail}`\n );\n }\n}\n\nasync function mapWithConcurrency<T>(\n items: T[],\n concurrency: number,\n fn: (item: T, index: number) => Promise<void>\n): Promise<void> {\n let cursor = 0;\n\n async function worker() {\n while (true) {\n const index = cursor++;\n if (index >= items.length) {\n return;\n }\n const item = items[index];\n if (item === undefined) {\n return;\n }\n await fn(item, index);\n }\n }\n\n await Promise.all(\n Array.from({ length: Math.min(concurrency, items.length) }, () => worker())\n );\n}\n"],"mappings":"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"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { ReleaseSlug } from "@interfere/types/releases/slug";
|
|
2
|
+
|
|
3
|
+
//#region src/internal/release-slug.d.ts
|
|
4
|
+
declare function resolveCommitSha(): string | null;
|
|
5
|
+
declare function resolveReleaseSlug(): {
|
|
6
|
+
commitSha: string | null;
|
|
7
|
+
slug: ReleaseSlug | null;
|
|
8
|
+
};
|
|
9
|
+
//#endregion
|
|
10
|
+
export { resolveCommitSha, resolveReleaseSlug };
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"release-slug.d.mts","names":[],"sources":["../../src/internal/release-slug.ts"],"mappings":";;;iBAqBgB,gBAAA,CAAA;AAAA,iBAOA,kBAAA,CAAA;EACd,SAAA;EACA,IAAA,EAAM,WAAW;AAAA"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{readFirstEnvValue}from"@interfere/types/sdk/env";import{deriveReleaseSlug}from"@interfere/types/releases/slug";import{execSync}from"node:child_process";import{releaseSourceIdEnvKeys}from"@interfere/types/integrations";function runGitCommand(command){try{let output=execSync(command,{encoding:`utf8`,stdio:[`ignore`,`pipe`,`ignore`]}).trim();return output.length>0?output:null}catch{return null}}function resolveCommitSha(){return readFirstEnvValue(process.env,releaseSourceIdEnvKeys)??runGitCommand(`git rev-parse HEAD`)}function resolveReleaseSlug(){let commitSha=resolveCommitSha();return{commitSha,slug:commitSha?deriveReleaseSlug(commitSha):null}}export{resolveCommitSha,resolveReleaseSlug};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"release-slug.mjs","names":[],"sources":["../../src/internal/release-slug.ts"],"sourcesContent":["import { releaseSourceIdEnvKeys } from \"@interfere/types/integrations\";\nimport {\n deriveReleaseSlug,\n type ReleaseSlug,\n} from \"@interfere/types/releases/slug\";\nimport { readFirstEnvValue } from \"@interfere/types/sdk/env\";\n\nimport { execSync } from \"node:child_process\";\n\nfunction runGitCommand(command: string): string | null {\n try {\n const output = execSync(command, {\n encoding: \"utf8\",\n stdio: [\"ignore\", \"pipe\", \"ignore\"],\n }).trim();\n return output.length > 0 ? output : null;\n } catch {\n return null;\n }\n}\n\nexport function resolveCommitSha(): string | null {\n return (\n readFirstEnvValue(process.env, releaseSourceIdEnvKeys) ??\n runGitCommand(\"git rev-parse HEAD\")\n );\n}\n\nexport function resolveReleaseSlug(): {\n commitSha: string | null;\n slug: ReleaseSlug | null;\n} {\n const commitSha = resolveCommitSha();\n return {\n commitSha,\n slug: commitSha ? deriveReleaseSlug(commitSha) : null,\n };\n}\n"],"mappings":"iOASA,SAAS,cAAc,QAAgC,CACrD,GAAI,CACF,IAAM,OAAS,SAAS,QAAS,CAC/B,SAAU,OACV,MAAO,CAAC,SAAU,OAAQ,QAAQ,CACpC,CAAC,EAAE,KAAK,EACR,OAAO,OAAO,OAAS,EAAI,OAAS,IACtC,MAAQ,CACN,OAAO,IACT,CACF,CAEA,SAAgB,kBAAkC,CAChD,OACE,kBAAkB,QAAQ,IAAK,sBAAsB,GACrD,cAAc,oBAAoB,CAEtC,CAEA,SAAgB,oBAGd,CACA,IAAM,UAAY,iBAAiB,EACnC,MAAO,CACL,UACA,KAAM,UAAY,kBAAkB,SAAS,EAAI,IACnD,CACF"}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
//#region src/internal/route/handle.d.ts
|
|
2
|
+
/**
|
|
3
|
+
* Web-Standards `Request → Response` handler that customers wire
|
|
4
|
+
* into their server framework's catch-all API route. Same proxy
|
|
5
|
+
* behavior as `@interfere/next/route-handler` but built for
|
|
6
|
+
* TanStack Start / Nitro's Web-Standards request handlers.
|
|
7
|
+
*
|
|
8
|
+
* Routes by HTTP method:
|
|
9
|
+
* - `GET /sw` — serves the SDK service worker so customers get
|
|
10
|
+
* offline-durable telemetry without shipping a SW from their
|
|
11
|
+
* own domain.
|
|
12
|
+
* - `GET /*` — proxies to the collector (config fetch).
|
|
13
|
+
* - `POST /*` — proxies to the collector (OTLP ingest, replay,
|
|
14
|
+
* session sync).
|
|
15
|
+
* - `OPTIONS /*` — CORS preflight.
|
|
16
|
+
* - everything else — 405.
|
|
17
|
+
*/
|
|
18
|
+
declare function handle(request: Request): Promise<Response>;
|
|
19
|
+
//#endregion
|
|
20
|
+
export { handle };
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"handle.d.mts","names":[],"sources":["../../../src/internal/route/handle.ts"],"mappings":";;AAyCA;;;;;;;;;;;;;AAAgE;;iBAA1C,MAAA,CAAO,OAAA,EAAS,OAAA,GAAU,OAAA,CAAQ,QAAA"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{isEnabledOnServer}from"../server/env.mjs";import{extractSubPath,formatProxyError,forwardToCollector,resolveAuthenticatedEnv}from"./proxy.mjs";import{SW_SCRIPT}from"@interfere/react/sw";const SW_HEADERS={"content-type":`application/javascript; charset=utf-8`,"service-worker-allowed":`/`,"cache-control":`public, max-age=3600`},CORS_HEADERS={"Access-Control-Allow-Origin":`*`,"Access-Control-Allow-Methods":`GET, POST, OPTIONS`,"Access-Control-Allow-Headers":`Content-Type`,"Access-Control-Max-Age":`86400`},DISABLED_RESPONSE=()=>new Response(null,{status:204});async function handle(request){let method=request.method;return method===`OPTIONS`?new Response(null,{status:200,headers:CORS_HEADERS}):method===`GET`?await handleGet(request):method===`POST`?await handlePost(request):new Response(null,{status:405})}async function handleGet(request){let subPath=extractSubPath(request);if(subPath===`/sw`)return new Response(SW_SCRIPT,{status:200,headers:SW_HEADERS});if(!isEnabledOnServer())return DISABLED_RESPONSE();let env=resolveAuthenticatedEnv();try{return await forwardToCollector(request,env,subPath)}catch(error){let detail=formatProxyError(error);return console.error(`[interfere] Proxy ${request.method} ${subPath} failed: ${detail.lines.join(` | `)}`),Response.json({code:`INTERFERE_PROXY_ERROR`,message:detail.message},{status:502})}}async function handlePost(request){if(!isEnabledOnServer())return DISABLED_RESPONSE();let env=resolveAuthenticatedEnv(),subPath=extractSubPath(request);try{return await forwardToCollector(request,env,subPath)}catch(error){let detail=formatProxyError(error);return console.error(`[interfere] Proxy ${request.method} ${subPath} failed: ${detail.lines.join(` | `)}`),Response.json({code:`INTERFERE_PROXY_ERROR`,message:detail.message},{status:502})}}export{handle};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"handle.mjs","names":[],"sources":["../../../src/internal/route/handle.ts"],"sourcesContent":["import { SW_SCRIPT } from \"@interfere/react/sw\";\n\nimport { isEnabledOnServer } from \"../server/env.js\";\nimport {\n extractSubPath,\n formatProxyError,\n forwardToCollector,\n resolveAuthenticatedEnv,\n} from \"./proxy.js\";\n\nconst SW_HEADERS: Record<string, string> = {\n \"content-type\": \"application/javascript; charset=utf-8\",\n \"service-worker-allowed\": \"/\",\n \"cache-control\": \"public, max-age=3600\",\n};\n\nconst CORS_HEADERS = {\n \"Access-Control-Allow-Origin\": \"*\",\n \"Access-Control-Allow-Methods\": \"GET, POST, OPTIONS\",\n \"Access-Control-Allow-Headers\": \"Content-Type\",\n \"Access-Control-Max-Age\": \"86400\",\n};\n\nconst DISABLED_RESPONSE = () => new Response(null, { status: 204 });\n\n/**\n * Web-Standards `Request → Response` handler that customers wire\n * into their server framework's catch-all API route. Same proxy\n * behavior as `@interfere/next/route-handler` but built for\n * TanStack Start / Nitro's Web-Standards request handlers.\n *\n * Routes by HTTP method:\n * - `GET /sw` — serves the SDK service worker so customers get\n * offline-durable telemetry without shipping a SW from their\n * own domain.\n * - `GET /*` — proxies to the collector (config fetch).\n * - `POST /*` — proxies to the collector (OTLP ingest, replay,\n * session sync).\n * - `OPTIONS /*` — CORS preflight.\n * - everything else — 405.\n */\nexport async function handle(request: Request): Promise<Response> {\n const method = request.method;\n\n if (method === \"OPTIONS\") {\n return new Response(null, { status: 200, headers: CORS_HEADERS });\n }\n\n if (method === \"GET\") {\n return await handleGet(request);\n }\n\n if (method === \"POST\") {\n return await handlePost(request);\n }\n\n return new Response(null, { status: 405 });\n}\n\nasync function handleGet(request: Request): Promise<Response> {\n const subPath = extractSubPath(request);\n\n if (subPath === \"/sw\") {\n return new Response(SW_SCRIPT, { status: 200, headers: SW_HEADERS });\n }\n\n if (!isEnabledOnServer()) {\n return DISABLED_RESPONSE();\n }\n\n const env = resolveAuthenticatedEnv();\n try {\n return await forwardToCollector(request, env, subPath);\n } catch (error) {\n const detail = formatProxyError(error);\n console.error(\n `[interfere] Proxy ${request.method} ${subPath} failed: ${detail.lines.join(\" | \")}`\n );\n return Response.json(\n { code: \"INTERFERE_PROXY_ERROR\", message: detail.message },\n { status: 502 }\n );\n }\n}\n\nasync function handlePost(request: Request): Promise<Response> {\n if (!isEnabledOnServer()) {\n return DISABLED_RESPONSE();\n }\n\n const env = resolveAuthenticatedEnv();\n const subPath = extractSubPath(request);\n try {\n return await forwardToCollector(request, env, subPath);\n } catch (error) {\n const detail = formatProxyError(error);\n console.error(\n `[interfere] Proxy ${request.method} ${subPath} failed: ${detail.lines.join(\" | \")}`\n );\n return Response.json(\n { code: \"INTERFERE_PROXY_ERROR\", message: detail.message },\n { status: 502 }\n );\n }\n}\n"],"mappings":"gMAUA,MAAM,WAAqC,CACzC,eAAgB,wCAChB,yBAA0B,IAC1B,gBAAiB,sBACnB,EAEM,aAAe,CACnB,8BAA+B,IAC/B,+BAAgC,qBAChC,+BAAgC,eAChC,yBAA0B,OAC5B,EAEM,sBAA0B,IAAI,SAAS,KAAM,CAAE,OAAQ,GAAI,CAAC,EAkBlE,eAAsB,OAAO,QAAqC,CAChE,IAAM,OAAS,QAAQ,OAcvB,OAZI,SAAW,UACN,IAAI,SAAS,KAAM,CAAE,OAAQ,IAAK,QAAS,YAAa,CAAC,EAG9D,SAAW,MACN,MAAM,UAAU,OAAO,EAG5B,SAAW,OACN,MAAM,WAAW,OAAO,EAG1B,IAAI,SAAS,KAAM,CAAE,OAAQ,GAAI,CAAC,CAC3C,CAEA,eAAe,UAAU,QAAqC,CAC5D,IAAM,QAAU,eAAe,OAAO,EAEtC,GAAI,UAAY,MACd,OAAO,IAAI,SAAS,UAAW,CAAE,OAAQ,IAAK,QAAS,UAAW,CAAC,EAGrE,GAAI,CAAC,kBAAkB,EACrB,OAAO,kBAAkB,EAG3B,IAAM,IAAM,wBAAwB,EACpC,GAAI,CACF,OAAO,MAAM,mBAAmB,QAAS,IAAK,OAAO,CACvD,OAAS,MAAO,CACd,IAAM,OAAS,iBAAiB,KAAK,EAIrC,OAHA,QAAQ,MACN,qBAAqB,QAAQ,OAAO,GAAG,QAAQ,WAAW,OAAO,MAAM,KAAK,KAAK,GACnF,EACO,SAAS,KACd,CAAE,KAAM,wBAAyB,QAAS,OAAO,OAAQ,EACzD,CAAE,OAAQ,GAAI,CAChB,CACF,CACF,CAEA,eAAe,WAAW,QAAqC,CAC7D,GAAI,CAAC,kBAAkB,EACrB,OAAO,kBAAkB,EAG3B,IAAM,IAAM,wBAAwB,EAC9B,QAAU,eAAe,OAAO,EACtC,GAAI,CACF,OAAO,MAAM,mBAAmB,QAAS,IAAK,OAAO,CACvD,OAAS,MAAO,CACd,IAAM,OAAS,iBAAiB,KAAK,EAIrC,OAHA,QAAQ,MACN,qBAAqB,QAAQ,OAAO,GAAG,QAAQ,WAAW,OAAO,MAAM,KAAK,KAAK,GACnF,EACO,SAAS,KACd,CAAE,KAAM,wBAAyB,QAAS,OAAO,OAAQ,EACzD,CAAE,OAAQ,GAAI,CAChB,CACF,CACF"}
|