@augmenting-integrations/deploy-tools 8.4.0 → 8.6.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/dist/chunk-A7IIB34G.js +0 -0
- package/dist/{chunk-Q5W2NBVE.js → chunk-RYVRSM25.js} +1 -1
- package/dist/chunk-RYVRSM25.js.map +1 -0
- package/dist/chunk-ZOKDIN2F.js +314 -0
- package/dist/chunk-ZOKDIN2F.js.map +1 -0
- package/dist/cli.js +8 -1
- package/dist/cli.js.map +1 -1
- package/dist/package-next-lambda.d.ts.map +1 -1
- package/dist/package-next-lambda.js +1 -1
- package/dist/validate-app-roster.d.ts +2 -0
- package/dist/validate-app-roster.d.ts.map +1 -0
- package/dist/validate-app-roster.js +8 -0
- package/dist/validate-app-roster.js.map +1 -0
- package/dist/yaml-parser.d.ts +6 -0
- package/dist/yaml-parser.d.ts.map +1 -0
- package/package.json +11 -10
- package/dist/chunk-Q5W2NBVE.js.map +0 -1
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Augmenting Integrations LLC
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/dist/chunk-A7IIB34G.js
CHANGED
|
File without changes
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/package-next-lambda.ts"],"sourcesContent":["import {\n cpSync,\n existsSync,\n lstatSync,\n mkdirSync,\n readdirSync,\n readlinkSync,\n realpathSync,\n rmSync,\n statSync,\n chmodSync,\n} from \"node:fs\";\nimport { dirname, join, resolve } from \"node:path\";\nimport process from \"node:process\";\n\n// =============================================================================\n// `augint package-next-lambda`\n//\n// Stages a Next.js standalone build into a Lambda-ready directory at\n// `.next/standalone/`. Lifts the symlink-flatten loop, force-copy of\n// runtime-required pnpm packages, Prisma .prisma hoist, and .pnpm purge\n// from each spoke's CI workflow so the logic is fixed in one place.\n//\n// Defaults assume the spoke convention:\n// - cwd contains .next/ (from `next build`)\n// - run.sh at cwd root (LWA entry)\n// - optional Makefile at cwd root (SAM BuildMethod=makefile)\n// - optional public/ and content/ at cwd root\n//\n// Flags:\n// --cwd <path> Override working directory\n// --no-prisma Skip Prisma .prisma hoist (use for apex)\n// --no-makefile Skip Makefile stage\n// =============================================================================\n\ntype Options = {\n cwd: string;\n prismaHoist: boolean;\n stageMakefile: boolean;\n};\n\nfunction parseArgs(argv: string[]): Options {\n let cwd = process.cwd();\n let prismaHoist = true;\n let stageMakefile = true;\n for (let i = 0; i < argv.length; i++) {\n const a = argv[i];\n if (a === \"--cwd\" || a === \"--root\") {\n const next = argv[i + 1];\n if (next) {\n cwd = resolve(next);\n i++;\n }\n } else if (a === \"--no-prisma\") {\n prismaHoist = false;\n } else if (a === \"--no-makefile\") {\n stageMakefile = false;\n }\n }\n return { cwd, prismaHoist, stageMakefile };\n}\n\nfunction copyIfExists(src: string, dst: string, opts: { dereference?: boolean } = {}) {\n if (!existsSync(src)) return;\n cpSync(src, dst, { recursive: true, dereference: !!opts.dereference, force: true });\n}\n\nfunction* walkSymlinks(root: string): Generator<string> {\n if (!existsSync(root)) return;\n const stack = [root];\n while (stack.length > 0) {\n const dir = stack.pop()!;\n let entries: Array<{\n name: string;\n isDirectory(): boolean;\n isSymbolicLink(): boolean;\n }>;\n try {\n entries = readdirSync(dir, { withFileTypes: true }) as unknown as Array<{\n name: string;\n isDirectory(): boolean;\n isSymbolicLink(): boolean;\n }>;\n } catch {\n continue;\n }\n for (const e of entries) {\n const full = join(dir, e.name);\n let lst: ReturnType<typeof lstatSync>;\n try {\n lst = lstatSync(full);\n } catch {\n continue;\n }\n if (lst.isSymbolicLink()) {\n yield full;\n } else if (lst.isDirectory()) {\n stack.push(full);\n }\n }\n }\n}\n\nfunction flattenSymlinks(roots: string[]) {\n // Multiple passes: dereferencing one link can expose a deeper one.\n for (let pass = 0; pass < 5; pass++) {\n let flattened = 0;\n for (const root of roots) {\n for (const link of walkSymlinks(root)) {\n let target: string;\n try {\n target = realpathSync(link);\n } catch {\n continue;\n }\n if (!existsSync(target)) continue;\n rmSync(link, { force: true });\n cpSync(target, link, { recursive: true, dereference: true, force: true });\n flattened++;\n }\n }\n if (flattened === 0) return;\n }\n}\n\nfunction copyRuntimePkg(cwd: string, pkg: string, standaloneNodeMods: string) {\n // Look in the standard tree and the .pnpm/node_modules hoist position.\n const candidates = [\n join(cwd, \"node_modules\", pkg),\n join(cwd, \"node_modules\", \".pnpm\", \"node_modules\", pkg),\n ];\n for (const src of candidates) {\n if (existsSync(src)) {\n const dst = join(standaloneNodeMods, pkg);\n rmSync(dst, { recursive: true, force: true });\n mkdirSync(dirname(dst), { recursive: true });\n cpSync(src, dst, { recursive: true, dereference: true, force: true });\n return;\n }\n }\n throw new Error(`runtime package not found: ${pkg}`);\n}\n\nfunction hoistPrismaClient(standaloneNodeMods: string) {\n // pnpm keeps .prisma/client inside the .pnpm subdir alongside @prisma/client.\n // After we flatten and purge .pnpm, that path disappears, but @prisma/client\n // does require('.prisma/client/...') at runtime. Hoist a copy first.\n const pnpmRoot = join(standaloneNodeMods, \".pnpm\");\n if (!existsSync(pnpmRoot)) return;\n const found = findFirst(pnpmRoot, (full) =>\n full.endsWith(join(\"node_modules\", \".prisma\", \"client\")),\n );\n if (!found) return;\n const dst = join(standaloneNodeMods, \".prisma\", \"client\");\n mkdirSync(dirname(dst), { recursive: true });\n cpSync(found, dst, { recursive: true, dereference: true, force: true });\n}\n\nfunction findFirst(root: string, predicate: (path: string) => boolean): string | null {\n const stack = [root];\n while (stack.length > 0) {\n const dir = stack.pop()!;\n let entries: Array<{\n name: string;\n isDirectory(): boolean;\n isSymbolicLink(): boolean;\n }>;\n try {\n entries = readdirSync(dir, { withFileTypes: true }) as unknown as Array<{\n name: string;\n isDirectory(): boolean;\n isSymbolicLink(): boolean;\n }>;\n } catch {\n continue;\n }\n for (const e of entries) {\n const full = join(dir, e.name);\n if (predicate(full)) return full;\n if (e.isDirectory()) stack.push(full);\n }\n }\n return null;\n}\n\nexport async function runPackageNextLambda(argv: string[]): Promise<void> {\n const opts = parseArgs(argv);\n const cwd = opts.cwd;\n const standalone = join(cwd, \".next\", \"standalone\");\n if (!existsSync(standalone)) {\n process.stderr.write(\n `package-next-lambda: ${standalone} missing. Run \\`next build\\` first.\\n`,\n );\n process.exit(1);\n }\n\n // ----- Stage static + public + content + run.sh + Makefile + manifest -----\n mkdirSync(join(standalone, \".next\"), { recursive: true });\n copyIfExists(join(cwd, \".next\", \"static\"), join(standalone, \".next\", \"static\"));\n copyIfExists(join(cwd, \"public\"), join(standalone, \"public\"));\n copyIfExists(join(cwd, \"content\"), join(standalone, \"content\"));\n copyIfExists(join(cwd, \"app.manifest.json\"), join(standalone, \"app.manifest.json\"));\n const runSh = join(cwd, \"run.sh\");\n if (existsSync(runSh)) {\n cpSync(runSh, join(standalone, \"run.sh\"));\n try {\n chmodSync(join(standalone, \"run.sh\"), 0o755);\n } catch {\n // chmod may fail on Windows runners; ignore.\n }\n }\n if (opts.stageMakefile) {\n copyIfExists(join(cwd, \"Makefile\"), join(standalone, \"Makefile\"));\n }\n\n // ----- Flatten pnpm symlinks (Lambda runtime can't follow them) -----\n flattenSymlinks([\n join(standalone, \"node_modules\"),\n join(standalone, \".next\", \"node_modules\"),\n ]);\n\n // ----- Force-copy known runtime-required packages -----\n const standaloneNodeMods = join(standalone, \"node_modules\");\n for (const pkg of [\"@swc/helpers\", \"@next/env\"]) {\n try {\n copyRuntimePkg(cwd, pkg, standaloneNodeMods);\n } catch (err) {\n process.stderr.write(\n `package-next-lambda: ${(err as Error).message}\\n` +\n \"Consider adding the package to dependencies or removing it from the runtime list.\\n\",\n );\n process.exit(1);\n }\n }\n\n // ----- Prisma .prisma hoist (spokes with a data plane) -----\n if (opts.prismaHoist) {\n hoistPrismaClient(standaloneNodeMods);\n }\n\n // ----- Purge .pnpm (unreferenced after symlink flatten) -----\n const pnpmRoot = join(standaloneNodeMods, \".pnpm\");\n if (existsSync(pnpmRoot)) {\n rmSync(pnpmRoot, { recursive: true, force: true });\n }\n\n // ----- Report size -----\n const bytes = directorySize(standalone);\n process.stdout.write(\n `package-next-lambda: staged ${standalone} (${(bytes / 1024 / 1024).toFixed(1)} MB)\\n`,\n );\n}\n\nfunction directorySize(root: string): number {\n let total = 0;\n const stack = [root];\n while (stack.length > 0) {\n const dir = stack.pop()!;\n let entries: Array<{\n name: string;\n isDirectory(): boolean;\n isSymbolicLink(): boolean;\n }>;\n try {\n entries = readdirSync(dir, { withFileTypes: true }) as unknown as Array<{\n name: string;\n isDirectory(): boolean;\n isSymbolicLink(): boolean;\n }>;\n } catch {\n continue;\n }\n for (const e of entries) {\n const full = join(dir, e.name);\n try {\n if (e.isDirectory()) {\n stack.push(full);\n } else {\n total += statSync(full).size;\n }\n } catch {\n // ignore unreadable\n }\n }\n }\n return total;\n}\n\nvoid readlinkSync; // referenced for completeness in walk; silence unused warning\n\nconst isDirectInvocation =\n import.meta.url === `file://${process.argv[1]}` ||\n process.argv[1]?.endsWith(\"package-next-lambda.js\");\nif (isDirectInvocation) {\n runPackageNextLambda(process.argv.slice(2)).catch((err) => {\n process.stderr.write(\n `package-next-lambda: ${err instanceof Error ? err.message : String(err)}\\n`,\n );\n process.exit(1);\n });\n}\n"],"mappings":";;;AAAA;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OACK;AACP,SAAS,SAAS,MAAM,eAAe;AACvC,OAAO,aAAa;AA4BpB,SAAS,UAAU,MAAyB;AAC1C,MAAI,MAAM,QAAQ,IAAI;AACtB,MAAI,cAAc;AAClB,MAAI,gBAAgB;AACpB,WAAS,IAAI,GAAG,IAAI,KAAK,QAAQ,KAAK;AACpC,UAAM,IAAI,KAAK,CAAC;AAChB,QAAI,MAAM,WAAW,MAAM,UAAU;AACnC,YAAM,OAAO,KAAK,IAAI,CAAC;AACvB,UAAI,MAAM;AACR,cAAM,QAAQ,IAAI;AAClB;AAAA,MACF;AAAA,IACF,WAAW,MAAM,eAAe;AAC9B,oBAAc;AAAA,IAChB,WAAW,MAAM,iBAAiB;AAChC,sBAAgB;AAAA,IAClB;AAAA,EACF;AACA,SAAO,EAAE,KAAK,aAAa,cAAc;AAC3C;AAEA,SAAS,aAAa,KAAa,KAAa,OAAkC,CAAC,GAAG;AACpF,MAAI,CAAC,WAAW,GAAG,EAAG;AACtB,SAAO,KAAK,KAAK,EAAE,WAAW,MAAM,aAAa,CAAC,CAAC,KAAK,aAAa,OAAO,KAAK,CAAC;AACpF;AAEA,UAAU,aAAa,MAAiC;AACtD,MAAI,CAAC,WAAW,IAAI,EAAG;AACvB,QAAM,QAAQ,CAAC,IAAI;AACnB,SAAO,MAAM,SAAS,GAAG;AACvB,UAAM,MAAM,MAAM,IAAI;AACtB,QAAI;AAKJ,QAAI;AACF,gBAAU,YAAY,KAAK,EAAE,eAAe,KAAK,CAAC;AAAA,IAKpD,QAAQ;AACN;AAAA,IACF;AACA,eAAW,KAAK,SAAS;AACvB,YAAM,OAAO,KAAK,KAAK,EAAE,IAAI;AAC7B,UAAI;AACJ,UAAI;AACF,cAAM,UAAU,IAAI;AAAA,MACtB,QAAQ;AACN;AAAA,MACF;AACA,UAAI,IAAI,eAAe,GAAG;AACxB,cAAM;AAAA,MACR,WAAW,IAAI,YAAY,GAAG;AAC5B,cAAM,KAAK,IAAI;AAAA,MACjB;AAAA,IACF;AAAA,EACF;AACF;AAEA,SAAS,gBAAgB,OAAiB;AAExC,WAAS,OAAO,GAAG,OAAO,GAAG,QAAQ;AACnC,QAAI,YAAY;AAChB,eAAW,QAAQ,OAAO;AACxB,iBAAW,QAAQ,aAAa,IAAI,GAAG;AACrC,YAAI;AACJ,YAAI;AACF,mBAAS,aAAa,IAAI;AAAA,QAC5B,QAAQ;AACN;AAAA,QACF;AACA,YAAI,CAAC,WAAW,MAAM,EAAG;AACzB,eAAO,MAAM,EAAE,OAAO,KAAK,CAAC;AAC5B,eAAO,QAAQ,MAAM,EAAE,WAAW,MAAM,aAAa,MAAM,OAAO,KAAK,CAAC;AACxE;AAAA,MACF;AAAA,IACF;AACA,QAAI,cAAc,EAAG;AAAA,EACvB;AACF;AAEA,SAAS,eAAe,KAAa,KAAa,oBAA4B;AAE5E,QAAM,aAAa;AAAA,IACjB,KAAK,KAAK,gBAAgB,GAAG;AAAA,IAC7B,KAAK,KAAK,gBAAgB,SAAS,gBAAgB,GAAG;AAAA,EACxD;AACA,aAAW,OAAO,YAAY;AAC5B,QAAI,WAAW,GAAG,GAAG;AACnB,YAAM,MAAM,KAAK,oBAAoB,GAAG;AACxC,aAAO,KAAK,EAAE,WAAW,MAAM,OAAO,KAAK,CAAC;AAC5C,gBAAU,QAAQ,GAAG,GAAG,EAAE,WAAW,KAAK,CAAC;AAC3C,aAAO,KAAK,KAAK,EAAE,WAAW,MAAM,aAAa,MAAM,OAAO,KAAK,CAAC;AACpE;AAAA,IACF;AAAA,EACF;AACA,QAAM,IAAI,MAAM,8BAA8B,GAAG,EAAE;AACrD;AAEA,SAAS,kBAAkB,oBAA4B;AAIrD,QAAM,WAAW,KAAK,oBAAoB,OAAO;AACjD,MAAI,CAAC,WAAW,QAAQ,EAAG;AAC3B,QAAM,QAAQ;AAAA,IAAU;AAAA,IAAU,CAAC,SACjC,KAAK,SAAS,KAAK,gBAAgB,WAAW,QAAQ,CAAC;AAAA,EACzD;AACA,MAAI,CAAC,MAAO;AACZ,QAAM,MAAM,KAAK,oBAAoB,WAAW,QAAQ;AACxD,YAAU,QAAQ,GAAG,GAAG,EAAE,WAAW,KAAK,CAAC;AAC3C,SAAO,OAAO,KAAK,EAAE,WAAW,MAAM,aAAa,MAAM,OAAO,KAAK,CAAC;AACxE;AAEA,SAAS,UAAU,MAAc,WAAqD;AACpF,QAAM,QAAQ,CAAC,IAAI;AACnB,SAAO,MAAM,SAAS,GAAG;AACvB,UAAM,MAAM,MAAM,IAAI;AACtB,QAAI;AAKJ,QAAI;AACF,gBAAU,YAAY,KAAK,EAAE,eAAe,KAAK,CAAC;AAAA,IAKpD,QAAQ;AACN;AAAA,IACF;AACA,eAAW,KAAK,SAAS;AACvB,YAAM,OAAO,KAAK,KAAK,EAAE,IAAI;AAC7B,UAAI,UAAU,IAAI,EAAG,QAAO;AAC5B,UAAI,EAAE,YAAY,EAAG,OAAM,KAAK,IAAI;AAAA,IACtC;AAAA,EACF;AACA,SAAO;AACT;AAEA,eAAsB,qBAAqB,MAA+B;AACxE,QAAM,OAAO,UAAU,IAAI;AAC3B,QAAM,MAAM,KAAK;AACjB,QAAM,aAAa,KAAK,KAAK,SAAS,YAAY;AAClD,MAAI,CAAC,WAAW,UAAU,GAAG;AAC3B,YAAQ,OAAO;AAAA,MACb,wBAAwB,UAAU;AAAA;AAAA,IACpC;AACA,YAAQ,KAAK,CAAC;AAAA,EAChB;AAGA,YAAU,KAAK,YAAY,OAAO,GAAG,EAAE,WAAW,KAAK,CAAC;AACxD,eAAa,KAAK,KAAK,SAAS,QAAQ,GAAG,KAAK,YAAY,SAAS,QAAQ,CAAC;AAC9E,eAAa,KAAK,KAAK,QAAQ,GAAG,KAAK,YAAY,QAAQ,CAAC;AAC5D,eAAa,KAAK,KAAK,SAAS,GAAG,KAAK,YAAY,SAAS,CAAC;AAC9D,eAAa,KAAK,KAAK,mBAAmB,GAAG,KAAK,YAAY,mBAAmB,CAAC;AAClF,QAAM,QAAQ,KAAK,KAAK,QAAQ;AAChC,MAAI,WAAW,KAAK,GAAG;AACrB,WAAO,OAAO,KAAK,YAAY,QAAQ,CAAC;AACxC,QAAI;AACF,gBAAU,KAAK,YAAY,QAAQ,GAAG,GAAK;AAAA,IAC7C,QAAQ;AAAA,IAER;AAAA,EACF;AACA,MAAI,KAAK,eAAe;AACtB,iBAAa,KAAK,KAAK,UAAU,GAAG,KAAK,YAAY,UAAU,CAAC;AAAA,EAClE;AAGA,kBAAgB;AAAA,IACd,KAAK,YAAY,cAAc;AAAA,IAC/B,KAAK,YAAY,SAAS,cAAc;AAAA,EAC1C,CAAC;AAGD,QAAM,qBAAqB,KAAK,YAAY,cAAc;AAC1D,aAAW,OAAO,CAAC,gBAAgB,WAAW,GAAG;AAC/C,QAAI;AACF,qBAAe,KAAK,KAAK,kBAAkB;AAAA,IAC7C,SAAS,KAAK;AACZ,cAAQ,OAAO;AAAA,QACb,wBAAyB,IAAc,OAAO;AAAA;AAAA;AAAA,MAEhD;AACA,cAAQ,KAAK,CAAC;AAAA,IAChB;AAAA,EACF;AAGA,MAAI,KAAK,aAAa;AACpB,sBAAkB,kBAAkB;AAAA,EACtC;AAGA,QAAM,WAAW,KAAK,oBAAoB,OAAO;AACjD,MAAI,WAAW,QAAQ,GAAG;AACxB,WAAO,UAAU,EAAE,WAAW,MAAM,OAAO,KAAK,CAAC;AAAA,EACnD;AAGA,QAAM,QAAQ,cAAc,UAAU;AACtC,UAAQ,OAAO;AAAA,IACb,+BAA+B,UAAU,MAAM,QAAQ,OAAO,MAAM,QAAQ,CAAC,CAAC;AAAA;AAAA,EAChF;AACF;AAEA,SAAS,cAAc,MAAsB;AAC3C,MAAI,QAAQ;AACZ,QAAM,QAAQ,CAAC,IAAI;AACnB,SAAO,MAAM,SAAS,GAAG;AACvB,UAAM,MAAM,MAAM,IAAI;AACtB,QAAI;AAKJ,QAAI;AACF,gBAAU,YAAY,KAAK,EAAE,eAAe,KAAK,CAAC;AAAA,IAKpD,QAAQ;AACN;AAAA,IACF;AACA,eAAW,KAAK,SAAS;AACvB,YAAM,OAAO,KAAK,KAAK,EAAE,IAAI;AAC7B,UAAI;AACF,YAAI,EAAE,YAAY,GAAG;AACnB,gBAAM,KAAK,IAAI;AAAA,QACjB,OAAO;AACL,mBAAS,SAAS,IAAI,EAAE;AAAA,QAC1B;AAAA,MACF,QAAQ;AAAA,MAER;AAAA,IACF;AAAA,EACF;AACA,SAAO;AACT;AAIA,IAAM,qBACJ,YAAY,QAAQ,UAAU,QAAQ,KAAK,CAAC,CAAC,MAC7C,QAAQ,KAAK,CAAC,GAAG,SAAS,wBAAwB;AACpD,IAAI,oBAAoB;AACtB,uBAAqB,QAAQ,KAAK,MAAM,CAAC,CAAC,EAAE,MAAM,CAAC,QAAQ;AACzD,YAAQ,OAAO;AAAA,MACb,wBAAwB,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG,CAAC;AAAA;AAAA,IAC1E;AACA,YAAQ,KAAK,CAAC;AAAA,EAChB,CAAC;AACH;","names":[]}
|
|
@@ -0,0 +1,314 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
// src/validate-app-roster.ts
|
|
4
|
+
import { readFileSync, existsSync } from "fs";
|
|
5
|
+
import { resolve } from "path";
|
|
6
|
+
import process from "process";
|
|
7
|
+
import {
|
|
8
|
+
validateAppsRoster
|
|
9
|
+
} from "@augmenting-integrations/platform/apps-roster";
|
|
10
|
+
|
|
11
|
+
// src/yaml-parser.ts
|
|
12
|
+
var KEY_VALUE = /^([A-Za-z_][A-Za-z0-9_]*):\s*(.*)$/;
|
|
13
|
+
var KEY_PREFIX = /^[A-Za-z_][A-Za-z0-9_]*:/;
|
|
14
|
+
var IDENT_START = /^[A-Za-z_]/;
|
|
15
|
+
var INT_RE = /^-?\d+$/;
|
|
16
|
+
var FLOAT_RE = /^-?\d+\.\d+$/;
|
|
17
|
+
function parseScalar(raw) {
|
|
18
|
+
const s = raw.trim();
|
|
19
|
+
if (s === "") return "";
|
|
20
|
+
if (s === "null" || s === "~") return null;
|
|
21
|
+
if (s === "true") return true;
|
|
22
|
+
if (s === "false") return false;
|
|
23
|
+
if (INT_RE.test(s)) return Number(s);
|
|
24
|
+
if (FLOAT_RE.test(s)) return Number(s);
|
|
25
|
+
if (s.startsWith('"') && s.endsWith('"') || s.startsWith("'") && s.endsWith("'")) {
|
|
26
|
+
return s.slice(1, -1);
|
|
27
|
+
}
|
|
28
|
+
return s;
|
|
29
|
+
}
|
|
30
|
+
function parseInlineArray(s) {
|
|
31
|
+
const inner = s.slice(1, -1).trim();
|
|
32
|
+
if (inner === "") return [];
|
|
33
|
+
return inner.split(",").map((x) => parseScalar(x));
|
|
34
|
+
}
|
|
35
|
+
function tokenize(source) {
|
|
36
|
+
const out = [];
|
|
37
|
+
for (const raw of source.split("\n")) {
|
|
38
|
+
const noComment = raw.replace(/\s+#.*$/, "").replace(/^\s*#.*$/, "");
|
|
39
|
+
if (noComment.trim() === "") continue;
|
|
40
|
+
const indent = noComment.length - noComment.replace(/^ +/, "").length;
|
|
41
|
+
out.push({ indent, raw: noComment.slice(indent) });
|
|
42
|
+
}
|
|
43
|
+
return out;
|
|
44
|
+
}
|
|
45
|
+
function matchKeyValue(line) {
|
|
46
|
+
const m = line.match(KEY_VALUE);
|
|
47
|
+
if (!m) return null;
|
|
48
|
+
return [m[1], m[2]];
|
|
49
|
+
}
|
|
50
|
+
function parseValue(lines, i, baseIndent) {
|
|
51
|
+
if (i >= lines.length) return { value: null, consumed: 0 };
|
|
52
|
+
const next = lines[i];
|
|
53
|
+
if (next.indent <= baseIndent) return { value: null, consumed: 0 };
|
|
54
|
+
if (next.raw.startsWith("- ")) {
|
|
55
|
+
return parseSequence(lines, i, next.indent);
|
|
56
|
+
}
|
|
57
|
+
return parseMap(lines, i, next.indent);
|
|
58
|
+
}
|
|
59
|
+
function parseSequence(lines, start, indent) {
|
|
60
|
+
const out = [];
|
|
61
|
+
let i = start;
|
|
62
|
+
while (i < lines.length) {
|
|
63
|
+
const line = lines[i];
|
|
64
|
+
if (line.indent < indent) break;
|
|
65
|
+
if (line.indent === indent && line.raw.startsWith("- ")) {
|
|
66
|
+
const rest = line.raw.slice(2);
|
|
67
|
+
if (KEY_PREFIX.test(rest)) {
|
|
68
|
+
const virtualMap = {};
|
|
69
|
+
const kv = matchKeyValue(rest);
|
|
70
|
+
if (kv) {
|
|
71
|
+
const [key, valRaw] = kv;
|
|
72
|
+
if (valRaw === "") {
|
|
73
|
+
const sub = parseValue(lines, i + 1, line.indent);
|
|
74
|
+
virtualMap[key] = sub.value;
|
|
75
|
+
i += 1 + sub.consumed;
|
|
76
|
+
} else if (valRaw.startsWith("[") && valRaw.endsWith("]")) {
|
|
77
|
+
virtualMap[key] = parseInlineArray(valRaw);
|
|
78
|
+
i++;
|
|
79
|
+
} else {
|
|
80
|
+
virtualMap[key] = parseScalar(valRaw);
|
|
81
|
+
i++;
|
|
82
|
+
}
|
|
83
|
+
} else {
|
|
84
|
+
i++;
|
|
85
|
+
}
|
|
86
|
+
const mapIndent = line.indent + 2;
|
|
87
|
+
while (i < lines.length) {
|
|
88
|
+
const inner = lines[i];
|
|
89
|
+
if (inner.indent < mapIndent) break;
|
|
90
|
+
if (inner.indent === mapIndent && IDENT_START.test(inner.raw)) {
|
|
91
|
+
const skv = matchKeyValue(inner.raw);
|
|
92
|
+
if (!skv) {
|
|
93
|
+
i++;
|
|
94
|
+
continue;
|
|
95
|
+
}
|
|
96
|
+
const [k, v] = skv;
|
|
97
|
+
if (v === "") {
|
|
98
|
+
const sub = parseValue(lines, i + 1, inner.indent);
|
|
99
|
+
virtualMap[k] = sub.value;
|
|
100
|
+
i += 1 + sub.consumed;
|
|
101
|
+
} else if (v.startsWith("[") && v.endsWith("]")) {
|
|
102
|
+
virtualMap[k] = parseInlineArray(v);
|
|
103
|
+
i++;
|
|
104
|
+
} else {
|
|
105
|
+
virtualMap[k] = parseScalar(v);
|
|
106
|
+
i++;
|
|
107
|
+
}
|
|
108
|
+
} else {
|
|
109
|
+
break;
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
out.push(virtualMap);
|
|
113
|
+
} else if (rest.startsWith("[") && rest.endsWith("]")) {
|
|
114
|
+
out.push(parseInlineArray(rest));
|
|
115
|
+
i++;
|
|
116
|
+
} else {
|
|
117
|
+
out.push(parseScalar(rest));
|
|
118
|
+
i++;
|
|
119
|
+
}
|
|
120
|
+
} else {
|
|
121
|
+
break;
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
return { value: out, consumed: i - start };
|
|
125
|
+
}
|
|
126
|
+
function parseMap(lines, start, indent) {
|
|
127
|
+
const out = {};
|
|
128
|
+
let i = start;
|
|
129
|
+
while (i < lines.length) {
|
|
130
|
+
const line = lines[i];
|
|
131
|
+
if (line.indent < indent) break;
|
|
132
|
+
if (line.indent !== indent) {
|
|
133
|
+
i++;
|
|
134
|
+
continue;
|
|
135
|
+
}
|
|
136
|
+
const kv = matchKeyValue(line.raw);
|
|
137
|
+
if (!kv) {
|
|
138
|
+
i++;
|
|
139
|
+
continue;
|
|
140
|
+
}
|
|
141
|
+
const [key, valRaw] = kv;
|
|
142
|
+
if (valRaw === "") {
|
|
143
|
+
const sub = parseValue(lines, i + 1, indent);
|
|
144
|
+
out[key] = sub.value;
|
|
145
|
+
i += 1 + sub.consumed;
|
|
146
|
+
} else if (valRaw.startsWith("[") && valRaw.endsWith("]")) {
|
|
147
|
+
out[key] = parseInlineArray(valRaw);
|
|
148
|
+
i++;
|
|
149
|
+
} else {
|
|
150
|
+
out[key] = parseScalar(valRaw);
|
|
151
|
+
i++;
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
return { value: out, consumed: i - start };
|
|
155
|
+
}
|
|
156
|
+
function parseYamlSubset(source) {
|
|
157
|
+
const lines = tokenize(source);
|
|
158
|
+
const result = parseMap(lines, 0, 0);
|
|
159
|
+
return result.value;
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
// src/validate-app-roster.ts
|
|
163
|
+
function parseArgs(argv) {
|
|
164
|
+
const flags = { yaml: "", json: "", spokes: [] };
|
|
165
|
+
for (let i = 0; i < argv.length; i++) {
|
|
166
|
+
const a = argv[i];
|
|
167
|
+
const next = argv[i + 1];
|
|
168
|
+
if (a === "--yaml" && next) {
|
|
169
|
+
flags.yaml = resolve(next);
|
|
170
|
+
i++;
|
|
171
|
+
} else if (a === "--json" && next) {
|
|
172
|
+
flags.json = resolve(next);
|
|
173
|
+
i++;
|
|
174
|
+
} else if (a === "--spoke" && next) {
|
|
175
|
+
flags.spokes.push(resolve(next));
|
|
176
|
+
i++;
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
return flags;
|
|
180
|
+
}
|
|
181
|
+
function loadJsonFile(path) {
|
|
182
|
+
if (!existsSync(path)) throw new Error(`file not found: ${path}`);
|
|
183
|
+
const raw = readFileSync(path, "utf8");
|
|
184
|
+
try {
|
|
185
|
+
return JSON.parse(raw);
|
|
186
|
+
} catch (err) {
|
|
187
|
+
throw new Error(`invalid JSON in ${path}: ${err.message}`, {
|
|
188
|
+
cause: err
|
|
189
|
+
});
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
function loadYamlFile(path) {
|
|
193
|
+
if (!existsSync(path)) throw new Error(`file not found: ${path}`);
|
|
194
|
+
const raw = readFileSync(path, "utf8");
|
|
195
|
+
try {
|
|
196
|
+
return parseYamlSubset(raw);
|
|
197
|
+
} catch (err) {
|
|
198
|
+
throw new Error(`invalid YAML in ${path}: ${err.message}`, {
|
|
199
|
+
cause: err
|
|
200
|
+
});
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
function validateOrFail(label, raw) {
|
|
204
|
+
const result = validateAppsRoster(raw);
|
|
205
|
+
if (!result.ok) {
|
|
206
|
+
const lines = result.errors.map((e) => ` - ${e.path}: ${e.message}`).join("\n");
|
|
207
|
+
throw new Error(`${label} failed schema validation:
|
|
208
|
+
${lines}`);
|
|
209
|
+
}
|
|
210
|
+
return result.value;
|
|
211
|
+
}
|
|
212
|
+
function rostersAgree(a, b) {
|
|
213
|
+
const errors = [];
|
|
214
|
+
if (a.apps.length !== b.apps.length) {
|
|
215
|
+
errors.push(`app count mismatch: ${a.apps.length} vs ${b.apps.length}`);
|
|
216
|
+
}
|
|
217
|
+
const bySlugA = new Map(a.apps.map((x) => [x.slug, x]));
|
|
218
|
+
const bySlugB = new Map(b.apps.map((x) => [x.slug, x]));
|
|
219
|
+
for (const slug of /* @__PURE__ */ new Set([...bySlugA.keys(), ...bySlugB.keys()])) {
|
|
220
|
+
const ea = bySlugA.get(slug);
|
|
221
|
+
const eb = bySlugB.get(slug);
|
|
222
|
+
if (!ea) {
|
|
223
|
+
errors.push(`apps[slug=${slug}] missing from first file`);
|
|
224
|
+
continue;
|
|
225
|
+
}
|
|
226
|
+
if (!eb) {
|
|
227
|
+
errors.push(`apps[slug=${slug}] missing from second file`);
|
|
228
|
+
continue;
|
|
229
|
+
}
|
|
230
|
+
const keys = [
|
|
231
|
+
"role",
|
|
232
|
+
"subdomain",
|
|
233
|
+
"displayName",
|
|
234
|
+
"navOrder",
|
|
235
|
+
"requiredIdentityGroups",
|
|
236
|
+
"enabled"
|
|
237
|
+
];
|
|
238
|
+
for (const k of keys) {
|
|
239
|
+
const va = JSON.stringify(ea[k] ?? null);
|
|
240
|
+
const vb = JSON.stringify(eb[k] ?? null);
|
|
241
|
+
if (va !== vb) {
|
|
242
|
+
errors.push(`apps[slug=${slug}].${String(k)}: ${va} vs ${vb}`);
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
}
|
|
246
|
+
return errors;
|
|
247
|
+
}
|
|
248
|
+
async function runValidateAppRoster(argv) {
|
|
249
|
+
const flags = parseArgs(argv);
|
|
250
|
+
if (!flags.yaml && !flags.json && flags.spokes.length === 0) {
|
|
251
|
+
process.stderr.write(
|
|
252
|
+
"Usage: augint validate-app-roster [--yaml <path>] [--json <path>] [--spoke <path>]...\n\nSchema-validate each file individually. If both --yaml and --json are\nprovided, also cross-check they agree. Each --spoke is cross-checked\nagainst --json (or, if no --json, against --yaml).\n"
|
|
253
|
+
);
|
|
254
|
+
process.exit(2);
|
|
255
|
+
}
|
|
256
|
+
try {
|
|
257
|
+
const yamlRoster = flags.yaml ? validateOrFail(flags.yaml, loadYamlFile(flags.yaml)) : null;
|
|
258
|
+
const jsonRoster = flags.json ? validateOrFail(flags.json, loadJsonFile(flags.json)) : null;
|
|
259
|
+
if (yamlRoster && jsonRoster) {
|
|
260
|
+
const drift = rostersAgree(yamlRoster, jsonRoster);
|
|
261
|
+
if (drift.length > 0) {
|
|
262
|
+
process.stderr.write(
|
|
263
|
+
`validate-app-roster: ${flags.yaml} and ${flags.json} disagree:
|
|
264
|
+
` + drift.map((d) => ` - ${d}`).join("\n") + "\n"
|
|
265
|
+
);
|
|
266
|
+
process.exit(1);
|
|
267
|
+
}
|
|
268
|
+
}
|
|
269
|
+
const cmp = jsonRoster ?? yamlRoster;
|
|
270
|
+
for (const spokePath of flags.spokes) {
|
|
271
|
+
const spokeRoster = validateOrFail(spokePath, loadJsonFile(spokePath));
|
|
272
|
+
if (cmp) {
|
|
273
|
+
const spokeDrift = rostersAgree(cmp, spokeRoster);
|
|
274
|
+
if (spokeDrift.length > 0) {
|
|
275
|
+
process.stderr.write(
|
|
276
|
+
`validate-app-roster: ${spokePath} disagrees with reference:
|
|
277
|
+
` + spokeDrift.map((d) => ` - ${d}`).join("\n") + "\n"
|
|
278
|
+
);
|
|
279
|
+
process.exit(1);
|
|
280
|
+
}
|
|
281
|
+
}
|
|
282
|
+
}
|
|
283
|
+
const reference = jsonRoster ?? yamlRoster;
|
|
284
|
+
const checked = [];
|
|
285
|
+
if (yamlRoster) checked.push("infra YAML");
|
|
286
|
+
if (jsonRoster) checked.push("apex JSON");
|
|
287
|
+
if (flags.spokes.length > 0) checked.push(`${flags.spokes.length} spoke(s)`);
|
|
288
|
+
process.stdout.write(
|
|
289
|
+
`validate-app-roster: OK -- ${reference?.apps.length ?? 0} apps; ${checked.join(" + ")} pass.
|
|
290
|
+
`
|
|
291
|
+
);
|
|
292
|
+
} catch (err) {
|
|
293
|
+
process.stderr.write(
|
|
294
|
+
`validate-app-roster: ${err instanceof Error ? err.message : String(err)}
|
|
295
|
+
`
|
|
296
|
+
);
|
|
297
|
+
process.exit(1);
|
|
298
|
+
}
|
|
299
|
+
}
|
|
300
|
+
var isDirectInvocation = import.meta.url === `file://${process.argv[1]}` || process.argv[1]?.endsWith("validate-app-roster.js");
|
|
301
|
+
if (isDirectInvocation) {
|
|
302
|
+
runValidateAppRoster(process.argv.slice(2)).catch((err) => {
|
|
303
|
+
process.stderr.write(
|
|
304
|
+
`validate-app-roster: ${err instanceof Error ? err.message : String(err)}
|
|
305
|
+
`
|
|
306
|
+
);
|
|
307
|
+
process.exit(1);
|
|
308
|
+
});
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
export {
|
|
312
|
+
runValidateAppRoster
|
|
313
|
+
};
|
|
314
|
+
//# sourceMappingURL=chunk-ZOKDIN2F.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/validate-app-roster.ts","../src/yaml-parser.ts"],"sourcesContent":["import { readFileSync, existsSync } from \"node:fs\";\nimport { resolve } from \"node:path\";\nimport process from \"node:process\";\n\nimport {\n validateAppsRoster,\n type AppsRoster,\n} from \"@augmenting-integrations/platform/apps-roster\";\n\nimport { parseYamlSubset } from \"./yaml-parser.js\";\n\n// =============================================================================\n// `augint validate-app-roster`\n//\n// Reads two files:\n// - infra/config/apps.yaml (canonical tenant roster)\n// - apex/config/apps.json (runtime mirror served by /api/apps)\n//\n// And, optionally:\n// - spoke /config/apps.json copies (each spoke ships its own /api/apps)\n//\n// Asserts:\n// 1. Each file individually passes the apps-roster schema (duplicate\n// slug/subdomain/navOrder, required fields, apex subdomain=\"\",\n// exactly one apex entry, etc.)\n// 2. The infra YAML and the apex JSON agree (semantic equality, not\n// string equality -- order-preserving)\n// 3. If --spoke <path>... is passed, each spoke's apps.json also agrees.\n//\n// Exits 0 on success with a one-line OK summary. Exit 1 on any failure\n// with a field-by-field error list.\n// =============================================================================\n\ntype Flags = {\n yaml: string;\n json: string;\n spokes: string[];\n cwd?: string;\n};\n\nfunction parseArgs(argv: string[]): Flags {\n const flags: Flags = { yaml: \"\", json: \"\", spokes: [] };\n for (let i = 0; i < argv.length; i++) {\n const a = argv[i];\n const next = argv[i + 1];\n if (a === \"--yaml\" && next) {\n flags.yaml = resolve(next);\n i++;\n } else if (a === \"--json\" && next) {\n flags.json = resolve(next);\n i++;\n } else if (a === \"--spoke\" && next) {\n flags.spokes.push(resolve(next));\n i++;\n }\n }\n return flags;\n}\n\nfunction loadJsonFile(path: string): unknown {\n if (!existsSync(path)) throw new Error(`file not found: ${path}`);\n const raw = readFileSync(path, \"utf8\");\n try {\n return JSON.parse(raw);\n } catch (err) {\n throw new Error(`invalid JSON in ${path}: ${(err as Error).message}`, {\n cause: err,\n });\n }\n}\n\nfunction loadYamlFile(path: string): unknown {\n if (!existsSync(path)) throw new Error(`file not found: ${path}`);\n const raw = readFileSync(path, \"utf8\");\n try {\n return parseYamlSubset(raw);\n } catch (err) {\n throw new Error(`invalid YAML in ${path}: ${(err as Error).message}`, {\n cause: err,\n });\n }\n}\n\nfunction validateOrFail(label: string, raw: unknown): AppsRoster {\n const result = validateAppsRoster(raw);\n if (!result.ok) {\n const lines = result.errors.map((e) => ` - ${e.path}: ${e.message}`).join(\"\\n\");\n throw new Error(`${label} failed schema validation:\\n${lines}`);\n }\n return result.value;\n}\n\nfunction rostersAgree(a: AppsRoster, b: AppsRoster): string[] {\n const errors: string[] = [];\n if (a.apps.length !== b.apps.length) {\n errors.push(`app count mismatch: ${a.apps.length} vs ${b.apps.length}`);\n }\n const bySlugA = new Map(a.apps.map((x) => [x.slug, x]));\n const bySlugB = new Map(b.apps.map((x) => [x.slug, x]));\n for (const slug of new Set([...bySlugA.keys(), ...bySlugB.keys()])) {\n const ea = bySlugA.get(slug);\n const eb = bySlugB.get(slug);\n if (!ea) {\n errors.push(`apps[slug=${slug}] missing from first file`);\n continue;\n }\n if (!eb) {\n errors.push(`apps[slug=${slug}] missing from second file`);\n continue;\n }\n const keys: (keyof typeof ea)[] = [\n \"role\",\n \"subdomain\",\n \"displayName\",\n \"navOrder\",\n \"requiredIdentityGroups\",\n \"enabled\",\n ];\n for (const k of keys) {\n const va = JSON.stringify(ea[k] ?? null);\n const vb = JSON.stringify(eb[k] ?? null);\n if (va !== vb) {\n errors.push(`apps[slug=${slug}].${String(k)}: ${va} vs ${vb}`);\n }\n }\n }\n return errors;\n}\n\nexport async function runValidateAppRoster(argv: string[]): Promise<void> {\n const flags = parseArgs(argv);\n\n if (!flags.yaml && !flags.json && flags.spokes.length === 0) {\n process.stderr.write(\n \"Usage: augint validate-app-roster [--yaml <path>] [--json <path>] [--spoke <path>]...\\n\" +\n \"\\n\" +\n \"Schema-validate each file individually. If both --yaml and --json are\\n\" +\n \"provided, also cross-check they agree. Each --spoke is cross-checked\\n\" +\n \"against --json (or, if no --json, against --yaml).\\n\",\n );\n process.exit(2);\n }\n\n try {\n const yamlRoster = flags.yaml\n ? validateOrFail(flags.yaml, loadYamlFile(flags.yaml))\n : null;\n const jsonRoster = flags.json\n ? validateOrFail(flags.json, loadJsonFile(flags.json))\n : null;\n\n if (yamlRoster && jsonRoster) {\n const drift = rostersAgree(yamlRoster, jsonRoster);\n if (drift.length > 0) {\n process.stderr.write(\n `validate-app-roster: ${flags.yaml} and ${flags.json} disagree:\\n` +\n drift.map((d) => ` - ${d}`).join(\"\\n\") +\n \"\\n\",\n );\n process.exit(1);\n }\n }\n\n const cmp = jsonRoster ?? yamlRoster;\n for (const spokePath of flags.spokes) {\n const spokeRoster = validateOrFail(spokePath, loadJsonFile(spokePath));\n if (cmp) {\n const spokeDrift = rostersAgree(cmp, spokeRoster);\n if (spokeDrift.length > 0) {\n process.stderr.write(\n `validate-app-roster: ${spokePath} disagrees with reference:\\n` +\n spokeDrift.map((d) => ` - ${d}`).join(\"\\n\") +\n \"\\n\",\n );\n process.exit(1);\n }\n }\n }\n\n const reference = jsonRoster ?? yamlRoster;\n const checked: string[] = [];\n if (yamlRoster) checked.push(\"infra YAML\");\n if (jsonRoster) checked.push(\"apex JSON\");\n if (flags.spokes.length > 0) checked.push(`${flags.spokes.length} spoke(s)`);\n process.stdout.write(\n `validate-app-roster: OK -- ${reference?.apps.length ?? 0} apps; ${checked.join(\" + \")} pass.\\n`,\n );\n } catch (err) {\n process.stderr.write(\n `validate-app-roster: ${err instanceof Error ? err.message : String(err)}\\n`,\n );\n process.exit(1);\n }\n}\n\nconst isDirectInvocation =\n import.meta.url === `file://${process.argv[1]}` ||\n process.argv[1]?.endsWith(\"validate-app-roster.js\");\nif (isDirectInvocation) {\n runValidateAppRoster(process.argv.slice(2)).catch((err) => {\n process.stderr.write(\n `validate-app-roster: ${err instanceof Error ? err.message : String(err)}\\n`,\n );\n process.exit(1);\n });\n}\n","// =============================================================================\n// Tiny YAML subset parser. Sufficient to read the tenant app roster shape:\n//\n// apps:\n// - slug: foo\n// role: spoke\n// subdomain: bar\n// displayName: Foo\n// navOrder: 10\n// requiredIdentityGroups: []\n// enabled: true\n// - slug: ...\n//\n// Supports: maps, sequences (top-level and nested), inline empty arrays \"[]\",\n// double-quoted strings, single-quoted strings, plain scalars (strings,\n// integers, booleans, null). Comments (#) and blank lines are stripped.\n//\n// We do NOT pull in a real YAML library here -- the roster shape is fixed\n// and we control both producer and consumer; bringing in `js-yaml` (and\n// its transitive deps) for one file is overkill. The validator (in\n// schema.ts) will reject anything weird the parser doesn't recognize.\n// =============================================================================\n\ntype Scalar = string | number | boolean | null;\n\nconst KEY_VALUE = /^([A-Za-z_][A-Za-z0-9_]*):\\s*(.*)$/;\nconst KEY_PREFIX = /^[A-Za-z_][A-Za-z0-9_]*:/;\nconst IDENT_START = /^[A-Za-z_]/;\nconst INT_RE = /^-?\\d+$/;\nconst FLOAT_RE = /^-?\\d+\\.\\d+$/;\n\nfunction parseScalar(raw: string): Scalar {\n const s = raw.trim();\n if (s === \"\") return \"\";\n if (s === \"null\" || s === \"~\") return null;\n if (s === \"true\") return true;\n if (s === \"false\") return false;\n if (INT_RE.test(s)) return Number(s);\n if (FLOAT_RE.test(s)) return Number(s);\n if ((s.startsWith('\"') && s.endsWith('\"')) || (s.startsWith(\"'\") && s.endsWith(\"'\"))) {\n return s.slice(1, -1);\n }\n return s;\n}\n\nfunction parseInlineArray(s: string): Scalar[] {\n const inner = s.slice(1, -1).trim();\n if (inner === \"\") return [];\n return inner.split(\",\").map((x) => parseScalar(x));\n}\n\ntype Line = { indent: number; raw: string };\n\nfunction tokenize(source: string): Line[] {\n const out: Line[] = [];\n for (const raw of source.split(\"\\n\")) {\n const noComment = raw.replace(/\\s+#.*$/, \"\").replace(/^\\s*#.*$/, \"\");\n if (noComment.trim() === \"\") continue;\n const indent = noComment.length - noComment.replace(/^ +/, \"\").length;\n out.push({ indent, raw: noComment.slice(indent) });\n }\n return out;\n}\n\nfunction matchKeyValue(line: string): [string, string] | null {\n const m = line.match(KEY_VALUE);\n if (!m) return null;\n return [m[1]!, m[2]!];\n}\n\ntype ParseResult = { value: unknown; consumed: number };\n\nfunction parseValue(lines: Line[], i: number, baseIndent: number): ParseResult {\n if (i >= lines.length) return { value: null, consumed: 0 };\n const next = lines[i]!;\n if (next.indent <= baseIndent) return { value: null, consumed: 0 };\n if (next.raw.startsWith(\"- \")) {\n return parseSequence(lines, i, next.indent);\n }\n return parseMap(lines, i, next.indent);\n}\n\nfunction parseSequence(lines: Line[], start: number, indent: number): ParseResult {\n const out: unknown[] = [];\n let i = start;\n while (i < lines.length) {\n const line = lines[i]!;\n if (line.indent < indent) break;\n if (line.indent === indent && line.raw.startsWith(\"- \")) {\n const rest = line.raw.slice(2);\n if (KEY_PREFIX.test(rest)) {\n // First key-value of a map entry, possibly followed by indented siblings.\n const virtualMap: Record<string, unknown> = {};\n const kv = matchKeyValue(rest);\n if (kv) {\n const [key, valRaw] = kv;\n if (valRaw === \"\") {\n const sub = parseValue(lines, i + 1, line.indent);\n virtualMap[key] = sub.value;\n i += 1 + sub.consumed;\n } else if (valRaw.startsWith(\"[\") && valRaw.endsWith(\"]\")) {\n virtualMap[key] = parseInlineArray(valRaw);\n i++;\n } else {\n virtualMap[key] = parseScalar(valRaw);\n i++;\n }\n } else {\n i++;\n }\n const mapIndent = line.indent + 2;\n while (i < lines.length) {\n const inner = lines[i]!;\n if (inner.indent < mapIndent) break;\n if (inner.indent === mapIndent && IDENT_START.test(inner.raw)) {\n const skv = matchKeyValue(inner.raw);\n if (!skv) {\n i++;\n continue;\n }\n const [k, v] = skv;\n if (v === \"\") {\n const sub = parseValue(lines, i + 1, inner.indent);\n virtualMap[k] = sub.value;\n i += 1 + sub.consumed;\n } else if (v.startsWith(\"[\") && v.endsWith(\"]\")) {\n virtualMap[k] = parseInlineArray(v);\n i++;\n } else {\n virtualMap[k] = parseScalar(v);\n i++;\n }\n } else {\n break;\n }\n }\n out.push(virtualMap);\n } else if (rest.startsWith(\"[\") && rest.endsWith(\"]\")) {\n out.push(parseInlineArray(rest));\n i++;\n } else {\n out.push(parseScalar(rest));\n i++;\n }\n } else {\n break;\n }\n }\n return { value: out, consumed: i - start };\n}\n\nfunction parseMap(lines: Line[], start: number, indent: number): ParseResult {\n const out: Record<string, unknown> = {};\n let i = start;\n while (i < lines.length) {\n const line = lines[i]!;\n if (line.indent < indent) break;\n if (line.indent !== indent) {\n i++;\n continue;\n }\n const kv = matchKeyValue(line.raw);\n if (!kv) {\n i++;\n continue;\n }\n const [key, valRaw] = kv;\n if (valRaw === \"\") {\n const sub = parseValue(lines, i + 1, indent);\n out[key] = sub.value;\n i += 1 + sub.consumed;\n } else if (valRaw.startsWith(\"[\") && valRaw.endsWith(\"]\")) {\n out[key] = parseInlineArray(valRaw);\n i++;\n } else {\n out[key] = parseScalar(valRaw);\n i++;\n }\n }\n return { value: out, consumed: i - start };\n}\n\n/**\n * Parse a YAML document into a plain JS object. Top-level structure must\n * be a map. Supports nested maps + sequences of maps/scalars.\n */\nexport function parseYamlSubset(source: string): unknown {\n const lines = tokenize(source);\n const result = parseMap(lines, 0, 0);\n return result.value;\n}\n"],"mappings":"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","names":[]}
|
package/dist/cli.js
CHANGED
|
@@ -2,9 +2,12 @@
|
|
|
2
2
|
import {
|
|
3
3
|
runValidateSpoke
|
|
4
4
|
} from "./chunk-A7IIB34G.js";
|
|
5
|
+
import {
|
|
6
|
+
runValidateAppRoster
|
|
7
|
+
} from "./chunk-ZOKDIN2F.js";
|
|
5
8
|
import {
|
|
6
9
|
runPackageNextLambda
|
|
7
|
-
} from "./chunk-
|
|
10
|
+
} from "./chunk-RYVRSM25.js";
|
|
8
11
|
|
|
9
12
|
// src/cli.ts
|
|
10
13
|
import process from "process";
|
|
@@ -12,6 +15,7 @@ var USAGE = `Usage: augint <command> [args]
|
|
|
12
15
|
|
|
13
16
|
Commands:
|
|
14
17
|
validate-spoke Validate Prisma schema against canonical contract
|
|
18
|
+
validate-app-roster Validate tenant app roster (infra YAML + apex JSON + optional spoke mirrors)
|
|
15
19
|
package-next-lambda Package Next standalone build for Lambda
|
|
16
20
|
`;
|
|
17
21
|
async function main() {
|
|
@@ -24,6 +28,9 @@ async function main() {
|
|
|
24
28
|
case "validate-spoke":
|
|
25
29
|
await runValidateSpoke(rest);
|
|
26
30
|
return;
|
|
31
|
+
case "validate-app-roster":
|
|
32
|
+
await runValidateAppRoster(rest);
|
|
33
|
+
return;
|
|
27
34
|
case "package-next-lambda":
|
|
28
35
|
await runPackageNextLambda(rest);
|
|
29
36
|
return;
|
package/dist/cli.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/cli.ts"],"sourcesContent":["import process from \"node:process\";\nimport { runValidateSpoke } from \"./validate-spoke.js\";\nimport { runPackageNextLambda } from \"./package-next-lambda.js\";\n\nconst USAGE = `Usage: augint <command> [args]\n\nCommands:\n validate-spoke Validate Prisma schema against canonical contract\n package-next-lambda Package Next standalone build for Lambda\n`;\n\nasync function main(): Promise<void> {\n const [, , cmd, ...rest] = process.argv;\n if (!cmd || cmd === \"--help\" || cmd === \"-h\") {\n process.stdout.write(USAGE);\n return;\n }\n switch (cmd) {\n case \"validate-spoke\":\n await runValidateSpoke(rest);\n return;\n case \"package-next-lambda\":\n await runPackageNextLambda(rest);\n return;\n default:\n process.stderr.write(`augint: unknown command '${cmd}'\\n${USAGE}`);\n process.exit(2);\n }\n}\n\nmain().catch((err) => {\n process.stderr.write(`augint: ${err instanceof Error ? err.message : String(err)}\\n`);\n process.exit(1);\n});\n"],"mappings":"
|
|
1
|
+
{"version":3,"sources":["../src/cli.ts"],"sourcesContent":["import process from \"node:process\";\nimport { runValidateSpoke } from \"./validate-spoke.js\";\nimport { runPackageNextLambda } from \"./package-next-lambda.js\";\nimport { runValidateAppRoster } from \"./validate-app-roster.js\";\n\nconst USAGE = `Usage: augint <command> [args]\n\nCommands:\n validate-spoke Validate Prisma schema against canonical contract\n validate-app-roster Validate tenant app roster (infra YAML + apex JSON + optional spoke mirrors)\n package-next-lambda Package Next standalone build for Lambda\n`;\n\nasync function main(): Promise<void> {\n const [, , cmd, ...rest] = process.argv;\n if (!cmd || cmd === \"--help\" || cmd === \"-h\") {\n process.stdout.write(USAGE);\n return;\n }\n switch (cmd) {\n case \"validate-spoke\":\n await runValidateSpoke(rest);\n return;\n case \"validate-app-roster\":\n await runValidateAppRoster(rest);\n return;\n case \"package-next-lambda\":\n await runPackageNextLambda(rest);\n return;\n default:\n process.stderr.write(`augint: unknown command '${cmd}'\\n${USAGE}`);\n process.exit(2);\n }\n}\n\nmain().catch((err) => {\n process.stderr.write(`augint: ${err instanceof Error ? err.message : String(err)}\\n`);\n process.exit(1);\n});\n"],"mappings":";;;;;;;;;;;;AAAA,OAAO,aAAa;AAKpB,IAAM,QAAQ;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAQd,eAAe,OAAsB;AACnC,QAAM,CAAC,EAAE,EAAE,KAAK,GAAG,IAAI,IAAI,QAAQ;AACnC,MAAI,CAAC,OAAO,QAAQ,YAAY,QAAQ,MAAM;AAC5C,YAAQ,OAAO,MAAM,KAAK;AAC1B;AAAA,EACF;AACA,UAAQ,KAAK;AAAA,IACX,KAAK;AACH,YAAM,iBAAiB,IAAI;AAC3B;AAAA,IACF,KAAK;AACH,YAAM,qBAAqB,IAAI;AAC/B;AAAA,IACF,KAAK;AACH,YAAM,qBAAqB,IAAI;AAC/B;AAAA,IACF;AACE,cAAQ,OAAO,MAAM,4BAA4B,GAAG;AAAA,EAAM,KAAK,EAAE;AACjE,cAAQ,KAAK,CAAC;AAAA,EAClB;AACF;AAEA,KAAK,EAAE,MAAM,CAAC,QAAQ;AACpB,UAAQ,OAAO,MAAM,WAAW,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG,CAAC;AAAA,CAAI;AACpF,UAAQ,KAAK,CAAC;AAChB,CAAC;","names":[]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"package-next-lambda.d.ts","sourceRoot":"","sources":["../src/package-next-lambda.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"package-next-lambda.d.ts","sourceRoot":"","sources":["../src/package-next-lambda.ts"],"names":[],"mappings":"AAyLA,wBAAsB,oBAAoB,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAkExE"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"validate-app-roster.d.ts","sourceRoot":"","sources":["../src/validate-app-roster.ts"],"names":[],"mappings":"AAiIA,wBAAsB,oBAAoB,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAgExE"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":[],"sourcesContent":[],"mappings":"","names":[]}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"yaml-parser.d.ts","sourceRoot":"","sources":["../src/yaml-parser.ts"],"names":[],"mappings":"AAsLA;;;GAGG;AACH,wBAAgB,eAAe,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAIvD"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@augmenting-integrations/deploy-tools",
|
|
3
|
-
"version": "8.
|
|
3
|
+
"version": "8.6.0",
|
|
4
4
|
"description": "Augint platform deploy tooling. `augint validate-spoke` checks Prisma canonical schema against the app manifest; `augint package-next-lambda` packages a Next standalone build for Lambda. Shared across every spoke + apex repo so deploy logic isn't copy/pasted into each app's CI workflow.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"publishConfig": {
|
|
@@ -10,6 +10,7 @@
|
|
|
10
10
|
"bin": {
|
|
11
11
|
"augint": "./dist/cli.js",
|
|
12
12
|
"augint-validate-spoke": "./dist/validate-spoke.js",
|
|
13
|
+
"augint-validate-app-roster": "./dist/validate-app-roster.js",
|
|
13
14
|
"augint-package-next-lambda": "./dist/package-next-lambda.js"
|
|
14
15
|
},
|
|
15
16
|
"files": [
|
|
@@ -17,19 +18,19 @@
|
|
|
17
18
|
"scripts",
|
|
18
19
|
"README.md"
|
|
19
20
|
],
|
|
20
|
-
"scripts": {
|
|
21
|
-
"build": "tsup",
|
|
22
|
-
"clean": "rm -rf dist",
|
|
23
|
-
"test": "vitest run --passWithNoTests"
|
|
24
|
-
},
|
|
25
21
|
"dependencies": {
|
|
26
|
-
"@augmenting-integrations/platform": "
|
|
22
|
+
"@augmenting-integrations/platform": "8.6.0"
|
|
27
23
|
},
|
|
28
24
|
"devDependencies": {
|
|
29
|
-
"@augmenting-integrations/platform": "workspace:*",
|
|
30
25
|
"@types/node": "^20.17.6",
|
|
31
26
|
"tsup": "^8.3.5",
|
|
32
27
|
"typescript": "^5.7.2",
|
|
33
|
-
"vitest": "^4.1.5"
|
|
28
|
+
"vitest": "^4.1.5",
|
|
29
|
+
"@augmenting-integrations/platform": "8.6.0"
|
|
30
|
+
},
|
|
31
|
+
"scripts": {
|
|
32
|
+
"build": "tsup",
|
|
33
|
+
"clean": "rm -rf dist",
|
|
34
|
+
"test": "vitest run --passWithNoTests"
|
|
34
35
|
}
|
|
35
|
-
}
|
|
36
|
+
}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/package-next-lambda.ts"],"sourcesContent":["import {\n cpSync,\n existsSync,\n lstatSync,\n mkdirSync,\n readdirSync,\n readlinkSync,\n realpathSync,\n rmSync,\n statSync,\n chmodSync,\n} from \"node:fs\";\nimport { dirname, join, resolve } from \"node:path\";\nimport process from \"node:process\";\n\n// =============================================================================\n// `augint package-next-lambda`\n//\n// Stages a Next.js standalone build into a Lambda-ready directory at\n// `.next/standalone/`. Lifts the symlink-flatten loop, force-copy of\n// runtime-required pnpm packages, Prisma .prisma hoist, and .pnpm purge\n// from each spoke's CI workflow so the logic is fixed in one place.\n//\n// Defaults assume the spoke convention:\n// - cwd contains .next/ (from `next build`)\n// - run.sh at cwd root (LWA entry)\n// - optional Makefile at cwd root (SAM BuildMethod=makefile)\n// - optional public/ and content/ at cwd root\n//\n// Flags:\n// --cwd <path> Override working directory\n// --no-prisma Skip Prisma .prisma hoist (use for apex)\n// --no-makefile Skip Makefile stage\n// =============================================================================\n\ntype Options = {\n cwd: string;\n prismaHoist: boolean;\n stageMakefile: boolean;\n};\n\nfunction parseArgs(argv: string[]): Options {\n let cwd = process.cwd();\n let prismaHoist = true;\n let stageMakefile = true;\n for (let i = 0; i < argv.length; i++) {\n const a = argv[i];\n if (a === \"--cwd\" || a === \"--root\") {\n const next = argv[i + 1];\n if (next) {\n cwd = resolve(next);\n i++;\n }\n } else if (a === \"--no-prisma\") {\n prismaHoist = false;\n } else if (a === \"--no-makefile\") {\n stageMakefile = false;\n }\n }\n return { cwd, prismaHoist, stageMakefile };\n}\n\nfunction copyIfExists(src: string, dst: string, opts: { dereference?: boolean } = {}) {\n if (!existsSync(src)) return;\n cpSync(src, dst, { recursive: true, dereference: !!opts.dereference, force: true });\n}\n\nfunction* walkSymlinks(root: string): Generator<string> {\n if (!existsSync(root)) return;\n const stack = [root];\n while (stack.length > 0) {\n const dir = stack.pop()!;\n let entries: Array<{ name: string; isDirectory(): boolean; isSymbolicLink(): boolean }>;\n try {\n entries = readdirSync(dir, { withFileTypes: true }) as unknown as Array<{\n name: string;\n isDirectory(): boolean;\n isSymbolicLink(): boolean;\n }>;\n } catch {\n continue;\n }\n for (const e of entries) {\n const full = join(dir, e.name);\n let lst: ReturnType<typeof lstatSync>;\n try {\n lst = lstatSync(full);\n } catch {\n continue;\n }\n if (lst.isSymbolicLink()) {\n yield full;\n } else if (lst.isDirectory()) {\n stack.push(full);\n }\n }\n }\n}\n\nfunction flattenSymlinks(roots: string[]) {\n // Multiple passes: dereferencing one link can expose a deeper one.\n for (let pass = 0; pass < 5; pass++) {\n let flattened = 0;\n for (const root of roots) {\n for (const link of walkSymlinks(root)) {\n let target: string;\n try {\n target = realpathSync(link);\n } catch {\n continue;\n }\n if (!existsSync(target)) continue;\n rmSync(link, { force: true });\n cpSync(target, link, { recursive: true, dereference: true, force: true });\n flattened++;\n }\n }\n if (flattened === 0) return;\n }\n}\n\nfunction copyRuntimePkg(cwd: string, pkg: string, standaloneNodeMods: string) {\n // Look in the standard tree and the .pnpm/node_modules hoist position.\n const candidates = [\n join(cwd, \"node_modules\", pkg),\n join(cwd, \"node_modules\", \".pnpm\", \"node_modules\", pkg),\n ];\n for (const src of candidates) {\n if (existsSync(src)) {\n const dst = join(standaloneNodeMods, pkg);\n rmSync(dst, { recursive: true, force: true });\n mkdirSync(dirname(dst), { recursive: true });\n cpSync(src, dst, { recursive: true, dereference: true, force: true });\n return;\n }\n }\n throw new Error(`runtime package not found: ${pkg}`);\n}\n\nfunction hoistPrismaClient(standaloneNodeMods: string) {\n // pnpm keeps .prisma/client inside the .pnpm subdir alongside @prisma/client.\n // After we flatten and purge .pnpm, that path disappears, but @prisma/client\n // does require('.prisma/client/...') at runtime. Hoist a copy first.\n const pnpmRoot = join(standaloneNodeMods, \".pnpm\");\n if (!existsSync(pnpmRoot)) return;\n const found = findFirst(pnpmRoot, (full) =>\n full.endsWith(join(\"node_modules\", \".prisma\", \"client\")),\n );\n if (!found) return;\n const dst = join(standaloneNodeMods, \".prisma\", \"client\");\n mkdirSync(dirname(dst), { recursive: true });\n cpSync(found, dst, { recursive: true, dereference: true, force: true });\n}\n\nfunction findFirst(root: string, predicate: (path: string) => boolean): string | null {\n const stack = [root];\n while (stack.length > 0) {\n const dir = stack.pop()!;\n let entries: Array<{ name: string; isDirectory(): boolean; isSymbolicLink(): boolean }>;\n try {\n entries = readdirSync(dir, { withFileTypes: true }) as unknown as Array<{\n name: string;\n isDirectory(): boolean;\n isSymbolicLink(): boolean;\n }>;\n } catch {\n continue;\n }\n for (const e of entries) {\n const full = join(dir, e.name);\n if (predicate(full)) return full;\n if (e.isDirectory()) stack.push(full);\n }\n }\n return null;\n}\n\nexport async function runPackageNextLambda(argv: string[]): Promise<void> {\n const opts = parseArgs(argv);\n const cwd = opts.cwd;\n const standalone = join(cwd, \".next\", \"standalone\");\n if (!existsSync(standalone)) {\n process.stderr.write(\n `package-next-lambda: ${standalone} missing. Run \\`next build\\` first.\\n`,\n );\n process.exit(1);\n }\n\n // ----- Stage static + public + content + run.sh + Makefile + manifest -----\n mkdirSync(join(standalone, \".next\"), { recursive: true });\n copyIfExists(join(cwd, \".next\", \"static\"), join(standalone, \".next\", \"static\"));\n copyIfExists(join(cwd, \"public\"), join(standalone, \"public\"));\n copyIfExists(join(cwd, \"content\"), join(standalone, \"content\"));\n copyIfExists(join(cwd, \"app.manifest.json\"), join(standalone, \"app.manifest.json\"));\n const runSh = join(cwd, \"run.sh\");\n if (existsSync(runSh)) {\n cpSync(runSh, join(standalone, \"run.sh\"));\n try {\n chmodSync(join(standalone, \"run.sh\"), 0o755);\n } catch {\n // chmod may fail on Windows runners; ignore.\n }\n }\n if (opts.stageMakefile) {\n copyIfExists(join(cwd, \"Makefile\"), join(standalone, \"Makefile\"));\n }\n\n // ----- Flatten pnpm symlinks (Lambda runtime can't follow them) -----\n flattenSymlinks([\n join(standalone, \"node_modules\"),\n join(standalone, \".next\", \"node_modules\"),\n ]);\n\n // ----- Force-copy known runtime-required packages -----\n const standaloneNodeMods = join(standalone, \"node_modules\");\n for (const pkg of [\"@swc/helpers\", \"@next/env\"]) {\n try {\n copyRuntimePkg(cwd, pkg, standaloneNodeMods);\n } catch (err) {\n process.stderr.write(\n `package-next-lambda: ${(err as Error).message}\\n` +\n \"Consider adding the package to dependencies or removing it from the runtime list.\\n\",\n );\n process.exit(1);\n }\n }\n\n // ----- Prisma .prisma hoist (spokes with a data plane) -----\n if (opts.prismaHoist) {\n hoistPrismaClient(standaloneNodeMods);\n }\n\n // ----- Purge .pnpm (unreferenced after symlink flatten) -----\n const pnpmRoot = join(standaloneNodeMods, \".pnpm\");\n if (existsSync(pnpmRoot)) {\n rmSync(pnpmRoot, { recursive: true, force: true });\n }\n\n // ----- Report size -----\n const bytes = directorySize(standalone);\n process.stdout.write(\n `package-next-lambda: staged ${standalone} (${(bytes / 1024 / 1024).toFixed(1)} MB)\\n`,\n );\n}\n\nfunction directorySize(root: string): number {\n let total = 0;\n const stack = [root];\n while (stack.length > 0) {\n const dir = stack.pop()!;\n let entries: Array<{ name: string; isDirectory(): boolean; isSymbolicLink(): boolean }>;\n try {\n entries = readdirSync(dir, { withFileTypes: true }) as unknown as Array<{\n name: string;\n isDirectory(): boolean;\n isSymbolicLink(): boolean;\n }>;\n } catch {\n continue;\n }\n for (const e of entries) {\n const full = join(dir, e.name);\n try {\n if (e.isDirectory()) {\n stack.push(full);\n } else {\n total += statSync(full).size;\n }\n } catch {\n // ignore unreadable\n }\n }\n }\n return total;\n}\n\nvoid readlinkSync; // referenced for completeness in walk; silence unused warning\n\nconst isDirectInvocation =\n import.meta.url === `file://${process.argv[1]}` ||\n process.argv[1]?.endsWith(\"package-next-lambda.js\");\nif (isDirectInvocation) {\n runPackageNextLambda(process.argv.slice(2)).catch((err) => {\n process.stderr.write(\n `package-next-lambda: ${err instanceof Error ? err.message : String(err)}\\n`,\n );\n process.exit(1);\n });\n}\n"],"mappings":"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","names":[]}
|