@getargus/build-tools 0.0.0-stage → 0.3.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.
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/next.ts","../src/ids.ts","../src/next-upload.ts","../src/collect.ts","../src/upload.ts","../src/http-upload.ts"],"sourcesContent":["/**\n * Next.js integration: `withArgus(nextConfig, { artifactSetId })`.\n *\n * The id reaches the bundles through Next's own `env` config (inlined at build time by the\n * bundler that also writes the source maps) — no DefinePlugin, no post-build patching.\n * Browser and server chunks live in different artifact sets (`web` / `node`).\n *\n * Source maps are uploaded from `compiler.runAfterProductionCompile` (Next >= 15.4): Next calls\n * it once per `next build`, in the main process, after every compiler (server, edge, client;\n * webpack or Turbopack) has written its output and before type checking and static generation.\n * A webpack plugin would run once per compiler, in worker processes, with no \"last one\" signal.\n */\nimport { createRequire } from 'node:module';\nimport { join } from 'node:path';\nimport { NEXT_PUBLIC_ENV, NEXT_SERVER_ENV, assertArtifactSetId, newArtifactSetId, resolveArtifactSetId } from './ids';\nimport { uploadNextBuild } from './next-upload';\n\n// Loose on purpose: Next's own `NextConfig['webpack']` (any config, a context with required\n// fields) must be assignable, or `withArgus(nextConfig)` does not type-check in next.config.ts.\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\ntype WebpackHook = (config: any, context: any) => any;\ntype AfterProductionCompile = (metadata: { projectDir: string; distDir: string }) => Promise<void>;\n\nexport interface NextConfigLike {\n env?: Record<string, string | undefined>;\n productionBrowserSourceMaps?: boolean;\n webpack?: WebpackHook | null;\n [key: string]: unknown;\n}\n\nexport interface NextArgusOptions {\n /**\n * Artifact set of the browser chunks. Env `ARGUS_ARTIFACT_SET_ID_WEB` / `ARGUS_ARTIFACT_SET_ID` wins.\n * When neither is given and this build will upload, a fresh id is generated for the build.\n */\n artifactSetId?: string;\n /** Artifact set of the server chunks. Default `<artifactSetId>-node` (env `ARGUS_ARTIFACT_SET_ID_NODE` wins). */\n serverArtifactSetId?: string;\n /**\n * Emit browser source maps (`productionBrowserSourceMaps`). Default: true for a build that uploads\n * them, false otherwise (maps left in the output would be served publicly). Pass true when you\n * upload in a separate step with `argus-build upload next --delete-maps`.\n */\n browserSourceMaps?: boolean;\n /**\n * webpack builds only: set `devtool = 'source-map'` for the production server compilation so\n * `.next/server/**.js.map` exists. Default: true when this build uploads (a server set needs\n * its maps), else false. Turbopack writes server maps on its own.\n */\n serverSourceMaps?: boolean;\n /**\n * Upload source maps at the end of `next build`. `'auto'` (default): when `ARGUS_UPLOAD_KEY`\n * and `ARGUS_URL` are both set, otherwise nothing happens and nothing is printed. `true`: always\n * try (missing credentials are an upload error). `false`: never.\n */\n upload?: boolean | 'auto';\n /** A failed upload warns and the build continues (`'warn'`, default) or fails the build (`'fail'`). */\n onUploadError?: 'warn' | 'fail';\n /**\n * Remove `.next/static/**.map` once the upload step is over, so the maps are not deployed and\n * served. Default: true when `withArgus` itself turned `productionBrowserSourceMaps` on, false\n * when you enabled it in your own config.\n */\n deleteBrowserMapsAfterUpload?: boolean;\n /** Public path of the browser chunks. Default: the path of `assetPrefix`, else `basePath`, + `/_next/`. */\n urlPrefix?: string;\n env?: Record<string, string | undefined>;\n /** Where upload progress and warnings go. Default `console.log`. */\n log?: (line: string) => void;\n}\n\n/** The pair of ids a Next build uses. */\nexport function nextArtifactSetIds(options: NextArgusOptions = {}): { web: string | undefined; node: string | undefined } {\n const env = options.env ?? process.env;\n // The generic variable names the browser set; the server set is derived unless given.\n const web = resolveArtifactSetId(options.artifactSetId, 'web', env);\n const nodeExplicit = env.ARGUS_ARTIFACT_SET_ID_NODE || options.serverArtifactSetId;\n const node = nodeExplicit ? assertArtifactSetId(nodeExplicit, 'server artifact set id') : web ? assertArtifactSetId(`${web}-node`, 'server artifact set id') : undefined;\n return { web, node };\n}\n\nconst PHASE_PRODUCTION_BUILD = 'phase-production-build';\n// Set in the environment so it is said once per build: Next evaluates the config again in each worker.\nconst WARNED_ENV = '__ARGUS_NEXT_UPLOAD_WARNED';\n\n/** Version of the `next` the project resolves, or undefined (then the hook is assumed to exist). */\nfunction installedNextVersion(): [number, number] | undefined {\n try {\n const { version } = createRequire(join(process.cwd(), 'package.json'))('next/package.json') as { version?: string };\n const m = /^(\\d+)\\.(\\d+)\\./.exec(version ?? '');\n return m ? [Number(m[1]), Number(m[2])] : undefined;\n } catch {\n return undefined;\n }\n}\n\n/** `/_next/` below the path the browser loads chunks from. */\nexport function nextUrlPrefix(config: Record<string, unknown>): string {\n let base = typeof config.assetPrefix === 'string' && config.assetPrefix ? config.assetPrefix : typeof config.basePath === 'string' ? config.basePath : '';\n // An absolute assetPrefix (CDN): names in the set are paths, so only its path counts.\n if (/^https?:\\/\\//i.test(base)) {\n try {\n base = new URL(base).pathname;\n } catch {\n base = '';\n }\n }\n const path = base.replace(/^\\/+|\\/+$/g, '');\n return path ? `/${path}/_next/` : '/_next/';\n}\n\nfunction apply<T extends NextConfigLike>(config: T, options: NextArgusOptions, phase: string | undefined): T & NextConfigLike {\n const env = options.env ?? process.env;\n const mode = options.upload ?? 'auto';\n let uploads = mode === true || (mode === 'auto' && !!env.ARGUS_UPLOAD_KEY && !!env.ARGUS_URL);\n if (uploads) {\n const version = installedNextVersion();\n if (version && (version[0] < 15 || (version[0] === 15 && version[1] < 4))) {\n uploads = false;\n if (!env[WARNED_ENV]) {\n env[WARNED_ENV] = '1';\n (options.log ?? console.warn)(\n `[argus] source maps are not uploaded by this build: Next ${version.join('.')} has no compiler.runAfterProductionCompile (15.4+). Run \\`argus-build upload next --delete-maps\\` after \\`next build\\`.`,\n );\n }\n }\n }\n\n let ids = nextArtifactSetIds(options);\n // An object config is not told the phase. NODE_ENV=production also covers `next start`, where\n // the generated id is simply unused.\n const building = phase !== undefined ? phase === PHASE_PRODUCTION_BUILD : env.NODE_ENV === 'production';\n if (uploads && building && !ids.web) {\n // Kept in the environment: the build workers evaluate this config again and must compile\n // the same id into the bundles that the upload hook (main process) puts on the manifest.\n env.ARGUS_ARTIFACT_SET_ID_WEB = newArtifactSetId('next');\n ids = nextArtifactSetIds(options);\n }\n\n const out: NextConfigLike = { ...config, env: { ...config.env } };\n if (ids.web) out.env![NEXT_PUBLIC_ENV] = ids.web;\n if (ids.node) out.env![NEXT_SERVER_ENV] = ids.node;\n // Browser maps are public once deployed. They are switched on by default only for a build that\n // uploads (and then deletes) them; the separate-step flow asks for them with `browserSourceMaps: true`.\n const wantMaps = options.browserSourceMaps ?? uploads;\n const enabledMaps = wantMaps && config.productionBrowserSourceMaps === undefined;\n if (enabledMaps) out.productionBrowserSourceMaps = true;\n if (options.serverSourceMaps ?? uploads) {\n const previous = config.webpack;\n out.webpack = (webpackConfig: Record<string, unknown>, context: { isServer?: boolean; dev?: boolean } | undefined) => {\n const next = (typeof previous === 'function' ? previous(webpackConfig, context) : webpackConfig) as Record<string, unknown>;\n if (context?.isServer && !context.dev) next.devtool = 'source-map';\n return next;\n };\n }\n if (uploads) {\n const compiler = (config.compiler ?? {}) as { runAfterProductionCompile?: AfterProductionCompile; [key: string]: unknown };\n const previous = compiler.runAfterProductionCompile;\n const hook: AfterProductionCompile = async (metadata) => {\n if (typeof previous === 'function') await previous(metadata);\n const upload: Parameters<typeof uploadNextBuild>[0] = {\n projectDir: metadata.projectDir,\n distDir: metadata.distDir,\n artifactSetId: ids.web,\n serverArtifactSetId: ids.node,\n urlPrefix: options.urlPrefix ?? nextUrlPrefix(config),\n onUploadError: options.onUploadError ?? 'warn',\n deleteBrowserMaps: options.deleteBrowserMapsAfterUpload ?? enabledMaps,\n env,\n };\n if (options.log) upload.log = options.log;\n await uploadNextBuild(upload);\n };\n out.compiler = { ...compiler, runAfterProductionCompile: hook };\n }\n return out as T & NextConfigLike;\n}\n\ntype ConfigFn<T> = (phase: string, context?: unknown) => T | Promise<T>;\n\n/** Accepts a config object or a config function (sync or async), like other Next plugins. */\nexport function withArgus<T extends NextConfigLike>(nextConfig: (phase: string, context?: unknown) => Promise<T>, options?: NextArgusOptions): (phase: string, context?: unknown) => Promise<T & NextConfigLike>;\nexport function withArgus<T extends NextConfigLike>(nextConfig: (phase: string, context?: unknown) => T, options?: NextArgusOptions): (phase: string, context?: unknown) => T & NextConfigLike;\nexport function withArgus<T extends NextConfigLike>(nextConfig: T, options?: NextArgusOptions): T & NextConfigLike;\nexport function withArgus<T extends NextConfigLike>(nextConfig: T | ConfigFn<T>, options: NextArgusOptions = {}): unknown {\n if (typeof nextConfig === 'function') {\n return (phase: string, context?: unknown) => {\n const result = nextConfig(phase, context);\n return result instanceof Promise ? result.then((c) => apply(c, options, phase)) : apply(result, options, phase);\n };\n }\n return apply(nextConfig, options, undefined);\n}\n","/**\n * Artifact set identity (docs/protocol/artifacts-v1.md §1): generated at build start, compiled\n * into the app and written to the upload manifest. `release` / `dist` are human context only.\n */\nimport { randomBytes } from 'node:crypto';\nimport { existsSync, mkdirSync, readFileSync, writeFileSync } from 'node:fs';\nimport { dirname, resolve } from 'node:path';\n\n/** The global the SDKs read (`@getargus/react-native` → `globalThis.__ARGUS_ARTIFACT_SET_ID__`). */\nexport const ARTIFACT_SET_GLOBAL = '__ARGUS_ARTIFACT_SET_ID__';\nexport const NEXT_PUBLIC_ENV = 'NEXT_PUBLIC_ARGUS_ARTIFACT_SET_ID';\nexport const NEXT_SERVER_ENV = 'ARGUS_SERVER_ARTIFACT_SET_ID';\n\nconst RE_ARTIFACT_SET_ID = /^[A-Za-z0-9._:-]{1,128}$/;\nconst GENERATED_MARK = '/* generated by @getargus/build-tools — do not edit, do not commit */';\n\nexport type BuildPlatform = 'ios' | 'android' | 'web' | 'node';\n\nexport function isValidArtifactSetId(id: unknown): id is string {\n return typeof id === 'string' && RE_ARTIFACT_SET_ID.test(id);\n}\n\nexport function assertArtifactSetId(id: unknown, what = 'artifact set id'): string {\n if (!isValidArtifactSetId(id)) {\n throw new Error(`Argus: invalid ${what} ${JSON.stringify(id)} — expected 1..128 chars of [A-Za-z0-9._:-]`);\n }\n return id;\n}\n\n/**\n * Same format as `argus artifacts new-id`: `<prefix>-<uuidv7 without dashes>`. The prefix keeps\n * only `[A-Za-z0-9._-]` (max 80 chars), e.g. `ios-1.2.0-34`.\n */\nexport function newArtifactSetId(prefix = 'build', now: number = Date.now()): string {\n const clean = Array.from(String(prefix))\n .filter((c) => /[A-Za-z0-9._-]/.test(c))\n .slice(0, 80)\n .join('');\n const b = randomBytes(16);\n b.writeUIntBE(now, 0, 6); // 48-bit ms timestamp\n b[6] = (b[6]! & 0x0f) | 0x70;\n b[8] = (b[8]! & 0x3f) | 0x80;\n return `${clean || 'build'}-${b.toString('hex')}`;\n}\n\nexport type ArtifactSetIdInput = string | Partial<Record<BuildPlatform, string>> | ((platform: BuildPlatform) => string | undefined) | undefined;\n\n/**\n * Picks the id for one platform. Environment wins over configuration so CI can inject the id\n * generated at build start (same rule as the `@getargus/expo` config plugin):\n * `ARGUS_ARTIFACT_SET_ID_<PLATFORM>` → `ARGUS_ARTIFACT_SET_ID` → the `artifactSetId` option.\n */\nexport function resolveArtifactSetId(input: ArtifactSetIdInput, platform: BuildPlatform, env: Record<string, string | undefined> = process.env): string | undefined {\n const fromEnv = env[`ARGUS_ARTIFACT_SET_ID_${platform.toUpperCase()}`] || env.ARGUS_ARTIFACT_SET_ID;\n const fromOption = typeof input === 'function' ? input(platform) : typeof input === 'string' ? input : input?.[platform];\n const id = fromEnv || fromOption;\n return id ? assertArtifactSetId(id, `artifact set id for ${platform}`) : undefined;\n}\n\n/** A script that defines the global. Valid as a Metro polyfill, a plain `<script>` or a module with side effects. */\nexport function artifactSetPrelude(artifactSetId: string): string {\n const id = JSON.stringify(assertArtifactSetId(artifactSetId));\n return (\n `${GENERATED_MARK}\\n` +\n `(function (g) {\\n g.${ARTIFACT_SET_GLOBAL} = ${id};\\n})(\\n` +\n \" typeof globalThis !== 'undefined' ? globalThis : typeof global !== 'undefined' ? global : typeof window !== 'undefined' ? window : this,\\n\" +\n ');\\n'\n );\n}\n\nexport interface WriteArtifactSetModuleOptions {\n /** Where to write the generated source file. It is an INPUT of the bundler, never a built output. */\n file: string;\n artifactSetId: string;\n}\n\n/**\n * Writes a tiny generated source file that defines `globalThis.__ARGUS_ARTIFACT_SET_ID__`.\n *\n * This is the only way the id gets into a bundle: as source that goes through the bundler, so\n * bundle ↔ source map coordinates stay consistent. Nothing here ever edits a built bundle, a\n * `.map` or Hermes bytecode, and the function refuses to overwrite a file it did not generate.\n */\nexport function writeArtifactSetModule(options: WriteArtifactSetModuleOptions): { file: string; changed: boolean } {\n const file = resolve(options.file);\n const content = artifactSetPrelude(options.artifactSetId);\n if (existsSync(file)) {\n const current = readFileSync(file, 'utf8');\n if (current === content) return { file, changed: false };\n if (!current.startsWith(GENERATED_MARK)) {\n throw new Error(`Argus: refusing to overwrite ${file}: it was not generated by @getargus/build-tools (built output is never patched)`);\n }\n }\n mkdirSync(dirname(file), { recursive: true });\n writeFileSync(file, content);\n return { file, changed: true };\n}\n\n/** Alias of `writeArtifactSetModule` under the name the integration docs use. */\nexport const injectArtifactSetId = writeArtifactSetModule;\n","/**\n * The upload step `withArgus` runs at the end of a production Next build: browser and server\n * source maps go to their two artifact sets, then the browser maps are removed from the output.\n * Kept apart from the config helper so it can be tested without Next.\n */\nimport { rmSync } from 'node:fs';\nimport { browserSourceMaps, planNext, type NextPlanOptions } from './collect';\nimport { runUploads, type RunOptions } from './upload';\n\nexport interface NextUploadOptions {\n projectDir: string;\n /** Absolute, or relative to `projectDir`. */\n distDir: string;\n artifactSetId: string | undefined;\n serverArtifactSetId?: string | undefined;\n urlPrefix?: string | undefined;\n /** `warn`: log and let the build continue. `fail`: reject, which fails the build. */\n onUploadError: 'warn' | 'fail';\n deleteBrowserMaps: boolean;\n env?: Record<string, string | undefined>;\n log?: (line: string) => void;\n fetch?: RunOptions['fetch'];\n}\n\nexport interface NextUploadResult {\n ok: boolean;\n /** Artifact sets that ended up `ready`. */\n uploaded: string[];\n deletedMaps: number;\n error?: string;\n}\n\n/** Never rejects with `onUploadError: 'warn'`: a monitoring outage must not block a deploy. */\nexport async function uploadNextBuild(options: NextUploadOptions): Promise<NextUploadResult> {\n const env = options.env ?? process.env;\n const log = options.log ?? ((line: string) => console.log(line));\n const uploaded: string[] = [];\n let error: string | undefined;\n try {\n const missing = ['ARGUS_URL', 'ARGUS_UPLOAD_KEY'].filter((k) => !env[k]);\n if (missing.length > 0) throw new Error(`${missing.join(' and ')} not set`);\n if (!options.artifactSetId) throw new Error('no artifact set id (set ARGUS_ARTIFACT_SET_ID or the artifactSetId option)');\n const plan: NextPlanOptions = { projectDir: options.projectDir, distDir: options.distDir, artifactSetId: options.artifactSetId };\n if (options.serverArtifactSetId) plan.serverArtifactSetId = options.serverArtifactSetId;\n if (options.urlPrefix !== undefined) plan.urlPrefix = options.urlPrefix;\n if (env.ARGUS_RELEASE) plan.release = env.ARGUS_RELEASE;\n if (env.ARGUS_GIT_SHA) plan.gitSha = env.ARGUS_GIT_SHA;\n const run: RunOptions = {\n env,\n cwd: options.projectDir,\n // One line per chunk would bury the build log, and every Next build has runtime files\n // without a map; the per-set summary line stays.\n log: (line) => {\n if (!line.startsWith('[argus] uploading ') && !line.endsWith('without a source map were skipped')) log(line);\n },\n };\n if (options.fetch) run.fetch = options.fetch;\n const results = await runUploads(planNext(plan), run);\n for (const r of results) if (r.code === 0) uploaded.push(r.plan.artifactSetId);\n const failed = results.find((r) => r.code !== 0);\n if (failed) throw new Error(`${failed.plan.label} was not uploaded (${failed.command})`);\n } catch (e) {\n error = (e instanceof Error ? e.message : String(e)).replace(/^Argus: /, '');\n if (options.onUploadError === 'fail') {\n // Maps are left in place: the build stops here, nothing is deployed, and a retry\n // (`argus-build upload next`) can still find them.\n throw new Error(`Argus: source map upload failed: ${error}`);\n }\n log(`[argus] warning: source map upload failed, the build continues (onUploadError: 'fail' stops it): ${error}`);\n }\n // Also after a failed upload that only warned: that build goes on to be deployed, and maps\n // that exist only because of withArgus must not be served with it.\n let deletedMaps = 0;\n if (options.deleteBrowserMaps) {\n const maps = browserSourceMaps(options.projectDir, options.distDir);\n for (const m of maps) rmSync(m, { force: true });\n deletedMaps = maps.length;\n if (deletedMaps > 0) log(`[argus] removed ${deletedMaps} browser source map(s) from the build output${error ? ' (they were not uploaded: errors of this build stay unsymbolicated)' : ''}`);\n }\n const result: NextUploadResult = { ok: !error, uploaded, deletedMaps };\n if (error) result.error = error;\n return result;\n}\n","/**\n * Artifact discovery and upload planning. A plan is one `argus artifacts upload` invocation:\n * one artifact set, one platform, an explicit file list. The Rust CLI (`crates/cli`) hashes the\n * files, builds the manifest and uploads; this module only decides WHAT goes into WHICH set and\n * with which naming flags, so that namespaces never mix (browser vs server chunks, iOS vs\n * Android, embedded build vs OTA update).\n */\nimport { closeSync, existsSync, openSync, readFileSync, readSync, readdirSync, statSync } from 'node:fs';\nimport { basename, dirname, join, relative, resolve, sep } from 'node:path';\nimport { assertArtifactSetId, type BuildPlatform } from './ids';\n\nexport type ArtifactFileKind = 'sourcemap' | 'js_bundle' | 'dsym' | 'proguard' | 'elf';\n\n/** Mirrors `classify` in crates/cli/src/upload.rs (hermes maps are detected by the CLI from content). */\nexport function classifyArtifact(path: string): ArtifactFileKind | undefined {\n const lower = basename(path).toLowerCase();\n if (lower.endsWith('.map')) return 'sourcemap';\n if (lower === 'mapping.txt' || lower.endsWith('.mapping.txt')) return 'proguard';\n if (lower.endsWith('.so') || lower.endsWith('.so.dbg')) return 'elf';\n const parts = path.split(/[\\\\/]/);\n if (parts.includes('DWARF') && parts.some((p) => p.endsWith('.dSYM'))) return 'dsym';\n if (/\\.(js|mjs|cjs|bundle|jsbundle|hbc)$/.test(lower)) return 'js_bundle';\n return undefined;\n}\n\nconst SKIP_DIRS = new Set(['node_modules', '.git', 'cache', '.cache', 'Pods']);\n\n/** Recursive file list, sorted, symlinks not followed. */\nexport function walkFiles(dir: string, opts: { skipDirs?: ReadonlySet<string> } = {}): string[] {\n const skip = opts.skipDirs ?? SKIP_DIRS;\n const out: string[] = [];\n const visit = (d: string): void => {\n let entries;\n try {\n entries = readdirSync(d, { withFileTypes: true });\n } catch {\n return;\n }\n for (const e of entries.sort((a, b) => (a.name < b.name ? -1 : a.name > b.name ? 1 : 0))) {\n const p = join(d, e.name);\n if (e.isDirectory()) {\n if (!skip.has(e.name)) visit(p);\n } else if (e.isFile()) out.push(p);\n }\n };\n visit(dir);\n return out;\n}\n\nexport interface UploadMeta {\n release?: string | undefined;\n dist?: string | undefined;\n nativeRelease?: string | undefined;\n nativeBuild?: string | undefined;\n runtimeVersion?: string | undefined;\n gitSha?: string | undefined;\n}\n\nexport interface UploadPlan extends UploadMeta {\n /** e.g. `next:browser`, `expo-export:ios`, `native:android`. */\n label: string;\n artifactSetId: string;\n platform: BuildPlatform;\n /** Absolute paths handed to the CLI. A `.dSYM` bundle is passed as its directory. */\n paths: string[];\n /** Every file that will be part of the set, with its kind — what `collect` prints. */\n files: { path: string; kind: ArtifactFileKind; size: number }[];\n /** `--strip-prefix`: removed from JS paths to form the name frames are matched against. */\n stripPrefix?: string | undefined;\n /** `--url-prefix`: prepended to that name. */\n urlPrefix?: string | undefined;\n /**\n * Source map → generated file, for maps not named `<generated file>.map` (Turbopack chunks).\n * Only the HTTP transport honours it; the argus CLI names a map after its own file name.\n */\n generatedFor?: Record<string, string> | undefined;\n /** OTA update (not embedded in a native binary). */\n ota?: boolean | undefined;\n updateId?: string | undefined;\n /** Artifact set of the native build this OTA update runs on (native symbols are resolved there). */\n parentSetId?: string | undefined;\n warnings: string[];\n}\n\nfunction describe(paths: string[]): UploadPlan['files'] {\n const out: UploadPlan['files'] = [];\n for (const p of paths) {\n const files = statSync(p).isDirectory() ? walkFiles(p, { skipDirs: new Set() }) : [p];\n for (const f of files) {\n const kind = classifyArtifact(f);\n if (kind) out.push({ path: f, kind, size: statSync(f).size });\n }\n }\n return out;\n}\n\nfunction meta(m: UploadMeta): UploadMeta {\n const out: UploadMeta = {};\n for (const k of ['release', 'dist', 'nativeRelease', 'nativeBuild', 'runtimeVersion', 'gitSha'] as const) {\n if (m[k]) out[k] = m[k];\n }\n return out;\n}\n\nconst RE_JS = /\\.(js|mjs|cjs|bundle|jsbundle|hbc)$/;\nconst RE_JS_MAP = /\\.(js|mjs|cjs|bundle|jsbundle|hbc)\\.map$/;\n\n/** The file named by the trailing `//# sourceMappingURL=` comment of a generated file, if any. */\nfunction referencedMap(file: string): string | undefined {\n let tail = '';\n try {\n const size = statSync(file).size;\n const buf = Buffer.alloc(Math.min(size, 1024));\n const fd = openSync(file, 'r');\n try {\n readSync(fd, buf, 0, buf.length, size - buf.length);\n } finally {\n closeSync(fd);\n }\n tail = buf.toString('utf8');\n } catch {\n return undefined;\n }\n const ref = /\\/\\/[#@] sourceMappingURL=([^\\s'\"]+)\\s*$/.exec(tail)?.[1];\n if (!ref || /^[a-z][a-z0-9+.-]*:/i.test(ref)) return undefined; // data: or absolute URL\n return resolve(dirname(file), ref.split(/[?#]/)[0]!);\n}\n\ninterface JsPairs {\n /** Source maps and (with bundles) their generated files, sorted. */\n paths: string[];\n /** Map → generated file, for maps that are not named `<generated file>.map`. */\n generatedFor: Record<string, string>;\n}\n\n/**\n * Source maps with their generated JS file. The usual pairing is the sibling `<file>.map`;\n * Turbopack names a chunk's map after the map's own hash, so the chunk's `sourceMappingURL`\n * comment is the only link. Maps without a generated file are reported.\n */\nfunction jsPairs(dir: string, includeBundles: boolean, warnings: string[], label: string): JsPairs {\n const files = walkFiles(dir);\n const set = new Set(files);\n const orphans = new Set(files.filter((f) => RE_JS_MAP.test(f.toLowerCase()) && !set.has(f.slice(0, -4))));\n const generatedFor: Record<string, string> = {};\n const referenced = new Set<string>();\n if (orphans.size > 0) {\n for (const f of files) {\n if (!RE_JS.test(f.toLowerCase()) || set.has(`${f}.map`)) continue;\n const map = referencedMap(f);\n if (map && orphans.has(map) && !generatedFor[map]) {\n generatedFor[map] = f;\n referenced.add(f);\n }\n }\n }\n const out: string[] = [];\n let unmapped = 0;\n for (const f of files) {\n const lower = f.toLowerCase();\n if (RE_JS_MAP.test(lower)) {\n const generated = generatedFor[f] ?? (set.has(f.slice(0, -4)) ? f.slice(0, -4) : undefined);\n if (!generated) warnings.push(`${label}: ${f} has no generated file next to it`);\n out.push(f);\n if (includeBundles && generated) out.push(generated);\n } else if (RE_JS.test(lower) && !set.has(`${f}.map`) && !referenced.has(f)) unmapped++;\n }\n if (unmapped > 0) warnings.push(`${label}: ${unmapped} JS file(s) without a source map were skipped`);\n return { paths: [...new Set(out)].sort(), generatedFor };\n}\n\n/* --------------------------------------------------------------------- Next */\n\nexport interface NextPlanOptions extends UploadMeta {\n /** Project directory containing the build output. Default `process.cwd()`. */\n projectDir?: string;\n /** Build output directory relative to the project. Default `.next`. */\n distDir?: string;\n /** Artifact set of the browser chunks. */\n artifactSetId: string;\n /** Artifact set of the server chunks. Default `<artifactSetId>-node`. */\n serverArtifactSetId?: string;\n /** Public path the browser loads chunks from. Default `/_next/` (add your basePath / assetPrefix path). */\n urlPrefix?: string;\n /** Upload the generated JS next to each map. Default true. */\n includeBundles?: boolean;\n}\n\n/**\n * Two plans, two artifact sets:\n * - `next:browser` — `<dist>/static/**` as `/_next/static/...` (platform `web`);\n * - `next:server` — `<dist>/server/**` named relative to the project (`.next/server/...`, platform `node`).\n * A plan is omitted (with a warning on the other one) when it has no source maps.\n */\nconst NO_PAIRS: JsPairs = { paths: [], generatedFor: {} };\nconst renamed = (pairs: JsPairs): Pick<UploadPlan, 'generatedFor'> => (Object.keys(pairs.generatedFor).length > 0 ? { generatedFor: pairs.generatedFor } : {});\n\nexport function planNext(options: NextPlanOptions): UploadPlan[] {\n const projectDir = resolve(options.projectDir ?? process.cwd());\n const dist = resolve(projectDir, options.distDir ?? '.next');\n if (!existsSync(dist)) throw new Error(`Argus: Next build output not found at ${dist} (run \\`next build\\` first)`);\n const web = assertArtifactSetId(options.artifactSetId);\n const node = assertArtifactSetId(options.serverArtifactSetId ?? `${web}-node`, 'server artifact set id');\n if (web === node) throw new Error('Argus: browser and server chunks must use different artifact set ids');\n const include = options.includeBundles !== false;\n const plans: UploadPlan[] = [];\n const notes: string[] = [];\n\n const browserWarnings: string[] = [];\n const browser = existsSync(join(dist, 'static')) ? jsPairs(join(dist, 'static'), include, browserWarnings, 'next:browser') : NO_PAIRS;\n if (browser.paths.some((f) => f.endsWith('.map'))) {\n plans.push({\n label: 'next:browser',\n artifactSetId: web,\n platform: 'web',\n paths: browser.paths,\n files: describe(browser.paths),\n stripPrefix: dist,\n urlPrefix: options.urlPrefix ?? '/_next/',\n ...renamed(browser),\n ...meta(options),\n warnings: browserWarnings,\n });\n } else notes.push('next:browser: no source maps under static/ (is productionBrowserSourceMaps enabled?)');\n\n const serverWarnings: string[] = [];\n const server = existsSync(join(dist, 'server')) ? jsPairs(join(dist, 'server'), include, serverWarnings, 'next:server') : NO_PAIRS;\n if (server.paths.some((f) => f.endsWith('.map'))) {\n plans.push({\n label: 'next:server',\n artifactSetId: node,\n platform: 'node',\n paths: server.paths,\n files: describe(server.paths),\n // Server frames are filesystem paths ending in `.next/server/...`.\n stripPrefix: projectDir,\n urlPrefix: '',\n ...renamed(server),\n ...meta(options),\n warnings: serverWarnings,\n });\n } else notes.push('next:server: no source maps under server/ (server source maps are not emitted by default)');\n\n if (plans.length === 0) throw new Error(`Argus: no source maps found in ${dist}. ${notes.join('; ')}`);\n plans[0]!.warnings.push(...notes);\n return plans;\n}\n\n/** Deletes browser `.map` files from the build output so they are never deployed or served. Returns the removed paths. */\nexport function browserSourceMaps(projectDir: string, distDir = '.next'): string[] {\n const dir = resolve(projectDir, distDir, 'static');\n return existsSync(dir) ? walkFiles(dir).filter((f) => f.endsWith('.map')) : [];\n}\n\n/* -------------------------------------------------------------- Expo export */\n\nexport type MobilePlatform = 'ios' | 'android';\n\nexport interface ExpoExportPlanOptions extends UploadMeta {\n /** Output directory of `expo export`. Default `dist`. */\n exportDir?: string;\n /** One artifact set per platform (an artifact set has exactly one platform). */\n artifactSetIds: Partial<Record<MobilePlatform, string>>;\n /** Limit to these platforms. Default: every platform in `metadata.json` that has an id. */\n platforms?: MobilePlatform[];\n /** OTA update id per platform (or one string for a single platform). Falls back to `metadata.json` when it carries one. */\n updateId?: string | Partial<Record<MobilePlatform, string>>;\n /** Artifact set of the native build the update targets, per platform. */\n parentSetIds?: Partial<Record<MobilePlatform, string>>;\n}\n\ninterface ExpoMetadata {\n id?: unknown;\n updateId?: unknown;\n fileMetadata?: Record<string, { bundle?: unknown; id?: unknown; updateId?: unknown } | undefined>;\n}\n\nfunction str(v: unknown): string | undefined {\n return typeof v === 'string' && v ? v : undefined;\n}\n\n/**\n * One plan per platform from `expo export` output: the bundle named by\n * `metadata.json → fileMetadata.<platform>.bundle` and its `.map` (export with\n * `--dump-sourcemap` / `--source-maps`). Marked `--ota` with update id, runtime version and the\n * parent (native build) set.\n */\nexport function planExpoExport(options: ExpoExportPlanOptions): UploadPlan[] {\n const dir = resolve(options.exportDir ?? 'dist');\n const metadataPath = join(dir, 'metadata.json');\n if (!existsSync(metadataPath)) throw new Error(`Argus: ${metadataPath} not found (run \\`expo export\\` first)`);\n const metadata = JSON.parse(readFileSync(metadataPath, 'utf8')) as ExpoMetadata;\n const available = Object.keys(metadata.fileMetadata ?? {}).filter((p): p is MobilePlatform => p === 'ios' || p === 'android');\n const wanted = options.platforms ?? available.filter((p) => options.artifactSetIds[p]);\n if (wanted.length === 0) throw new Error('Argus: no platform to upload — pass an artifact set id for ios and/or android');\n const ids = wanted.map((p) => options.artifactSetIds[p]);\n if (new Set(ids).size !== ids.length) throw new Error('Argus: iOS and Android updates need different artifact set ids');\n\n const plans: UploadPlan[] = [];\n for (const platform of wanted) {\n const label = `expo-export:${platform}`;\n const artifactSetId = assertArtifactSetId(options.artifactSetIds[platform], `artifact set id for ${platform}`);\n const entry = metadata.fileMetadata?.[platform];\n const bundleRel = str(entry?.bundle);\n if (!bundleRel) throw new Error(`Argus: metadata.json has no bundle for ${platform}`);\n const bundle = resolve(dir, bundleRel);\n if (!bundle.startsWith(dir + sep)) throw new Error(`Argus: metadata.json bundle path escapes the export directory: ${bundleRel}`);\n const map = `${bundle}.map`;\n if (!existsSync(bundle)) throw new Error(`Argus: ${bundle} is missing`);\n if (!existsSync(map)) throw new Error(`Argus: ${map} is missing — export with source maps (\\`expo export --dump-sourcemap\\`)`);\n const warnings: string[] = [];\n const given = typeof options.updateId === 'string' ? (wanted.length === 1 ? options.updateId : undefined) : options.updateId?.[platform];\n if (typeof options.updateId === 'string' && wanted.length > 1) warnings.push(`${label}: a single --update-id cannot apply to several platforms; pass one per platform`);\n const updateId = given ?? str(entry?.updateId) ?? str(entry?.id) ?? str(metadata.updateId) ?? str(metadata.id);\n if (!updateId) warnings.push(`${label}: no update id (not in metadata.json, none given) — the set is still matched by artifact_set_id`);\n const parentSetId = options.parentSetIds?.[platform];\n if (!parentSetId) warnings.push(`${label}: no parent set id — native frames of crashes during this update cannot be tied to the native build's symbols`);\n const paths = [bundle, map];\n plans.push({\n label,\n artifactSetId,\n platform,\n paths,\n files: describe(paths),\n // Named by file name: `entry-<hash>.hbc` ← `entry-<hash>.hbc.map`.\n stripPrefix: dirname(bundle),\n urlPrefix: '',\n ota: true,\n updateId,\n parentSetId: parentSetId ? assertArtifactSetId(parentSetId, `parent set id for ${platform}`) : undefined,\n ...meta(options),\n warnings,\n });\n }\n return plans;\n}\n\n/* ------------------------------------------------------------ native builds */\n\nexport interface NativePlanOptions extends UploadMeta {\n platform: MobilePlatform;\n artifactSetId: string;\n /**\n * Directories / files to search: an `.xcarchive`, a `dSYMs` folder, `ios/build`,\n * `android/app/build`, an EAS artifacts folder, or explicit files.\n */\n searchPaths: string[];\n /** Embedded JS bundle and its (Hermes-composed) source map, when not found by the search. */\n bundle?: string;\n sourcemap?: string;\n /** Android: also upload unstripped `.so` files found under the search paths. Default false. */\n includeNativeLibs?: boolean;\n}\n\nfunction findDsyms(root: string): string[] {\n const out: string[] = [];\n const visit = (d: string, depth: number): void => {\n if (depth > 12) return;\n let entries;\n try {\n entries = readdirSync(d, { withFileTypes: true });\n } catch {\n return;\n }\n for (const e of entries) {\n if (!e.isDirectory() || e.name === 'node_modules' || e.name === '.git') continue;\n const p = join(d, e.name);\n if (e.name.endsWith('.dSYM')) out.push(p);\n else visit(p, depth + 1);\n }\n };\n if (root.endsWith('.dSYM')) out.push(root);\n else visit(root, 0);\n return out.sort();\n}\n\n/**\n * The embedded build of one platform — one artifact set holding\n * - iOS: every `.dSYM` bundle + `main.jsbundle(.map)`;\n * - Android: R8 `mapping.txt` + `index.android.bundle(.map)` (+ unstripped `.so` on request).\n * JS files keep their file name (`index.android.bundle`), which is what Hermes frames report.\n */\nexport function planNative(options: NativePlanOptions): UploadPlan {\n const label = `native:${options.platform}`;\n const artifactSetId = assertArtifactSetId(options.artifactSetId);\n const warnings: string[] = [];\n const paths = new Set<string>();\n const roots = options.searchPaths.map((p) => resolve(p));\n for (const root of roots) if (!existsSync(root)) throw new Error(`Argus: ${root} does not exist`);\n\n const jsMaps: string[] = [];\n for (const root of roots) {\n const isDir = statSync(root).isDirectory();\n if (options.platform === 'ios') {\n if (isDir) for (const d of findDsyms(root)) paths.add(d);\n }\n const files = isDir ? (root.endsWith('.dSYM') ? [] : walkFiles(root, { skipDirs: new Set(['node_modules', '.git', 'Pods']) })) : [root];\n for (const f of files) {\n const name = basename(f).toLowerCase();\n if (f.split(sep).some((part) => part.endsWith('.dSYM'))) continue; // covered by the bundle directory\n if (options.platform === 'android') {\n if (name === 'mapping.txt') paths.add(f);\n else if (options.includeNativeLibs && name.endsWith('.so')) paths.add(f);\n }\n if (/\\.(jsbundle|bundle)\\.map$/.test(name)) jsMaps.push(f);\n }\n }\n if (options.sourcemap) jsMaps.unshift(resolve(options.sourcemap));\n\n const uniqueMaps = [...new Set(jsMaps)];\n if (uniqueMaps.length > 1 && !options.sourcemap) {\n warnings.push(`${label}: several JS source maps found, using ${uniqueMaps[0]} (pass --sourcemap to choose): ${uniqueMaps.slice(1).join(', ')}`);\n }\n const map = uniqueMaps[0];\n if (map) {\n if (!existsSync(map)) throw new Error(`Argus: ${map} does not exist`);\n paths.add(map);\n const bundle = options.bundle ? resolve(options.bundle) : map.slice(0, -4);\n if (existsSync(bundle)) {\n if (basename(bundle) !== basename(map).slice(0, -4)) {\n warnings.push(`${label}: bundle ${basename(bundle)} and map ${basename(map)} have different names; frames are matched against \"${basename(map).slice(0, -4)}\"`);\n }\n paths.add(bundle);\n }\n } else warnings.push(`${label}: no JS source map found (*.bundle.map / *.jsbundle.map) — JS frames of this build will stay unsymbolicated`);\n\n const list = [...paths].sort();\n const files = describe(list);\n if (options.platform === 'ios' && !files.some((f) => f.kind === 'dsym')) warnings.push(`${label}: no .dSYM found — native iOS frames will stay unsymbolicated`);\n if (options.platform === 'android') {\n const mappings = files.filter((f) => f.kind === 'proguard');\n if (mappings.length === 0) warnings.push(`${label}: no mapping.txt found — fine only if R8/ProGuard is disabled for this build`);\n if (mappings.length > 1) throw new Error(`Argus: several mapping.txt files found (${mappings.map((m) => m.path).join(', ')}); point --dir at one build variant`);\n }\n if (list.length === 0) throw new Error(`Argus: nothing to upload for ${label} under ${roots.join(', ')}`);\n return { label, artifactSetId, platform: options.platform, paths: list, files, ...meta(options), warnings };\n}\n\n/* ------------------------------------------------------------------ generic */\n\nexport interface FilesPlanOptions extends UploadMeta {\n artifactSetId: string;\n platform: BuildPlatform;\n /** Files or directories; directories are searched for `*.map` with their generated file. */\n paths: string[];\n stripPrefix?: string;\n urlPrefix?: string;\n includeBundles?: boolean;\n}\n\n/** Any bundler output (esbuild, Vite, a worker build…): source maps plus their generated files. */\nexport function planFiles(options: FilesPlanOptions): UploadPlan {\n const label = `files:${options.platform}`;\n const warnings: string[] = [];\n const paths: string[] = [];\n const generatedFor: Record<string, string> = {};\n for (const p of options.paths.map((x) => resolve(x))) {\n if (!existsSync(p)) throw new Error(`Argus: ${p} does not exist`);\n if (statSync(p).isDirectory()) {\n const pairs = jsPairs(p, options.includeBundles !== false, warnings, label);\n paths.push(...pairs.paths);\n Object.assign(generatedFor, pairs.generatedFor);\n } else paths.push(p);\n }\n const unique = [...new Set(paths)].sort();\n if (unique.length === 0) throw new Error(`Argus: no artifacts found in ${options.paths.join(', ')}`);\n const plan: UploadPlan = {\n label,\n artifactSetId: assertArtifactSetId(options.artifactSetId),\n platform: options.platform,\n paths: unique,\n files: describe(unique),\n ...meta(options),\n warnings,\n };\n if (options.stripPrefix !== undefined) plan.stripPrefix = resolve(options.stripPrefix);\n if (options.urlPrefix !== undefined) plan.urlPrefix = options.urlPrefix;\n if (Object.keys(generatedFor).length > 0) plan.generatedFor = generatedFor;\n return plan;\n}\n\n/* ----------------------------------------------------------- CLI arguments */\n\n/**\n * Arguments for the Rust CLI: `argus artifacts upload …` (flags as defined in\n * crates/cli/src/upload.rs). The upload key is never put on the command line; the CLI reads\n * `ARGUS_UPLOAD_KEY` (and `ARGUS_URL`) from the environment.\n */\nexport function uploadArgs(plan: UploadPlan, opts: { dryRun?: boolean; url?: string } = {}): string[] {\n const args = ['artifacts', 'upload', '--set-id', plan.artifactSetId, '--platform', plan.platform];\n const flag = (name: string, value: string | undefined): void => {\n if (value !== undefined && value !== '') args.push(name, value);\n };\n flag('--url', opts.url);\n flag('--release', plan.release);\n flag('--dist', plan.dist);\n flag('--native-release', plan.nativeRelease);\n flag('--native-build', plan.nativeBuild);\n flag('--runtime-version', plan.runtimeVersion);\n if (plan.ota) args.push('--ota');\n flag('--update-id', plan.updateId);\n flag('--parent-set-id', plan.parentSetId);\n flag('--git-sha', plan.gitSha);\n flag('--strip-prefix', plan.stripPrefix);\n flag('--url-prefix', plan.urlPrefix);\n if (opts.dryRun) args.push('--dry-run');\n args.push('--', ...plan.paths);\n return args;\n}\n\n/** The name a JS file gets in the manifest (`bundle_name`), mirroring the CLI's rule. For display and tests. */\nexport function manifestName(plan: Pick<UploadPlan, 'stripPrefix' | 'urlPrefix' | 'generatedFor'>, file: string): string {\n const generated = file.endsWith('.map') ? (plan.generatedFor?.[file] ?? file.slice(0, -4)) : file;\n const prefix = plan.stripPrefix;\n const rel = prefix && (generated === prefix || generated.startsWith(prefix.endsWith(sep) ? prefix : prefix + sep)) ? relative(prefix, generated) : basename(generated);\n return `${plan.urlPrefix ?? ''}${rel.split(sep).join('/').replace(/^\\/+/, '')}`;\n}\n\n/** A copy-pasteable shell command for a plan (paths relative to `cwd` when inside it). */\nexport function formatCommand(bin: string, args: string[], cwd: string = process.cwd()): string {\n const quote = (s: string): string => (/^[A-Za-z0-9_./:@=+-]+$/.test(s) ? s : `'${s.replace(/'/g, `'\\\\''`)}'`);\n const short = (s: string): string => {\n if (!s.startsWith(cwd + sep)) return s;\n return relative(cwd, s);\n };\n return [bin, ...args.map((a) => quote(short(a)))].join(' ');\n}\n","/**\n * Runs upload plans: JavaScript sets go straight to the server over HTTP (no binary needed),\n * sets with native symbols through the Rust CLI (`argus artifacts upload`).\n */\nimport { spawn } from 'node:child_process';\nimport { formatCommand, uploadArgs, type UploadPlan } from './collect';\nimport { isJsOnlyPlan, uploadPlanOverHttp, type HttpFetch } from './http-upload';\n\nexport interface RunResult {\n plan: UploadPlan;\n command: string;\n code: number;\n}\n\nexport interface RunOptions {\n /** The `argus` binary. Default: `$ARGUS_BIN`, else `argus` on PATH. */\n bin?: string;\n /** Pass `--dry-run`: the CLI prints the manifest and uploads nothing. */\n dryRun?: boolean;\n /** Server base URL (`--url`). Default: the CLI's own `ARGUS_URL` handling. */\n url?: string;\n env?: Record<string, string | undefined>;\n cwd?: string;\n /**\n * `http`: upload from Node (JS artifacts only). `cli`: run the `argus` binary. Default `auto`\n * (env `ARGUS_UPLOAD_TRANSPORT`): HTTP for JS-only sets unless `ARGUS_BIN` names a binary,\n * the CLI for sets with native symbols.\n */\n transport?: 'auto' | 'http' | 'cli';\n /** HTTP client for the `http` transport, replaceable in tests. */\n fetch?: HttpFetch;\n /** Process launcher, replaceable in tests. Resolves with the exit code. */\n exec?: (bin: string, args: string[], opts: { env: Record<string, string | undefined>; cwd: string }) => Promise<number>;\n log?: (line: string) => void;\n}\n\nfunction defaultExec(bin: string, args: string[], opts: { env: Record<string, string | undefined>; cwd: string }): Promise<number> {\n return new Promise((resolvePromise, reject) => {\n const child = spawn(bin, args, { stdio: 'inherit', env: opts.env as NodeJS.ProcessEnv, cwd: opts.cwd });\n child.on('error', (e: NodeJS.ErrnoException) => {\n reject(e.code === 'ENOENT' ? new Error(`Argus: cannot run \"${bin}\" — install the argus CLI or set ARGUS_BIN`) : e);\n });\n child.on('close', (code) => resolvePromise(code ?? 1));\n });\n}\n\n/**\n * Uploads the plans one after another and stops at the first failure (a build must not be\n * promoted with a half-uploaded artifact set). Credentials come from the environment\n * (`ARGUS_UPLOAD_KEY`); they are never placed on the command line.\n */\nexport async function runUploads(plans: UploadPlan[], options: RunOptions = {}): Promise<RunResult[]> {\n const env = options.env ?? process.env;\n const cwd = options.cwd ?? process.cwd();\n const bin = options.bin ?? env.ARGUS_BIN ?? 'argus';\n const exec = options.exec ?? defaultExec;\n const log = options.log ?? ((line: string) => console.error(line));\n const requested = options.transport ?? env.ARGUS_UPLOAD_TRANSPORT ?? 'auto';\n if (requested !== 'auto' && requested !== 'http' && requested !== 'cli') throw new Error(`Argus: unknown upload transport \"${requested}\" (auto, http or cli)`);\n const transport: 'auto' | 'http' | 'cli' = requested;\n const results: RunResult[] = [];\n if (!options.dryRun && !env.ARGUS_UPLOAD_KEY) throw new Error('Argus: ARGUS_UPLOAD_KEY is not set (an upload key, never the public ingest key)');\n for (const plan of plans) {\n const argOpts: { dryRun?: boolean; url?: string } = {};\n if (options.dryRun) argOpts.dryRun = true;\n if (options.url) argOpts.url = options.url;\n const args = uploadArgs(plan, argOpts);\n const command = formatCommand(bin, args, cwd);\n for (const w of plan.warnings) log(`[argus] warning: ${w}`);\n log(`[argus] ${plan.label}: ${plan.files.length} file(s) → set ${plan.artifactSetId}`);\n const viaHttp = transport === 'http' || (transport === 'auto' && !options.exec && !env.ARGUS_BIN && isJsOnlyPlan(plan));\n if (viaHttp) {\n const url = options.url ?? env.ARGUS_URL;\n if (!url) throw new Error('Argus: ARGUS_URL is not set (the server base URL, e.g. https://argus.example.com)');\n const http: Parameters<typeof uploadPlanOverHttp>[1] = { url, uploadKey: env.ARGUS_UPLOAD_KEY ?? '', log };\n if (options.dryRun) http.dryRun = true;\n if (options.fetch) http.fetch = options.fetch;\n let code = 0;\n try {\n await uploadPlanOverHttp(plan, http);\n } catch (e) {\n log(`[argus] ${e instanceof Error ? e.message : String(e)}`);\n code = 1;\n }\n results.push({ plan, command: `http upload → ${url}`, code });\n if (code !== 0) break;\n continue;\n }\n const renamedMaps = Object.keys(plan.generatedFor ?? {}).length;\n if (renamedMaps > 0) log(`[argus] warning: ${plan.label}: ${renamedMaps} source map(s) are tied to their chunk only by its sourceMappingURL comment (Turbopack); the argus CLI names them after the map file, so their frames will not resolve — use the http transport`);\n const code = await exec(bin, args, { env, cwd });\n results.push({ plan, command, code });\n if (code !== 0) break;\n }\n return results;\n}\n","/**\n * Uploads a JavaScript artifact set straight to the server (artifacts-v1: manifest → missing\n * blobs → finalize). No `argus` binary needed, so a web / Node / OTA build can upload from any CI\n * image that has Node. Mirrors `argus artifacts upload` for the kinds it supports.\n *\n * Native symbols (dSYM, ELF, R8 mapping) are NOT uploaded here: the CLI validates them locally\n * with the server's own parser and declares their debug ids. Plans that contain them go through\n * the CLI.\n */\nimport { createHash } from 'node:crypto';\nimport { createReadStream, openSync, readSync, closeSync, statSync, readFileSync } from 'node:fs';\nimport { basename, relative, sep } from 'node:path';\nimport { manifestName, type UploadPlan } from './collect';\n\nexport type HttpFetch = (url: string, init: { method: string; headers: Record<string, string>; body?: string | Uint8Array }) => Promise<{\n status: number;\n text(): Promise<string>;\n}>;\n\nexport interface HttpUploadOptions {\n /** Server base URL, e.g. `https://argus.example.com`. */\n url: string;\n /** Upload key (kind `upload`). */\n uploadKey: string;\n dryRun?: boolean;\n fetch?: HttpFetch;\n log?: (line: string) => void;\n}\n\nexport interface ManifestFileEntry {\n kind: 'sourcemap' | 'hermes_sourcemap' | 'js_bundle';\n name: string;\n bundle_name?: string;\n sha256: string;\n size: number;\n}\n\ninterface Found {\n path: string;\n file: ManifestFileEntry;\n}\n\nconst NATIVE_KINDS = new Set(['dsym', 'elf', 'proguard']);\n\n/** True when every file of the plan can be uploaded without the CLI. */\nexport function isJsOnlyPlan(plan: UploadPlan): boolean {\n return plan.files.length > 0 && plan.files.every((f) => !NATIVE_KINDS.has(f.kind));\n}\n\nfunction sha256File(path: string): Promise<string> {\n return new Promise((resolvePromise, reject) => {\n const hash = createHash('sha256');\n createReadStream(path)\n .on('data', (chunk) => hash.update(chunk))\n .on('error', reject)\n .on('end', () => resolvePromise(hash.digest('hex')));\n });\n}\n\n/** Hermes-composed maps carry Metro's function map; that is what makes them \"hermes\" maps. */\nfunction isHermesMap(path: string): boolean {\n const needle = 'x_facebook_sources';\n const head = Buffer.alloc(256 * 1024);\n const fd = openSync(path, 'r');\n let n = 0;\n try {\n n = readSync(fd, head, 0, head.length, 0);\n } finally {\n closeSync(fd);\n }\n if (head.subarray(0, n).includes(needle)) return true;\n return statSync(path).size > n && readFileSync(path).includes(needle);\n}\n\n/** The name of a file inside the set: its path below the strip prefix (the CLI's rule). */\nfunction setName(plan: Pick<UploadPlan, 'stripPrefix'>, file: string): string {\n const prefix = plan.stripPrefix;\n const inside = prefix && (file === prefix || file.startsWith(prefix.endsWith(sep) ? prefix : prefix + sep));\n return (inside ? relative(prefix, file) : file).split(sep).join('/').replace(/^\\/+/, '');\n}\n\n/** Builds the manifest for a JS-only plan. Exported for tests and `--dry-run`. */\nexport async function buildManifest(plan: UploadPlan): Promise<{ manifest: Record<string, unknown>; found: Found[] }> {\n const found: Found[] = [];\n const paths = [...new Set(plan.files.map((f) => f.path))].sort();\n for (const path of paths) {\n const kind = plan.files.find((f) => f.path === path)!.kind;\n if (NATIVE_KINDS.has(kind)) throw new Error(`Argus: ${basename(path)} is a native symbol file; upload it with the argus CLI`);\n const size = statSync(path).size;\n if (size === 0) throw new Error(`Argus: ${path} is empty`);\n const sha256 = await sha256File(path);\n if (kind === 'sourcemap') {\n found.push({\n path,\n file: { kind: isHermesMap(path) ? 'hermes_sourcemap' : 'sourcemap', name: setName(plan, path), bundle_name: manifestName(plan, path), sha256, size },\n });\n } else {\n found.push({ path, file: { kind: 'js_bundle', name: manifestName(plan, path), sha256, size } });\n }\n }\n // The same file reached through two paths must not appear twice under one name.\n found.sort((a, b) => (a.file.name < b.file.name ? -1 : a.file.name > b.file.name ? 1 : 0));\n const unique = found.filter((f, i) => i === 0 || found[i - 1]!.file.name !== f.file.name);\n if (unique.length === 0) throw new Error('Argus: no artifacts found in the given paths');\n\n const manifest: Record<string, unknown> = {\n schema_version: 1,\n artifact_set_id: plan.artifactSetId,\n platform: plan.platform,\n is_embedded: !plan.ota,\n files: unique.map((f) => f.file),\n };\n const set = (key: string, value: string | undefined): void => {\n if (value !== undefined && value !== '') manifest[key] = value;\n };\n set('release', plan.release);\n set('dist', plan.dist);\n set('native_release', plan.nativeRelease);\n set('native_build', plan.nativeBuild);\n set('runtime_version', plan.runtimeVersion);\n set('update_id', plan.updateId);\n set('git_sha', plan.gitSha);\n set('parent_artifact_set_id', plan.parentSetId);\n return { manifest, found: unique };\n}\n\nconst defaultFetch: HttpFetch = async (url, init) => {\n const res = await fetch(url, init as RequestInit);\n return { status: res.status, text: () => res.text() };\n};\n\nasync function call(doFetch: HttpFetch, method: string, url: string, key: string, body?: { json?: unknown; bytes?: Uint8Array }): Promise<Record<string, unknown>> {\n const headers: Record<string, string> = { authorization: `Bearer ${key}` };\n let payload: string | Uint8Array | undefined;\n if (body?.json !== undefined) {\n headers['content-type'] = 'application/json';\n payload = JSON.stringify(body.json);\n } else if (body?.bytes) {\n headers['content-type'] = 'application/octet-stream';\n payload = body.bytes;\n }\n const init: { method: string; headers: Record<string, string>; body?: string | Uint8Array } = { method, headers };\n if (payload !== undefined) init.body = payload;\n let res;\n try {\n res = await doFetch(url, init);\n } catch (e) {\n throw new Error(`Argus: cannot reach ${new URL(url).origin} (${e instanceof Error ? e.message : String(e)})`);\n }\n const text = await res.text();\n let parsed: unknown;\n try {\n parsed = text ? JSON.parse(text) : {};\n } catch {\n parsed = undefined;\n }\n if (res.status < 200 || res.status >= 300) {\n const detail = parsed && typeof parsed === 'object' ? JSON.stringify(parsed) : text.slice(0, 300);\n throw new Error(`Argus: ${method} ${new URL(url).pathname} → HTTP ${res.status} ${detail}`);\n }\n if (!parsed || typeof parsed !== 'object') throw new Error(`Argus: ${method} ${new URL(url).pathname} did not return JSON (is ARGUS_URL the server's base URL?)`);\n return parsed as Record<string, unknown>;\n}\n\n/**\n * Creates the set, uploads the blobs the server does not have yet and finalizes. Idempotent:\n * re-running with identical files uploads nothing. Throws unless the set ends up `ready`.\n */\nexport async function uploadPlanOverHttp(plan: UploadPlan, options: HttpUploadOptions): Promise<{ status: string; uploaded: number; files: number }> {\n const log = options.log ?? ((line: string) => console.error(line));\n const { manifest, found } = await buildManifest(plan);\n if (options.dryRun) {\n log(JSON.stringify(manifest, null, 2));\n return { status: 'dry_run', uploaded: 0, files: found.length };\n }\n const base = options.url.replace(/\\/+$/, '');\n if (!/^https?:\\/\\//i.test(base)) throw new Error('Argus: ARGUS_URL must be the server base URL (https://host)');\n const doFetch = options.fetch ?? defaultFetch;\n const id = encodeURIComponent(plan.artifactSetId);\n\n const created = await call(doFetch, 'POST', `${base}/v1/artifact-sets`, options.uploadKey, { json: manifest });\n const states = Array.isArray(created.files) ? (created.files as { sha256?: string; state?: string }[]) : [];\n const done = new Set<string>();\n let uploaded = 0;\n for (const f of states) {\n if (!f.sha256 || f.state === 'uploaded' || done.has(f.sha256)) continue;\n done.add(f.sha256);\n const local = found.find((x) => x.file.sha256 === f.sha256);\n if (!local) throw new Error(`Argus: server asks for unknown blob ${f.sha256}`);\n log(`[argus] uploading ${local.file.name} (${local.file.size} bytes)`);\n await call(doFetch, 'PUT', `${base}/v1/artifact-sets/${id}/files/${f.sha256}`, options.uploadKey, { bytes: readFileSync(local.path) });\n uploaded++;\n }\n const final = await call(doFetch, 'POST', `${base}/v1/artifact-sets/${id}/finalize`, options.uploadKey);\n const status = typeof final.status === 'string' ? final.status : 'unknown';\n const queued = typeof final.reprocess_queued === 'number' ? final.reprocess_queued : 0;\n log(`[argus] set ${plan.artifactSetId}: ${status}, ${found.length} file(s), ${uploaded} uploaded${queued > 0 ? `, ${queued} waiting event(s) queued for reprocessing` : ''}`);\n if (status !== 'ready') throw new Error(`Argus: artifact set ${plan.artifactSetId} is not ready (${status})`);\n return { status, uploaded, files: found.length };\n}\n"],"mappings":"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","names":["import_node_path","import_node_fs","import_node_fs","import_node_path","import_node_crypto","import_node_fs","import_node_path","code"]}
@@ -0,0 +1,60 @@
1
+ type WebpackHook = (config: any, context: any) => any;
2
+ interface NextConfigLike {
3
+ env?: Record<string, string | undefined>;
4
+ productionBrowserSourceMaps?: boolean;
5
+ webpack?: WebpackHook | null;
6
+ [key: string]: unknown;
7
+ }
8
+ interface NextArgusOptions {
9
+ /**
10
+ * Artifact set of the browser chunks. Env `ARGUS_ARTIFACT_SET_ID_WEB` / `ARGUS_ARTIFACT_SET_ID` wins.
11
+ * When neither is given and this build will upload, a fresh id is generated for the build.
12
+ */
13
+ artifactSetId?: string;
14
+ /** Artifact set of the server chunks. Default `<artifactSetId>-node` (env `ARGUS_ARTIFACT_SET_ID_NODE` wins). */
15
+ serverArtifactSetId?: string;
16
+ /**
17
+ * Emit browser source maps (`productionBrowserSourceMaps`). Default: true for a build that uploads
18
+ * them, false otherwise (maps left in the output would be served publicly). Pass true when you
19
+ * upload in a separate step with `argus-build upload next --delete-maps`.
20
+ */
21
+ browserSourceMaps?: boolean;
22
+ /**
23
+ * webpack builds only: set `devtool = 'source-map'` for the production server compilation so
24
+ * `.next/server/**.js.map` exists. Default: true when this build uploads (a server set needs
25
+ * its maps), else false. Turbopack writes server maps on its own.
26
+ */
27
+ serverSourceMaps?: boolean;
28
+ /**
29
+ * Upload source maps at the end of `next build`. `'auto'` (default): when `ARGUS_UPLOAD_KEY`
30
+ * and `ARGUS_URL` are both set, otherwise nothing happens and nothing is printed. `true`: always
31
+ * try (missing credentials are an upload error). `false`: never.
32
+ */
33
+ upload?: boolean | 'auto';
34
+ /** A failed upload warns and the build continues (`'warn'`, default) or fails the build (`'fail'`). */
35
+ onUploadError?: 'warn' | 'fail';
36
+ /**
37
+ * Remove `.next/static/**.map` once the upload step is over, so the maps are not deployed and
38
+ * served. Default: true when `withArgus` itself turned `productionBrowserSourceMaps` on, false
39
+ * when you enabled it in your own config.
40
+ */
41
+ deleteBrowserMapsAfterUpload?: boolean;
42
+ /** Public path of the browser chunks. Default: the path of `assetPrefix`, else `basePath`, + `/_next/`. */
43
+ urlPrefix?: string;
44
+ env?: Record<string, string | undefined>;
45
+ /** Where upload progress and warnings go. Default `console.log`. */
46
+ log?: (line: string) => void;
47
+ }
48
+ /** The pair of ids a Next build uses. */
49
+ declare function nextArtifactSetIds(options?: NextArgusOptions): {
50
+ web: string | undefined;
51
+ node: string | undefined;
52
+ };
53
+ /** `/_next/` below the path the browser loads chunks from. */
54
+ declare function nextUrlPrefix(config: Record<string, unknown>): string;
55
+ /** Accepts a config object or a config function (sync or async), like other Next plugins. */
56
+ declare function withArgus<T extends NextConfigLike>(nextConfig: (phase: string, context?: unknown) => Promise<T>, options?: NextArgusOptions): (phase: string, context?: unknown) => Promise<T & NextConfigLike>;
57
+ declare function withArgus<T extends NextConfigLike>(nextConfig: (phase: string, context?: unknown) => T, options?: NextArgusOptions): (phase: string, context?: unknown) => T & NextConfigLike;
58
+ declare function withArgus<T extends NextConfigLike>(nextConfig: T, options?: NextArgusOptions): T & NextConfigLike;
59
+
60
+ export { type NextArgusOptions, type NextConfigLike, nextArtifactSetIds, nextUrlPrefix, withArgus };
package/dist/next.d.ts ADDED
@@ -0,0 +1,60 @@
1
+ type WebpackHook = (config: any, context: any) => any;
2
+ interface NextConfigLike {
3
+ env?: Record<string, string | undefined>;
4
+ productionBrowserSourceMaps?: boolean;
5
+ webpack?: WebpackHook | null;
6
+ [key: string]: unknown;
7
+ }
8
+ interface NextArgusOptions {
9
+ /**
10
+ * Artifact set of the browser chunks. Env `ARGUS_ARTIFACT_SET_ID_WEB` / `ARGUS_ARTIFACT_SET_ID` wins.
11
+ * When neither is given and this build will upload, a fresh id is generated for the build.
12
+ */
13
+ artifactSetId?: string;
14
+ /** Artifact set of the server chunks. Default `<artifactSetId>-node` (env `ARGUS_ARTIFACT_SET_ID_NODE` wins). */
15
+ serverArtifactSetId?: string;
16
+ /**
17
+ * Emit browser source maps (`productionBrowserSourceMaps`). Default: true for a build that uploads
18
+ * them, false otherwise (maps left in the output would be served publicly). Pass true when you
19
+ * upload in a separate step with `argus-build upload next --delete-maps`.
20
+ */
21
+ browserSourceMaps?: boolean;
22
+ /**
23
+ * webpack builds only: set `devtool = 'source-map'` for the production server compilation so
24
+ * `.next/server/**.js.map` exists. Default: true when this build uploads (a server set needs
25
+ * its maps), else false. Turbopack writes server maps on its own.
26
+ */
27
+ serverSourceMaps?: boolean;
28
+ /**
29
+ * Upload source maps at the end of `next build`. `'auto'` (default): when `ARGUS_UPLOAD_KEY`
30
+ * and `ARGUS_URL` are both set, otherwise nothing happens and nothing is printed. `true`: always
31
+ * try (missing credentials are an upload error). `false`: never.
32
+ */
33
+ upload?: boolean | 'auto';
34
+ /** A failed upload warns and the build continues (`'warn'`, default) or fails the build (`'fail'`). */
35
+ onUploadError?: 'warn' | 'fail';
36
+ /**
37
+ * Remove `.next/static/**.map` once the upload step is over, so the maps are not deployed and
38
+ * served. Default: true when `withArgus` itself turned `productionBrowserSourceMaps` on, false
39
+ * when you enabled it in your own config.
40
+ */
41
+ deleteBrowserMapsAfterUpload?: boolean;
42
+ /** Public path of the browser chunks. Default: the path of `assetPrefix`, else `basePath`, + `/_next/`. */
43
+ urlPrefix?: string;
44
+ env?: Record<string, string | undefined>;
45
+ /** Where upload progress and warnings go. Default `console.log`. */
46
+ log?: (line: string) => void;
47
+ }
48
+ /** The pair of ids a Next build uses. */
49
+ declare function nextArtifactSetIds(options?: NextArgusOptions): {
50
+ web: string | undefined;
51
+ node: string | undefined;
52
+ };
53
+ /** `/_next/` below the path the browser loads chunks from. */
54
+ declare function nextUrlPrefix(config: Record<string, unknown>): string;
55
+ /** Accepts a config object or a config function (sync or async), like other Next plugins. */
56
+ declare function withArgus<T extends NextConfigLike>(nextConfig: (phase: string, context?: unknown) => Promise<T>, options?: NextArgusOptions): (phase: string, context?: unknown) => Promise<T & NextConfigLike>;
57
+ declare function withArgus<T extends NextConfigLike>(nextConfig: (phase: string, context?: unknown) => T, options?: NextArgusOptions): (phase: string, context?: unknown) => T & NextConfigLike;
58
+ declare function withArgus<T extends NextConfigLike>(nextConfig: T, options?: NextArgusOptions): T & NextConfigLike;
59
+
60
+ export { type NextArgusOptions, type NextConfigLike, nextArtifactSetIds, nextUrlPrefix, withArgus };