@stardeck-customer-apps/compose 0.9.0 → 0.11.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/dist/index.js CHANGED
@@ -2027,6 +2027,7 @@ var require_semver2 = __commonJS({
2027
2027
  // src/index.ts
2028
2028
  var index_exports = {};
2029
2029
  __export(index_exports, {
2030
+ BUILD_TSCONFIG_PATH: () => BUILD_TSCONFIG_PATH,
2030
2031
  COMPOSE_INPUTS_PATH: () => COMPOSE_INPUTS_PATH,
2031
2032
  assertSupportedTypescript: () => assertSupportedTypescript,
2032
2033
  compose: () => compose,
@@ -2098,11 +2099,54 @@ function shellQuote(value) {
2098
2099
  return `'${value.replace(/'/g, `'\\''`)}'`;
2099
2100
  }
2100
2101
 
2101
- // ../../packages/lib/src/shared/module-composition.ts
2102
- var import_zod6 = require("zod");
2102
+ // ../../packages/lib/src/shared/compose-inputs.ts
2103
+ var import_zod = require("zod");
2104
+ var COMPOSE_INPUTS_PATH = "apps/web/stardeck.compose.json";
2105
+ var composeInputsSchema = import_zod.z.strictObject({
2106
+ connectedStores: import_zod.z.array(
2107
+ import_zod.z.strictObject({
2108
+ storeId: import_zod.z.string().min(1),
2109
+ slug: import_zod.z.string().min(1),
2110
+ // A row with an empty binding key must not fail a deploy: the rail
2111
+ // treats falsy as "no binding key", so normalise rather than reject.
2112
+ bindingKey: import_zod.z.string().nullish().transform((value) => value || null),
2113
+ accessLevel: import_zod.z.enum(["read", "write", "admin"]),
2114
+ // Defaulted so a file written before the platform emitted store types
2115
+ // (database rows only) still parses. The platform starts writing
2116
+ // storage rows, with `type` set, once forks run a compose that reads it.
2117
+ type: import_zod.z.enum(["database", "storage"]).default("database")
2118
+ })
2119
+ ).default([]),
2120
+ installs: import_zod.z.record(
2121
+ import_zod.z.string(),
2122
+ import_zod.z.strictObject({
2123
+ installedVersion: import_zod.z.string().min(1),
2124
+ datastoreBindings: import_zod.z.record(import_zod.z.string(), import_zod.z.string()).nullish()
2125
+ })
2126
+ ).default({})
2127
+ });
2128
+ var STUB_IGNORE_PATH = "apps/web/src/app/.gitignore";
2129
+ var STUB_IGNORE_HEADER = "# Generated by stardeck-compose \u2014 Module-rail stubs are build outputs; do not edit or commit them.";
2130
+ function escapeStubIgnorePattern(pattern) {
2131
+ const escaped = pattern.replace(/[\\[\]*?]/g, (char) => `\\${char}`);
2132
+ return /^[#!]/.test(escaped) ? `\\${escaped}` : escaped;
2133
+ }
2134
+ function buildStubIgnore(artifactPaths) {
2135
+ const prefix = "apps/web/src/app/";
2136
+ const entries = artifactPaths.filter((artifact) => artifact.startsWith(prefix)).map((artifact) => escapeStubIgnorePattern(`/${artifact.slice(prefix.length)}`)).sort();
2137
+ return [STUB_IGNORE_HEADER, ...entries].join("\n") + "\n";
2138
+ }
2139
+
2140
+ // ../../packages/lib/src/shared/module-enablement.ts
2141
+ function isModuleEnabledByList(raw, name, kindOf) {
2142
+ if (!raw) return true;
2143
+ const kind = kindOf(name);
2144
+ if (kind != null && kind !== "feature") return true;
2145
+ return raw.split(",").includes(name);
2146
+ }
2103
2147
 
2104
2148
  // ../../packages/module-contract/src/module-manifest.ts
2105
- var import_zod = require("zod");
2149
+ var import_zod2 = require("zod");
2106
2150
 
2107
2151
  // ../../packages/module-contract/src/slug.ts
2108
2152
  function validateSlug(slug) {
@@ -2137,13 +2181,13 @@ var ROUTE_GROUP_REGEX = /^\([a-z0-9-]+\)$/;
2137
2181
  var ENDPOINT_STATIC_SEGMENT_REGEX = /^[a-z0-9]+(?:-[a-z0-9]+)*$/;
2138
2182
  var ENDPOINT_PARAM_NAME_REGEX = /^[a-z][a-z0-9_-]*$/;
2139
2183
  var ENDPOINT_METHODS = ["GET", "HEAD", "POST", "PUT", "PATCH", "DELETE", "OPTIONS"];
2140
- var moduleNameSchema = import_zod.z.string().max(40).regex(KEBAB_SLUG_REGEX, "must be a kebab-case slug (lowercase letters, digits, hyphens)");
2184
+ var moduleNameSchema = import_zod2.z.string().max(40).regex(KEBAB_SLUG_REGEX, "must be a kebab-case slug (lowercase letters, digits, hyphens)");
2141
2185
  function isValidModuleName(value) {
2142
2186
  return moduleNameSchema.safeParse(value).success;
2143
2187
  }
2144
- var projectSlugSchema = import_zod.z.string().refine((value) => validateSlug(value).valid, "must be a valid project slug");
2145
- var moduleKindSchema = import_zod.z.enum(["feature", "library", "contract"]);
2146
- var endpointMethodSchema = import_zod.z.enum(ENDPOINT_METHODS);
2188
+ var projectSlugSchema = import_zod2.z.string().refine((value) => validateSlug(value).valid, "must be a valid project slug");
2189
+ var moduleKindSchema = import_zod2.z.enum(["feature", "library", "contract"]);
2190
+ var endpointMethodSchema = import_zod2.z.enum(ENDPOINT_METHODS);
2147
2191
  function endpointPathValidationError(path4) {
2148
2192
  if (!path4.startsWith("/api/")) {
2149
2193
  return 'must begin with "/api/"';
@@ -2228,21 +2272,21 @@ function normalizeEndpointPathForCollision(path4) {
2228
2272
  return segment;
2229
2273
  }).join("/");
2230
2274
  }
2231
- var endpointPathSchema = import_zod.z.string().superRefine((path4, ctx) => {
2275
+ var endpointPathSchema = import_zod2.z.string().superRefine((path4, ctx) => {
2232
2276
  const error = endpointPathValidationError(path4);
2233
2277
  if (error != null) {
2234
- ctx.addIssue({ code: import_zod.z.ZodIssueCode.custom, message: error });
2278
+ ctx.addIssue({ code: import_zod2.z.ZodIssueCode.custom, message: error });
2235
2279
  }
2236
2280
  });
2237
- var endpointClaimSchema = import_zod.z.object({
2281
+ var endpointClaimSchema = import_zod2.z.object({
2238
2282
  path: endpointPathSchema,
2239
- methods: import_zod.z.array(endpointMethodSchema).min(1, "methods must be non-empty").superRefine((methods, ctx) => {
2283
+ methods: import_zod2.z.array(endpointMethodSchema).min(1, "methods must be non-empty").superRefine((methods, ctx) => {
2240
2284
  const seen = /* @__PURE__ */ new Set();
2241
2285
  for (let i = 0; i < methods.length; i += 1) {
2242
2286
  const method = methods[i];
2243
2287
  if (seen.has(method)) {
2244
2288
  ctx.addIssue({
2245
- code: import_zod.z.ZodIssueCode.custom,
2289
+ code: import_zod2.z.ZodIssueCode.custom,
2246
2290
  message: `duplicate method "${method}"`,
2247
2291
  path: [i]
2248
2292
  });
@@ -2279,14 +2323,14 @@ function mountSegmentValidationError(segment) {
2279
2323
  }
2280
2324
  return null;
2281
2325
  }
2282
- var mountSegmentSchema = import_zod.z.string().superRefine((segment, ctx) => {
2326
+ var mountSegmentSchema = import_zod2.z.string().superRefine((segment, ctx) => {
2283
2327
  const error = mountSegmentValidationError(segment);
2284
2328
  if (error != null) {
2285
- ctx.addIssue({ code: import_zod.z.ZodIssueCode.custom, message: error });
2329
+ ctx.addIssue({ code: import_zod2.z.ZodIssueCode.custom, message: error });
2286
2330
  }
2287
2331
  });
2288
- var mountSchema = import_zod.z.object({
2289
- group: import_zod.z.string().regex(ROUTE_GROUP_REGEX, 'must be a Next.js route group like "(admin)"'),
2332
+ var mountSchema = import_zod2.z.object({
2333
+ group: import_zod2.z.string().regex(ROUTE_GROUP_REGEX, 'must be a Next.js route group like "(admin)"'),
2290
2334
  segment: mountSegmentSchema
2291
2335
  }).strict();
2292
2336
  function splitMountSegment(segment) {
@@ -2299,21 +2343,21 @@ function splitMountSegment(segment) {
2299
2343
  }
2300
2344
  return segment.split("/");
2301
2345
  }
2302
- var tableNameSchema = import_zod.z.string().regex(SNAKE_TABLE_REGEX, "must be snake_case");
2346
+ var tableNameSchema = import_zod2.z.string().regex(SNAKE_TABLE_REGEX, "must be snake_case");
2303
2347
  var NPM_PACKAGE_NAME_REGEX = /^(@[a-z0-9-~][a-z0-9-._~]*\/)?[a-z0-9-~][a-z0-9-._~]*$/;
2304
- var npmPackageNameSchema = import_zod.z.string().max(214).regex(NPM_PACKAGE_NAME_REGEX, "must be a valid npm package name");
2305
- var descriptionSchema = import_zod.z.string().max(200, "must be at most 200 characters").refine((value) => value.trim().length > 0, "must be non-empty after trimming");
2306
- var crossAppSchema = import_zod.z.object({
2307
- exposes: import_zod.z.array(import_zod.z.unknown()).max(0, "must be empty until cross-app contracts are defined"),
2308
- consumes: import_zod.z.array(import_zod.z.unknown()).max(0, "must be empty until cross-app contracts are defined")
2348
+ var npmPackageNameSchema = import_zod2.z.string().max(214).regex(NPM_PACKAGE_NAME_REGEX, "must be a valid npm package name");
2349
+ var descriptionSchema = import_zod2.z.string().max(200, "must be at most 200 characters").refine((value) => value.trim().length > 0, "must be non-empty after trimming");
2350
+ var crossAppSchema = import_zod2.z.object({
2351
+ exposes: import_zod2.z.array(import_zod2.z.unknown()).max(0, "must be empty until cross-app contracts are defined"),
2352
+ consumes: import_zod2.z.array(import_zod2.z.unknown()).max(0, "must be empty until cross-app contracts are defined")
2309
2353
  }).strict();
2310
- var enhancementWorkflowsSchema = import_zod.z.record(moduleNameSchema, import_zod.z.array(import_zod.z.string().min(1))).default({});
2311
- var enhancementEndpointsSchema = import_zod.z.record(moduleNameSchema, import_zod.z.array(endpointClaimSchema)).default({});
2312
- var datastoreRequirementSchema = import_zod.z.object({
2354
+ var enhancementWorkflowsSchema = import_zod2.z.record(moduleNameSchema, import_zod2.z.array(import_zod2.z.string().min(1))).default({});
2355
+ var enhancementEndpointsSchema = import_zod2.z.record(moduleNameSchema, import_zod2.z.array(endpointClaimSchema)).default({});
2356
+ var datastoreRequirementSchema = import_zod2.z.object({
2313
2357
  /** Logical name, module-local, snake_case. Never a physical store key. */
2314
2358
  id: tableNameSchema,
2315
2359
  /** "app" = this project's app-local store; "org" = an org-level shared store. */
2316
- scope: import_zod.z.enum(["app", "org"]).default("app"),
2360
+ scope: import_zod2.z.enum(["app", "org"]).default("app"),
2317
2361
  /**
2318
2362
  * Which kind of connected store satisfies this requirement. A "database"
2319
2363
  * requirement only ever binds to a database store and a "storage" one
@@ -2321,34 +2365,34 @@ var datastoreRequirementSchema = import_zod.z.object({
2321
2365
  * rail never crosses the two. Defaults to "database", the only kind the
2322
2366
  * rail resolved before this field existed.
2323
2367
  */
2324
- type: import_zod.z.enum(["database", "storage"]).default("database"),
2368
+ type: import_zod2.z.enum(["database", "storage"]).default("database"),
2325
2369
  /** true → install fails when no store resolves; false → binding omitted, module degrades. */
2326
- required: import_zod.z.boolean().default(true),
2370
+ required: import_zod2.z.boolean().default(true),
2327
2371
  /** Checked against the connected store's accessLevel at install. */
2328
- access: import_zod.z.enum(["read", "write", "admin"]).default("write")
2372
+ access: import_zod2.z.enum(["read", "write", "admin"]).default("write")
2329
2373
  }).strict();
2330
- var permissionClaimSchema = import_zod.z.object({
2374
+ var permissionClaimSchema = import_zod2.z.object({
2331
2375
  /**
2332
2376
  * Lowercase resource:action with one colon and no underscores. This grammar
2333
2377
  * is deliberately narrower than the platform permission tool's charset.
2334
2378
  */
2335
- key: import_zod.z.string().regex(/^[a-z0-9][a-z0-9-]*:[a-z0-9][a-z0-9-]*$/, "must be a lowercase resource:action key").max(100, "must be at most 100 characters (platform permission tool limit)"),
2379
+ key: import_zod2.z.string().regex(/^[a-z0-9][a-z0-9-]*:[a-z0-9][a-z0-9-]*$/, "must be a lowercase resource:action key").max(100, "must be at most 100 characters (platform permission tool limit)"),
2336
2380
  /** Human label for the deployment auth config row. */
2337
2381
  description: descriptionSchema
2338
2382
  }).strict();
2339
- var seedBundleSchema = import_zod.z.object({
2383
+ var seedBundleSchema = import_zod2.z.object({
2340
2384
  table: tableNameSchema,
2341
2385
  /** Columns forming the ON CONFLICT key — must appear in every row. */
2342
- conflictTarget: import_zod.z.array(import_zod.z.string().min(1)).min(1),
2386
+ conflictTarget: import_zod2.z.array(import_zod2.z.string().min(1)).min(1),
2343
2387
  /** Scalar JSON values only (no nested objects/arrays). */
2344
- rows: import_zod.z.array(import_zod.z.record(import_zod.z.string(), import_zod.z.union([import_zod.z.string(), import_zod.z.number(), import_zod.z.boolean(), import_zod.z.null()]))).min(1)
2388
+ rows: import_zod2.z.array(import_zod2.z.record(import_zod2.z.string(), import_zod2.z.union([import_zod2.z.string(), import_zod2.z.number(), import_zod2.z.boolean(), import_zod2.z.null()]))).min(1)
2345
2389
  }).strict().superRefine((bundle, ctx) => {
2346
2390
  const rowKeys = bundle.rows.map((row) => Object.keys(row).sort().join("\0"));
2347
2391
  const canonical = rowKeys[0];
2348
2392
  for (let i = 1; i < rowKeys.length; i += 1) {
2349
2393
  if (rowKeys[i] !== canonical) {
2350
2394
  ctx.addIssue({
2351
- code: import_zod.z.ZodIssueCode.custom,
2395
+ code: import_zod2.z.ZodIssueCode.custom,
2352
2396
  message: "all rows in a seed bundle must have identical key sets",
2353
2397
  path: ["rows", i]
2354
2398
  });
@@ -2360,7 +2404,7 @@ var seedBundleSchema = import_zod.z.object({
2360
2404
  for (const col of bundle.conflictTarget) {
2361
2405
  if (!keys.has(col)) {
2362
2406
  ctx.addIssue({
2363
- code: import_zod.z.ZodIssueCode.custom,
2407
+ code: import_zod2.z.ZodIssueCode.custom,
2364
2408
  message: `conflictTarget column "${col}" must be present in every row`,
2365
2409
  path: ["rows", i]
2366
2410
  });
@@ -2368,35 +2412,35 @@ var seedBundleSchema = import_zod.z.object({
2368
2412
  }
2369
2413
  }
2370
2414
  });
2371
- var moduleManifestSchema = import_zod.z.object({
2415
+ var moduleManifestSchema = import_zod2.z.object({
2372
2416
  name: moduleNameSchema,
2373
2417
  kind: moduleKindSchema,
2374
2418
  // Release versions are platform-owned in module_versions. Accept this
2375
2419
  // legacy field while existing Module source ages out, but strip it from the
2376
2420
  // parsed contract so no runtime can treat module.json as version authority.
2377
- version: import_zod.z.unknown().optional(),
2421
+ version: import_zod2.z.unknown().optional(),
2378
2422
  home: projectSlugSchema,
2379
2423
  /** Machine-checkable purpose line — required, ≤200 code units, non-blank when trimmed. */
2380
2424
  description: descriptionSchema,
2381
- uses: import_zod.z.array(moduleNameSchema).default([]),
2425
+ uses: import_zod2.z.array(moduleNameSchema).default([]),
2382
2426
  /**
2383
2427
  * Soft peers: this module ships `enhancements/<peer>/` directories that are
2384
2428
  * composition-pruned — the installer includes them only when the peer is
2385
2429
  * present, so the peer is NOT an install-time requirement. Disjoint from
2386
2430
  * `uses`; entries may name modules absent from the composition.
2387
2431
  */
2388
- enhancements: import_zod.z.array(moduleNameSchema).default([]),
2389
- tables: import_zod.z.array(tableNameSchema).default([]),
2390
- mounts: import_zod.z.array(mountSchema).default([]),
2391
- integration: import_zod.z.array(import_zod.z.string()).default([]),
2392
- workflows: import_zod.z.array(import_zod.z.string().min(1)).default([]),
2432
+ enhancements: import_zod2.z.array(moduleNameSchema).default([]),
2433
+ tables: import_zod2.z.array(tableNameSchema).default([]),
2434
+ mounts: import_zod2.z.array(mountSchema).default([]),
2435
+ integration: import_zod2.z.array(import_zod2.z.string()).default([]),
2436
+ workflows: import_zod2.z.array(import_zod2.z.string().min(1)).default([]),
2393
2437
  /**
2394
2438
  * Slice-scoped workflow names keyed by peer. Keys must be ⊆ `enhancements`;
2395
2439
  * names must be unique across root `workflows` and every slice list.
2396
2440
  */
2397
2441
  enhancementWorkflows: enhancementWorkflowsSchema,
2398
2442
  /** Root API endpoint path claims. */
2399
- endpoints: import_zod.z.array(endpointClaimSchema).default([]),
2443
+ endpoints: import_zod2.z.array(endpointClaimSchema).default([]),
2400
2444
  /**
2401
2445
  * Slice-scoped endpoint claims keyed by peer. Keys must be ⊆ `enhancements`;
2402
2446
  * normalized paths must be unique across root and every slice.
@@ -2412,38 +2456,44 @@ var moduleManifestSchema = import_zod.z.object({
2412
2456
  * to a physical connected store and generates module-datastores.gen.ts;
2413
2457
  * unlike seeds, this field drives generated output.
2414
2458
  */
2415
- datastores: import_zod.z.array(datastoreRequirementSchema).optional(),
2459
+ datastores: import_zod2.z.array(datastoreRequirementSchema).optional(),
2416
2460
  /**
2417
2461
  * Keys this module's guards enforce. Install registers them in deployment
2418
2462
  * auth config; registration only — declaring is never granting.
2419
2463
  */
2420
- permissions: import_zod.z.array(permissionClaimSchema).optional(),
2464
+ permissions: import_zod2.z.array(permissionClaimSchema).optional(),
2421
2465
  /**
2422
2466
  * Optional starter rows for tables this module owns. Replay is
2423
2467
  * `INSERT ... ON CONFLICT (conflictTarget) DO NOTHING` — idempotent by
2424
2468
  * construction; the rail (not this schema) performs the replay.
2425
2469
  */
2426
- seeds: import_zod.z.array(seedBundleSchema).optional(),
2470
+ seeds: import_zod2.z.array(seedBundleSchema).optional(),
2427
2471
  /** npm packages the source imports beyond the base app. Names only; the rail installs each at the home app's range. */
2428
- packages: import_zod.z.array(npmPackageNameSchema).optional(),
2472
+ packages: import_zod2.z.array(npmPackageNameSchema).optional(),
2429
2473
  /**
2430
2474
  * UI-layer contract. `separable: true` asserts the Module's components/ and
2431
2475
  * routes/ hold presentation only — the Blueprint's
2432
2476
  * `module-boundaries/ui-layer` lint rule enforces it — so a fork may
2433
2477
  * soft-eject them. See docs/module-ui-soft-eject-plan.md.
2434
2478
  */
2435
- ui: import_zod.z.object({ separable: import_zod.z.boolean() }).strict().optional()
2479
+ ui: import_zod2.z.object({ separable: import_zod2.z.boolean() }).strict().optional(),
2480
+ /**
2481
+ * `false` keeps a feature Module off in a new Blueprint fork unless the
2482
+ * creator ticks it: the fork picker leaves it unchecked and "every Module"
2483
+ * is written out without it. Omitted means on. Library Modules are always on.
2484
+ */
2485
+ defaultEnabled: import_zod2.z.boolean().optional()
2436
2486
  }).strict().superRefine((manifest, ctx) => {
2437
2487
  if (manifest.uses.includes(manifest.name)) {
2438
2488
  ctx.addIssue({
2439
- code: import_zod.z.ZodIssueCode.custom,
2489
+ code: import_zod2.z.ZodIssueCode.custom,
2440
2490
  message: "a module cannot list itself in uses",
2441
2491
  path: ["uses"]
2442
2492
  });
2443
2493
  }
2444
2494
  if (manifest.enhancements.includes(manifest.name)) {
2445
2495
  ctx.addIssue({
2446
- code: import_zod.z.ZodIssueCode.custom,
2496
+ code: import_zod2.z.ZodIssueCode.custom,
2447
2497
  message: "a module cannot list itself in enhancements",
2448
2498
  path: ["enhancements"]
2449
2499
  });
@@ -2451,7 +2501,7 @@ var moduleManifestSchema = import_zod.z.object({
2451
2501
  const hardAndSoft = manifest.enhancements.filter((peer) => manifest.uses.includes(peer));
2452
2502
  if (hardAndSoft.length > 0) {
2453
2503
  ctx.addIssue({
2454
- code: import_zod.z.ZodIssueCode.custom,
2504
+ code: import_zod2.z.ZodIssueCode.custom,
2455
2505
  message: `uses and enhancements must be disjoint (a peer is either a hard dep or a soft one): ${hardAndSoft.join(", ")}`,
2456
2506
  path: ["enhancements"]
2457
2507
  });
@@ -2460,7 +2510,7 @@ var moduleManifestSchema = import_zod.z.object({
2460
2510
  for (const peer of Object.keys(manifest.enhancementWorkflows)) {
2461
2511
  if (!enhancementPeers.has(peer)) {
2462
2512
  ctx.addIssue({
2463
- code: import_zod.z.ZodIssueCode.custom,
2513
+ code: import_zod2.z.ZodIssueCode.custom,
2464
2514
  message: `enhancementWorkflows key "${peer}" must be listed in enhancements`,
2465
2515
  path: ["enhancementWorkflows", peer]
2466
2516
  });
@@ -2469,7 +2519,7 @@ var moduleManifestSchema = import_zod.z.object({
2469
2519
  for (const peer of Object.keys(manifest.enhancementEndpoints)) {
2470
2520
  if (!enhancementPeers.has(peer)) {
2471
2521
  ctx.addIssue({
2472
- code: import_zod.z.ZodIssueCode.custom,
2522
+ code: import_zod2.z.ZodIssueCode.custom,
2473
2523
  message: `enhancementEndpoints key "${peer}" must be listed in enhancements`,
2474
2524
  path: ["enhancementEndpoints", peer]
2475
2525
  });
@@ -2480,7 +2530,7 @@ var moduleManifestSchema = import_zod.z.object({
2480
2530
  const existing = seenWorkflows.get(name);
2481
2531
  if (existing != null) {
2482
2532
  ctx.addIssue({
2483
- code: import_zod.z.ZodIssueCode.custom,
2533
+ code: import_zod2.z.ZodIssueCode.custom,
2484
2534
  message: `duplicate workflow name "${name}" (also at ${existing})`,
2485
2535
  path: path4
2486
2536
  });
@@ -2507,7 +2557,7 @@ var moduleManifestSchema = import_zod.z.object({
2507
2557
  const existing = seenEndpointKeys.get(key);
2508
2558
  if (existing != null) {
2509
2559
  ctx.addIssue({
2510
- code: import_zod.z.ZodIssueCode.custom,
2560
+ code: import_zod2.z.ZodIssueCode.custom,
2511
2561
  message: `duplicate normalized endpoint path "${key}" (also at ${existing})`,
2512
2562
  path: path4
2513
2563
  });
@@ -2529,7 +2579,7 @@ var moduleManifestSchema = import_zod.z.object({
2529
2579
  const id = manifest.datastores[i].id;
2530
2580
  if (seenDatastoreIds.has(id)) {
2531
2581
  ctx.addIssue({
2532
- code: import_zod.z.ZodIssueCode.custom,
2582
+ code: import_zod2.z.ZodIssueCode.custom,
2533
2583
  message: `duplicate datastore id "${id}"`,
2534
2584
  path: ["datastores", i, "id"]
2535
2585
  });
@@ -2544,7 +2594,7 @@ var moduleManifestSchema = import_zod.z.object({
2544
2594
  const key = manifest.permissions[i].key;
2545
2595
  if (seenPermissionKeys.has(key)) {
2546
2596
  ctx.addIssue({
2547
- code: import_zod.z.ZodIssueCode.custom,
2597
+ code: import_zod2.z.ZodIssueCode.custom,
2548
2598
  message: `duplicate permission key "${key}"`,
2549
2599
  path: ["permissions", i, "key"]
2550
2600
  });
@@ -2556,35 +2606,35 @@ var moduleManifestSchema = import_zod.z.object({
2556
2606
  if (manifest.kind === "library") {
2557
2607
  if (manifest.tables.length > 0) {
2558
2608
  ctx.addIssue({
2559
- code: import_zod.z.ZodIssueCode.custom,
2609
+ code: import_zod2.z.ZodIssueCode.custom,
2560
2610
  message: "library modules must not declare tables",
2561
2611
  path: ["tables"]
2562
2612
  });
2563
2613
  }
2564
2614
  if (manifest.mounts.length > 0) {
2565
2615
  ctx.addIssue({
2566
- code: import_zod.z.ZodIssueCode.custom,
2616
+ code: import_zod2.z.ZodIssueCode.custom,
2567
2617
  message: "library modules must not declare mounts",
2568
2618
  path: ["mounts"]
2569
2619
  });
2570
2620
  }
2571
2621
  if (manifest.seeds != null && manifest.seeds.length > 0) {
2572
2622
  ctx.addIssue({
2573
- code: import_zod.z.ZodIssueCode.custom,
2623
+ code: import_zod2.z.ZodIssueCode.custom,
2574
2624
  message: "library modules must not declare seeds",
2575
2625
  path: ["seeds"]
2576
2626
  });
2577
2627
  }
2578
2628
  if (manifest.datastores != null && manifest.datastores.length > 0) {
2579
2629
  ctx.addIssue({
2580
- code: import_zod.z.ZodIssueCode.custom,
2630
+ code: import_zod2.z.ZodIssueCode.custom,
2581
2631
  message: "library modules must not declare datastores",
2582
2632
  path: ["datastores"]
2583
2633
  });
2584
2634
  }
2585
2635
  if (manifest.permissions != null && manifest.permissions.length > 0) {
2586
2636
  ctx.addIssue({
2587
- code: import_zod.z.ZodIssueCode.custom,
2637
+ code: import_zod2.z.ZodIssueCode.custom,
2588
2638
  message: "library modules must not declare permissions",
2589
2639
  path: ["permissions"]
2590
2640
  });
@@ -2592,7 +2642,7 @@ var moduleManifestSchema = import_zod.z.object({
2592
2642
  }
2593
2643
  if (manifest.kind === "contract" && manifest.mounts.length > 0) {
2594
2644
  ctx.addIssue({
2595
- code: import_zod.z.ZodIssueCode.custom,
2645
+ code: import_zod2.z.ZodIssueCode.custom,
2596
2646
  message: "contract modules must not declare mounts",
2597
2647
  path: ["mounts"]
2598
2648
  });
@@ -2603,7 +2653,7 @@ var moduleManifestSchema = import_zod.z.object({
2603
2653
  const bundle = manifest.seeds[i];
2604
2654
  if (!ownedTables.has(bundle.table)) {
2605
2655
  ctx.addIssue({
2606
- code: import_zod.z.ZodIssueCode.custom,
2656
+ code: import_zod2.z.ZodIssueCode.custom,
2607
2657
  message: `seeds may only target tables listed in tables (got "${bundle.table}")`,
2608
2658
  path: ["seeds", i, "table"]
2609
2659
  });
@@ -2654,10 +2704,10 @@ var MANDATORY_MODULE_CHECK_DESCRIPTORS = Object.freeze([
2654
2704
  ]);
2655
2705
 
2656
2706
  // ../../packages/module-contract/src/module-structure.ts
2657
- var import_zod3 = require("zod");
2707
+ var import_zod4 = require("zod");
2658
2708
 
2659
2709
  // ../../packages/module-contract/src/module-e2e-manifest.ts
2660
- var import_zod2 = require("zod");
2710
+ var import_zod3 = require("zod");
2661
2711
  function e2eSpecFileValidationError(file) {
2662
2712
  if (file.length === 0) {
2663
2713
  return "must be a non-empty relative path ending in .spec.ts";
@@ -2685,22 +2735,22 @@ function e2eSpecFileValidationError(file) {
2685
2735
  }
2686
2736
  return null;
2687
2737
  }
2688
- var e2eSpecFileSchema = import_zod2.z.string().superRefine((file, ctx) => {
2738
+ var e2eSpecFileSchema = import_zod3.z.string().superRefine((file, ctx) => {
2689
2739
  const error = e2eSpecFileValidationError(file);
2690
2740
  if (error != null) {
2691
- ctx.addIssue({ code: import_zod2.z.ZodIssueCode.custom, message: error });
2741
+ ctx.addIssue({ code: import_zod3.z.ZodIssueCode.custom, message: error });
2692
2742
  }
2693
2743
  });
2694
- var e2eSpecSchema = import_zod2.z.object({
2744
+ var e2eSpecSchema = import_zod3.z.object({
2695
2745
  file: e2eSpecFileSchema,
2696
- requires: import_zod2.z.array(moduleNameSchema).min(1, "requires must be non-empty")
2746
+ requires: import_zod3.z.array(moduleNameSchema).min(1, "requires must be non-empty")
2697
2747
  }).strict().superRefine((spec, ctx) => {
2698
2748
  const seen = /* @__PURE__ */ new Set();
2699
2749
  for (let i = 0; i < spec.requires.length; i += 1) {
2700
2750
  const name = spec.requires[i];
2701
2751
  if (seen.has(name)) {
2702
2752
  ctx.addIssue({
2703
- code: import_zod2.z.ZodIssueCode.custom,
2753
+ code: import_zod3.z.ZodIssueCode.custom,
2704
2754
  message: `duplicate requirement "${name}"`,
2705
2755
  path: ["requires", i]
2706
2756
  });
@@ -2709,15 +2759,15 @@ var e2eSpecSchema = import_zod2.z.object({
2709
2759
  }
2710
2760
  }
2711
2761
  });
2712
- var moduleE2eManifestSchema = import_zod2.z.object({
2713
- specs: import_zod2.z.array(e2eSpecSchema).min(1, "specs must contain at least one entry")
2762
+ var moduleE2eManifestSchema = import_zod3.z.object({
2763
+ specs: import_zod3.z.array(e2eSpecSchema).min(1, "specs must contain at least one entry")
2714
2764
  }).strict().superRefine((manifest, ctx) => {
2715
2765
  const seenFiles = /* @__PURE__ */ new Set();
2716
2766
  for (let i = 0; i < manifest.specs.length; i += 1) {
2717
2767
  const file = manifest.specs[i].file;
2718
2768
  if (seenFiles.has(file)) {
2719
2769
  ctx.addIssue({
2720
- code: import_zod2.z.ZodIssueCode.custom,
2770
+ code: import_zod3.z.ZodIssueCode.custom,
2721
2771
  message: `duplicate file "${file}"`,
2722
2772
  path: ["specs", i, "file"]
2723
2773
  });
@@ -2959,7 +3009,7 @@ function compareCodeUnit(a, b) {
2959
3009
  // ../../packages/module-contract/src/module-structure.ts
2960
3010
  var MODULE_STRUCTURE_JSON_BYTE_CAP = 64 * 1024;
2961
3011
  function uniqueSortedStringArray(label) {
2962
- return import_zod3.z.array(import_zod3.z.string()).superRefine((arr, ctx) => {
3012
+ return import_zod4.z.array(import_zod4.z.string()).superRefine((arr, ctx) => {
2963
3013
  if (new Set(arr).size !== arr.length) {
2964
3014
  ctx.addIssue({ code: "custom", message: `${label} must be unique` });
2965
3015
  return;
@@ -2975,10 +3025,10 @@ function uniqueSortedStringArray(label) {
2975
3025
  });
2976
3026
  }
2977
3027
  function contributionPermissionsSchema(label) {
2978
- return import_zod3.z.array(
2979
- import_zod3.z.object({
2980
- contributionId: import_zod3.z.string().min(1),
2981
- permission: import_zod3.z.string().min(1)
3028
+ return import_zod4.z.array(
3029
+ import_zod4.z.object({
3030
+ contributionId: import_zod4.z.string().min(1),
3031
+ permission: import_zod4.z.string().min(1)
2982
3032
  }).strict()
2983
3033
  ).superRefine((entries, ctx) => {
2984
3034
  const keys = entries.map((entry) => `${entry.contributionId}\0${entry.permission}`);
@@ -2996,17 +3046,17 @@ function contributionPermissionsSchema(label) {
2996
3046
  }
2997
3047
  }).optional();
2998
3048
  }
2999
- var collectedFilePayloadSchema = import_zod3.z.discriminatedUnion("status", [
3000
- import_zod3.z.object({ status: import_zod3.z.literal("ok"), text: import_zod3.z.string() }).strict(),
3001
- import_zod3.z.object({ status: import_zod3.z.literal("missing") }).strict(),
3002
- import_zod3.z.object({ status: import_zod3.z.literal("too-large") }).strict(),
3003
- import_zod3.z.object({ status: import_zod3.z.literal("unreadable") }).strict()
3049
+ var collectedFilePayloadSchema = import_zod4.z.discriminatedUnion("status", [
3050
+ import_zod4.z.object({ status: import_zod4.z.literal("ok"), text: import_zod4.z.string() }).strict(),
3051
+ import_zod4.z.object({ status: import_zod4.z.literal("missing") }).strict(),
3052
+ import_zod4.z.object({ status: import_zod4.z.literal("too-large") }).strict(),
3053
+ import_zod4.z.object({ status: import_zod4.z.literal("unreadable") }).strict()
3004
3054
  ]);
3005
- var collectedLocaleFileSchema = import_zod3.z.object({
3006
- locale: import_zod3.z.string().min(1),
3055
+ var collectedLocaleFileSchema = import_zod4.z.object({
3056
+ locale: import_zod4.z.string().min(1),
3007
3057
  payload: collectedFilePayloadSchema
3008
3058
  }).strict();
3009
- var collectedE2eFactsSchema = import_zod3.z.object({
3059
+ var collectedE2eFactsSchema = import_zod4.z.object({
3010
3060
  manifest: collectedFilePayloadSchema,
3011
3061
  specFiles: uniqueSortedStringArray("specFiles"),
3012
3062
  escapingSymlinks: uniqueSortedStringArray("escapingSymlinks")
@@ -3028,20 +3078,20 @@ function validateRouteExportEvidenceCongruence(input) {
3028
3078
  }
3029
3079
  }
3030
3080
  }
3031
- var collectedEnhancementFactsSchema = import_zod3.z.object({
3032
- peer: import_zod3.z.string().min(1),
3033
- hasContributionsTs: import_zod3.z.boolean(),
3081
+ var collectedEnhancementFactsSchema = import_zod4.z.object({
3082
+ peer: import_zod4.z.string().min(1),
3083
+ hasContributionsTs: import_zod4.z.boolean(),
3034
3084
  contributionPermissions: contributionPermissionsSchema("enhancement contributionPermissions"),
3035
- hasInitializeServerTs: import_zod3.z.boolean(),
3085
+ hasInitializeServerTs: import_zod4.z.boolean(),
3036
3086
  contributionsCollectionErrors: uniqueSortedStringArray(
3037
3087
  "enhancement contributionsCollectionErrors"
3038
3088
  ),
3039
3089
  initializeServerCollectionErrors: uniqueSortedStringArray(
3040
3090
  "enhancement initializeServerCollectionErrors"
3041
3091
  ),
3042
- hasRoutesDir: import_zod3.z.boolean(),
3092
+ hasRoutesDir: import_zod4.z.boolean(),
3043
3093
  routeCollectionErrors: uniqueSortedStringArray("enhancement routeCollectionErrors"),
3044
- locales: import_zod3.z.array(collectedLocaleFileSchema).superRefine((locales, ctx) => {
3094
+ locales: import_zod4.z.array(collectedLocaleFileSchema).superRefine((locales, ctx) => {
3045
3095
  const names = locales.map((l) => l.locale);
3046
3096
  if (new Set(names).size !== names.length) {
3047
3097
  ctx.addIssue({ code: "custom", message: "enhancement locales must be unique by locale" });
@@ -3056,27 +3106,27 @@ var collectedEnhancementFactsSchema = import_zod3.z.object({
3056
3106
  }),
3057
3107
  e2e: collectedE2eFactsSchema.nullable()
3058
3108
  }).strict();
3059
- var moduleStructureFactsSchema = import_zod3.z.object({
3060
- collected: import_zod3.z.literal(true),
3061
- dirName: import_zod3.z.string().min(1),
3062
- hasIndexTs: import_zod3.z.boolean(),
3063
- hasContributionsTs: import_zod3.z.boolean(),
3109
+ var moduleStructureFactsSchema = import_zod4.z.object({
3110
+ collected: import_zod4.z.literal(true),
3111
+ dirName: import_zod4.z.string().min(1),
3112
+ hasIndexTs: import_zod4.z.boolean(),
3113
+ hasContributionsTs: import_zod4.z.boolean(),
3064
3114
  contributionPermissions: contributionPermissionsSchema("contributionPermissions"),
3065
- hasSlotsTs: import_zod3.z.boolean(),
3115
+ hasSlotsTs: import_zod4.z.boolean(),
3066
3116
  contributionsCollectionErrors: uniqueSortedStringArray("contributionsCollectionErrors"),
3067
3117
  slotsCollectionErrors: uniqueSortedStringArray("slotsCollectionErrors"),
3068
- hasTestsDir: import_zod3.z.boolean(),
3069
- hasDatastoreDir: import_zod3.z.boolean(),
3070
- datastoreFileCount: import_zod3.z.number().int().nonnegative(),
3071
- hasServerIndexTs: import_zod3.z.boolean(),
3072
- hasOtherServerTs: import_zod3.z.boolean(),
3073
- hasE2eDir: import_zod3.z.boolean(),
3074
- hasRoutesDir: import_zod3.z.boolean(),
3118
+ hasTestsDir: import_zod4.z.boolean(),
3119
+ hasDatastoreDir: import_zod4.z.boolean(),
3120
+ datastoreFileCount: import_zod4.z.number().int().nonnegative(),
3121
+ hasServerIndexTs: import_zod4.z.boolean(),
3122
+ hasOtherServerTs: import_zod4.z.boolean(),
3123
+ hasE2eDir: import_zod4.z.boolean(),
3124
+ hasRoutesDir: import_zod4.z.boolean(),
3075
3125
  routeEntries: uniqueSortedStringArray("routeEntries"),
3076
- routePageExports: import_zod3.z.array(
3077
- import_zod3.z.object({
3078
- nextRelativePath: import_zod3.z.string().min(1),
3079
- hasGenerateMetadata: import_zod3.z.boolean()
3126
+ routePageExports: import_zod4.z.array(
3127
+ import_zod4.z.object({
3128
+ nextRelativePath: import_zod4.z.string().min(1),
3129
+ hasGenerateMetadata: import_zod4.z.boolean()
3080
3130
  }).strict()
3081
3131
  ).superRefine((entries, ctx) => {
3082
3132
  const paths = entries.map((e) => e.nextRelativePath);
@@ -3098,7 +3148,7 @@ var moduleStructureFactsSchema = import_zod3.z.object({
3098
3148
  }
3099
3149
  }),
3100
3150
  routeCollectionErrors: uniqueSortedStringArray("routeCollectionErrors"),
3101
- rootLocales: import_zod3.z.array(collectedLocaleFileSchema).superRefine((locales, ctx) => {
3151
+ rootLocales: import_zod4.z.array(collectedLocaleFileSchema).superRefine((locales, ctx) => {
3102
3152
  const names = locales.map((l) => l.locale);
3103
3153
  if (new Set(names).size !== names.length) {
3104
3154
  ctx.addIssue({ code: "custom", message: "rootLocales must be unique by locale" });
@@ -3112,7 +3162,7 @@ var moduleStructureFactsSchema = import_zod3.z.object({
3112
3162
  }
3113
3163
  }),
3114
3164
  rootE2e: collectedE2eFactsSchema.nullable(),
3115
- enhancements: import_zod3.z.array(collectedEnhancementFactsSchema).superRefine((enhancements, ctx) => {
3165
+ enhancements: import_zod4.z.array(collectedEnhancementFactsSchema).superRefine((enhancements, ctx) => {
3116
3166
  const peers = enhancements.map((e) => e.peer);
3117
3167
  if (new Set(peers).size !== peers.length) {
3118
3168
  ctx.addIssue({ code: "custom", message: "enhancement peers must be unique" });
@@ -3133,10 +3183,10 @@ var moduleStructureFactsSchema = import_zod3.z.object({
3133
3183
  onIssue: (message) => ctx.addIssue({ code: "custom", message })
3134
3184
  });
3135
3185
  });
3136
- var moduleStructureCollectionSchema = import_zod3.z.object({
3186
+ var moduleStructureCollectionSchema = import_zod4.z.object({
3137
3187
  homeLocales: uniqueSortedStringArray("homeLocales"),
3138
- modules: import_zod3.z.array(moduleStructureFactsSchema),
3139
- truncated: import_zod3.z.boolean().optional(),
3188
+ modules: import_zod4.z.array(moduleStructureFactsSchema),
3189
+ truncated: import_zod4.z.boolean().optional(),
3140
3190
  collectionErrors: uniqueSortedStringArray("collectionErrors").optional()
3141
3191
  }).strict().superRefine((collection, ctx) => {
3142
3192
  const dirs = collection.modules.map((m) => m.dirName);
@@ -3153,9 +3203,9 @@ var moduleStructureCollectionSchema = import_zod3.z.object({
3153
3203
  });
3154
3204
 
3155
3205
  // ../../packages/module-contract/src/locale.ts
3156
- var import_zod4 = require("zod");
3206
+ var import_zod5 = require("zod");
3157
3207
  var LOCALE_BASENAME_REGEX = /^[a-z]{2,3}(-[A-Za-z0-9]+)*$/;
3158
- var localeBasenameSchema = import_zod4.z.string().max(35).regex(LOCALE_BASENAME_REGEX, "must be a BCP47-like locale tag (e.g. en, th, en-US)");
3208
+ var localeBasenameSchema = import_zod5.z.string().max(35).regex(LOCALE_BASENAME_REGEX, "must be a BCP47-like locale tag (e.g. en, th, en-US)");
3159
3209
  function isValidLocaleBasename(value) {
3160
3210
  return localeBasenameSchema.safeParse(value).success;
3161
3211
  }
@@ -3558,43 +3608,43 @@ function formatRoutePageExportErrors(nextRelativePath, validation) {
3558
3608
  var import_typescript2 = __toESM(require("typescript"), 1);
3559
3609
 
3560
3610
  // ../../packages/module-contract/src/module-registry.ts
3561
- var import_zod5 = require("zod");
3562
- var projectSlugSchema2 = import_zod5.z.string().refine((value) => validateSlug(value).valid, "must be a valid project slug");
3563
- var registryEnhancementSchema = import_zod5.z.object({
3611
+ var import_zod6 = require("zod");
3612
+ var projectSlugSchema2 = import_zod6.z.string().refine((value) => validateSlug(value).valid, "must be a valid project slug");
3613
+ var registryEnhancementSchema = import_zod6.z.object({
3564
3614
  peer: moduleNameSchema,
3565
- active: import_zod5.z.boolean()
3615
+ active: import_zod6.z.boolean()
3566
3616
  }).strict();
3567
- var registryModuleSchema = import_zod5.z.object({
3617
+ var registryModuleSchema = import_zod6.z.object({
3568
3618
  name: moduleNameSchema,
3569
3619
  /** Installed version as recorded by the rail (non-empty string). */
3570
- version: import_zod5.z.string().min(1),
3620
+ version: import_zod6.z.string().min(1),
3571
3621
  home: projectSlugSchema2,
3572
3622
  kind: moduleKindSchema,
3573
- mounts: import_zod5.z.array(mountSchema),
3574
- enhancements: import_zod5.z.array(registryEnhancementSchema)
3623
+ mounts: import_zod6.z.array(mountSchema),
3624
+ enhancements: import_zod6.z.array(registryEnhancementSchema)
3575
3625
  }).strict().superRefine((mod, ctx) => {
3576
3626
  for (let i = 0; i < mod.enhancements.length; i += 1) {
3577
3627
  if (mod.enhancements[i].peer === mod.name) {
3578
3628
  ctx.addIssue({
3579
- code: import_zod5.z.ZodIssueCode.custom,
3629
+ code: import_zod6.z.ZodIssueCode.custom,
3580
3630
  message: "enhancement peer must not equal the module's own name",
3581
3631
  path: ["enhancements", i, "peer"]
3582
3632
  });
3583
3633
  }
3584
3634
  }
3585
3635
  });
3586
- var generatedModuleRegistrySchema = import_zod5.z.object({
3587
- registryVersion: import_zod5.z.literal(1),
3636
+ var generatedModuleRegistrySchema = import_zod6.z.object({
3637
+ registryVersion: import_zod6.z.literal(1),
3588
3638
  /** Rail run id, or `"manual"` for fixtures. */
3589
- generatedBy: import_zod5.z.string().min(1),
3590
- modules: import_zod5.z.array(registryModuleSchema)
3639
+ generatedBy: import_zod6.z.string().min(1),
3640
+ modules: import_zod6.z.array(registryModuleSchema)
3591
3641
  }).strict().superRefine((registry, ctx) => {
3592
3642
  const seen = /* @__PURE__ */ new Set();
3593
3643
  for (let i = 0; i < registry.modules.length; i += 1) {
3594
3644
  const name = registry.modules[i].name;
3595
3645
  if (seen.has(name)) {
3596
3646
  ctx.addIssue({
3597
- code: import_zod5.z.ZodIssueCode.custom,
3647
+ code: import_zod6.z.ZodIssueCode.custom,
3598
3648
  message: `duplicate module name "${name}"`,
3599
3649
  path: ["modules", i, "name"]
3600
3650
  });
@@ -3965,171 +4015,9 @@ function analyzeClientSafeEntryImports(sourceText, fileName) {
3965
4015
  return analyzeClientSafeEntryImportsWithTs(import_typescript3.default, sourceText, fileName);
3966
4016
  }
3967
4017
 
3968
- // ../../packages/lib/src/shared/module-composition.ts
3969
- var moduleRefSchema = import_zod6.z.object({
3970
- homeProjectId: import_zod6.z.string().uuid(),
3971
- moduleName: moduleNameSchema
3972
- });
3973
- var creationSourceBlankSchema = import_zod6.z.object({
3974
- type: import_zod6.z.literal("blank")
3975
- });
3976
- var creationSourceBlueprintSchema = import_zod6.z.object({
3977
- type: import_zod6.z.literal("blueprint"),
3978
- /** Internal template/fork project id — keep template naming in identifiers. */
3979
- blueprintProjectId: import_zod6.z.string().uuid(),
3980
- /**
3981
- * `null`/absent means every feature Module. `[]` is refused: the platform
3982
- * serialises it to an empty `NEXT_PUBLIC_STARDECK_ENABLED_MODULES`, which the
3983
- * enablement parser reads back as "all" (`module-enablement.ts`) — the
3984
- * opposite of what an empty selection means.
3985
- */
3986
- enabledModules: import_zod6.z.array(moduleNameSchema).min(1, "Enable at least one Module").max(100).nullable().optional()
3987
- });
3988
- var creationSourceModulesSchema = import_zod6.z.object({
3989
- type: import_zod6.z.literal("modules"),
3990
- requested: import_zod6.z.array(moduleRefSchema).min(1)
3991
- });
3992
- var creationSourceSchema = import_zod6.z.discriminatedUnion("type", [
3993
- creationSourceBlankSchema,
3994
- creationSourceBlueprintSchema,
3995
- creationSourceModulesSchema
3996
- ]);
3997
- var moduleCompositionStatusSchema = import_zod6.z.enum([
3998
- "pending",
3999
- "installing",
4000
- "ready",
4001
- "partial",
4002
- "failed"
4003
- ]);
4004
- var resolvedModuleSnapshotSchema = moduleRefSchema.extend({
4005
- version: import_zod6.z.string().min(1),
4006
- homeCommitSha: import_zod6.z.string().min(1)
4007
- });
4008
- var moduleInstallHandoffSchema = import_zod6.z.object({
4009
- moduleName: import_zod6.z.string().min(1),
4010
- homeProjectId: import_zod6.z.string().uuid(),
4011
- installedVersion: import_zod6.z.string().min(1),
4012
- baselineSha: import_zod6.z.string().min(1),
4013
- mounts: import_zod6.z.array(
4014
- import_zod6.z.object({
4015
- group: import_zod6.z.string(),
4016
- segment: import_zod6.z.string()
4017
- })
4018
- ),
4019
- integration: import_zod6.z.array(import_zod6.z.string()),
4020
- workflows: import_zod6.z.array(import_zod6.z.string()),
4021
- prunedEnhancements: import_zod6.z.array(import_zod6.z.string()),
4022
- restoredEnhancements: import_zod6.z.array(import_zod6.z.string()).optional(),
4023
- permissions: import_zod6.z.array(
4024
- import_zod6.z.object({
4025
- key: import_zod6.z.string().min(1),
4026
- description: import_zod6.z.string().min(1)
4027
- })
4028
- ).optional()
4029
- });
4030
- var moduleCompositionRunAttemptSchema = import_zod6.z.object({
4031
- module: moduleRefSchema,
4032
- runId: import_zod6.z.string().min(1),
4033
- status: import_zod6.z.string().min(1),
4034
- schemaApplied: import_zod6.z.boolean(),
4035
- error: import_zod6.z.string().optional(),
4036
- /** Prefer full ModuleInstallHandoff; identity fields optional for older rows. */
4037
- handoff: moduleInstallHandoffSchema.partial({ moduleName: true, homeProjectId: true }).optional()
4038
- });
4039
- var initialModuleCompositionSchema = import_zod6.z.object({
4040
- version: import_zod6.z.literal(1),
4041
- status: moduleCompositionStatusSchema,
4042
- requested: import_zod6.z.array(moduleRefSchema).min(1),
4043
- resolved: import_zod6.z.array(resolvedModuleSnapshotSchema),
4044
- installOrder: import_zod6.z.array(moduleRefSchema),
4045
- runs: import_zod6.z.array(moduleCompositionRunAttemptSchema).default([]),
4046
- /**
4047
- * True when any failed/partial attempt applied schema before failing.
4048
- * Never claim transactional rollback across git/schema.
4049
- */
4050
- schemaApplied: import_zod6.z.boolean().default(false),
4051
- /**
4052
- * Present when retry would silently change pinned home SHAs — caller must
4053
- * reconfirm the new plan rather than continue.
4054
- */
4055
- reconfirmationRequired: import_zod6.z.object({
4056
- reason: import_zod6.z.string(),
4057
- previous: import_zod6.z.array(resolvedModuleSnapshotSchema),
4058
- next: import_zod6.z.array(resolvedModuleSnapshotSchema)
4059
- }).optional(),
4060
- error: import_zod6.z.string().optional(),
4061
- /**
4062
- * First-turn system handoff lifecycle. Absent/`pending` means inject when
4063
- * status is ready; `consumed` means a successful agent turn already used it.
4064
- */
4065
- systemHandoffStatus: import_zod6.z.enum(["pending", "consumed"]).optional(),
4066
- /**
4067
- * CAS ownership token for concurrent retry attempts. Only the attempt that
4068
- * currently owns this value may reset or compensate durable composition state.
4069
- */
4070
- retryAttemptId: import_zod6.z.string().min(1).optional(),
4071
- /**
4072
- * When the current `installing` attempt was claimed. A setup run that dies
4073
- * with its host (a killed Vercel instance) leaves the composition `installing`
4074
- * forever, and the creating page's poll only stops on ready/partial/failed —
4075
- * so staleness, not a queue's stall detector, is what settles it. Absent on
4076
- * rows claimed before this field existed; treated as stale.
4077
- */
4078
- attemptStartedAt: import_zod6.z.string().datetime().optional(),
4079
- /** Outside-module files the agent changed during connection work. */
4080
- integrationFiles: import_zod6.z.array(import_zod6.z.string()).optional(),
4081
- verificationSummary: import_zod6.z.string().optional()
4082
- });
4083
- var MODULE_SETUP_ATTEMPT_STALE_MS = 10 * 60 * 1e3;
4084
-
4085
- // ../../packages/lib/src/shared/compose-inputs.ts
4086
- var import_zod7 = require("zod");
4087
- var COMPOSE_INPUTS_PATH = "apps/web/stardeck.compose.json";
4088
- var composeInputsSchema = import_zod7.z.strictObject({
4089
- connectedStores: import_zod7.z.array(
4090
- import_zod7.z.strictObject({
4091
- storeId: import_zod7.z.string().min(1),
4092
- slug: import_zod7.z.string().min(1),
4093
- // A row with an empty binding key must not fail a deploy: the rail
4094
- // treats falsy as "no binding key", so normalise rather than reject.
4095
- bindingKey: import_zod7.z.string().nullish().transform((value) => value || null),
4096
- accessLevel: import_zod7.z.enum(["read", "write", "admin"]),
4097
- // Defaulted so a file written before the platform emitted store types
4098
- // (database rows only) still parses. The platform starts writing
4099
- // storage rows, with `type` set, once forks run a compose that reads it.
4100
- type: import_zod7.z.enum(["database", "storage"]).default("database")
4101
- })
4102
- ).default([]),
4103
- installs: import_zod7.z.record(
4104
- import_zod7.z.string(),
4105
- import_zod7.z.strictObject({
4106
- installedVersion: import_zod7.z.string().min(1),
4107
- datastoreBindings: import_zod7.z.record(import_zod7.z.string(), import_zod7.z.string()).nullish()
4108
- })
4109
- ).default({})
4110
- });
4111
- var STUB_IGNORE_PATH = "apps/web/src/app/.gitignore";
4112
- var STUB_IGNORE_HEADER = "# Generated by stardeck-compose \u2014 Module-rail stubs are build outputs; do not edit or commit them.";
4113
- function escapeStubIgnorePattern(pattern) {
4114
- const escaped = pattern.replace(/[\\[\]*?]/g, (char) => `\\${char}`);
4115
- return /^[#!]/.test(escaped) ? `\\${escaped}` : escaped;
4116
- }
4117
- function buildStubIgnore(artifactPaths) {
4118
- const prefix = "apps/web/src/app/";
4119
- const entries = artifactPaths.filter((artifact) => artifact.startsWith(prefix)).map((artifact) => escapeStubIgnorePattern(`/${artifact.slice(prefix.length)}`)).sort();
4120
- return [STUB_IGNORE_HEADER, ...entries].join("\n") + "\n";
4121
- }
4122
-
4123
- // ../../packages/lib/src/shared/module-enablement.ts
4124
- function isModuleEnabledByList(raw, name, kindOf) {
4125
- if (!raw) return true;
4126
- const kind = kindOf(name);
4127
- if (kind != null && kind !== "feature") return true;
4128
- return raw.split(",").includes(name);
4129
- }
4130
-
4131
4018
  // ../../packages/lib/src/shared/platform-owned-paths.ts
4132
4019
  var APP_WEB_PREFIX = "apps/web/";
4020
+ var BLUEPRINT_LINT_MARKER = `${APP_WEB_PREFIX}eslint-rules/module-boundaries.mjs`;
4133
4021
  var MODULE_STUB_MARKER = "@stardeck-module-rail-generated";
4134
4022
  var ENABLED_MODULES_ENV = "NEXT_PUBLIC_STARDECK_ENABLED_MODULES";
4135
4023
  var HEADLESS_MOUNTS_ENV = "NEXT_PUBLIC_STARDECK_HEADLESS_MOUNTS";
@@ -6054,6 +5942,52 @@ function rejectPseudoModuleEntries(entries, parentDir, label) {
6054
5942
  return dirs;
6055
5943
  }
6056
5944
 
5945
+ // ../../packages/lib/src/shared/module-composition.ts
5946
+ var import_zod7 = require("zod");
5947
+ var creationSourceBlankSchema = import_zod7.z.object({
5948
+ type: import_zod7.z.literal("blank")
5949
+ });
5950
+ var creationSourceBlueprintSchema = import_zod7.z.object({
5951
+ type: import_zod7.z.literal("blueprint"),
5952
+ /** Internal template/fork project id — keep template naming in identifiers. */
5953
+ blueprintProjectId: import_zod7.z.string().uuid(),
5954
+ /**
5955
+ * `null`/absent means every feature Module: the platform stores that as the
5956
+ * explicit list of feature Modules in the published Blueprint version the fork
5957
+ * is cut from, so a Module a later Blueprint update adds arrives off. `[]` is
5958
+ * refused: the platform serialises it to an empty
5959
+ * `NEXT_PUBLIC_STARDECK_ENABLED_MODULES`, which the enablement parser reads
5960
+ * back as "all" (`module-enablement.ts`) — the opposite of an empty selection.
5961
+ */
5962
+ enabledModules: import_zod7.z.array(moduleNameSchema).min(1, "Enable at least one Module").max(100).nullable().optional()
5963
+ });
5964
+ var creationSourceSchema = import_zod7.z.discriminatedUnion("type", [
5965
+ creationSourceBlankSchema,
5966
+ creationSourceBlueprintSchema
5967
+ ]);
5968
+ var moduleInstallHandoffSchema = import_zod7.z.object({
5969
+ moduleName: import_zod7.z.string().min(1),
5970
+ homeProjectId: import_zod7.z.string().uuid(),
5971
+ installedVersion: import_zod7.z.string().min(1),
5972
+ baselineSha: import_zod7.z.string().min(1),
5973
+ mounts: import_zod7.z.array(
5974
+ import_zod7.z.object({
5975
+ group: import_zod7.z.string(),
5976
+ segment: import_zod7.z.string()
5977
+ })
5978
+ ),
5979
+ integration: import_zod7.z.array(import_zod7.z.string()),
5980
+ workflows: import_zod7.z.array(import_zod7.z.string()),
5981
+ prunedEnhancements: import_zod7.z.array(import_zod7.z.string()),
5982
+ restoredEnhancements: import_zod7.z.array(import_zod7.z.string()).optional(),
5983
+ permissions: import_zod7.z.array(
5984
+ import_zod7.z.object({
5985
+ key: import_zod7.z.string().min(1),
5986
+ description: import_zod7.z.string().min(1)
5987
+ })
5988
+ ).optional()
5989
+ });
5990
+
6057
5991
  // ../../packages/lib/src/shared/schema-ops.ts
6058
5992
  var import_zod8 = require("zod");
6059
5993
  var columnSpecSchema = import_zod8.z.object({
@@ -7517,6 +7451,9 @@ async function reconcileCompositionArtifacts(context, options = {}) {
7517
7451
  var HOME_I18N_SUBSTRATE_DIR = `${APP_PACKAGE_DIR}/src/lib/i18n/substrate`;
7518
7452
  var HOME_I18N_MESSAGES_DIR = `${APP_PACKAGE_DIR}/src/lib/i18n/messages`;
7519
7453
 
7454
+ // src/index.ts
7455
+ var import_typescript6 = __toESM(require("typescript"));
7456
+
7520
7457
  // src/module-boundaries.ts
7521
7458
  var import_node_fs2 = __toESM(require("fs"));
7522
7459
  var import_node_path2 = __toESM(require("path"));
@@ -7786,6 +7723,41 @@ function assertNoAppLayerImporters(cwd, excluded) {
7786
7723
  );
7787
7724
  }
7788
7725
  }
7726
+ var TSCONFIG_PATH = "apps/web/tsconfig.json";
7727
+ var BUILD_TSCONFIG_PATH = "apps/web/tsconfig.build.gen.json";
7728
+ var BUILD_TSCONFIG_HEADER = "// Generated by stardeck-compose \u2014 the tsconfig `next build` type-checks. Do not edit or commit.";
7729
+ function writeBuildTsconfig(cwd, excluded) {
7730
+ const baseFile = import_node_path3.default.join(cwd, TSCONFIG_PATH);
7731
+ if (!import_node_fs3.default.existsSync(import_node_path3.default.join(cwd, MODULES_DIR2)) || !import_node_fs3.default.existsSync(baseFile)) return;
7732
+ const base = import_typescript6.default.readConfigFile(baseFile, import_typescript6.default.sys.readFile);
7733
+ if (base.error) {
7734
+ throw new Error(
7735
+ `[compose] cannot read ${TSCONFIG_PATH}: ${import_typescript6.default.flattenDiagnosticMessageText(base.error.messageText, "\n")}`
7736
+ );
7737
+ }
7738
+ const baseExclude = base.config?.exclude ?? ["node_modules"];
7739
+ const modulesDir = import_node_path3.default.posix.relative("apps/web", MODULES_DIR2);
7740
+ const config = {
7741
+ extends: "./tsconfig.json",
7742
+ exclude: [
7743
+ ...baseExclude,
7744
+ ...excluded.flatMap((name) => [
7745
+ `${modulesDir}/${name}`,
7746
+ `${modulesDir}/*/enhancements/${name}`
7747
+ ])
7748
+ ]
7749
+ };
7750
+ const content = `${BUILD_TSCONFIG_HEADER}
7751
+ ${JSON.stringify(config, null, 2)}
7752
+ `;
7753
+ const file = import_node_path3.default.join(cwd, BUILD_TSCONFIG_PATH);
7754
+ if (!import_node_fs3.default.existsSync(file) || import_node_fs3.default.readFileSync(file, "utf8") !== content) {
7755
+ import_node_fs3.default.writeFileSync(file, content);
7756
+ }
7757
+ console.log(
7758
+ `[compose] ${BUILD_TSCONFIG_PATH} excludes ${excluded.length} Module(s): ${excluded.join(",") || "none"}`
7759
+ );
7760
+ }
7789
7761
  function removeDir(absolute) {
7790
7762
  if (!import_node_fs3.default.existsSync(absolute)) return false;
7791
7763
  import_node_fs3.default.rmSync(absolute, { recursive: true, force: true });
@@ -7833,6 +7805,7 @@ async function compose(options) {
7833
7805
  skipComposeInputs: true
7834
7806
  });
7835
7807
  const gitignoreEntries = options.enabled ? null : writeStubGitignore(options.cwd, result.artifactPaths);
7808
+ writeBuildTsconfig(options.cwd, result.excludedModules);
7836
7809
  let pruned = 0;
7837
7810
  if (options.prune) {
7838
7811
  for (const name of result.excludedModules) {
@@ -7855,6 +7828,7 @@ async function compose(options) {
7855
7828
  }
7856
7829
  // Annotate the CommonJS export names for ESM import in node:
7857
7830
  0 && (module.exports = {
7831
+ BUILD_TSCONFIG_PATH,
7858
7832
  COMPOSE_INPUTS_PATH,
7859
7833
  assertSupportedTypescript,
7860
7834
  compose,