@stardeck-customer-apps/compose 0.9.0 → 0.10.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.mjs CHANGED
@@ -2080,11 +2080,54 @@ function shellQuote(value) {
2080
2080
  return `'${value.replace(/'/g, `'\\''`)}'`;
2081
2081
  }
2082
2082
 
2083
- // ../../packages/lib/src/shared/module-composition.ts
2084
- import { z as z6 } from "zod";
2083
+ // ../../packages/lib/src/shared/compose-inputs.ts
2084
+ import { z } from "zod";
2085
+ var COMPOSE_INPUTS_PATH = "apps/web/stardeck.compose.json";
2086
+ var composeInputsSchema = z.strictObject({
2087
+ connectedStores: z.array(
2088
+ z.strictObject({
2089
+ storeId: z.string().min(1),
2090
+ slug: z.string().min(1),
2091
+ // A row with an empty binding key must not fail a deploy: the rail
2092
+ // treats falsy as "no binding key", so normalise rather than reject.
2093
+ bindingKey: z.string().nullish().transform((value) => value || null),
2094
+ accessLevel: z.enum(["read", "write", "admin"]),
2095
+ // Defaulted so a file written before the platform emitted store types
2096
+ // (database rows only) still parses. The platform starts writing
2097
+ // storage rows, with `type` set, once forks run a compose that reads it.
2098
+ type: z.enum(["database", "storage"]).default("database")
2099
+ })
2100
+ ).default([]),
2101
+ installs: z.record(
2102
+ z.string(),
2103
+ z.strictObject({
2104
+ installedVersion: z.string().min(1),
2105
+ datastoreBindings: z.record(z.string(), z.string()).nullish()
2106
+ })
2107
+ ).default({})
2108
+ });
2109
+ var STUB_IGNORE_PATH = "apps/web/src/app/.gitignore";
2110
+ var STUB_IGNORE_HEADER = "# Generated by stardeck-compose \u2014 Module-rail stubs are build outputs; do not edit or commit them.";
2111
+ function escapeStubIgnorePattern(pattern) {
2112
+ const escaped = pattern.replace(/[\\[\]*?]/g, (char) => `\\${char}`);
2113
+ return /^[#!]/.test(escaped) ? `\\${escaped}` : escaped;
2114
+ }
2115
+ function buildStubIgnore(artifactPaths) {
2116
+ const prefix = "apps/web/src/app/";
2117
+ const entries = artifactPaths.filter((artifact) => artifact.startsWith(prefix)).map((artifact) => escapeStubIgnorePattern(`/${artifact.slice(prefix.length)}`)).sort();
2118
+ return [STUB_IGNORE_HEADER, ...entries].join("\n") + "\n";
2119
+ }
2120
+
2121
+ // ../../packages/lib/src/shared/module-enablement.ts
2122
+ function isModuleEnabledByList(raw, name, kindOf) {
2123
+ if (!raw) return true;
2124
+ const kind = kindOf(name);
2125
+ if (kind != null && kind !== "feature") return true;
2126
+ return raw.split(",").includes(name);
2127
+ }
2085
2128
 
2086
2129
  // ../../packages/module-contract/src/module-manifest.ts
2087
- import { z } from "zod";
2130
+ import { z as z2 } from "zod";
2088
2131
 
2089
2132
  // ../../packages/module-contract/src/slug.ts
2090
2133
  function validateSlug(slug) {
@@ -2119,13 +2162,13 @@ var ROUTE_GROUP_REGEX = /^\([a-z0-9-]+\)$/;
2119
2162
  var ENDPOINT_STATIC_SEGMENT_REGEX = /^[a-z0-9]+(?:-[a-z0-9]+)*$/;
2120
2163
  var ENDPOINT_PARAM_NAME_REGEX = /^[a-z][a-z0-9_-]*$/;
2121
2164
  var ENDPOINT_METHODS = ["GET", "HEAD", "POST", "PUT", "PATCH", "DELETE", "OPTIONS"];
2122
- var moduleNameSchema = z.string().max(40).regex(KEBAB_SLUG_REGEX, "must be a kebab-case slug (lowercase letters, digits, hyphens)");
2165
+ var moduleNameSchema = z2.string().max(40).regex(KEBAB_SLUG_REGEX, "must be a kebab-case slug (lowercase letters, digits, hyphens)");
2123
2166
  function isValidModuleName(value) {
2124
2167
  return moduleNameSchema.safeParse(value).success;
2125
2168
  }
2126
- var projectSlugSchema = z.string().refine((value) => validateSlug(value).valid, "must be a valid project slug");
2127
- var moduleKindSchema = z.enum(["feature", "library", "contract"]);
2128
- var endpointMethodSchema = z.enum(ENDPOINT_METHODS);
2169
+ var projectSlugSchema = z2.string().refine((value) => validateSlug(value).valid, "must be a valid project slug");
2170
+ var moduleKindSchema = z2.enum(["feature", "library", "contract"]);
2171
+ var endpointMethodSchema = z2.enum(ENDPOINT_METHODS);
2129
2172
  function endpointPathValidationError(path4) {
2130
2173
  if (!path4.startsWith("/api/")) {
2131
2174
  return 'must begin with "/api/"';
@@ -2210,21 +2253,21 @@ function normalizeEndpointPathForCollision(path4) {
2210
2253
  return segment;
2211
2254
  }).join("/");
2212
2255
  }
2213
- var endpointPathSchema = z.string().superRefine((path4, ctx) => {
2256
+ var endpointPathSchema = z2.string().superRefine((path4, ctx) => {
2214
2257
  const error = endpointPathValidationError(path4);
2215
2258
  if (error != null) {
2216
- ctx.addIssue({ code: z.ZodIssueCode.custom, message: error });
2259
+ ctx.addIssue({ code: z2.ZodIssueCode.custom, message: error });
2217
2260
  }
2218
2261
  });
2219
- var endpointClaimSchema = z.object({
2262
+ var endpointClaimSchema = z2.object({
2220
2263
  path: endpointPathSchema,
2221
- methods: z.array(endpointMethodSchema).min(1, "methods must be non-empty").superRefine((methods, ctx) => {
2264
+ methods: z2.array(endpointMethodSchema).min(1, "methods must be non-empty").superRefine((methods, ctx) => {
2222
2265
  const seen = /* @__PURE__ */ new Set();
2223
2266
  for (let i = 0; i < methods.length; i += 1) {
2224
2267
  const method = methods[i];
2225
2268
  if (seen.has(method)) {
2226
2269
  ctx.addIssue({
2227
- code: z.ZodIssueCode.custom,
2270
+ code: z2.ZodIssueCode.custom,
2228
2271
  message: `duplicate method "${method}"`,
2229
2272
  path: [i]
2230
2273
  });
@@ -2261,14 +2304,14 @@ function mountSegmentValidationError(segment) {
2261
2304
  }
2262
2305
  return null;
2263
2306
  }
2264
- var mountSegmentSchema = z.string().superRefine((segment, ctx) => {
2307
+ var mountSegmentSchema = z2.string().superRefine((segment, ctx) => {
2265
2308
  const error = mountSegmentValidationError(segment);
2266
2309
  if (error != null) {
2267
- ctx.addIssue({ code: z.ZodIssueCode.custom, message: error });
2310
+ ctx.addIssue({ code: z2.ZodIssueCode.custom, message: error });
2268
2311
  }
2269
2312
  });
2270
- var mountSchema = z.object({
2271
- group: z.string().regex(ROUTE_GROUP_REGEX, 'must be a Next.js route group like "(admin)"'),
2313
+ var mountSchema = z2.object({
2314
+ group: z2.string().regex(ROUTE_GROUP_REGEX, 'must be a Next.js route group like "(admin)"'),
2272
2315
  segment: mountSegmentSchema
2273
2316
  }).strict();
2274
2317
  function splitMountSegment(segment) {
@@ -2281,21 +2324,21 @@ function splitMountSegment(segment) {
2281
2324
  }
2282
2325
  return segment.split("/");
2283
2326
  }
2284
- var tableNameSchema = z.string().regex(SNAKE_TABLE_REGEX, "must be snake_case");
2327
+ var tableNameSchema = z2.string().regex(SNAKE_TABLE_REGEX, "must be snake_case");
2285
2328
  var NPM_PACKAGE_NAME_REGEX = /^(@[a-z0-9-~][a-z0-9-._~]*\/)?[a-z0-9-~][a-z0-9-._~]*$/;
2286
- var npmPackageNameSchema = z.string().max(214).regex(NPM_PACKAGE_NAME_REGEX, "must be a valid npm package name");
2287
- var descriptionSchema = z.string().max(200, "must be at most 200 characters").refine((value) => value.trim().length > 0, "must be non-empty after trimming");
2288
- var crossAppSchema = z.object({
2289
- exposes: z.array(z.unknown()).max(0, "must be empty until cross-app contracts are defined"),
2290
- consumes: z.array(z.unknown()).max(0, "must be empty until cross-app contracts are defined")
2329
+ var npmPackageNameSchema = z2.string().max(214).regex(NPM_PACKAGE_NAME_REGEX, "must be a valid npm package name");
2330
+ var descriptionSchema = z2.string().max(200, "must be at most 200 characters").refine((value) => value.trim().length > 0, "must be non-empty after trimming");
2331
+ var crossAppSchema = z2.object({
2332
+ exposes: z2.array(z2.unknown()).max(0, "must be empty until cross-app contracts are defined"),
2333
+ consumes: z2.array(z2.unknown()).max(0, "must be empty until cross-app contracts are defined")
2291
2334
  }).strict();
2292
- var enhancementWorkflowsSchema = z.record(moduleNameSchema, z.array(z.string().min(1))).default({});
2293
- var enhancementEndpointsSchema = z.record(moduleNameSchema, z.array(endpointClaimSchema)).default({});
2294
- var datastoreRequirementSchema = z.object({
2335
+ var enhancementWorkflowsSchema = z2.record(moduleNameSchema, z2.array(z2.string().min(1))).default({});
2336
+ var enhancementEndpointsSchema = z2.record(moduleNameSchema, z2.array(endpointClaimSchema)).default({});
2337
+ var datastoreRequirementSchema = z2.object({
2295
2338
  /** Logical name, module-local, snake_case. Never a physical store key. */
2296
2339
  id: tableNameSchema,
2297
2340
  /** "app" = this project's app-local store; "org" = an org-level shared store. */
2298
- scope: z.enum(["app", "org"]).default("app"),
2341
+ scope: z2.enum(["app", "org"]).default("app"),
2299
2342
  /**
2300
2343
  * Which kind of connected store satisfies this requirement. A "database"
2301
2344
  * requirement only ever binds to a database store and a "storage" one
@@ -2303,34 +2346,34 @@ var datastoreRequirementSchema = z.object({
2303
2346
  * rail never crosses the two. Defaults to "database", the only kind the
2304
2347
  * rail resolved before this field existed.
2305
2348
  */
2306
- type: z.enum(["database", "storage"]).default("database"),
2349
+ type: z2.enum(["database", "storage"]).default("database"),
2307
2350
  /** true → install fails when no store resolves; false → binding omitted, module degrades. */
2308
- required: z.boolean().default(true),
2351
+ required: z2.boolean().default(true),
2309
2352
  /** Checked against the connected store's accessLevel at install. */
2310
- access: z.enum(["read", "write", "admin"]).default("write")
2353
+ access: z2.enum(["read", "write", "admin"]).default("write")
2311
2354
  }).strict();
2312
- var permissionClaimSchema = z.object({
2355
+ var permissionClaimSchema = z2.object({
2313
2356
  /**
2314
2357
  * Lowercase resource:action with one colon and no underscores. This grammar
2315
2358
  * is deliberately narrower than the platform permission tool's charset.
2316
2359
  */
2317
- key: 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)"),
2360
+ key: z2.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)"),
2318
2361
  /** Human label for the deployment auth config row. */
2319
2362
  description: descriptionSchema
2320
2363
  }).strict();
2321
- var seedBundleSchema = z.object({
2364
+ var seedBundleSchema = z2.object({
2322
2365
  table: tableNameSchema,
2323
2366
  /** Columns forming the ON CONFLICT key — must appear in every row. */
2324
- conflictTarget: z.array(z.string().min(1)).min(1),
2367
+ conflictTarget: z2.array(z2.string().min(1)).min(1),
2325
2368
  /** Scalar JSON values only (no nested objects/arrays). */
2326
- rows: z.array(z.record(z.string(), z.union([z.string(), z.number(), z.boolean(), z.null()]))).min(1)
2369
+ rows: z2.array(z2.record(z2.string(), z2.union([z2.string(), z2.number(), z2.boolean(), z2.null()]))).min(1)
2327
2370
  }).strict().superRefine((bundle, ctx) => {
2328
2371
  const rowKeys = bundle.rows.map((row) => Object.keys(row).sort().join("\0"));
2329
2372
  const canonical = rowKeys[0];
2330
2373
  for (let i = 1; i < rowKeys.length; i += 1) {
2331
2374
  if (rowKeys[i] !== canonical) {
2332
2375
  ctx.addIssue({
2333
- code: z.ZodIssueCode.custom,
2376
+ code: z2.ZodIssueCode.custom,
2334
2377
  message: "all rows in a seed bundle must have identical key sets",
2335
2378
  path: ["rows", i]
2336
2379
  });
@@ -2342,7 +2385,7 @@ var seedBundleSchema = z.object({
2342
2385
  for (const col of bundle.conflictTarget) {
2343
2386
  if (!keys.has(col)) {
2344
2387
  ctx.addIssue({
2345
- code: z.ZodIssueCode.custom,
2388
+ code: z2.ZodIssueCode.custom,
2346
2389
  message: `conflictTarget column "${col}" must be present in every row`,
2347
2390
  path: ["rows", i]
2348
2391
  });
@@ -2350,35 +2393,35 @@ var seedBundleSchema = z.object({
2350
2393
  }
2351
2394
  }
2352
2395
  });
2353
- var moduleManifestSchema = z.object({
2396
+ var moduleManifestSchema = z2.object({
2354
2397
  name: moduleNameSchema,
2355
2398
  kind: moduleKindSchema,
2356
2399
  // Release versions are platform-owned in module_versions. Accept this
2357
2400
  // legacy field while existing Module source ages out, but strip it from the
2358
2401
  // parsed contract so no runtime can treat module.json as version authority.
2359
- version: z.unknown().optional(),
2402
+ version: z2.unknown().optional(),
2360
2403
  home: projectSlugSchema,
2361
2404
  /** Machine-checkable purpose line — required, ≤200 code units, non-blank when trimmed. */
2362
2405
  description: descriptionSchema,
2363
- uses: z.array(moduleNameSchema).default([]),
2406
+ uses: z2.array(moduleNameSchema).default([]),
2364
2407
  /**
2365
2408
  * Soft peers: this module ships `enhancements/<peer>/` directories that are
2366
2409
  * composition-pruned — the installer includes them only when the peer is
2367
2410
  * present, so the peer is NOT an install-time requirement. Disjoint from
2368
2411
  * `uses`; entries may name modules absent from the composition.
2369
2412
  */
2370
- enhancements: z.array(moduleNameSchema).default([]),
2371
- tables: z.array(tableNameSchema).default([]),
2372
- mounts: z.array(mountSchema).default([]),
2373
- integration: z.array(z.string()).default([]),
2374
- workflows: z.array(z.string().min(1)).default([]),
2413
+ enhancements: z2.array(moduleNameSchema).default([]),
2414
+ tables: z2.array(tableNameSchema).default([]),
2415
+ mounts: z2.array(mountSchema).default([]),
2416
+ integration: z2.array(z2.string()).default([]),
2417
+ workflows: z2.array(z2.string().min(1)).default([]),
2375
2418
  /**
2376
2419
  * Slice-scoped workflow names keyed by peer. Keys must be ⊆ `enhancements`;
2377
2420
  * names must be unique across root `workflows` and every slice list.
2378
2421
  */
2379
2422
  enhancementWorkflows: enhancementWorkflowsSchema,
2380
2423
  /** Root API endpoint path claims. */
2381
- endpoints: z.array(endpointClaimSchema).default([]),
2424
+ endpoints: z2.array(endpointClaimSchema).default([]),
2382
2425
  /**
2383
2426
  * Slice-scoped endpoint claims keyed by peer. Keys must be ⊆ `enhancements`;
2384
2427
  * normalized paths must be unique across root and every slice.
@@ -2394,38 +2437,38 @@ var moduleManifestSchema = z.object({
2394
2437
  * to a physical connected store and generates module-datastores.gen.ts;
2395
2438
  * unlike seeds, this field drives generated output.
2396
2439
  */
2397
- datastores: z.array(datastoreRequirementSchema).optional(),
2440
+ datastores: z2.array(datastoreRequirementSchema).optional(),
2398
2441
  /**
2399
2442
  * Keys this module's guards enforce. Install registers them in deployment
2400
2443
  * auth config; registration only — declaring is never granting.
2401
2444
  */
2402
- permissions: z.array(permissionClaimSchema).optional(),
2445
+ permissions: z2.array(permissionClaimSchema).optional(),
2403
2446
  /**
2404
2447
  * Optional starter rows for tables this module owns. Replay is
2405
2448
  * `INSERT ... ON CONFLICT (conflictTarget) DO NOTHING` — idempotent by
2406
2449
  * construction; the rail (not this schema) performs the replay.
2407
2450
  */
2408
- seeds: z.array(seedBundleSchema).optional(),
2451
+ seeds: z2.array(seedBundleSchema).optional(),
2409
2452
  /** npm packages the source imports beyond the base app. Names only; the rail installs each at the home app's range. */
2410
- packages: z.array(npmPackageNameSchema).optional(),
2453
+ packages: z2.array(npmPackageNameSchema).optional(),
2411
2454
  /**
2412
2455
  * UI-layer contract. `separable: true` asserts the Module's components/ and
2413
2456
  * routes/ hold presentation only — the Blueprint's
2414
2457
  * `module-boundaries/ui-layer` lint rule enforces it — so a fork may
2415
2458
  * soft-eject them. See docs/module-ui-soft-eject-plan.md.
2416
2459
  */
2417
- ui: z.object({ separable: z.boolean() }).strict().optional()
2460
+ ui: z2.object({ separable: z2.boolean() }).strict().optional()
2418
2461
  }).strict().superRefine((manifest, ctx) => {
2419
2462
  if (manifest.uses.includes(manifest.name)) {
2420
2463
  ctx.addIssue({
2421
- code: z.ZodIssueCode.custom,
2464
+ code: z2.ZodIssueCode.custom,
2422
2465
  message: "a module cannot list itself in uses",
2423
2466
  path: ["uses"]
2424
2467
  });
2425
2468
  }
2426
2469
  if (manifest.enhancements.includes(manifest.name)) {
2427
2470
  ctx.addIssue({
2428
- code: z.ZodIssueCode.custom,
2471
+ code: z2.ZodIssueCode.custom,
2429
2472
  message: "a module cannot list itself in enhancements",
2430
2473
  path: ["enhancements"]
2431
2474
  });
@@ -2433,7 +2476,7 @@ var moduleManifestSchema = z.object({
2433
2476
  const hardAndSoft = manifest.enhancements.filter((peer) => manifest.uses.includes(peer));
2434
2477
  if (hardAndSoft.length > 0) {
2435
2478
  ctx.addIssue({
2436
- code: z.ZodIssueCode.custom,
2479
+ code: z2.ZodIssueCode.custom,
2437
2480
  message: `uses and enhancements must be disjoint (a peer is either a hard dep or a soft one): ${hardAndSoft.join(", ")}`,
2438
2481
  path: ["enhancements"]
2439
2482
  });
@@ -2442,7 +2485,7 @@ var moduleManifestSchema = z.object({
2442
2485
  for (const peer of Object.keys(manifest.enhancementWorkflows)) {
2443
2486
  if (!enhancementPeers.has(peer)) {
2444
2487
  ctx.addIssue({
2445
- code: z.ZodIssueCode.custom,
2488
+ code: z2.ZodIssueCode.custom,
2446
2489
  message: `enhancementWorkflows key "${peer}" must be listed in enhancements`,
2447
2490
  path: ["enhancementWorkflows", peer]
2448
2491
  });
@@ -2451,7 +2494,7 @@ var moduleManifestSchema = z.object({
2451
2494
  for (const peer of Object.keys(manifest.enhancementEndpoints)) {
2452
2495
  if (!enhancementPeers.has(peer)) {
2453
2496
  ctx.addIssue({
2454
- code: z.ZodIssueCode.custom,
2497
+ code: z2.ZodIssueCode.custom,
2455
2498
  message: `enhancementEndpoints key "${peer}" must be listed in enhancements`,
2456
2499
  path: ["enhancementEndpoints", peer]
2457
2500
  });
@@ -2462,7 +2505,7 @@ var moduleManifestSchema = z.object({
2462
2505
  const existing = seenWorkflows.get(name);
2463
2506
  if (existing != null) {
2464
2507
  ctx.addIssue({
2465
- code: z.ZodIssueCode.custom,
2508
+ code: z2.ZodIssueCode.custom,
2466
2509
  message: `duplicate workflow name "${name}" (also at ${existing})`,
2467
2510
  path: path4
2468
2511
  });
@@ -2489,7 +2532,7 @@ var moduleManifestSchema = z.object({
2489
2532
  const existing = seenEndpointKeys.get(key);
2490
2533
  if (existing != null) {
2491
2534
  ctx.addIssue({
2492
- code: z.ZodIssueCode.custom,
2535
+ code: z2.ZodIssueCode.custom,
2493
2536
  message: `duplicate normalized endpoint path "${key}" (also at ${existing})`,
2494
2537
  path: path4
2495
2538
  });
@@ -2511,7 +2554,7 @@ var moduleManifestSchema = z.object({
2511
2554
  const id = manifest.datastores[i].id;
2512
2555
  if (seenDatastoreIds.has(id)) {
2513
2556
  ctx.addIssue({
2514
- code: z.ZodIssueCode.custom,
2557
+ code: z2.ZodIssueCode.custom,
2515
2558
  message: `duplicate datastore id "${id}"`,
2516
2559
  path: ["datastores", i, "id"]
2517
2560
  });
@@ -2526,7 +2569,7 @@ var moduleManifestSchema = z.object({
2526
2569
  const key = manifest.permissions[i].key;
2527
2570
  if (seenPermissionKeys.has(key)) {
2528
2571
  ctx.addIssue({
2529
- code: z.ZodIssueCode.custom,
2572
+ code: z2.ZodIssueCode.custom,
2530
2573
  message: `duplicate permission key "${key}"`,
2531
2574
  path: ["permissions", i, "key"]
2532
2575
  });
@@ -2538,35 +2581,35 @@ var moduleManifestSchema = z.object({
2538
2581
  if (manifest.kind === "library") {
2539
2582
  if (manifest.tables.length > 0) {
2540
2583
  ctx.addIssue({
2541
- code: z.ZodIssueCode.custom,
2584
+ code: z2.ZodIssueCode.custom,
2542
2585
  message: "library modules must not declare tables",
2543
2586
  path: ["tables"]
2544
2587
  });
2545
2588
  }
2546
2589
  if (manifest.mounts.length > 0) {
2547
2590
  ctx.addIssue({
2548
- code: z.ZodIssueCode.custom,
2591
+ code: z2.ZodIssueCode.custom,
2549
2592
  message: "library modules must not declare mounts",
2550
2593
  path: ["mounts"]
2551
2594
  });
2552
2595
  }
2553
2596
  if (manifest.seeds != null && manifest.seeds.length > 0) {
2554
2597
  ctx.addIssue({
2555
- code: z.ZodIssueCode.custom,
2598
+ code: z2.ZodIssueCode.custom,
2556
2599
  message: "library modules must not declare seeds",
2557
2600
  path: ["seeds"]
2558
2601
  });
2559
2602
  }
2560
2603
  if (manifest.datastores != null && manifest.datastores.length > 0) {
2561
2604
  ctx.addIssue({
2562
- code: z.ZodIssueCode.custom,
2605
+ code: z2.ZodIssueCode.custom,
2563
2606
  message: "library modules must not declare datastores",
2564
2607
  path: ["datastores"]
2565
2608
  });
2566
2609
  }
2567
2610
  if (manifest.permissions != null && manifest.permissions.length > 0) {
2568
2611
  ctx.addIssue({
2569
- code: z.ZodIssueCode.custom,
2612
+ code: z2.ZodIssueCode.custom,
2570
2613
  message: "library modules must not declare permissions",
2571
2614
  path: ["permissions"]
2572
2615
  });
@@ -2574,7 +2617,7 @@ var moduleManifestSchema = z.object({
2574
2617
  }
2575
2618
  if (manifest.kind === "contract" && manifest.mounts.length > 0) {
2576
2619
  ctx.addIssue({
2577
- code: z.ZodIssueCode.custom,
2620
+ code: z2.ZodIssueCode.custom,
2578
2621
  message: "contract modules must not declare mounts",
2579
2622
  path: ["mounts"]
2580
2623
  });
@@ -2585,7 +2628,7 @@ var moduleManifestSchema = z.object({
2585
2628
  const bundle = manifest.seeds[i];
2586
2629
  if (!ownedTables.has(bundle.table)) {
2587
2630
  ctx.addIssue({
2588
- code: z.ZodIssueCode.custom,
2631
+ code: z2.ZodIssueCode.custom,
2589
2632
  message: `seeds may only target tables listed in tables (got "${bundle.table}")`,
2590
2633
  path: ["seeds", i, "table"]
2591
2634
  });
@@ -2636,10 +2679,10 @@ var MANDATORY_MODULE_CHECK_DESCRIPTORS = Object.freeze([
2636
2679
  ]);
2637
2680
 
2638
2681
  // ../../packages/module-contract/src/module-structure.ts
2639
- import { z as z3 } from "zod";
2682
+ import { z as z4 } from "zod";
2640
2683
 
2641
2684
  // ../../packages/module-contract/src/module-e2e-manifest.ts
2642
- import { z as z2 } from "zod";
2685
+ import { z as z3 } from "zod";
2643
2686
  function e2eSpecFileValidationError(file) {
2644
2687
  if (file.length === 0) {
2645
2688
  return "must be a non-empty relative path ending in .spec.ts";
@@ -2667,22 +2710,22 @@ function e2eSpecFileValidationError(file) {
2667
2710
  }
2668
2711
  return null;
2669
2712
  }
2670
- var e2eSpecFileSchema = z2.string().superRefine((file, ctx) => {
2713
+ var e2eSpecFileSchema = z3.string().superRefine((file, ctx) => {
2671
2714
  const error = e2eSpecFileValidationError(file);
2672
2715
  if (error != null) {
2673
- ctx.addIssue({ code: z2.ZodIssueCode.custom, message: error });
2716
+ ctx.addIssue({ code: z3.ZodIssueCode.custom, message: error });
2674
2717
  }
2675
2718
  });
2676
- var e2eSpecSchema = z2.object({
2719
+ var e2eSpecSchema = z3.object({
2677
2720
  file: e2eSpecFileSchema,
2678
- requires: z2.array(moduleNameSchema).min(1, "requires must be non-empty")
2721
+ requires: z3.array(moduleNameSchema).min(1, "requires must be non-empty")
2679
2722
  }).strict().superRefine((spec, ctx) => {
2680
2723
  const seen = /* @__PURE__ */ new Set();
2681
2724
  for (let i = 0; i < spec.requires.length; i += 1) {
2682
2725
  const name = spec.requires[i];
2683
2726
  if (seen.has(name)) {
2684
2727
  ctx.addIssue({
2685
- code: z2.ZodIssueCode.custom,
2728
+ code: z3.ZodIssueCode.custom,
2686
2729
  message: `duplicate requirement "${name}"`,
2687
2730
  path: ["requires", i]
2688
2731
  });
@@ -2691,15 +2734,15 @@ var e2eSpecSchema = z2.object({
2691
2734
  }
2692
2735
  }
2693
2736
  });
2694
- var moduleE2eManifestSchema = z2.object({
2695
- specs: z2.array(e2eSpecSchema).min(1, "specs must contain at least one entry")
2737
+ var moduleE2eManifestSchema = z3.object({
2738
+ specs: z3.array(e2eSpecSchema).min(1, "specs must contain at least one entry")
2696
2739
  }).strict().superRefine((manifest, ctx) => {
2697
2740
  const seenFiles = /* @__PURE__ */ new Set();
2698
2741
  for (let i = 0; i < manifest.specs.length; i += 1) {
2699
2742
  const file = manifest.specs[i].file;
2700
2743
  if (seenFiles.has(file)) {
2701
2744
  ctx.addIssue({
2702
- code: z2.ZodIssueCode.custom,
2745
+ code: z3.ZodIssueCode.custom,
2703
2746
  message: `duplicate file "${file}"`,
2704
2747
  path: ["specs", i, "file"]
2705
2748
  });
@@ -2941,7 +2984,7 @@ function compareCodeUnit(a, b) {
2941
2984
  // ../../packages/module-contract/src/module-structure.ts
2942
2985
  var MODULE_STRUCTURE_JSON_BYTE_CAP = 64 * 1024;
2943
2986
  function uniqueSortedStringArray(label) {
2944
- return z3.array(z3.string()).superRefine((arr, ctx) => {
2987
+ return z4.array(z4.string()).superRefine((arr, ctx) => {
2945
2988
  if (new Set(arr).size !== arr.length) {
2946
2989
  ctx.addIssue({ code: "custom", message: `${label} must be unique` });
2947
2990
  return;
@@ -2957,10 +3000,10 @@ function uniqueSortedStringArray(label) {
2957
3000
  });
2958
3001
  }
2959
3002
  function contributionPermissionsSchema(label) {
2960
- return z3.array(
2961
- z3.object({
2962
- contributionId: z3.string().min(1),
2963
- permission: z3.string().min(1)
3003
+ return z4.array(
3004
+ z4.object({
3005
+ contributionId: z4.string().min(1),
3006
+ permission: z4.string().min(1)
2964
3007
  }).strict()
2965
3008
  ).superRefine((entries, ctx) => {
2966
3009
  const keys = entries.map((entry) => `${entry.contributionId}\0${entry.permission}`);
@@ -2978,17 +3021,17 @@ function contributionPermissionsSchema(label) {
2978
3021
  }
2979
3022
  }).optional();
2980
3023
  }
2981
- var collectedFilePayloadSchema = z3.discriminatedUnion("status", [
2982
- z3.object({ status: z3.literal("ok"), text: z3.string() }).strict(),
2983
- z3.object({ status: z3.literal("missing") }).strict(),
2984
- z3.object({ status: z3.literal("too-large") }).strict(),
2985
- z3.object({ status: z3.literal("unreadable") }).strict()
3024
+ var collectedFilePayloadSchema = z4.discriminatedUnion("status", [
3025
+ z4.object({ status: z4.literal("ok"), text: z4.string() }).strict(),
3026
+ z4.object({ status: z4.literal("missing") }).strict(),
3027
+ z4.object({ status: z4.literal("too-large") }).strict(),
3028
+ z4.object({ status: z4.literal("unreadable") }).strict()
2986
3029
  ]);
2987
- var collectedLocaleFileSchema = z3.object({
2988
- locale: z3.string().min(1),
3030
+ var collectedLocaleFileSchema = z4.object({
3031
+ locale: z4.string().min(1),
2989
3032
  payload: collectedFilePayloadSchema
2990
3033
  }).strict();
2991
- var collectedE2eFactsSchema = z3.object({
3034
+ var collectedE2eFactsSchema = z4.object({
2992
3035
  manifest: collectedFilePayloadSchema,
2993
3036
  specFiles: uniqueSortedStringArray("specFiles"),
2994
3037
  escapingSymlinks: uniqueSortedStringArray("escapingSymlinks")
@@ -3010,20 +3053,20 @@ function validateRouteExportEvidenceCongruence(input) {
3010
3053
  }
3011
3054
  }
3012
3055
  }
3013
- var collectedEnhancementFactsSchema = z3.object({
3014
- peer: z3.string().min(1),
3015
- hasContributionsTs: z3.boolean(),
3056
+ var collectedEnhancementFactsSchema = z4.object({
3057
+ peer: z4.string().min(1),
3058
+ hasContributionsTs: z4.boolean(),
3016
3059
  contributionPermissions: contributionPermissionsSchema("enhancement contributionPermissions"),
3017
- hasInitializeServerTs: z3.boolean(),
3060
+ hasInitializeServerTs: z4.boolean(),
3018
3061
  contributionsCollectionErrors: uniqueSortedStringArray(
3019
3062
  "enhancement contributionsCollectionErrors"
3020
3063
  ),
3021
3064
  initializeServerCollectionErrors: uniqueSortedStringArray(
3022
3065
  "enhancement initializeServerCollectionErrors"
3023
3066
  ),
3024
- hasRoutesDir: z3.boolean(),
3067
+ hasRoutesDir: z4.boolean(),
3025
3068
  routeCollectionErrors: uniqueSortedStringArray("enhancement routeCollectionErrors"),
3026
- locales: z3.array(collectedLocaleFileSchema).superRefine((locales, ctx) => {
3069
+ locales: z4.array(collectedLocaleFileSchema).superRefine((locales, ctx) => {
3027
3070
  const names = locales.map((l) => l.locale);
3028
3071
  if (new Set(names).size !== names.length) {
3029
3072
  ctx.addIssue({ code: "custom", message: "enhancement locales must be unique by locale" });
@@ -3038,27 +3081,27 @@ var collectedEnhancementFactsSchema = z3.object({
3038
3081
  }),
3039
3082
  e2e: collectedE2eFactsSchema.nullable()
3040
3083
  }).strict();
3041
- var moduleStructureFactsSchema = z3.object({
3042
- collected: z3.literal(true),
3043
- dirName: z3.string().min(1),
3044
- hasIndexTs: z3.boolean(),
3045
- hasContributionsTs: z3.boolean(),
3084
+ var moduleStructureFactsSchema = z4.object({
3085
+ collected: z4.literal(true),
3086
+ dirName: z4.string().min(1),
3087
+ hasIndexTs: z4.boolean(),
3088
+ hasContributionsTs: z4.boolean(),
3046
3089
  contributionPermissions: contributionPermissionsSchema("contributionPermissions"),
3047
- hasSlotsTs: z3.boolean(),
3090
+ hasSlotsTs: z4.boolean(),
3048
3091
  contributionsCollectionErrors: uniqueSortedStringArray("contributionsCollectionErrors"),
3049
3092
  slotsCollectionErrors: uniqueSortedStringArray("slotsCollectionErrors"),
3050
- hasTestsDir: z3.boolean(),
3051
- hasDatastoreDir: z3.boolean(),
3052
- datastoreFileCount: z3.number().int().nonnegative(),
3053
- hasServerIndexTs: z3.boolean(),
3054
- hasOtherServerTs: z3.boolean(),
3055
- hasE2eDir: z3.boolean(),
3056
- hasRoutesDir: z3.boolean(),
3093
+ hasTestsDir: z4.boolean(),
3094
+ hasDatastoreDir: z4.boolean(),
3095
+ datastoreFileCount: z4.number().int().nonnegative(),
3096
+ hasServerIndexTs: z4.boolean(),
3097
+ hasOtherServerTs: z4.boolean(),
3098
+ hasE2eDir: z4.boolean(),
3099
+ hasRoutesDir: z4.boolean(),
3057
3100
  routeEntries: uniqueSortedStringArray("routeEntries"),
3058
- routePageExports: z3.array(
3059
- z3.object({
3060
- nextRelativePath: z3.string().min(1),
3061
- hasGenerateMetadata: z3.boolean()
3101
+ routePageExports: z4.array(
3102
+ z4.object({
3103
+ nextRelativePath: z4.string().min(1),
3104
+ hasGenerateMetadata: z4.boolean()
3062
3105
  }).strict()
3063
3106
  ).superRefine((entries, ctx) => {
3064
3107
  const paths = entries.map((e) => e.nextRelativePath);
@@ -3080,7 +3123,7 @@ var moduleStructureFactsSchema = z3.object({
3080
3123
  }
3081
3124
  }),
3082
3125
  routeCollectionErrors: uniqueSortedStringArray("routeCollectionErrors"),
3083
- rootLocales: z3.array(collectedLocaleFileSchema).superRefine((locales, ctx) => {
3126
+ rootLocales: z4.array(collectedLocaleFileSchema).superRefine((locales, ctx) => {
3084
3127
  const names = locales.map((l) => l.locale);
3085
3128
  if (new Set(names).size !== names.length) {
3086
3129
  ctx.addIssue({ code: "custom", message: "rootLocales must be unique by locale" });
@@ -3094,7 +3137,7 @@ var moduleStructureFactsSchema = z3.object({
3094
3137
  }
3095
3138
  }),
3096
3139
  rootE2e: collectedE2eFactsSchema.nullable(),
3097
- enhancements: z3.array(collectedEnhancementFactsSchema).superRefine((enhancements, ctx) => {
3140
+ enhancements: z4.array(collectedEnhancementFactsSchema).superRefine((enhancements, ctx) => {
3098
3141
  const peers = enhancements.map((e) => e.peer);
3099
3142
  if (new Set(peers).size !== peers.length) {
3100
3143
  ctx.addIssue({ code: "custom", message: "enhancement peers must be unique" });
@@ -3115,10 +3158,10 @@ var moduleStructureFactsSchema = z3.object({
3115
3158
  onIssue: (message) => ctx.addIssue({ code: "custom", message })
3116
3159
  });
3117
3160
  });
3118
- var moduleStructureCollectionSchema = z3.object({
3161
+ var moduleStructureCollectionSchema = z4.object({
3119
3162
  homeLocales: uniqueSortedStringArray("homeLocales"),
3120
- modules: z3.array(moduleStructureFactsSchema),
3121
- truncated: z3.boolean().optional(),
3163
+ modules: z4.array(moduleStructureFactsSchema),
3164
+ truncated: z4.boolean().optional(),
3122
3165
  collectionErrors: uniqueSortedStringArray("collectionErrors").optional()
3123
3166
  }).strict().superRefine((collection, ctx) => {
3124
3167
  const dirs = collection.modules.map((m) => m.dirName);
@@ -3135,9 +3178,9 @@ var moduleStructureCollectionSchema = z3.object({
3135
3178
  });
3136
3179
 
3137
3180
  // ../../packages/module-contract/src/locale.ts
3138
- import { z as z4 } from "zod";
3181
+ import { z as z5 } from "zod";
3139
3182
  var LOCALE_BASENAME_REGEX = /^[a-z]{2,3}(-[A-Za-z0-9]+)*$/;
3140
- var localeBasenameSchema = z4.string().max(35).regex(LOCALE_BASENAME_REGEX, "must be a BCP47-like locale tag (e.g. en, th, en-US)");
3183
+ var localeBasenameSchema = z5.string().max(35).regex(LOCALE_BASENAME_REGEX, "must be a BCP47-like locale tag (e.g. en, th, en-US)");
3141
3184
  function isValidLocaleBasename(value) {
3142
3185
  return localeBasenameSchema.safeParse(value).success;
3143
3186
  }
@@ -3540,43 +3583,43 @@ function formatRoutePageExportErrors(nextRelativePath, validation) {
3540
3583
  import ts2 from "typescript";
3541
3584
 
3542
3585
  // ../../packages/module-contract/src/module-registry.ts
3543
- import { z as z5 } from "zod";
3544
- var projectSlugSchema2 = z5.string().refine((value) => validateSlug(value).valid, "must be a valid project slug");
3545
- var registryEnhancementSchema = z5.object({
3586
+ import { z as z6 } from "zod";
3587
+ var projectSlugSchema2 = z6.string().refine((value) => validateSlug(value).valid, "must be a valid project slug");
3588
+ var registryEnhancementSchema = z6.object({
3546
3589
  peer: moduleNameSchema,
3547
- active: z5.boolean()
3590
+ active: z6.boolean()
3548
3591
  }).strict();
3549
- var registryModuleSchema = z5.object({
3592
+ var registryModuleSchema = z6.object({
3550
3593
  name: moduleNameSchema,
3551
3594
  /** Installed version as recorded by the rail (non-empty string). */
3552
- version: z5.string().min(1),
3595
+ version: z6.string().min(1),
3553
3596
  home: projectSlugSchema2,
3554
3597
  kind: moduleKindSchema,
3555
- mounts: z5.array(mountSchema),
3556
- enhancements: z5.array(registryEnhancementSchema)
3598
+ mounts: z6.array(mountSchema),
3599
+ enhancements: z6.array(registryEnhancementSchema)
3557
3600
  }).strict().superRefine((mod, ctx) => {
3558
3601
  for (let i = 0; i < mod.enhancements.length; i += 1) {
3559
3602
  if (mod.enhancements[i].peer === mod.name) {
3560
3603
  ctx.addIssue({
3561
- code: z5.ZodIssueCode.custom,
3604
+ code: z6.ZodIssueCode.custom,
3562
3605
  message: "enhancement peer must not equal the module's own name",
3563
3606
  path: ["enhancements", i, "peer"]
3564
3607
  });
3565
3608
  }
3566
3609
  }
3567
3610
  });
3568
- var generatedModuleRegistrySchema = z5.object({
3569
- registryVersion: z5.literal(1),
3611
+ var generatedModuleRegistrySchema = z6.object({
3612
+ registryVersion: z6.literal(1),
3570
3613
  /** Rail run id, or `"manual"` for fixtures. */
3571
- generatedBy: z5.string().min(1),
3572
- modules: z5.array(registryModuleSchema)
3614
+ generatedBy: z6.string().min(1),
3615
+ modules: z6.array(registryModuleSchema)
3573
3616
  }).strict().superRefine((registry, ctx) => {
3574
3617
  const seen = /* @__PURE__ */ new Set();
3575
3618
  for (let i = 0; i < registry.modules.length; i += 1) {
3576
3619
  const name = registry.modules[i].name;
3577
3620
  if (seen.has(name)) {
3578
3621
  ctx.addIssue({
3579
- code: z5.ZodIssueCode.custom,
3622
+ code: z6.ZodIssueCode.custom,
3580
3623
  message: `duplicate module name "${name}"`,
3581
3624
  path: ["modules", i, "name"]
3582
3625
  });
@@ -3947,169 +3990,6 @@ function analyzeClientSafeEntryImports(sourceText, fileName) {
3947
3990
  return analyzeClientSafeEntryImportsWithTs(ts3, sourceText, fileName);
3948
3991
  }
3949
3992
 
3950
- // ../../packages/lib/src/shared/module-composition.ts
3951
- var moduleRefSchema = z6.object({
3952
- homeProjectId: z6.string().uuid(),
3953
- moduleName: moduleNameSchema
3954
- });
3955
- var creationSourceBlankSchema = z6.object({
3956
- type: z6.literal("blank")
3957
- });
3958
- var creationSourceBlueprintSchema = z6.object({
3959
- type: z6.literal("blueprint"),
3960
- /** Internal template/fork project id — keep template naming in identifiers. */
3961
- blueprintProjectId: z6.string().uuid(),
3962
- /**
3963
- * `null`/absent means every feature Module. `[]` is refused: the platform
3964
- * serialises it to an empty `NEXT_PUBLIC_STARDECK_ENABLED_MODULES`, which the
3965
- * enablement parser reads back as "all" (`module-enablement.ts`) — the
3966
- * opposite of what an empty selection means.
3967
- */
3968
- enabledModules: z6.array(moduleNameSchema).min(1, "Enable at least one Module").max(100).nullable().optional()
3969
- });
3970
- var creationSourceModulesSchema = z6.object({
3971
- type: z6.literal("modules"),
3972
- requested: z6.array(moduleRefSchema).min(1)
3973
- });
3974
- var creationSourceSchema = z6.discriminatedUnion("type", [
3975
- creationSourceBlankSchema,
3976
- creationSourceBlueprintSchema,
3977
- creationSourceModulesSchema
3978
- ]);
3979
- var moduleCompositionStatusSchema = z6.enum([
3980
- "pending",
3981
- "installing",
3982
- "ready",
3983
- "partial",
3984
- "failed"
3985
- ]);
3986
- var resolvedModuleSnapshotSchema = moduleRefSchema.extend({
3987
- version: z6.string().min(1),
3988
- homeCommitSha: z6.string().min(1)
3989
- });
3990
- var moduleInstallHandoffSchema = z6.object({
3991
- moduleName: z6.string().min(1),
3992
- homeProjectId: z6.string().uuid(),
3993
- installedVersion: z6.string().min(1),
3994
- baselineSha: z6.string().min(1),
3995
- mounts: z6.array(
3996
- z6.object({
3997
- group: z6.string(),
3998
- segment: z6.string()
3999
- })
4000
- ),
4001
- integration: z6.array(z6.string()),
4002
- workflows: z6.array(z6.string()),
4003
- prunedEnhancements: z6.array(z6.string()),
4004
- restoredEnhancements: z6.array(z6.string()).optional(),
4005
- permissions: z6.array(
4006
- z6.object({
4007
- key: z6.string().min(1),
4008
- description: z6.string().min(1)
4009
- })
4010
- ).optional()
4011
- });
4012
- var moduleCompositionRunAttemptSchema = z6.object({
4013
- module: moduleRefSchema,
4014
- runId: z6.string().min(1),
4015
- status: z6.string().min(1),
4016
- schemaApplied: z6.boolean(),
4017
- error: z6.string().optional(),
4018
- /** Prefer full ModuleInstallHandoff; identity fields optional for older rows. */
4019
- handoff: moduleInstallHandoffSchema.partial({ moduleName: true, homeProjectId: true }).optional()
4020
- });
4021
- var initialModuleCompositionSchema = z6.object({
4022
- version: z6.literal(1),
4023
- status: moduleCompositionStatusSchema,
4024
- requested: z6.array(moduleRefSchema).min(1),
4025
- resolved: z6.array(resolvedModuleSnapshotSchema),
4026
- installOrder: z6.array(moduleRefSchema),
4027
- runs: z6.array(moduleCompositionRunAttemptSchema).default([]),
4028
- /**
4029
- * True when any failed/partial attempt applied schema before failing.
4030
- * Never claim transactional rollback across git/schema.
4031
- */
4032
- schemaApplied: z6.boolean().default(false),
4033
- /**
4034
- * Present when retry would silently change pinned home SHAs — caller must
4035
- * reconfirm the new plan rather than continue.
4036
- */
4037
- reconfirmationRequired: z6.object({
4038
- reason: z6.string(),
4039
- previous: z6.array(resolvedModuleSnapshotSchema),
4040
- next: z6.array(resolvedModuleSnapshotSchema)
4041
- }).optional(),
4042
- error: z6.string().optional(),
4043
- /**
4044
- * First-turn system handoff lifecycle. Absent/`pending` means inject when
4045
- * status is ready; `consumed` means a successful agent turn already used it.
4046
- */
4047
- systemHandoffStatus: z6.enum(["pending", "consumed"]).optional(),
4048
- /**
4049
- * CAS ownership token for concurrent retry attempts. Only the attempt that
4050
- * currently owns this value may reset or compensate durable composition state.
4051
- */
4052
- retryAttemptId: z6.string().min(1).optional(),
4053
- /**
4054
- * When the current `installing` attempt was claimed. A setup run that dies
4055
- * with its host (a killed Vercel instance) leaves the composition `installing`
4056
- * forever, and the creating page's poll only stops on ready/partial/failed —
4057
- * so staleness, not a queue's stall detector, is what settles it. Absent on
4058
- * rows claimed before this field existed; treated as stale.
4059
- */
4060
- attemptStartedAt: z6.string().datetime().optional(),
4061
- /** Outside-module files the agent changed during connection work. */
4062
- integrationFiles: z6.array(z6.string()).optional(),
4063
- verificationSummary: z6.string().optional()
4064
- });
4065
- var MODULE_SETUP_ATTEMPT_STALE_MS = 10 * 60 * 1e3;
4066
-
4067
- // ../../packages/lib/src/shared/compose-inputs.ts
4068
- import { z as z7 } from "zod";
4069
- var COMPOSE_INPUTS_PATH = "apps/web/stardeck.compose.json";
4070
- var composeInputsSchema = z7.strictObject({
4071
- connectedStores: z7.array(
4072
- z7.strictObject({
4073
- storeId: z7.string().min(1),
4074
- slug: z7.string().min(1),
4075
- // A row with an empty binding key must not fail a deploy: the rail
4076
- // treats falsy as "no binding key", so normalise rather than reject.
4077
- bindingKey: z7.string().nullish().transform((value) => value || null),
4078
- accessLevel: z7.enum(["read", "write", "admin"]),
4079
- // Defaulted so a file written before the platform emitted store types
4080
- // (database rows only) still parses. The platform starts writing
4081
- // storage rows, with `type` set, once forks run a compose that reads it.
4082
- type: z7.enum(["database", "storage"]).default("database")
4083
- })
4084
- ).default([]),
4085
- installs: z7.record(
4086
- z7.string(),
4087
- z7.strictObject({
4088
- installedVersion: z7.string().min(1),
4089
- datastoreBindings: z7.record(z7.string(), z7.string()).nullish()
4090
- })
4091
- ).default({})
4092
- });
4093
- var STUB_IGNORE_PATH = "apps/web/src/app/.gitignore";
4094
- var STUB_IGNORE_HEADER = "# Generated by stardeck-compose \u2014 Module-rail stubs are build outputs; do not edit or commit them.";
4095
- function escapeStubIgnorePattern(pattern) {
4096
- const escaped = pattern.replace(/[\\[\]*?]/g, (char) => `\\${char}`);
4097
- return /^[#!]/.test(escaped) ? `\\${escaped}` : escaped;
4098
- }
4099
- function buildStubIgnore(artifactPaths) {
4100
- const prefix = "apps/web/src/app/";
4101
- const entries = artifactPaths.filter((artifact) => artifact.startsWith(prefix)).map((artifact) => escapeStubIgnorePattern(`/${artifact.slice(prefix.length)}`)).sort();
4102
- return [STUB_IGNORE_HEADER, ...entries].join("\n") + "\n";
4103
- }
4104
-
4105
- // ../../packages/lib/src/shared/module-enablement.ts
4106
- function isModuleEnabledByList(raw, name, kindOf) {
4107
- if (!raw) return true;
4108
- const kind = kindOf(name);
4109
- if (kind != null && kind !== "feature") return true;
4110
- return raw.split(",").includes(name);
4111
- }
4112
-
4113
3993
  // ../../packages/lib/src/shared/platform-owned-paths.ts
4114
3994
  var APP_WEB_PREFIX = "apps/web/";
4115
3995
  var MODULE_STUB_MARKER = "@stardeck-module-rail-generated";
@@ -6036,6 +5916,50 @@ function rejectPseudoModuleEntries(entries, parentDir, label) {
6036
5916
  return dirs;
6037
5917
  }
6038
5918
 
5919
+ // ../../packages/lib/src/shared/module-composition.ts
5920
+ import { z as z7 } from "zod";
5921
+ var creationSourceBlankSchema = z7.object({
5922
+ type: z7.literal("blank")
5923
+ });
5924
+ var creationSourceBlueprintSchema = z7.object({
5925
+ type: z7.literal("blueprint"),
5926
+ /** Internal template/fork project id — keep template naming in identifiers. */
5927
+ blueprintProjectId: z7.string().uuid(),
5928
+ /**
5929
+ * `null`/absent means every feature Module. `[]` is refused: the platform
5930
+ * serialises it to an empty `NEXT_PUBLIC_STARDECK_ENABLED_MODULES`, which the
5931
+ * enablement parser reads back as "all" (`module-enablement.ts`) — the
5932
+ * opposite of what an empty selection means.
5933
+ */
5934
+ enabledModules: z7.array(moduleNameSchema).min(1, "Enable at least one Module").max(100).nullable().optional()
5935
+ });
5936
+ var creationSourceSchema = z7.discriminatedUnion("type", [
5937
+ creationSourceBlankSchema,
5938
+ creationSourceBlueprintSchema
5939
+ ]);
5940
+ var moduleInstallHandoffSchema = z7.object({
5941
+ moduleName: z7.string().min(1),
5942
+ homeProjectId: z7.string().uuid(),
5943
+ installedVersion: z7.string().min(1),
5944
+ baselineSha: z7.string().min(1),
5945
+ mounts: z7.array(
5946
+ z7.object({
5947
+ group: z7.string(),
5948
+ segment: z7.string()
5949
+ })
5950
+ ),
5951
+ integration: z7.array(z7.string()),
5952
+ workflows: z7.array(z7.string()),
5953
+ prunedEnhancements: z7.array(z7.string()),
5954
+ restoredEnhancements: z7.array(z7.string()).optional(),
5955
+ permissions: z7.array(
5956
+ z7.object({
5957
+ key: z7.string().min(1),
5958
+ description: z7.string().min(1)
5959
+ })
5960
+ ).optional()
5961
+ });
5962
+
6039
5963
  // ../../packages/lib/src/shared/schema-ops.ts
6040
5964
  import { z as z8 } from "zod";
6041
5965
  var columnSpecSchema = z8.object({
@@ -7499,6 +7423,9 @@ async function reconcileCompositionArtifacts(context, options = {}) {
7499
7423
  var HOME_I18N_SUBSTRATE_DIR = `${APP_PACKAGE_DIR}/src/lib/i18n/substrate`;
7500
7424
  var HOME_I18N_MESSAGES_DIR = `${APP_PACKAGE_DIR}/src/lib/i18n/messages`;
7501
7425
 
7426
+ // src/index.ts
7427
+ import ts6 from "typescript";
7428
+
7502
7429
  // src/module-boundaries.ts
7503
7430
  import fs2 from "fs";
7504
7431
  import path2 from "path";
@@ -7768,6 +7695,41 @@ function assertNoAppLayerImporters(cwd, excluded) {
7768
7695
  );
7769
7696
  }
7770
7697
  }
7698
+ var TSCONFIG_PATH = "apps/web/tsconfig.json";
7699
+ var BUILD_TSCONFIG_PATH = "apps/web/tsconfig.build.gen.json";
7700
+ var BUILD_TSCONFIG_HEADER = "// Generated by stardeck-compose \u2014 the tsconfig `next build` type-checks. Do not edit or commit.";
7701
+ function writeBuildTsconfig(cwd, excluded) {
7702
+ const baseFile = path3.join(cwd, TSCONFIG_PATH);
7703
+ if (!fs3.existsSync(path3.join(cwd, MODULES_DIR2)) || !fs3.existsSync(baseFile)) return;
7704
+ const base = ts6.readConfigFile(baseFile, ts6.sys.readFile);
7705
+ if (base.error) {
7706
+ throw new Error(
7707
+ `[compose] cannot read ${TSCONFIG_PATH}: ${ts6.flattenDiagnosticMessageText(base.error.messageText, "\n")}`
7708
+ );
7709
+ }
7710
+ const baseExclude = base.config?.exclude ?? ["node_modules"];
7711
+ const modulesDir = path3.posix.relative("apps/web", MODULES_DIR2);
7712
+ const config = {
7713
+ extends: "./tsconfig.json",
7714
+ exclude: [
7715
+ ...baseExclude,
7716
+ ...excluded.flatMap((name) => [
7717
+ `${modulesDir}/${name}`,
7718
+ `${modulesDir}/*/enhancements/${name}`
7719
+ ])
7720
+ ]
7721
+ };
7722
+ const content = `${BUILD_TSCONFIG_HEADER}
7723
+ ${JSON.stringify(config, null, 2)}
7724
+ `;
7725
+ const file = path3.join(cwd, BUILD_TSCONFIG_PATH);
7726
+ if (!fs3.existsSync(file) || fs3.readFileSync(file, "utf8") !== content) {
7727
+ fs3.writeFileSync(file, content);
7728
+ }
7729
+ console.log(
7730
+ `[compose] ${BUILD_TSCONFIG_PATH} excludes ${excluded.length} Module(s): ${excluded.join(",") || "none"}`
7731
+ );
7732
+ }
7771
7733
  function removeDir(absolute) {
7772
7734
  if (!fs3.existsSync(absolute)) return false;
7773
7735
  fs3.rmSync(absolute, { recursive: true, force: true });
@@ -7815,6 +7777,7 @@ async function compose(options) {
7815
7777
  skipComposeInputs: true
7816
7778
  });
7817
7779
  const gitignoreEntries = options.enabled ? null : writeStubGitignore(options.cwd, result.artifactPaths);
7780
+ writeBuildTsconfig(options.cwd, result.excludedModules);
7818
7781
  let pruned = 0;
7819
7782
  if (options.prune) {
7820
7783
  for (const name of result.excludedModules) {
@@ -7836,6 +7799,7 @@ async function compose(options) {
7836
7799
  };
7837
7800
  }
7838
7801
  export {
7802
+ BUILD_TSCONFIG_PATH,
7839
7803
  COMPOSE_INPUTS_PATH,
7840
7804
  assertSupportedTypescript,
7841
7805
  compose,