@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.
- package/LICENSE +21 -0
- package/README.md +218 -2
- package/bin/argus-build.cjs +8 -0
- package/dist/cli-C6Vb06ix.d.ts +317 -0
- package/dist/cli-Poqz5E1p.d.cts +317 -0
- package/dist/cli.cjs +1283 -0
- package/dist/cli.cjs.map +1 -0
- package/dist/cli.d.cts +2 -0
- package/dist/cli.d.ts +2 -0
- package/dist/cli.js +1254 -0
- package/dist/cli.js.map +1 -0
- package/dist/ids-T7ddcOxQ.d.cts +41 -0
- package/dist/ids-T7ddcOxQ.d.ts +41 -0
- package/dist/index.cjs +1548 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +31 -0
- package/dist/index.d.ts +31 -0
- package/dist/index.js +1486 -0
- package/dist/index.js.map +1 -0
- package/dist/metro.cjs +117 -0
- package/dist/metro.cjs.map +1 -0
- package/dist/metro.d.cts +40 -0
- package/dist/metro.d.ts +40 -0
- package/dist/metro.js +92 -0
- package/dist/metro.js.map +1 -0
- package/dist/next.cjs +609 -0
- package/dist/next.cjs.map +1 -0
- package/dist/next.d.cts +60 -0
- package/dist/next.d.ts +60 -0
- package/dist/next.js +582 -0
- package/dist/next.js.map +1 -0
- package/package.json +67 -3
package/dist/metro.js
ADDED
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
// src/metro.ts
|
|
2
|
+
import { createRequire } from "module";
|
|
3
|
+
import { join, resolve as resolve2 } from "path";
|
|
4
|
+
|
|
5
|
+
// src/ids.ts
|
|
6
|
+
import { randomBytes } from "crypto";
|
|
7
|
+
import { existsSync, mkdirSync, readFileSync, writeFileSync } from "fs";
|
|
8
|
+
import { dirname, resolve } from "path";
|
|
9
|
+
var ARTIFACT_SET_GLOBAL = "__ARGUS_ARTIFACT_SET_ID__";
|
|
10
|
+
var RE_ARTIFACT_SET_ID = /^[A-Za-z0-9._:-]{1,128}$/;
|
|
11
|
+
var GENERATED_MARK = "/* generated by @getargus/build-tools \u2014 do not edit, do not commit */";
|
|
12
|
+
function isValidArtifactSetId(id) {
|
|
13
|
+
return typeof id === "string" && RE_ARTIFACT_SET_ID.test(id);
|
|
14
|
+
}
|
|
15
|
+
function assertArtifactSetId(id, what = "artifact set id") {
|
|
16
|
+
if (!isValidArtifactSetId(id)) {
|
|
17
|
+
throw new Error(`Argus: invalid ${what} ${JSON.stringify(id)} \u2014 expected 1..128 chars of [A-Za-z0-9._:-]`);
|
|
18
|
+
}
|
|
19
|
+
return id;
|
|
20
|
+
}
|
|
21
|
+
function resolveArtifactSetId(input, platform, env = process.env) {
|
|
22
|
+
const fromEnv = env[`ARGUS_ARTIFACT_SET_ID_${platform.toUpperCase()}`] || env.ARGUS_ARTIFACT_SET_ID;
|
|
23
|
+
const fromOption = typeof input === "function" ? input(platform) : typeof input === "string" ? input : input?.[platform];
|
|
24
|
+
const id = fromEnv || fromOption;
|
|
25
|
+
return id ? assertArtifactSetId(id, `artifact set id for ${platform}`) : void 0;
|
|
26
|
+
}
|
|
27
|
+
function artifactSetPrelude(artifactSetId) {
|
|
28
|
+
const id = JSON.stringify(assertArtifactSetId(artifactSetId));
|
|
29
|
+
return `${GENERATED_MARK}
|
|
30
|
+
(function (g) {
|
|
31
|
+
g.${ARTIFACT_SET_GLOBAL} = ${id};
|
|
32
|
+
})(
|
|
33
|
+
typeof globalThis !== 'undefined' ? globalThis : typeof global !== 'undefined' ? global : typeof window !== 'undefined' ? window : this,
|
|
34
|
+
);
|
|
35
|
+
`;
|
|
36
|
+
}
|
|
37
|
+
function writeArtifactSetModule(options) {
|
|
38
|
+
const file = resolve(options.file);
|
|
39
|
+
const content = artifactSetPrelude(options.artifactSetId);
|
|
40
|
+
if (existsSync(file)) {
|
|
41
|
+
const current = readFileSync(file, "utf8");
|
|
42
|
+
if (current === content) return { file, changed: false };
|
|
43
|
+
if (!current.startsWith(GENERATED_MARK)) {
|
|
44
|
+
throw new Error(`Argus: refusing to overwrite ${file}: it was not generated by @getargus/build-tools (built output is never patched)`);
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
mkdirSync(dirname(file), { recursive: true });
|
|
48
|
+
writeFileSync(file, content);
|
|
49
|
+
return { file, changed: true };
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
// src/metro.ts
|
|
53
|
+
var PLATFORMS = ["ios", "android", "web"];
|
|
54
|
+
function withArgus(metroConfig, options = {}) {
|
|
55
|
+
const projectRoot = resolve2(options.projectRoot ?? metroConfig.projectRoot ?? process.cwd());
|
|
56
|
+
const outDir = resolve2(options.outDir ?? join(projectRoot, ".argus"));
|
|
57
|
+
const env = options.env ?? process.env;
|
|
58
|
+
const files = {};
|
|
59
|
+
for (const platform of PLATFORMS) {
|
|
60
|
+
const id = resolveArtifactSetId(options.artifactSetId, platform, env);
|
|
61
|
+
if (id) files[platform] = writeArtifactSetModule({ file: join(outDir, `argus-artifact-set.${platform}.js`), artifactSetId: id }).file;
|
|
62
|
+
}
|
|
63
|
+
const previous = metroConfig.serializer?.getPolyfills;
|
|
64
|
+
const warned = /* @__PURE__ */ new Set();
|
|
65
|
+
const basePolyfills = (ctx) => {
|
|
66
|
+
if (typeof previous === "function") return previous(ctx);
|
|
67
|
+
try {
|
|
68
|
+
const rnPolyfills = createRequire(join(projectRoot, "package.json"))("@react-native/js-polyfills");
|
|
69
|
+
return rnPolyfills();
|
|
70
|
+
} catch {
|
|
71
|
+
return [];
|
|
72
|
+
}
|
|
73
|
+
};
|
|
74
|
+
const getPolyfills = (ctx) => {
|
|
75
|
+
const base = basePolyfills(ctx);
|
|
76
|
+
const platform = String(ctx?.platform ?? "");
|
|
77
|
+
const file = files[platform];
|
|
78
|
+
if (!file) {
|
|
79
|
+
if (!warned.has(platform)) {
|
|
80
|
+
warned.add(platform);
|
|
81
|
+
(options.onMissing ?? ((p) => console.warn(`[argus] no artifact set id for platform "${p}": this bundle will not be matched to its source map (set ARGUS_ARTIFACT_SET_ID${p ? `_${p.toUpperCase()}` : ""})`)))(platform);
|
|
82
|
+
}
|
|
83
|
+
return base;
|
|
84
|
+
}
|
|
85
|
+
return [...base, file];
|
|
86
|
+
};
|
|
87
|
+
return { ...metroConfig, serializer: { ...metroConfig.serializer, getPolyfills } };
|
|
88
|
+
}
|
|
89
|
+
export {
|
|
90
|
+
withArgus
|
|
91
|
+
};
|
|
92
|
+
//# sourceMappingURL=metro.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/metro.ts","../src/ids.ts"],"sourcesContent":["/**\n * Metro integration: `withArgus(metroConfig, { artifactSetId })`.\n *\n * The id is compiled in as a generated polyfill script (`serializer.getPolyfills`), i.e. it is\n * part of the bundle Metro produces and of the source map Metro composes — before Hermes\n * compiles the bundle. Nothing is patched afterwards.\n */\nimport { createRequire } from 'node:module';\nimport { join, resolve } from 'node:path';\nimport { resolveArtifactSetId, writeArtifactSetModule, type ArtifactSetIdInput, type BuildPlatform } from './ids';\n\ntype PolyfillContext = { platform?: string | null };\nexport type GetPolyfills = (ctx: PolyfillContext) => readonly string[];\n\n/** The slice of a Metro config that is read or replaced (structural; Metro is not a dependency). */\nexport interface MetroConfigLike {\n projectRoot?: string;\n serializer?: { getPolyfills?: GetPolyfills; [key: string]: unknown };\n [key: string]: unknown;\n}\n\nexport interface MetroArgusOptions {\n /**\n * One id (single-platform builds such as an EAS build), or one per platform — required when a\n * single Metro process bundles several platforms (`expo export`), because an artifact set\n * belongs to exactly one platform. Environment variables win, see `resolveArtifactSetId`.\n */\n artifactSetId?: ArtifactSetIdInput;\n /** Default: `metroConfig.projectRoot`, else `process.cwd()`. */\n projectRoot?: string;\n /** Directory for the generated polyfill files, inside the project root. Default `<projectRoot>/.argus`. */\n outDir?: string;\n env?: Record<string, string | undefined>;\n /** Called once per platform that has no id. Default: `console.warn`. */\n onMissing?: (platform: string) => void;\n}\n\nconst PLATFORMS: BuildPlatform[] = ['ios', 'android', 'web'];\n\nexport type MetroConfigWithArgus<T> = Omit<T, 'serializer'> & { serializer: (T extends { serializer: infer S } ? S : unknown) & { getPolyfills: GetPolyfills } };\n\nexport function withArgus<T extends MetroConfigLike>(metroConfig: T, options: MetroArgusOptions = {}): MetroConfigWithArgus<T> {\n const projectRoot = resolve(options.projectRoot ?? metroConfig.projectRoot ?? process.cwd());\n const outDir = resolve(options.outDir ?? join(projectRoot, '.argus'));\n const env = options.env ?? process.env;\n\n // Generated when the config is evaluated, so the files exist before Metro crawls the project.\n const files: Partial<Record<BuildPlatform, string>> = {};\n for (const platform of PLATFORMS) {\n const id = resolveArtifactSetId(options.artifactSetId, platform, env);\n if (id) files[platform] = writeArtifactSetModule({ file: join(outDir, `argus-artifact-set.${platform}.js`), artifactSetId: id }).file;\n }\n\n const previous = metroConfig.serializer?.getPolyfills;\n const warned = new Set<string>();\n const basePolyfills = (ctx: PolyfillContext): readonly string[] => {\n if (typeof previous === 'function') return previous(ctx);\n // A config without getPolyfills would get React Native's default; setting ours must not drop it.\n try {\n const rnPolyfills = createRequire(join(projectRoot, 'package.json'))('@react-native/js-polyfills') as () => string[];\n return rnPolyfills();\n } catch {\n return [];\n }\n };\n const getPolyfills: GetPolyfills = (ctx) => {\n const base = basePolyfills(ctx);\n const platform = String(ctx?.platform ?? '');\n const file = files[platform as BuildPlatform];\n if (!file) {\n if (!warned.has(platform)) {\n warned.add(platform);\n (options.onMissing ??\n ((p: string) =>\n console.warn(`[argus] no artifact set id for platform \"${p}\": this bundle will not be matched to its source map (set ARGUS_ARTIFACT_SET_ID${p ? `_${p.toUpperCase()}` : ''})`)))(platform);\n }\n return base;\n }\n return [...base, file];\n };\n\n return { ...metroConfig, serializer: { ...metroConfig.serializer, getPolyfills } } as unknown as MetroConfigWithArgus<T>;\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"],"mappings":"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","names":["resolve","resolve"]}
|