@interfere/cli 0.0.1 → 0.0.2-canary.1

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 CHANGED
@@ -1,21 +1,100 @@
1
1
  # @interfere/cli
2
2
 
3
- > **Status: canary.** Pre-1.0 surface, expect breaking changes. Pin to a specific `10.0.0-canary.N` in CI.
4
-
5
- Command-line tool for [Interfere](https://interfere.com) release workflows.
3
+ Command-line tool for [Interfere](https://interfere.com) release workflows. Uploads source maps and registers releases so the collector accepts spans from your deployments.
6
4
 
7
5
  ## Install
8
6
 
9
7
  ```sh
8
+ npm install -D @interfere/cli
9
+ # or
10
10
  bun add -d @interfere/cli
11
+ # or
12
+ pnpm add -D @interfere/cli
11
13
  ```
12
14
 
13
15
  ## Usage
14
16
 
15
- After your build step, upload source maps:
17
+ Run after your build step to upload source maps and preflight the release:
16
18
 
17
19
  ```sh
18
- INTERFERE_API_KEY=ak_… bunx interfere sourcemaps upload ./dist
20
+ interfere sourcemaps upload ./dist
21
+ ```
22
+
23
+ Typically added as a `postbuild` script in `package.json`:
24
+
25
+ ```json
26
+ {
27
+ "scripts": {
28
+ "build": "tsc",
29
+ "postbuild": "interfere sourcemaps upload ./dist"
30
+ }
31
+ }
32
+ ```
33
+
34
+ ### What it does
35
+
36
+ 1. Derives a release slug from the commit SHA (same algorithm the SDK uses at runtime)
37
+ 2. Registers the release with the collector (`POST /v1/releases/`)
38
+ 3. Discovers `.js.map` files in the target directory
39
+ 4. Uploads source maps via presigned URLs
40
+ 5. Marks the release as preflight-confirmed so the collector accepts spans for it
41
+
42
+ ### Options
43
+
44
+ ```text
45
+ interfere sourcemaps upload <dir> [options]
46
+
47
+ Options:
48
+ --release <slug> Override the release slug (default: derived from commit SHA)
49
+ --url <api-url> Interfere collector URL (default: $INTERFERE_API_URL)
50
+ --auth-token <key> Interfere API key (default: $INTERFERE_API_KEY)
51
+ --skip-preflight Don't mark the release preflight-confirmed after upload
52
+ -h, --help Show help
53
+ --version Show version
19
54
  ```
20
55
 
21
- Slug is auto-derived from the commit SHA (same algorithm the SDK uses at runtime). Full docs at <https://interfere.com/docs>.
56
+ ## Environment Variables
57
+
58
+ | Variable | Required | Purpose |
59
+ |---|---|---|
60
+ | `INTERFERE_API_KEY` | Yes | Authenticates with the collector. Format: `interfere_ak_*` |
61
+ | `INTERFERE_SOURCE_ID` | No | Override the commit SHA used to derive the release slug. Falls back to `VERCEL_GIT_COMMIT_SHA`, `GITHUB_SHA`, or `git rev-parse HEAD`. |
62
+ | `INTERFERE_API_URL` | No | Override the default collector URL |
63
+
64
+ ## How release identity works
65
+
66
+ The CLI and the SDK independently derive the same release slug from the commit SHA using a shared `deriveReleaseSlug()` function. For this to work, both must see the same SHA:
67
+
68
+ - **At build time (CLI):** reads from `INTERFERE_SOURCE_ID`, `GITHUB_SHA`, `VERCEL_GIT_COMMIT_SHA`, or `git rev-parse HEAD`
69
+ - **At runtime (SDK):** reads from the same env vars or git
70
+
71
+ In Docker deployments where `.git` isn't in the image, set `INTERFERE_SOURCE_ID` in the runtime environment to the same commit SHA used during the build.
72
+
73
+ ## Examples
74
+
75
+ ### GitHub Actions
76
+
77
+ ```yaml
78
+ - name: Build
79
+ run: npm run build
80
+
81
+ - name: Upload source maps
82
+ run: npx interfere sourcemaps upload ./dist
83
+ env:
84
+ INTERFERE_API_KEY: ${{ secrets.INTERFERE_API_KEY }}
85
+ # GITHUB_SHA is automatically available
86
+ ```
87
+
88
+ ### Docker
89
+
90
+ ```dockerfile
91
+ ARG GIT_SHA
92
+ ENV INTERFERE_SOURCE_ID=$GIT_SHA
93
+
94
+ COPY dist/ ./dist/
95
+ CMD ["node", "dist/main.js"]
96
+ ```
97
+
98
+ ```sh
99
+ docker build --build-arg GIT_SHA=$(git rev-parse HEAD) .
100
+ ```
package/dist/index.mjs CHANGED
@@ -10,13 +10,13 @@ Usage:
10
10
  Options:
11
11
  --release <slug> Release slug (default: derived from commit SHA)
12
12
  --url <api-url> Interfere collector URL (default: $INTERFERE_API_URL or ${API_URL})
13
- --auth-token <key> API key (default: $INTERFERE_API_KEY)
14
- --skip-preflight Don't mark the release preflight-confirmed after upload
13
+ --auth-token <key> Interfere API key (default: $INTERFERE_API_KEY)
14
+ --skip-preflight Don't mark the release preflight-confirmed after publishing metadata
15
15
  -h, --help Show this help
16
16
  --version Show version
17
17
 
18
18
  Environment:
19
- INTERFERE_API_KEY Authentication
19
+ INTERFERE_API_KEY Interfere API key in the interfere_ak_* format
20
20
  INTERFERE_API_URL Override the default collector URL
21
21
  INTERFERE_SOURCE_ID Override the commit SHA used to derive the slug.
22
22
  Falls back to VERCEL_GIT_COMMIT_SHA, GITHUB_SHA,
@@ -1 +1 @@
1
- {"version":3,"file":"index.mjs","names":[],"sources":["../src/index.ts"],"sourcesContent":["#!/usr/bin/env node\nimport { API_URL } from \"@interfere/constants/api\";\n\nimport { resolve } from \"node:path\";\n\nimport { discoverSourceMaps } from \"./discover.js\";\nimport { VERSION } from \"./internal/version.js\";\nimport { confirmPreflight } from \"./preflight.js\";\nimport { ensureRelease } from \"./release.js\";\nimport { resolveReleaseSlug } from \"./release-slug.js\";\nimport { uploadSourceMaps } from \"./upload.js\";\n\nconst HELP = `\ninterfere ${VERSION}\n\nUsage:\n interfere sourcemaps upload <dir> [options]\n interfere --help\n interfere --version\n\nOptions:\n --release <slug> Release slug (default: derived from commit SHA)\n --url <api-url> Interfere collector URL (default: $INTERFERE_API_URL or ${API_URL})\n --auth-token <key> API key (default: $INTERFERE_API_KEY)\n --skip-preflight Don't mark the release preflight-confirmed after upload\n -h, --help Show this help\n --version Show version\n\nEnvironment:\n INTERFERE_API_KEY Authentication\n INTERFERE_API_URL Override the default collector URL\n INTERFERE_SOURCE_ID Override the commit SHA used to derive the slug.\n Falls back to VERCEL_GIT_COMMIT_SHA, GITHUB_SHA,\n or \\`git rev-parse HEAD\\`.\n`;\n\ninterface Flags {\n authToken: string | null;\n positional: string[];\n release: string | null;\n skipPreflight: boolean;\n url: string | null;\n}\n\nfunction parseFlags(argv: readonly string[]): Flags {\n if (argv.includes(\"--help\") || argv.includes(\"-h\")) {\n process.stdout.write(`${HELP.trim()}\\n`);\n process.exit(0);\n }\n if (argv.includes(\"--version\")) {\n process.stdout.write(`${VERSION}\\n`);\n process.exit(0);\n }\n const flags: Flags = {\n release: null,\n url: null,\n authToken: null,\n skipPreflight: false,\n positional: [],\n };\n let i = 0;\n while (i < argv.length) {\n const arg = argv[i++];\n switch (arg) {\n case \"--release\":\n flags.release = argv[i++] ?? null;\n break;\n case \"--url\":\n flags.url = argv[i++] ?? null;\n break;\n case \"--auth-token\":\n flags.authToken = argv[i++] ?? null;\n break;\n case \"--skip-preflight\":\n flags.skipPreflight = true;\n break;\n default:\n if (arg !== undefined) {\n flags.positional.push(arg);\n }\n }\n }\n return flags;\n}\n\nasync function sourcemapsUpload(dir: string, flags: Flags): Promise<void> {\n const apiKey = flags.authToken ?? process.env[\"INTERFERE_API_KEY\"];\n if (!apiKey) {\n die(\"Missing API key. Set INTERFERE_API_KEY or pass --auth-token.\");\n }\n const apiUrl = flags.url ?? process.env[\"INTERFERE_API_URL\"] ?? API_URL;\n\n let releaseSlug = flags.release;\n let commitSha: string | null = null;\n if (releaseSlug) {\n commitSha = resolveReleaseSlug().commitSha;\n } else {\n const resolved = resolveReleaseSlug();\n if (!resolved.slug) {\n die(\n \"Could not derive a release slug. Set INTERFERE_SOURCE_ID (or run inside a git repo with at least one commit), or pass --release.\"\n );\n }\n releaseSlug = resolved.slug;\n commitSha = resolved.commitSha;\n console.log(\n `Derived release ${releaseSlug} from commit ${resolved.commitSha}`\n );\n }\n\n // Upsert the release row before signing. Deployment-webhook integrations\n // (Vercel, GitHub Actions) create it for us in their flow, but customers\n // deploying to bare-metal / Fly / Render / AWS / etc have no webhook, so\n // without this the CLI's first `sign` call would 500 on an unknown slug.\n if (commitSha) {\n await ensureRelease({ apiKey, apiUrl, commitSha, releaseSlug });\n }\n\n const absDir = resolve(dir);\n const maps = await discoverSourceMaps(absDir);\n if (maps.length === 0) {\n console.log(`No .js.map files found under ${absDir}`);\n if (!flags.skipPreflight) {\n await confirmPreflight({ apiKey, apiUrl, releaseSlug });\n console.log(`Release ${releaseSlug} preflight-confirmed (no maps).`);\n }\n return;\n }\n\n console.log(`Uploading ${maps.length} source map(s) to ${releaseSlug}…`);\n const summary = await uploadSourceMaps({ apiKey, apiUrl, maps, releaseSlug });\n console.log(\n `Uploaded ${summary.fileCount} file(s), ${formatBytes(summary.totalBytes)} total.`\n );\n\n if (!flags.skipPreflight) {\n await confirmPreflight({ apiKey, apiUrl, releaseSlug });\n console.log(`Release ${releaseSlug} preflight-confirmed.`);\n }\n}\n\nfunction formatBytes(n: number): string {\n if (n < 1024) {\n return `${n} B`;\n }\n if (n < 1024 * 1024) {\n return `${(n / 1024).toFixed(1)} KB`;\n }\n return `${(n / (1024 * 1024)).toFixed(1)} MB`;\n}\n\nfunction die(message: string): never {\n process.stderr.write(`interfere: ${message}\\n`);\n process.exit(1);\n}\n\nasync function main(): Promise<void> {\n const argv = process.argv.slice(2);\n if (argv.length === 0) {\n process.stdout.write(`${HELP.trim()}\\n`);\n process.exit(0);\n }\n const flags = parseFlags(argv);\n const [command, sub, ...rest] = flags.positional;\n\n if (command === \"sourcemaps\" && sub === \"upload\") {\n const dir = rest[0];\n if (!dir) {\n die(\"Missing <dir>. Usage: interfere sourcemaps upload <dir>\");\n }\n await sourcemapsUpload(dir, flags);\n return;\n }\n\n die(\n `Unknown command: ${flags.positional.join(\" \") || \"(none)\"}. Try --help.`\n );\n}\n\nawait main();\n"],"mappings":"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"}
1
+ {"version":3,"file":"index.mjs","names":[],"sources":["../src/index.ts"],"sourcesContent":["#!/usr/bin/env node\nimport { API_URL } from \"@interfere/constants/api\";\n\nimport { resolve } from \"node:path\";\n\nimport { discoverSourceMaps } from \"./discover.js\";\nimport { VERSION } from \"./internal/version.js\";\nimport { confirmPreflight } from \"./preflight.js\";\nimport { ensureRelease } from \"./release.js\";\nimport { resolveReleaseSlug } from \"./release-slug.js\";\nimport { uploadSourceMaps } from \"./upload.js\";\n\nconst HELP = `\ninterfere ${VERSION}\n\nUsage:\n interfere sourcemaps upload <dir> [options]\n interfere --help\n interfere --version\n\nOptions:\n --release <slug> Release slug (default: derived from commit SHA)\n --url <api-url> Interfere collector URL (default: $INTERFERE_API_URL or ${API_URL})\n --auth-token <key> Interfere API key (default: $INTERFERE_API_KEY)\n --skip-preflight Don't mark the release preflight-confirmed after publishing metadata\n -h, --help Show this help\n --version Show version\n\nEnvironment:\n INTERFERE_API_KEY Interfere API key in the interfere_ak_* format\n INTERFERE_API_URL Override the default collector URL\n INTERFERE_SOURCE_ID Override the commit SHA used to derive the slug.\n Falls back to VERCEL_GIT_COMMIT_SHA, GITHUB_SHA,\n or \\`git rev-parse HEAD\\`.\n`;\n\ninterface Flags {\n authToken: string | null;\n positional: string[];\n release: string | null;\n skipPreflight: boolean;\n url: string | null;\n}\n\nfunction parseFlags(argv: readonly string[]): Flags {\n if (argv.includes(\"--help\") || argv.includes(\"-h\")) {\n process.stdout.write(`${HELP.trim()}\\n`);\n process.exit(0);\n }\n if (argv.includes(\"--version\")) {\n process.stdout.write(`${VERSION}\\n`);\n process.exit(0);\n }\n const flags: Flags = {\n release: null,\n url: null,\n authToken: null,\n skipPreflight: false,\n positional: [],\n };\n let i = 0;\n while (i < argv.length) {\n const arg = argv[i++];\n switch (arg) {\n case \"--release\":\n flags.release = argv[i++] ?? null;\n break;\n case \"--url\":\n flags.url = argv[i++] ?? null;\n break;\n case \"--auth-token\":\n flags.authToken = argv[i++] ?? null;\n break;\n case \"--skip-preflight\":\n flags.skipPreflight = true;\n break;\n default:\n if (arg !== undefined) {\n flags.positional.push(arg);\n }\n }\n }\n return flags;\n}\n\nasync function sourcemapsUpload(dir: string, flags: Flags): Promise<void> {\n const apiKey = flags.authToken ?? process.env[\"INTERFERE_API_KEY\"];\n if (!apiKey) {\n die(\"Missing API key. Set INTERFERE_API_KEY or pass --auth-token.\");\n }\n const apiUrl = flags.url ?? process.env[\"INTERFERE_API_URL\"] ?? API_URL;\n\n let releaseSlug = flags.release;\n let commitSha: string | null = null;\n if (releaseSlug) {\n commitSha = resolveReleaseSlug().commitSha;\n } else {\n const resolved = resolveReleaseSlug();\n if (!resolved.slug) {\n die(\n \"Could not derive a release slug. Set INTERFERE_SOURCE_ID (or run inside a git repo with at least one commit), or pass --release.\"\n );\n }\n releaseSlug = resolved.slug;\n commitSha = resolved.commitSha;\n console.log(\n `Derived release ${releaseSlug} from commit ${resolved.commitSha}`\n );\n }\n\n // Upsert the release row before signing. Deployment-webhook integrations\n // (Vercel, GitHub Actions) create it for us in their flow, but customers\n // deploying to bare-metal / Fly / Render / AWS / etc have no webhook, so\n // without this the CLI's first `sign` call would 500 on an unknown slug.\n if (commitSha) {\n await ensureRelease({ apiKey, apiUrl, commitSha, releaseSlug });\n }\n\n const absDir = resolve(dir);\n const maps = await discoverSourceMaps(absDir);\n if (maps.length === 0) {\n console.log(`No .js.map files found under ${absDir}`);\n if (!flags.skipPreflight) {\n await confirmPreflight({ apiKey, apiUrl, releaseSlug });\n console.log(`Release ${releaseSlug} preflight-confirmed (no maps).`);\n }\n return;\n }\n\n console.log(`Uploading ${maps.length} source map(s) to ${releaseSlug}…`);\n const summary = await uploadSourceMaps({ apiKey, apiUrl, maps, releaseSlug });\n console.log(\n `Uploaded ${summary.fileCount} file(s), ${formatBytes(summary.totalBytes)} total.`\n );\n\n if (!flags.skipPreflight) {\n await confirmPreflight({ apiKey, apiUrl, releaseSlug });\n console.log(`Release ${releaseSlug} preflight-confirmed.`);\n }\n}\n\nfunction formatBytes(n: number): string {\n if (n < 1024) {\n return `${n} B`;\n }\n if (n < 1024 * 1024) {\n return `${(n / 1024).toFixed(1)} KB`;\n }\n return `${(n / (1024 * 1024)).toFixed(1)} MB`;\n}\n\nfunction die(message: string): never {\n process.stderr.write(`interfere: ${message}\\n`);\n process.exit(1);\n}\n\nasync function main(): Promise<void> {\n const argv = process.argv.slice(2);\n if (argv.length === 0) {\n process.stdout.write(`${HELP.trim()}\\n`);\n process.exit(0);\n }\n const flags = parseFlags(argv);\n const [command, sub, ...rest] = flags.positional;\n\n if (command === \"sourcemaps\" && sub === \"upload\") {\n const dir = rest[0];\n if (!dir) {\n die(\"Missing <dir>. Usage: interfere sourcemaps upload <dir>\");\n }\n await sourcemapsUpload(dir, flags);\n return;\n }\n\n die(\n `Unknown command: ${flags.positional.join(\" \") || \"(none)\"}. Try --help.`\n );\n}\n\nawait main();\n"],"mappings":"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"}
package/dist/package.mjs CHANGED
@@ -1 +1 @@
1
- var name=`@interfere/cli`,version=`0.0.1`;export{name,version};
1
+ var name=`@interfere/cli`,version=`0.0.2-canary.1`;export{name,version};
@@ -1 +1 @@
1
- import{PRODUCER_VERSION}from"./internal/version.mjs";async function confirmPreflight({apiKey,apiUrl,releaseSlug}){let url=`${apiUrl}/v1/releases/${encodeURIComponent(releaseSlug)}/preflight`,response=await fetch(url,{method:`POST`,headers:{"content-type":`application/json`,"user-agent":PRODUCER_VERSION,"x-api-key":apiKey}});if(!response.ok){let detail=await response.text().catch(()=>``);throw Error(`POST ${url} → ${response.status} ${detail}`)}}export{confirmPreflight};
1
+ import{PRODUCER_VERSION}from"./internal/version.mjs";async function confirmPreflight({apiKey,apiUrl,releaseSlug}){let url=`${apiUrl}/v1/releases/${encodeURIComponent(releaseSlug)}/preflight`,response=await fetch(url,{method:`POST`,headers:{"content-type":`application/json`,"user-agent":PRODUCER_VERSION,Authorization:`Bearer ${apiKey}`}});if(!response.ok){let detail=await response.text().catch(()=>``);throw Error(`POST ${url} → ${response.status} ${detail}`)}}export{confirmPreflight};
@@ -1 +1 @@
1
- {"version":3,"file":"preflight.mjs","names":[],"sources":["../src/preflight.ts"],"sourcesContent":["import { PRODUCER_VERSION } from \"./internal/version.js\";\n\ninterface PreflightParams {\n readonly apiKey: string;\n readonly apiUrl: string;\n readonly releaseSlug: string;\n}\n\n/**\n * Marks the release as preflight-confirmed at the collector. After this\n * returns, OTLP traces and exception events for `releaseSlug` pass the\n * release-gate; before, they're rejected with `COLLECTOR_RELEASE_PREFLIGHT_UNCONFIRMED`.\n */\nexport async function confirmPreflight({\n apiKey,\n apiUrl,\n releaseSlug,\n}: PreflightParams): Promise<void> {\n const url = `${apiUrl}/v1/releases/${encodeURIComponent(releaseSlug)}/preflight`;\n const response = await fetch(url, {\n method: \"POST\",\n headers: {\n \"content-type\": \"application/json\",\n \"user-agent\": PRODUCER_VERSION,\n \"x-api-key\": apiKey,\n },\n });\n if (!response.ok) {\n const detail = await response.text().catch(() => \"\");\n throw new Error(`POST ${url} → ${response.status} ${detail}`);\n }\n}\n"],"mappings":"qDAaA,eAAsB,iBAAiB,CACrC,OACA,OACA,aACiC,CACjC,IAAM,IAAM,GAAG,OAAO,eAAe,mBAAmB,WAAW,EAAE,YAC/D,SAAW,MAAM,MAAM,IAAK,CAChC,OAAQ,OACR,QAAS,CACP,eAAgB,mBAChB,aAAc,iBACd,YAAa,MACf,CACF,CAAC,EACD,GAAI,CAAC,SAAS,GAAI,CAChB,IAAM,OAAS,MAAM,SAAS,KAAK,EAAE,UAAY,EAAE,EACnD,MAAU,MAAM,QAAQ,IAAI,KAAK,SAAS,OAAO,GAAG,QAAQ,CAC9D,CACF"}
1
+ {"version":3,"file":"preflight.mjs","names":[],"sources":["../src/preflight.ts"],"sourcesContent":["import { PRODUCER_VERSION } from \"./internal/version.js\";\n\ninterface PreflightParams {\n readonly apiKey: string;\n readonly apiUrl: string;\n readonly releaseSlug: string;\n}\n\n/**\n * Marks the release as preflight-confirmed at the collector. After this\n * returns, OTLP traces and exception events for `releaseSlug` pass the\n * release-gate; before, they're rejected with `COLLECTOR_RELEASE_PREFLIGHT_UNCONFIRMED`.\n */\nexport async function confirmPreflight({\n apiKey,\n apiUrl,\n releaseSlug,\n}: PreflightParams): Promise<void> {\n const url = `${apiUrl}/v1/releases/${encodeURIComponent(releaseSlug)}/preflight`;\n const response = await fetch(url, {\n method: \"POST\",\n headers: {\n \"content-type\": \"application/json\",\n \"user-agent\": PRODUCER_VERSION,\n Authorization: `Bearer ${apiKey}`,\n },\n });\n if (!response.ok) {\n const detail = await response.text().catch(() => \"\");\n throw new Error(`POST ${url} → ${response.status} ${detail}`);\n }\n}\n"],"mappings":"qDAaA,eAAsB,iBAAiB,CACrC,OACA,OACA,aACiC,CACjC,IAAM,IAAM,GAAG,OAAO,eAAe,mBAAmB,WAAW,EAAE,YAC/D,SAAW,MAAM,MAAM,IAAK,CAChC,OAAQ,OACR,QAAS,CACP,eAAgB,mBAChB,aAAc,iBACd,cAAe,UAAU,QAC3B,CACF,CAAC,EACD,GAAI,CAAC,SAAS,GAAI,CAChB,IAAM,OAAS,MAAM,SAAS,KAAK,EAAE,UAAY,EAAE,EACnD,MAAU,MAAM,QAAQ,IAAI,KAAK,SAAS,OAAO,GAAG,QAAQ,CAC9D,CACF"}
@@ -9,7 +9,7 @@ interface EnsureReleaseParams {
9
9
  * Idempotently create the release row at the collector. `POST /v1/releases`
10
10
  * is upsert-shaped — if a row already exists for `(surface, slug)` it's
11
11
  * updated in place rather than duplicated, so this is safe to call before
12
- * every source-map upload regardless of whether a deployment webhook
12
+ * every release metadata publish regardless of whether a deployment webhook
13
13
  * (Vercel, GitHub Actions) beat us there.
14
14
  *
15
15
  * Required because the CLI's `sourcemaps upload` flow assumes the release
package/dist/release.mjs CHANGED
@@ -1 +1 @@
1
- import{PRODUCER_VERSION}from"./internal/version.mjs";import{execSync}from"node:child_process";async function ensureRelease({apiKey,apiUrl,commitSha,releaseSlug}){let body={source:{provider:`github`,commitSha,commitMessage:gitCommitMessage()??``,branch:gitBranch()??``},destination:null,buildId:commitSha,slug:releaseSlug,producerVersion:PRODUCER_VERSION},url=`${apiUrl}/v1/releases/`,response=await fetch(url,{method:`POST`,headers:{"content-type":`application/json`,accept:`application/json`,"user-agent":PRODUCER_VERSION,"x-api-key":apiKey},body:JSON.stringify(body)});if(!response.ok){let detail=await response.text().catch(()=>``);throw Error(`POST ${url} → ${response.status} ${detail}`)}}function gitCommitMessage(){return runGit([`log`,`-1`,`--format=%s`])}function gitBranch(){return runGit([`rev-parse`,`--abbrev-ref`,`HEAD`])}function runGit(args){try{let out=execSync(`git ${args.join(` `)}`,{encoding:`utf8`,stdio:[`ignore`,`pipe`,`ignore`]}).trim();return out.length>0?out:null}catch{return null}}export{ensureRelease};
1
+ import{PRODUCER_VERSION}from"./internal/version.mjs";import{execSync}from"node:child_process";async function ensureRelease({apiKey,apiUrl,commitSha,releaseSlug}){let body={source:{provider:`github`,commitSha,commitMessage:gitCommitMessage()??``,branch:gitBranch()??``},destination:null,buildId:commitSha,slug:releaseSlug,producerVersion:PRODUCER_VERSION},url=`${apiUrl}/v1/releases/`,response=await fetch(url,{method:`POST`,headers:{"content-type":`application/json`,accept:`application/json`,"user-agent":PRODUCER_VERSION,Authorization:`Bearer ${apiKey}`},body:JSON.stringify(body)});if(!response.ok){let detail=await response.text().catch(()=>``);throw Error(`POST ${url} → ${response.status} ${detail}`)}}function gitCommitMessage(){return runGit([`log`,`-1`,`--format=%s`])}function gitBranch(){return runGit([`rev-parse`,`--abbrev-ref`,`HEAD`])}function runGit(args){try{let out=execSync(`git ${args.join(` `)}`,{encoding:`utf8`,stdio:[`ignore`,`pipe`,`ignore`]}).trim();return out.length>0?out:null}catch{return null}}export{ensureRelease};
@@ -1 +1 @@
1
- {"version":3,"file":"release.mjs","names":[],"sources":["../src/release.ts"],"sourcesContent":["import type { CreateReleaseRequest } from \"@interfere/types/releases/definition\";\n\nimport { execSync } from \"node:child_process\";\n\nimport { PRODUCER_VERSION } from \"./internal/version.js\";\n\ninterface EnsureReleaseParams {\n readonly apiKey: string;\n readonly apiUrl: string;\n readonly commitSha: string;\n readonly releaseSlug: string;\n}\n\n/**\n * Idempotently create the release row at the collector. `POST /v1/releases`\n * is upsert-shaped — if a row already exists for `(surface, slug)` it's\n * updated in place rather than duplicated, so this is safe to call before\n * every source-map upload regardless of whether a deployment webhook\n * (Vercel, GitHub Actions) beat us there.\n *\n * Required because the CLI's `sourcemaps upload` flow assumes the release\n * already exists when it calls `/source-maps/sign`; without this, customers\n * deploying outside an integration-provider webhook (bare-metal, Render,\n * Fly, AWS, etc) get a 500 on first upload.\n */\nexport async function ensureRelease({\n apiKey,\n apiUrl,\n commitSha,\n releaseSlug,\n}: EnsureReleaseParams): Promise<void> {\n const body: CreateReleaseRequest = {\n source: {\n provider: \"github\",\n commitSha,\n commitMessage: gitCommitMessage() ?? \"\",\n branch: gitBranch() ?? \"\",\n },\n destination: null,\n buildId: commitSha,\n slug: releaseSlug,\n producerVersion: PRODUCER_VERSION,\n };\n const url = `${apiUrl}/v1/releases/`;\n const response = await fetch(url, {\n method: \"POST\",\n headers: {\n \"content-type\": \"application/json\",\n accept: \"application/json\",\n \"user-agent\": PRODUCER_VERSION,\n \"x-api-key\": apiKey,\n },\n body: JSON.stringify(body),\n });\n if (!response.ok) {\n const detail = await response.text().catch(() => \"\");\n throw new Error(`POST ${url} → ${response.status} ${detail}`);\n }\n}\n\nfunction gitCommitMessage(): string | null {\n return runGit([\"log\", \"-1\", \"--format=%s\"]);\n}\n\nfunction gitBranch(): string | null {\n return runGit([\"rev-parse\", \"--abbrev-ref\", \"HEAD\"]);\n}\n\nfunction runGit(args: readonly string[]): string | null {\n try {\n const out = execSync(`git ${args.join(\" \")}`, {\n encoding: \"utf8\",\n stdio: [\"ignore\", \"pipe\", \"ignore\"],\n }).trim();\n return out.length > 0 ? out : null;\n } catch {\n return null;\n }\n}\n"],"mappings":"8FAyBA,eAAsB,cAAc,CAClC,OACA,OACA,UACA,aACqC,CACrC,IAAM,KAA6B,CACjC,OAAQ,CACN,SAAU,SACV,UACA,cAAe,iBAAiB,GAAK,GACrC,OAAQ,UAAU,GAAK,EACzB,EACA,YAAa,KACb,QAAS,UACT,KAAM,YACN,gBAAiB,gBACnB,EACM,IAAM,GAAG,OAAO,eAChB,SAAW,MAAM,MAAM,IAAK,CAChC,OAAQ,OACR,QAAS,CACP,eAAgB,mBAChB,OAAQ,mBACR,aAAc,iBACd,YAAa,MACf,EACA,KAAM,KAAK,UAAU,IAAI,CAC3B,CAAC,EACD,GAAI,CAAC,SAAS,GAAI,CAChB,IAAM,OAAS,MAAM,SAAS,KAAK,EAAE,UAAY,EAAE,EACnD,MAAU,MAAM,QAAQ,IAAI,KAAK,SAAS,OAAO,GAAG,QAAQ,CAC9D,CACF,CAEA,SAAS,kBAAkC,CACzC,OAAO,OAAO,CAAC,MAAO,KAAM,aAAa,CAAC,CAC5C,CAEA,SAAS,WAA2B,CAClC,OAAO,OAAO,CAAC,YAAa,eAAgB,MAAM,CAAC,CACrD,CAEA,SAAS,OAAO,KAAwC,CACtD,GAAI,CACF,IAAM,IAAM,SAAS,OAAO,KAAK,KAAK,GAAG,IAAK,CAC5C,SAAU,OACV,MAAO,CAAC,SAAU,OAAQ,QAAQ,CACpC,CAAC,EAAE,KAAK,EACR,OAAO,IAAI,OAAS,EAAI,IAAM,IAChC,MAAQ,CACN,OAAO,IACT,CACF"}
1
+ {"version":3,"file":"release.mjs","names":[],"sources":["../src/release.ts"],"sourcesContent":["import type { CreateReleaseRequest } from \"@interfere/types/releases/definition\";\n\nimport { execSync } from \"node:child_process\";\n\nimport { PRODUCER_VERSION } from \"./internal/version.js\";\n\ninterface EnsureReleaseParams {\n readonly apiKey: string;\n readonly apiUrl: string;\n readonly commitSha: string;\n readonly releaseSlug: string;\n}\n\n/**\n * Idempotently create the release row at the collector. `POST /v1/releases`\n * is upsert-shaped — if a row already exists for `(surface, slug)` it's\n * updated in place rather than duplicated, so this is safe to call before\n * every release metadata publish regardless of whether a deployment webhook\n * (Vercel, GitHub Actions) beat us there.\n *\n * Required because the CLI's `sourcemaps upload` flow assumes the release\n * already exists when it calls `/source-maps/sign`; without this, customers\n * deploying outside an integration-provider webhook (bare-metal, Render,\n * Fly, AWS, etc) get a 500 on first upload.\n */\nexport async function ensureRelease({\n apiKey,\n apiUrl,\n commitSha,\n releaseSlug,\n}: EnsureReleaseParams): Promise<void> {\n const body: CreateReleaseRequest = {\n source: {\n provider: \"github\",\n commitSha,\n commitMessage: gitCommitMessage() ?? \"\",\n branch: gitBranch() ?? \"\",\n },\n destination: null,\n buildId: commitSha,\n slug: releaseSlug,\n producerVersion: PRODUCER_VERSION,\n };\n const url = `${apiUrl}/v1/releases/`;\n const response = await fetch(url, {\n method: \"POST\",\n headers: {\n \"content-type\": \"application/json\",\n accept: \"application/json\",\n \"user-agent\": PRODUCER_VERSION,\n Authorization: `Bearer ${apiKey}`,\n },\n body: JSON.stringify(body),\n });\n if (!response.ok) {\n const detail = await response.text().catch(() => \"\");\n throw new Error(`POST ${url} → ${response.status} ${detail}`);\n }\n}\n\nfunction gitCommitMessage(): string | null {\n return runGit([\"log\", \"-1\", \"--format=%s\"]);\n}\n\nfunction gitBranch(): string | null {\n return runGit([\"rev-parse\", \"--abbrev-ref\", \"HEAD\"]);\n}\n\nfunction runGit(args: readonly string[]): string | null {\n try {\n const out = execSync(`git ${args.join(\" \")}`, {\n encoding: \"utf8\",\n stdio: [\"ignore\", \"pipe\", \"ignore\"],\n }).trim();\n return out.length > 0 ? out : null;\n } catch {\n return null;\n }\n}\n"],"mappings":"8FAyBA,eAAsB,cAAc,CAClC,OACA,OACA,UACA,aACqC,CACrC,IAAM,KAA6B,CACjC,OAAQ,CACN,SAAU,SACV,UACA,cAAe,iBAAiB,GAAK,GACrC,OAAQ,UAAU,GAAK,EACzB,EACA,YAAa,KACb,QAAS,UACT,KAAM,YACN,gBAAiB,gBACnB,EACM,IAAM,GAAG,OAAO,eAChB,SAAW,MAAM,MAAM,IAAK,CAChC,OAAQ,OACR,QAAS,CACP,eAAgB,mBAChB,OAAQ,mBACR,aAAc,iBACd,cAAe,UAAU,QAC3B,EACA,KAAM,KAAK,UAAU,IAAI,CAC3B,CAAC,EACD,GAAI,CAAC,SAAS,GAAI,CAChB,IAAM,OAAS,MAAM,SAAS,KAAK,EAAE,UAAY,EAAE,EACnD,MAAU,MAAM,QAAQ,IAAI,KAAK,SAAS,OAAO,GAAG,QAAQ,CAC9D,CACF,CAEA,SAAS,kBAAkC,CACzC,OAAO,OAAO,CAAC,MAAO,KAAM,aAAa,CAAC,CAC5C,CAEA,SAAS,WAA2B,CAClC,OAAO,OAAO,CAAC,YAAa,eAAgB,MAAM,CAAC,CACrD,CAEA,SAAS,OAAO,KAAwC,CACtD,GAAI,CACF,IAAM,IAAM,SAAS,OAAO,KAAK,KAAK,GAAG,IAAK,CAC5C,SAAU,OACV,MAAO,CAAC,SAAU,OAAQ,QAAQ,CACpC,CAAC,EAAE,KAAK,EACR,OAAO,IAAI,OAAS,EAAI,IAAM,IAChC,MAAQ,CACN,OAAO,IACT,CACF"}
package/dist/upload.mjs CHANGED
@@ -1 +1 @@
1
- import{PRODUCER_VERSION}from"./internal/version.mjs";import{createHash,randomUUID}from"node:crypto";const MAP_SUFFIX_RE=/\.map$/;function prepareEntries(maps){return maps.map(map=>{let debugId=randomUUID(),content=injectDebugId(map.content,debugId);return{relPath:map.relPath,chunkUrl:map.relPath.replace(MAP_SUFFIX_RE,``),debugId,content,contentBytes:Buffer.byteLength(content,`utf8`),hash:createHash(`sha256`).update(content).digest(`hex`)}})}function injectDebugId(rawMap,debugId){let parsed=JSON.parse(rawMap);return JSON.stringify({...parsed,debugId})}async function uploadSourceMaps({apiKey,apiUrl,maps,releaseSlug}){let entries=prepareEntries(maps),slug=encodeURIComponent(releaseSlug),signReq={files:entries.map(entry=>({path:entry.relPath,sizeBytes:entry.contentBytes,...richness(entry.content)}))},signRes=await postJson({apiKey,url:`${apiUrl}/v1/releases/${slug}/source-maps/sign`,body:signReq}),byPath=new Map(entries.map(entry=>[entry.relPath,entry])),totalBytes=0;await mapWithConcurrency(signRes.uploads,8,async upload=>{let entry=byPath.get(upload.path);if(!entry)throw Error(`Sign response referenced unknown path "${upload.path}"`);totalBytes+=entry.contentBytes,await putToR2(upload.presignedUrl,entry.content)});let completeReq={files:entries.map(entry=>({path:entry.relPath,hash:entry.hash,debugId:entry.debugId,chunkUrl:entry.chunkUrl})),sourceFileCount:entries.length,bundler:`tsc`};return{fileCount:(await postJson({apiKey,url:`${apiUrl}/v1/releases/${slug}/source-maps/complete`,body:completeReq})).fileCount,totalBytes}}function richness(content){let parsed=JSON.parse(content);return{hasSourcesContent:Array.isArray(parsed.sourcesContent)&&parsed.sourcesContent.length>0,hasNames:Array.isArray(parsed.names)&&parsed.names.length>0,hasFile:typeof parsed.file==`string`&&parsed.file.length>0,mappingsPresent:typeof parsed.mappings==`string`&&parsed.mappings.length>0}}async function postJson({apiKey,url,body}){let response=await fetch(url,{method:`POST`,headers:{"content-type":`application/json`,accept:`application/json`,"user-agent":PRODUCER_VERSION,"x-api-key":apiKey},body:JSON.stringify(body)});if(!response.ok){let detail=await response.text().catch(()=>``);throw Error(`POST ${url} → ${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(`PUT R2 → ${response.status} ${detail}`)}}async function mapWithConcurrency(items,concurrency,fn){let cursor=0;async function worker(){for(;cursor<items.length;){let item=items[cursor++];item!==void 0&&await fn(item)}}await Promise.all(Array.from({length:Math.min(concurrency,items.length)},()=>worker()))}export{uploadSourceMaps};
1
+ import{PRODUCER_VERSION}from"./internal/version.mjs";import{createHash,randomUUID}from"node:crypto";const MAP_SUFFIX_RE=/\.map$/;function prepareEntries(maps){return maps.map(map=>{let debugId=randomUUID(),content=injectDebugId(map.content,debugId);return{relPath:map.relPath,chunkUrl:map.relPath.replace(MAP_SUFFIX_RE,``),debugId,content,contentBytes:Buffer.byteLength(content,`utf8`),hash:createHash(`sha256`).update(content).digest(`hex`)}})}function injectDebugId(rawMap,debugId){let parsed=JSON.parse(rawMap);return JSON.stringify({...parsed,debugId})}async function uploadSourceMaps({apiKey,apiUrl,maps,releaseSlug}){let entries=prepareEntries(maps),slug=encodeURIComponent(releaseSlug),signReq={files:entries.map(entry=>({path:entry.relPath,sizeBytes:entry.contentBytes,...richness(entry.content)}))},signRes=await postJson({apiKey,url:`${apiUrl}/v1/releases/${slug}/source-maps/sign`,body:signReq}),byPath=new Map(entries.map(entry=>[entry.relPath,entry])),totalBytes=0;await mapWithConcurrency(signRes.uploads,8,async upload=>{let entry=byPath.get(upload.path);if(!entry)throw Error(`Sign response referenced unknown path "${upload.path}"`);totalBytes+=entry.contentBytes,await putToR2(upload.presignedUrl,entry.content)});let completeReq={files:entries.map(entry=>({path:entry.relPath,hash:entry.hash,debugId:entry.debugId,chunkUrl:entry.chunkUrl})),sourceFileCount:entries.length,bundler:`tsc`};return{fileCount:(await postJson({apiKey,url:`${apiUrl}/v1/releases/${slug}/source-maps/complete`,body:completeReq})).fileCount,totalBytes}}function richness(content){let parsed=JSON.parse(content);return{hasSourcesContent:Array.isArray(parsed.sourcesContent)&&parsed.sourcesContent.length>0,hasNames:Array.isArray(parsed.names)&&parsed.names.length>0,hasFile:typeof parsed.file==`string`&&parsed.file.length>0,mappingsPresent:typeof parsed.mappings==`string`&&parsed.mappings.length>0}}async function postJson({apiKey,url,body}){let response=await fetch(url,{method:`POST`,headers:{"content-type":`application/json`,accept:`application/json`,"user-agent":PRODUCER_VERSION,Authorization:`Bearer ${apiKey}`},body:JSON.stringify(body)});if(!response.ok){let detail=await response.text().catch(()=>``);throw Error(`POST ${url} → ${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(`PUT R2 → ${response.status} ${detail}`)}}async function mapWithConcurrency(items,concurrency,fn){let cursor=0;async function worker(){for(;cursor<items.length;){let item=items[cursor++];item!==void 0&&await fn(item)}}await Promise.all(Array.from({length:Math.min(concurrency,items.length)},()=>worker()))}export{uploadSourceMaps};
@@ -1 +1 @@
1
- {"version":3,"file":"upload.mjs","names":[],"sources":["../src/upload.ts"],"sourcesContent":["import type {\n CompleteSourceMapsRequest,\n CompleteSourceMapsResponse,\n SignSourceMapsRequest,\n SignSourceMapsResponse,\n} from \"@interfere/types/data/source-maps\";\n\nimport { createHash, randomUUID } from \"node:crypto\";\n\nimport type { DiscoveredMap } from \"./discover.js\";\nimport { PRODUCER_VERSION } from \"./internal/version.js\";\n\nconst PUT_CONCURRENCY = 8;\nconst MAP_SUFFIX_RE = /\\.map$/;\n\ninterface PreparedEntry {\n /** Path to the sibling .js — `main.js.map` → `main.js`. Drives `chunkUrl`. */\n readonly chunkUrl: string;\n readonly content: string;\n readonly contentBytes: number;\n readonly debugId: string;\n readonly hash: string;\n readonly relPath: string;\n}\n\n/**\n * Generates a `debugId` per map and injects it into the JSON. The\n * collector's symbolicator suffix-matches incoming `frame.fileName`\n * against the manifest's `chunkUrl` to look up the debugId server-side,\n * so we don't need to also write the debugId comment back into the .js\n * file at the cost of mutating the deploy artifact.\n */\nfunction prepareEntries(maps: DiscoveredMap[]): PreparedEntry[] {\n return maps.map((map) => {\n const debugId = randomUUID();\n const content = injectDebugId(map.content, debugId);\n return {\n relPath: map.relPath,\n chunkUrl: map.relPath.replace(MAP_SUFFIX_RE, \"\"),\n debugId,\n content,\n contentBytes: Buffer.byteLength(content, \"utf8\"),\n hash: createHash(\"sha256\").update(content).digest(\"hex\"),\n };\n });\n}\n\nfunction injectDebugId(rawMap: string, debugId: string): string {\n const parsed = JSON.parse(rawMap) as Record<string, unknown>;\n return JSON.stringify({ ...parsed, debugId });\n}\n\ninterface UploadParams {\n readonly apiKey: string;\n readonly apiUrl: string;\n readonly maps: DiscoveredMap[];\n readonly releaseSlug: string;\n}\n\nexport interface UploadSummary {\n readonly fileCount: number;\n readonly totalBytes: number;\n}\n\nexport async function uploadSourceMaps({\n apiKey,\n apiUrl,\n maps,\n releaseSlug,\n}: UploadParams): Promise<UploadSummary> {\n const entries = prepareEntries(maps);\n const slug = encodeURIComponent(releaseSlug);\n\n const signReq: SignSourceMapsRequest = {\n files: entries.map((entry) => ({\n path: entry.relPath,\n sizeBytes: entry.contentBytes,\n ...richness(entry.content),\n })),\n };\n\n const signRes = await postJson<SignSourceMapsResponse>({\n apiKey,\n url: `${apiUrl}/v1/releases/${slug}/source-maps/sign`,\n body: signReq,\n });\n\n const byPath = new Map(entries.map((entry) => [entry.relPath, entry]));\n let totalBytes = 0;\n\n await mapWithConcurrency(signRes.uploads, PUT_CONCURRENCY, async (upload) => {\n const entry = byPath.get(upload.path);\n if (!entry) {\n throw new Error(`Sign response referenced unknown path \"${upload.path}\"`);\n }\n totalBytes += entry.contentBytes;\n await putToR2(upload.presignedUrl, entry.content);\n });\n\n const completeReq: CompleteSourceMapsRequest = {\n files: entries.map((entry) => ({\n path: entry.relPath,\n hash: entry.hash,\n debugId: entry.debugId,\n chunkUrl: entry.chunkUrl,\n })),\n sourceFileCount: entries.length,\n bundler: \"tsc\",\n };\n\n const completeRes = await postJson<CompleteSourceMapsResponse>({\n apiKey,\n url: `${apiUrl}/v1/releases/${slug}/source-maps/complete`,\n body: completeReq,\n });\n\n return { fileCount: completeRes.fileCount, totalBytes };\n}\n\ninterface RichnessFields {\n readonly hasFile: boolean;\n readonly hasNames: boolean;\n readonly hasSourcesContent: boolean;\n readonly mappingsPresent: boolean;\n}\n\nfunction richness(content: string): RichnessFields {\n const parsed = JSON.parse(content) as Record<string, unknown>;\n return {\n hasSourcesContent:\n Array.isArray(parsed[\"sourcesContent\"]) &&\n (parsed[\"sourcesContent\"] as unknown[]).length > 0,\n hasNames:\n Array.isArray(parsed[\"names\"]) &&\n (parsed[\"names\"] as unknown[]).length > 0,\n hasFile:\n typeof parsed[\"file\"] === \"string\" &&\n (parsed[\"file\"] as string).length > 0,\n mappingsPresent:\n typeof parsed[\"mappings\"] === \"string\" &&\n (parsed[\"mappings\"] as string).length > 0,\n };\n}\n\nasync function postJson<T>({\n apiKey,\n url,\n body,\n}: {\n apiKey: string;\n url: string;\n body: unknown;\n}): Promise<T> {\n const response = await fetch(url, {\n method: \"POST\",\n headers: {\n \"content-type\": \"application/json\",\n accept: \"application/json\",\n \"user-agent\": PRODUCER_VERSION,\n \"x-api-key\": apiKey,\n },\n body: JSON.stringify(body),\n });\n if (!response.ok) {\n const detail = await response.text().catch(() => \"\");\n throw new Error(`POST ${url} → ${response.status} ${detail}`);\n }\n return (await response.json()) as T;\n}\n\nasync function putToR2(presignedUrl: string, content: string): Promise<void> {\n const response = await fetch(presignedUrl, {\n method: \"PUT\",\n headers: { \"content-type\": \"application/json\" },\n body: content,\n });\n if (!response.ok) {\n const detail = await response.text().catch(() => \"\");\n throw new Error(`PUT R2 → ${response.status} ${detail}`);\n }\n}\n\nasync function mapWithConcurrency<T>(\n items: readonly T[],\n concurrency: number,\n fn: (item: T) => Promise<void>\n): Promise<void> {\n let cursor = 0;\n async function worker(): Promise<void> {\n while (cursor < items.length) {\n const i = cursor++;\n const item = items[i];\n if (item !== undefined) {\n await fn(item);\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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"}
1
+ {"version":3,"file":"upload.mjs","names":[],"sources":["../src/upload.ts"],"sourcesContent":["import type {\n CompleteSourceMapsRequest,\n CompleteSourceMapsResponse,\n SignSourceMapsRequest,\n SignSourceMapsResponse,\n} from \"@interfere/types/data/source-maps\";\n\nimport { createHash, randomUUID } from \"node:crypto\";\n\nimport type { DiscoveredMap } from \"./discover.js\";\nimport { PRODUCER_VERSION } from \"./internal/version.js\";\n\nconst PUT_CONCURRENCY = 8;\nconst MAP_SUFFIX_RE = /\\.map$/;\n\ninterface PreparedEntry {\n /** Path to the sibling .js — `main.js.map` → `main.js`. Drives `chunkUrl`. */\n readonly chunkUrl: string;\n readonly content: string;\n readonly contentBytes: number;\n readonly debugId: string;\n readonly hash: string;\n readonly relPath: string;\n}\n\n/**\n * Generates a `debugId` per map and injects it into the JSON. The\n * collector's symbolicator suffix-matches incoming `frame.fileName`\n * against the manifest's `chunkUrl` to look up the debugId server-side,\n * so we don't need to also write the debugId comment back into the .js\n * file at the cost of mutating the deploy artifact.\n */\nfunction prepareEntries(maps: DiscoveredMap[]): PreparedEntry[] {\n return maps.map((map) => {\n const debugId = randomUUID();\n const content = injectDebugId(map.content, debugId);\n return {\n relPath: map.relPath,\n chunkUrl: map.relPath.replace(MAP_SUFFIX_RE, \"\"),\n debugId,\n content,\n contentBytes: Buffer.byteLength(content, \"utf8\"),\n hash: createHash(\"sha256\").update(content).digest(\"hex\"),\n };\n });\n}\n\nfunction injectDebugId(rawMap: string, debugId: string): string {\n const parsed = JSON.parse(rawMap) as Record<string, unknown>;\n return JSON.stringify({ ...parsed, debugId });\n}\n\ninterface UploadParams {\n readonly apiKey: string;\n readonly apiUrl: string;\n readonly maps: DiscoveredMap[];\n readonly releaseSlug: string;\n}\n\nexport interface UploadSummary {\n readonly fileCount: number;\n readonly totalBytes: number;\n}\n\nexport async function uploadSourceMaps({\n apiKey,\n apiUrl,\n maps,\n releaseSlug,\n}: UploadParams): Promise<UploadSummary> {\n const entries = prepareEntries(maps);\n const slug = encodeURIComponent(releaseSlug);\n\n const signReq: SignSourceMapsRequest = {\n files: entries.map((entry) => ({\n path: entry.relPath,\n sizeBytes: entry.contentBytes,\n ...richness(entry.content),\n })),\n };\n\n const signRes = await postJson<SignSourceMapsResponse>({\n apiKey,\n url: `${apiUrl}/v1/releases/${slug}/source-maps/sign`,\n body: signReq,\n });\n\n const byPath = new Map(entries.map((entry) => [entry.relPath, entry]));\n let totalBytes = 0;\n\n await mapWithConcurrency(signRes.uploads, PUT_CONCURRENCY, async (upload) => {\n const entry = byPath.get(upload.path);\n if (!entry) {\n throw new Error(`Sign response referenced unknown path \"${upload.path}\"`);\n }\n totalBytes += entry.contentBytes;\n await putToR2(upload.presignedUrl, entry.content);\n });\n\n const completeReq: CompleteSourceMapsRequest = {\n files: entries.map((entry) => ({\n path: entry.relPath,\n hash: entry.hash,\n debugId: entry.debugId,\n chunkUrl: entry.chunkUrl,\n })),\n sourceFileCount: entries.length,\n bundler: \"tsc\",\n };\n\n const completeRes = await postJson<CompleteSourceMapsResponse>({\n apiKey,\n url: `${apiUrl}/v1/releases/${slug}/source-maps/complete`,\n body: completeReq,\n });\n\n return { fileCount: completeRes.fileCount, totalBytes };\n}\n\ninterface RichnessFields {\n readonly hasFile: boolean;\n readonly hasNames: boolean;\n readonly hasSourcesContent: boolean;\n readonly mappingsPresent: boolean;\n}\n\nfunction richness(content: string): RichnessFields {\n const parsed = JSON.parse(content) as Record<string, unknown>;\n return {\n hasSourcesContent:\n Array.isArray(parsed[\"sourcesContent\"]) &&\n (parsed[\"sourcesContent\"] as unknown[]).length > 0,\n hasNames:\n Array.isArray(parsed[\"names\"]) &&\n (parsed[\"names\"] as unknown[]).length > 0,\n hasFile:\n typeof parsed[\"file\"] === \"string\" &&\n (parsed[\"file\"] as string).length > 0,\n mappingsPresent:\n typeof parsed[\"mappings\"] === \"string\" &&\n (parsed[\"mappings\"] as string).length > 0,\n };\n}\n\nasync function postJson<T>({\n apiKey,\n url,\n body,\n}: {\n apiKey: string;\n url: string;\n body: unknown;\n}): Promise<T> {\n const response = await fetch(url, {\n method: \"POST\",\n headers: {\n \"content-type\": \"application/json\",\n accept: \"application/json\",\n \"user-agent\": PRODUCER_VERSION,\n Authorization: `Bearer ${apiKey}`,\n },\n body: JSON.stringify(body),\n });\n if (!response.ok) {\n const detail = await response.text().catch(() => \"\");\n throw new Error(`POST ${url} → ${response.status} ${detail}`);\n }\n return (await response.json()) as T;\n}\n\nasync function putToR2(presignedUrl: string, content: string): Promise<void> {\n const response = await fetch(presignedUrl, {\n method: \"PUT\",\n headers: { \"content-type\": \"application/json\" },\n body: content,\n });\n if (!response.ok) {\n const detail = await response.text().catch(() => \"\");\n throw new Error(`PUT R2 → ${response.status} ${detail}`);\n }\n}\n\nasync function mapWithConcurrency<T>(\n items: readonly T[],\n concurrency: number,\n fn: (item: T) => Promise<void>\n): Promise<void> {\n let cursor = 0;\n async function worker(): Promise<void> {\n while (cursor < items.length) {\n const i = cursor++;\n const item = items[i];\n if (item !== undefined) {\n await fn(item);\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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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@interfere/cli",
3
- "version": "0.0.1",
3
+ "version": "0.0.2-canary.1",
4
4
  "license": "MIT",
5
5
  "description": "Command-line tool for Interfere. Uploads source maps and confirms releases as part of your CI deploy.",
6
6
  "keywords": [
@@ -36,8 +36,8 @@
36
36
  "typecheck": "tsc --noEmit --incremental"
37
37
  },
38
38
  "dependencies": {
39
- "@interfere/constants": "^9.0.1",
40
- "@interfere/types": "^9.0.2"
39
+ "@interfere/constants": "^9.0.2-canary.0",
40
+ "@interfere/types": "^9.0.3-canary.0"
41
41
  },
42
42
  "devDependencies": {
43
43
  "@interfere/test-utils": "^9.0.0",