@augmenting-integrations/deploy-tools 8.5.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.
@@ -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,6 +2,9 @@
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
10
  } from "./chunk-RYVRSM25.js";
@@ -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":";;;;;;;;;AAAA,OAAO,aAAa;AAIpB,IAAM,QAAQ;AAAA;AAAA;AAAA;AAAA;AAAA;AAOd,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;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
+ {"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":[]}
@@ -0,0 +1,2 @@
1
+ export declare function runValidateAppRoster(argv: string[]): Promise<void>;
2
+ //# sourceMappingURL=validate-app-roster.d.ts.map
@@ -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,8 @@
1
+ #!/usr/bin/env node
2
+ import {
3
+ runValidateAppRoster
4
+ } from "./chunk-ZOKDIN2F.js";
5
+ export {
6
+ runValidateAppRoster
7
+ };
8
+ //# sourceMappingURL=validate-app-roster.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":[],"sourcesContent":[],"mappings":"","names":[]}
@@ -0,0 +1,6 @@
1
+ /**
2
+ * Parse a YAML document into a plain JS object. Top-level structure must
3
+ * be a map. Supports nested maps + sequences of maps/scalars.
4
+ */
5
+ export declare function parseYamlSubset(source: string): unknown;
6
+ //# sourceMappingURL=yaml-parser.d.ts.map
@@ -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.5.0",
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": [
@@ -18,14 +19,14 @@
18
19
  "README.md"
19
20
  ],
20
21
  "dependencies": {
21
- "@augmenting-integrations/platform": "8.5.0"
22
+ "@augmenting-integrations/platform": "8.6.0"
22
23
  },
23
24
  "devDependencies": {
24
25
  "@types/node": "^20.17.6",
25
26
  "tsup": "^8.3.5",
26
27
  "typescript": "^5.7.2",
27
28
  "vitest": "^4.1.5",
28
- "@augmenting-integrations/platform": "8.5.0"
29
+ "@augmenting-integrations/platform": "8.6.0"
29
30
  },
30
31
  "scripts": {
31
32
  "build": "tsup",