@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/SKILL.md +9 -1
- package/dist/cli.js +109 -135
- package/dist/index.d.mts +2 -1
- package/dist/index.d.ts +2 -1
- package/dist/index.js +270 -296
- package/dist/index.mjs +269 -296
- package/package.json +3 -5
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/
|
|
2084
|
-
import { z
|
|
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 =
|
|
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 =
|
|
2127
|
-
var moduleKindSchema =
|
|
2128
|
-
var endpointMethodSchema =
|
|
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 =
|
|
2256
|
+
var endpointPathSchema = z2.string().superRefine((path4, ctx) => {
|
|
2214
2257
|
const error = endpointPathValidationError(path4);
|
|
2215
2258
|
if (error != null) {
|
|
2216
|
-
ctx.addIssue({ code:
|
|
2259
|
+
ctx.addIssue({ code: z2.ZodIssueCode.custom, message: error });
|
|
2217
2260
|
}
|
|
2218
2261
|
});
|
|
2219
|
-
var endpointClaimSchema =
|
|
2262
|
+
var endpointClaimSchema = z2.object({
|
|
2220
2263
|
path: endpointPathSchema,
|
|
2221
|
-
methods:
|
|
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:
|
|
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 =
|
|
2307
|
+
var mountSegmentSchema = z2.string().superRefine((segment, ctx) => {
|
|
2265
2308
|
const error = mountSegmentValidationError(segment);
|
|
2266
2309
|
if (error != null) {
|
|
2267
|
-
ctx.addIssue({ code:
|
|
2310
|
+
ctx.addIssue({ code: z2.ZodIssueCode.custom, message: error });
|
|
2268
2311
|
}
|
|
2269
2312
|
});
|
|
2270
|
-
var mountSchema =
|
|
2271
|
-
group:
|
|
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 =
|
|
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 =
|
|
2287
|
-
var descriptionSchema =
|
|
2288
|
-
var crossAppSchema =
|
|
2289
|
-
exposes:
|
|
2290
|
-
consumes:
|
|
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 =
|
|
2293
|
-
var enhancementEndpointsSchema =
|
|
2294
|
-
var datastoreRequirementSchema =
|
|
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:
|
|
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:
|
|
2349
|
+
type: z2.enum(["database", "storage"]).default("database"),
|
|
2307
2350
|
/** true → install fails when no store resolves; false → binding omitted, module degrades. */
|
|
2308
|
-
required:
|
|
2351
|
+
required: z2.boolean().default(true),
|
|
2309
2352
|
/** Checked against the connected store's accessLevel at install. */
|
|
2310
|
-
access:
|
|
2353
|
+
access: z2.enum(["read", "write", "admin"]).default("write")
|
|
2311
2354
|
}).strict();
|
|
2312
|
-
var permissionClaimSchema =
|
|
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:
|
|
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 =
|
|
2364
|
+
var seedBundleSchema = z2.object({
|
|
2322
2365
|
table: tableNameSchema,
|
|
2323
2366
|
/** Columns forming the ON CONFLICT key — must appear in every row. */
|
|
2324
|
-
conflictTarget:
|
|
2367
|
+
conflictTarget: z2.array(z2.string().min(1)).min(1),
|
|
2325
2368
|
/** Scalar JSON values only (no nested objects/arrays). */
|
|
2326
|
-
rows:
|
|
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:
|
|
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:
|
|
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 =
|
|
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:
|
|
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:
|
|
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:
|
|
2371
|
-
tables:
|
|
2372
|
-
mounts:
|
|
2373
|
-
integration:
|
|
2374
|
-
workflows:
|
|
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:
|
|
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,44 @@ 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:
|
|
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:
|
|
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:
|
|
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:
|
|
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:
|
|
2460
|
+
ui: z2.object({ separable: z2.boolean() }).strict().optional(),
|
|
2461
|
+
/**
|
|
2462
|
+
* `false` keeps a feature Module off in a new Blueprint fork unless the
|
|
2463
|
+
* creator ticks it: the fork picker leaves it unchecked and "every Module"
|
|
2464
|
+
* is written out without it. Omitted means on. Library Modules are always on.
|
|
2465
|
+
*/
|
|
2466
|
+
defaultEnabled: z2.boolean().optional()
|
|
2418
2467
|
}).strict().superRefine((manifest, ctx) => {
|
|
2419
2468
|
if (manifest.uses.includes(manifest.name)) {
|
|
2420
2469
|
ctx.addIssue({
|
|
2421
|
-
code:
|
|
2470
|
+
code: z2.ZodIssueCode.custom,
|
|
2422
2471
|
message: "a module cannot list itself in uses",
|
|
2423
2472
|
path: ["uses"]
|
|
2424
2473
|
});
|
|
2425
2474
|
}
|
|
2426
2475
|
if (manifest.enhancements.includes(manifest.name)) {
|
|
2427
2476
|
ctx.addIssue({
|
|
2428
|
-
code:
|
|
2477
|
+
code: z2.ZodIssueCode.custom,
|
|
2429
2478
|
message: "a module cannot list itself in enhancements",
|
|
2430
2479
|
path: ["enhancements"]
|
|
2431
2480
|
});
|
|
@@ -2433,7 +2482,7 @@ var moduleManifestSchema = z.object({
|
|
|
2433
2482
|
const hardAndSoft = manifest.enhancements.filter((peer) => manifest.uses.includes(peer));
|
|
2434
2483
|
if (hardAndSoft.length > 0) {
|
|
2435
2484
|
ctx.addIssue({
|
|
2436
|
-
code:
|
|
2485
|
+
code: z2.ZodIssueCode.custom,
|
|
2437
2486
|
message: `uses and enhancements must be disjoint (a peer is either a hard dep or a soft one): ${hardAndSoft.join(", ")}`,
|
|
2438
2487
|
path: ["enhancements"]
|
|
2439
2488
|
});
|
|
@@ -2442,7 +2491,7 @@ var moduleManifestSchema = z.object({
|
|
|
2442
2491
|
for (const peer of Object.keys(manifest.enhancementWorkflows)) {
|
|
2443
2492
|
if (!enhancementPeers.has(peer)) {
|
|
2444
2493
|
ctx.addIssue({
|
|
2445
|
-
code:
|
|
2494
|
+
code: z2.ZodIssueCode.custom,
|
|
2446
2495
|
message: `enhancementWorkflows key "${peer}" must be listed in enhancements`,
|
|
2447
2496
|
path: ["enhancementWorkflows", peer]
|
|
2448
2497
|
});
|
|
@@ -2451,7 +2500,7 @@ var moduleManifestSchema = z.object({
|
|
|
2451
2500
|
for (const peer of Object.keys(manifest.enhancementEndpoints)) {
|
|
2452
2501
|
if (!enhancementPeers.has(peer)) {
|
|
2453
2502
|
ctx.addIssue({
|
|
2454
|
-
code:
|
|
2503
|
+
code: z2.ZodIssueCode.custom,
|
|
2455
2504
|
message: `enhancementEndpoints key "${peer}" must be listed in enhancements`,
|
|
2456
2505
|
path: ["enhancementEndpoints", peer]
|
|
2457
2506
|
});
|
|
@@ -2462,7 +2511,7 @@ var moduleManifestSchema = z.object({
|
|
|
2462
2511
|
const existing = seenWorkflows.get(name);
|
|
2463
2512
|
if (existing != null) {
|
|
2464
2513
|
ctx.addIssue({
|
|
2465
|
-
code:
|
|
2514
|
+
code: z2.ZodIssueCode.custom,
|
|
2466
2515
|
message: `duplicate workflow name "${name}" (also at ${existing})`,
|
|
2467
2516
|
path: path4
|
|
2468
2517
|
});
|
|
@@ -2489,7 +2538,7 @@ var moduleManifestSchema = z.object({
|
|
|
2489
2538
|
const existing = seenEndpointKeys.get(key);
|
|
2490
2539
|
if (existing != null) {
|
|
2491
2540
|
ctx.addIssue({
|
|
2492
|
-
code:
|
|
2541
|
+
code: z2.ZodIssueCode.custom,
|
|
2493
2542
|
message: `duplicate normalized endpoint path "${key}" (also at ${existing})`,
|
|
2494
2543
|
path: path4
|
|
2495
2544
|
});
|
|
@@ -2511,7 +2560,7 @@ var moduleManifestSchema = z.object({
|
|
|
2511
2560
|
const id = manifest.datastores[i].id;
|
|
2512
2561
|
if (seenDatastoreIds.has(id)) {
|
|
2513
2562
|
ctx.addIssue({
|
|
2514
|
-
code:
|
|
2563
|
+
code: z2.ZodIssueCode.custom,
|
|
2515
2564
|
message: `duplicate datastore id "${id}"`,
|
|
2516
2565
|
path: ["datastores", i, "id"]
|
|
2517
2566
|
});
|
|
@@ -2526,7 +2575,7 @@ var moduleManifestSchema = z.object({
|
|
|
2526
2575
|
const key = manifest.permissions[i].key;
|
|
2527
2576
|
if (seenPermissionKeys.has(key)) {
|
|
2528
2577
|
ctx.addIssue({
|
|
2529
|
-
code:
|
|
2578
|
+
code: z2.ZodIssueCode.custom,
|
|
2530
2579
|
message: `duplicate permission key "${key}"`,
|
|
2531
2580
|
path: ["permissions", i, "key"]
|
|
2532
2581
|
});
|
|
@@ -2538,35 +2587,35 @@ var moduleManifestSchema = z.object({
|
|
|
2538
2587
|
if (manifest.kind === "library") {
|
|
2539
2588
|
if (manifest.tables.length > 0) {
|
|
2540
2589
|
ctx.addIssue({
|
|
2541
|
-
code:
|
|
2590
|
+
code: z2.ZodIssueCode.custom,
|
|
2542
2591
|
message: "library modules must not declare tables",
|
|
2543
2592
|
path: ["tables"]
|
|
2544
2593
|
});
|
|
2545
2594
|
}
|
|
2546
2595
|
if (manifest.mounts.length > 0) {
|
|
2547
2596
|
ctx.addIssue({
|
|
2548
|
-
code:
|
|
2597
|
+
code: z2.ZodIssueCode.custom,
|
|
2549
2598
|
message: "library modules must not declare mounts",
|
|
2550
2599
|
path: ["mounts"]
|
|
2551
2600
|
});
|
|
2552
2601
|
}
|
|
2553
2602
|
if (manifest.seeds != null && manifest.seeds.length > 0) {
|
|
2554
2603
|
ctx.addIssue({
|
|
2555
|
-
code:
|
|
2604
|
+
code: z2.ZodIssueCode.custom,
|
|
2556
2605
|
message: "library modules must not declare seeds",
|
|
2557
2606
|
path: ["seeds"]
|
|
2558
2607
|
});
|
|
2559
2608
|
}
|
|
2560
2609
|
if (manifest.datastores != null && manifest.datastores.length > 0) {
|
|
2561
2610
|
ctx.addIssue({
|
|
2562
|
-
code:
|
|
2611
|
+
code: z2.ZodIssueCode.custom,
|
|
2563
2612
|
message: "library modules must not declare datastores",
|
|
2564
2613
|
path: ["datastores"]
|
|
2565
2614
|
});
|
|
2566
2615
|
}
|
|
2567
2616
|
if (manifest.permissions != null && manifest.permissions.length > 0) {
|
|
2568
2617
|
ctx.addIssue({
|
|
2569
|
-
code:
|
|
2618
|
+
code: z2.ZodIssueCode.custom,
|
|
2570
2619
|
message: "library modules must not declare permissions",
|
|
2571
2620
|
path: ["permissions"]
|
|
2572
2621
|
});
|
|
@@ -2574,7 +2623,7 @@ var moduleManifestSchema = z.object({
|
|
|
2574
2623
|
}
|
|
2575
2624
|
if (manifest.kind === "contract" && manifest.mounts.length > 0) {
|
|
2576
2625
|
ctx.addIssue({
|
|
2577
|
-
code:
|
|
2626
|
+
code: z2.ZodIssueCode.custom,
|
|
2578
2627
|
message: "contract modules must not declare mounts",
|
|
2579
2628
|
path: ["mounts"]
|
|
2580
2629
|
});
|
|
@@ -2585,7 +2634,7 @@ var moduleManifestSchema = z.object({
|
|
|
2585
2634
|
const bundle = manifest.seeds[i];
|
|
2586
2635
|
if (!ownedTables.has(bundle.table)) {
|
|
2587
2636
|
ctx.addIssue({
|
|
2588
|
-
code:
|
|
2637
|
+
code: z2.ZodIssueCode.custom,
|
|
2589
2638
|
message: `seeds may only target tables listed in tables (got "${bundle.table}")`,
|
|
2590
2639
|
path: ["seeds", i, "table"]
|
|
2591
2640
|
});
|
|
@@ -2636,10 +2685,10 @@ var MANDATORY_MODULE_CHECK_DESCRIPTORS = Object.freeze([
|
|
|
2636
2685
|
]);
|
|
2637
2686
|
|
|
2638
2687
|
// ../../packages/module-contract/src/module-structure.ts
|
|
2639
|
-
import { z as
|
|
2688
|
+
import { z as z4 } from "zod";
|
|
2640
2689
|
|
|
2641
2690
|
// ../../packages/module-contract/src/module-e2e-manifest.ts
|
|
2642
|
-
import { z as
|
|
2691
|
+
import { z as z3 } from "zod";
|
|
2643
2692
|
function e2eSpecFileValidationError(file) {
|
|
2644
2693
|
if (file.length === 0) {
|
|
2645
2694
|
return "must be a non-empty relative path ending in .spec.ts";
|
|
@@ -2667,22 +2716,22 @@ function e2eSpecFileValidationError(file) {
|
|
|
2667
2716
|
}
|
|
2668
2717
|
return null;
|
|
2669
2718
|
}
|
|
2670
|
-
var e2eSpecFileSchema =
|
|
2719
|
+
var e2eSpecFileSchema = z3.string().superRefine((file, ctx) => {
|
|
2671
2720
|
const error = e2eSpecFileValidationError(file);
|
|
2672
2721
|
if (error != null) {
|
|
2673
|
-
ctx.addIssue({ code:
|
|
2722
|
+
ctx.addIssue({ code: z3.ZodIssueCode.custom, message: error });
|
|
2674
2723
|
}
|
|
2675
2724
|
});
|
|
2676
|
-
var e2eSpecSchema =
|
|
2725
|
+
var e2eSpecSchema = z3.object({
|
|
2677
2726
|
file: e2eSpecFileSchema,
|
|
2678
|
-
requires:
|
|
2727
|
+
requires: z3.array(moduleNameSchema).min(1, "requires must be non-empty")
|
|
2679
2728
|
}).strict().superRefine((spec, ctx) => {
|
|
2680
2729
|
const seen = /* @__PURE__ */ new Set();
|
|
2681
2730
|
for (let i = 0; i < spec.requires.length; i += 1) {
|
|
2682
2731
|
const name = spec.requires[i];
|
|
2683
2732
|
if (seen.has(name)) {
|
|
2684
2733
|
ctx.addIssue({
|
|
2685
|
-
code:
|
|
2734
|
+
code: z3.ZodIssueCode.custom,
|
|
2686
2735
|
message: `duplicate requirement "${name}"`,
|
|
2687
2736
|
path: ["requires", i]
|
|
2688
2737
|
});
|
|
@@ -2691,15 +2740,15 @@ var e2eSpecSchema = z2.object({
|
|
|
2691
2740
|
}
|
|
2692
2741
|
}
|
|
2693
2742
|
});
|
|
2694
|
-
var moduleE2eManifestSchema =
|
|
2695
|
-
specs:
|
|
2743
|
+
var moduleE2eManifestSchema = z3.object({
|
|
2744
|
+
specs: z3.array(e2eSpecSchema).min(1, "specs must contain at least one entry")
|
|
2696
2745
|
}).strict().superRefine((manifest, ctx) => {
|
|
2697
2746
|
const seenFiles = /* @__PURE__ */ new Set();
|
|
2698
2747
|
for (let i = 0; i < manifest.specs.length; i += 1) {
|
|
2699
2748
|
const file = manifest.specs[i].file;
|
|
2700
2749
|
if (seenFiles.has(file)) {
|
|
2701
2750
|
ctx.addIssue({
|
|
2702
|
-
code:
|
|
2751
|
+
code: z3.ZodIssueCode.custom,
|
|
2703
2752
|
message: `duplicate file "${file}"`,
|
|
2704
2753
|
path: ["specs", i, "file"]
|
|
2705
2754
|
});
|
|
@@ -2941,7 +2990,7 @@ function compareCodeUnit(a, b) {
|
|
|
2941
2990
|
// ../../packages/module-contract/src/module-structure.ts
|
|
2942
2991
|
var MODULE_STRUCTURE_JSON_BYTE_CAP = 64 * 1024;
|
|
2943
2992
|
function uniqueSortedStringArray(label) {
|
|
2944
|
-
return
|
|
2993
|
+
return z4.array(z4.string()).superRefine((arr, ctx) => {
|
|
2945
2994
|
if (new Set(arr).size !== arr.length) {
|
|
2946
2995
|
ctx.addIssue({ code: "custom", message: `${label} must be unique` });
|
|
2947
2996
|
return;
|
|
@@ -2957,10 +3006,10 @@ function uniqueSortedStringArray(label) {
|
|
|
2957
3006
|
});
|
|
2958
3007
|
}
|
|
2959
3008
|
function contributionPermissionsSchema(label) {
|
|
2960
|
-
return
|
|
2961
|
-
|
|
2962
|
-
contributionId:
|
|
2963
|
-
permission:
|
|
3009
|
+
return z4.array(
|
|
3010
|
+
z4.object({
|
|
3011
|
+
contributionId: z4.string().min(1),
|
|
3012
|
+
permission: z4.string().min(1)
|
|
2964
3013
|
}).strict()
|
|
2965
3014
|
).superRefine((entries, ctx) => {
|
|
2966
3015
|
const keys = entries.map((entry) => `${entry.contributionId}\0${entry.permission}`);
|
|
@@ -2978,17 +3027,17 @@ function contributionPermissionsSchema(label) {
|
|
|
2978
3027
|
}
|
|
2979
3028
|
}).optional();
|
|
2980
3029
|
}
|
|
2981
|
-
var collectedFilePayloadSchema =
|
|
2982
|
-
|
|
2983
|
-
|
|
2984
|
-
|
|
2985
|
-
|
|
3030
|
+
var collectedFilePayloadSchema = z4.discriminatedUnion("status", [
|
|
3031
|
+
z4.object({ status: z4.literal("ok"), text: z4.string() }).strict(),
|
|
3032
|
+
z4.object({ status: z4.literal("missing") }).strict(),
|
|
3033
|
+
z4.object({ status: z4.literal("too-large") }).strict(),
|
|
3034
|
+
z4.object({ status: z4.literal("unreadable") }).strict()
|
|
2986
3035
|
]);
|
|
2987
|
-
var collectedLocaleFileSchema =
|
|
2988
|
-
locale:
|
|
3036
|
+
var collectedLocaleFileSchema = z4.object({
|
|
3037
|
+
locale: z4.string().min(1),
|
|
2989
3038
|
payload: collectedFilePayloadSchema
|
|
2990
3039
|
}).strict();
|
|
2991
|
-
var collectedE2eFactsSchema =
|
|
3040
|
+
var collectedE2eFactsSchema = z4.object({
|
|
2992
3041
|
manifest: collectedFilePayloadSchema,
|
|
2993
3042
|
specFiles: uniqueSortedStringArray("specFiles"),
|
|
2994
3043
|
escapingSymlinks: uniqueSortedStringArray("escapingSymlinks")
|
|
@@ -3010,20 +3059,20 @@ function validateRouteExportEvidenceCongruence(input) {
|
|
|
3010
3059
|
}
|
|
3011
3060
|
}
|
|
3012
3061
|
}
|
|
3013
|
-
var collectedEnhancementFactsSchema =
|
|
3014
|
-
peer:
|
|
3015
|
-
hasContributionsTs:
|
|
3062
|
+
var collectedEnhancementFactsSchema = z4.object({
|
|
3063
|
+
peer: z4.string().min(1),
|
|
3064
|
+
hasContributionsTs: z4.boolean(),
|
|
3016
3065
|
contributionPermissions: contributionPermissionsSchema("enhancement contributionPermissions"),
|
|
3017
|
-
hasInitializeServerTs:
|
|
3066
|
+
hasInitializeServerTs: z4.boolean(),
|
|
3018
3067
|
contributionsCollectionErrors: uniqueSortedStringArray(
|
|
3019
3068
|
"enhancement contributionsCollectionErrors"
|
|
3020
3069
|
),
|
|
3021
3070
|
initializeServerCollectionErrors: uniqueSortedStringArray(
|
|
3022
3071
|
"enhancement initializeServerCollectionErrors"
|
|
3023
3072
|
),
|
|
3024
|
-
hasRoutesDir:
|
|
3073
|
+
hasRoutesDir: z4.boolean(),
|
|
3025
3074
|
routeCollectionErrors: uniqueSortedStringArray("enhancement routeCollectionErrors"),
|
|
3026
|
-
locales:
|
|
3075
|
+
locales: z4.array(collectedLocaleFileSchema).superRefine((locales, ctx) => {
|
|
3027
3076
|
const names = locales.map((l) => l.locale);
|
|
3028
3077
|
if (new Set(names).size !== names.length) {
|
|
3029
3078
|
ctx.addIssue({ code: "custom", message: "enhancement locales must be unique by locale" });
|
|
@@ -3038,27 +3087,27 @@ var collectedEnhancementFactsSchema = z3.object({
|
|
|
3038
3087
|
}),
|
|
3039
3088
|
e2e: collectedE2eFactsSchema.nullable()
|
|
3040
3089
|
}).strict();
|
|
3041
|
-
var moduleStructureFactsSchema =
|
|
3042
|
-
collected:
|
|
3043
|
-
dirName:
|
|
3044
|
-
hasIndexTs:
|
|
3045
|
-
hasContributionsTs:
|
|
3090
|
+
var moduleStructureFactsSchema = z4.object({
|
|
3091
|
+
collected: z4.literal(true),
|
|
3092
|
+
dirName: z4.string().min(1),
|
|
3093
|
+
hasIndexTs: z4.boolean(),
|
|
3094
|
+
hasContributionsTs: z4.boolean(),
|
|
3046
3095
|
contributionPermissions: contributionPermissionsSchema("contributionPermissions"),
|
|
3047
|
-
hasSlotsTs:
|
|
3096
|
+
hasSlotsTs: z4.boolean(),
|
|
3048
3097
|
contributionsCollectionErrors: uniqueSortedStringArray("contributionsCollectionErrors"),
|
|
3049
3098
|
slotsCollectionErrors: uniqueSortedStringArray("slotsCollectionErrors"),
|
|
3050
|
-
hasTestsDir:
|
|
3051
|
-
hasDatastoreDir:
|
|
3052
|
-
datastoreFileCount:
|
|
3053
|
-
hasServerIndexTs:
|
|
3054
|
-
hasOtherServerTs:
|
|
3055
|
-
hasE2eDir:
|
|
3056
|
-
hasRoutesDir:
|
|
3099
|
+
hasTestsDir: z4.boolean(),
|
|
3100
|
+
hasDatastoreDir: z4.boolean(),
|
|
3101
|
+
datastoreFileCount: z4.number().int().nonnegative(),
|
|
3102
|
+
hasServerIndexTs: z4.boolean(),
|
|
3103
|
+
hasOtherServerTs: z4.boolean(),
|
|
3104
|
+
hasE2eDir: z4.boolean(),
|
|
3105
|
+
hasRoutesDir: z4.boolean(),
|
|
3057
3106
|
routeEntries: uniqueSortedStringArray("routeEntries"),
|
|
3058
|
-
routePageExports:
|
|
3059
|
-
|
|
3060
|
-
nextRelativePath:
|
|
3061
|
-
hasGenerateMetadata:
|
|
3107
|
+
routePageExports: z4.array(
|
|
3108
|
+
z4.object({
|
|
3109
|
+
nextRelativePath: z4.string().min(1),
|
|
3110
|
+
hasGenerateMetadata: z4.boolean()
|
|
3062
3111
|
}).strict()
|
|
3063
3112
|
).superRefine((entries, ctx) => {
|
|
3064
3113
|
const paths = entries.map((e) => e.nextRelativePath);
|
|
@@ -3080,7 +3129,7 @@ var moduleStructureFactsSchema = z3.object({
|
|
|
3080
3129
|
}
|
|
3081
3130
|
}),
|
|
3082
3131
|
routeCollectionErrors: uniqueSortedStringArray("routeCollectionErrors"),
|
|
3083
|
-
rootLocales:
|
|
3132
|
+
rootLocales: z4.array(collectedLocaleFileSchema).superRefine((locales, ctx) => {
|
|
3084
3133
|
const names = locales.map((l) => l.locale);
|
|
3085
3134
|
if (new Set(names).size !== names.length) {
|
|
3086
3135
|
ctx.addIssue({ code: "custom", message: "rootLocales must be unique by locale" });
|
|
@@ -3094,7 +3143,7 @@ var moduleStructureFactsSchema = z3.object({
|
|
|
3094
3143
|
}
|
|
3095
3144
|
}),
|
|
3096
3145
|
rootE2e: collectedE2eFactsSchema.nullable(),
|
|
3097
|
-
enhancements:
|
|
3146
|
+
enhancements: z4.array(collectedEnhancementFactsSchema).superRefine((enhancements, ctx) => {
|
|
3098
3147
|
const peers = enhancements.map((e) => e.peer);
|
|
3099
3148
|
if (new Set(peers).size !== peers.length) {
|
|
3100
3149
|
ctx.addIssue({ code: "custom", message: "enhancement peers must be unique" });
|
|
@@ -3115,10 +3164,10 @@ var moduleStructureFactsSchema = z3.object({
|
|
|
3115
3164
|
onIssue: (message) => ctx.addIssue({ code: "custom", message })
|
|
3116
3165
|
});
|
|
3117
3166
|
});
|
|
3118
|
-
var moduleStructureCollectionSchema =
|
|
3167
|
+
var moduleStructureCollectionSchema = z4.object({
|
|
3119
3168
|
homeLocales: uniqueSortedStringArray("homeLocales"),
|
|
3120
|
-
modules:
|
|
3121
|
-
truncated:
|
|
3169
|
+
modules: z4.array(moduleStructureFactsSchema),
|
|
3170
|
+
truncated: z4.boolean().optional(),
|
|
3122
3171
|
collectionErrors: uniqueSortedStringArray("collectionErrors").optional()
|
|
3123
3172
|
}).strict().superRefine((collection, ctx) => {
|
|
3124
3173
|
const dirs = collection.modules.map((m) => m.dirName);
|
|
@@ -3135,9 +3184,9 @@ var moduleStructureCollectionSchema = z3.object({
|
|
|
3135
3184
|
});
|
|
3136
3185
|
|
|
3137
3186
|
// ../../packages/module-contract/src/locale.ts
|
|
3138
|
-
import { z as
|
|
3187
|
+
import { z as z5 } from "zod";
|
|
3139
3188
|
var LOCALE_BASENAME_REGEX = /^[a-z]{2,3}(-[A-Za-z0-9]+)*$/;
|
|
3140
|
-
var localeBasenameSchema =
|
|
3189
|
+
var localeBasenameSchema = z5.string().max(35).regex(LOCALE_BASENAME_REGEX, "must be a BCP47-like locale tag (e.g. en, th, en-US)");
|
|
3141
3190
|
function isValidLocaleBasename(value) {
|
|
3142
3191
|
return localeBasenameSchema.safeParse(value).success;
|
|
3143
3192
|
}
|
|
@@ -3540,43 +3589,43 @@ function formatRoutePageExportErrors(nextRelativePath, validation) {
|
|
|
3540
3589
|
import ts2 from "typescript";
|
|
3541
3590
|
|
|
3542
3591
|
// ../../packages/module-contract/src/module-registry.ts
|
|
3543
|
-
import { z as
|
|
3544
|
-
var projectSlugSchema2 =
|
|
3545
|
-
var registryEnhancementSchema =
|
|
3592
|
+
import { z as z6 } from "zod";
|
|
3593
|
+
var projectSlugSchema2 = z6.string().refine((value) => validateSlug(value).valid, "must be a valid project slug");
|
|
3594
|
+
var registryEnhancementSchema = z6.object({
|
|
3546
3595
|
peer: moduleNameSchema,
|
|
3547
|
-
active:
|
|
3596
|
+
active: z6.boolean()
|
|
3548
3597
|
}).strict();
|
|
3549
|
-
var registryModuleSchema =
|
|
3598
|
+
var registryModuleSchema = z6.object({
|
|
3550
3599
|
name: moduleNameSchema,
|
|
3551
3600
|
/** Installed version as recorded by the rail (non-empty string). */
|
|
3552
|
-
version:
|
|
3601
|
+
version: z6.string().min(1),
|
|
3553
3602
|
home: projectSlugSchema2,
|
|
3554
3603
|
kind: moduleKindSchema,
|
|
3555
|
-
mounts:
|
|
3556
|
-
enhancements:
|
|
3604
|
+
mounts: z6.array(mountSchema),
|
|
3605
|
+
enhancements: z6.array(registryEnhancementSchema)
|
|
3557
3606
|
}).strict().superRefine((mod, ctx) => {
|
|
3558
3607
|
for (let i = 0; i < mod.enhancements.length; i += 1) {
|
|
3559
3608
|
if (mod.enhancements[i].peer === mod.name) {
|
|
3560
3609
|
ctx.addIssue({
|
|
3561
|
-
code:
|
|
3610
|
+
code: z6.ZodIssueCode.custom,
|
|
3562
3611
|
message: "enhancement peer must not equal the module's own name",
|
|
3563
3612
|
path: ["enhancements", i, "peer"]
|
|
3564
3613
|
});
|
|
3565
3614
|
}
|
|
3566
3615
|
}
|
|
3567
3616
|
});
|
|
3568
|
-
var generatedModuleRegistrySchema =
|
|
3569
|
-
registryVersion:
|
|
3617
|
+
var generatedModuleRegistrySchema = z6.object({
|
|
3618
|
+
registryVersion: z6.literal(1),
|
|
3570
3619
|
/** Rail run id, or `"manual"` for fixtures. */
|
|
3571
|
-
generatedBy:
|
|
3572
|
-
modules:
|
|
3620
|
+
generatedBy: z6.string().min(1),
|
|
3621
|
+
modules: z6.array(registryModuleSchema)
|
|
3573
3622
|
}).strict().superRefine((registry, ctx) => {
|
|
3574
3623
|
const seen = /* @__PURE__ */ new Set();
|
|
3575
3624
|
for (let i = 0; i < registry.modules.length; i += 1) {
|
|
3576
3625
|
const name = registry.modules[i].name;
|
|
3577
3626
|
if (seen.has(name)) {
|
|
3578
3627
|
ctx.addIssue({
|
|
3579
|
-
code:
|
|
3628
|
+
code: z6.ZodIssueCode.custom,
|
|
3580
3629
|
message: `duplicate module name "${name}"`,
|
|
3581
3630
|
path: ["modules", i, "name"]
|
|
3582
3631
|
});
|
|
@@ -3947,171 +3996,9 @@ function analyzeClientSafeEntryImports(sourceText, fileName) {
|
|
|
3947
3996
|
return analyzeClientSafeEntryImportsWithTs(ts3, sourceText, fileName);
|
|
3948
3997
|
}
|
|
3949
3998
|
|
|
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
3999
|
// ../../packages/lib/src/shared/platform-owned-paths.ts
|
|
4114
4000
|
var APP_WEB_PREFIX = "apps/web/";
|
|
4001
|
+
var BLUEPRINT_LINT_MARKER = `${APP_WEB_PREFIX}eslint-rules/module-boundaries.mjs`;
|
|
4115
4002
|
var MODULE_STUB_MARKER = "@stardeck-module-rail-generated";
|
|
4116
4003
|
var ENABLED_MODULES_ENV = "NEXT_PUBLIC_STARDECK_ENABLED_MODULES";
|
|
4117
4004
|
var HEADLESS_MOUNTS_ENV = "NEXT_PUBLIC_STARDECK_HEADLESS_MOUNTS";
|
|
@@ -6036,6 +5923,52 @@ function rejectPseudoModuleEntries(entries, parentDir, label) {
|
|
|
6036
5923
|
return dirs;
|
|
6037
5924
|
}
|
|
6038
5925
|
|
|
5926
|
+
// ../../packages/lib/src/shared/module-composition.ts
|
|
5927
|
+
import { z as z7 } from "zod";
|
|
5928
|
+
var creationSourceBlankSchema = z7.object({
|
|
5929
|
+
type: z7.literal("blank")
|
|
5930
|
+
});
|
|
5931
|
+
var creationSourceBlueprintSchema = z7.object({
|
|
5932
|
+
type: z7.literal("blueprint"),
|
|
5933
|
+
/** Internal template/fork project id — keep template naming in identifiers. */
|
|
5934
|
+
blueprintProjectId: z7.string().uuid(),
|
|
5935
|
+
/**
|
|
5936
|
+
* `null`/absent means every feature Module: the platform stores that as the
|
|
5937
|
+
* explicit list of feature Modules in the published Blueprint version the fork
|
|
5938
|
+
* is cut from, so a Module a later Blueprint update adds arrives off. `[]` is
|
|
5939
|
+
* refused: the platform serialises it to an empty
|
|
5940
|
+
* `NEXT_PUBLIC_STARDECK_ENABLED_MODULES`, which the enablement parser reads
|
|
5941
|
+
* back as "all" (`module-enablement.ts`) — the opposite of an empty selection.
|
|
5942
|
+
*/
|
|
5943
|
+
enabledModules: z7.array(moduleNameSchema).min(1, "Enable at least one Module").max(100).nullable().optional()
|
|
5944
|
+
});
|
|
5945
|
+
var creationSourceSchema = z7.discriminatedUnion("type", [
|
|
5946
|
+
creationSourceBlankSchema,
|
|
5947
|
+
creationSourceBlueprintSchema
|
|
5948
|
+
]);
|
|
5949
|
+
var moduleInstallHandoffSchema = z7.object({
|
|
5950
|
+
moduleName: z7.string().min(1),
|
|
5951
|
+
homeProjectId: z7.string().uuid(),
|
|
5952
|
+
installedVersion: z7.string().min(1),
|
|
5953
|
+
baselineSha: z7.string().min(1),
|
|
5954
|
+
mounts: z7.array(
|
|
5955
|
+
z7.object({
|
|
5956
|
+
group: z7.string(),
|
|
5957
|
+
segment: z7.string()
|
|
5958
|
+
})
|
|
5959
|
+
),
|
|
5960
|
+
integration: z7.array(z7.string()),
|
|
5961
|
+
workflows: z7.array(z7.string()),
|
|
5962
|
+
prunedEnhancements: z7.array(z7.string()),
|
|
5963
|
+
restoredEnhancements: z7.array(z7.string()).optional(),
|
|
5964
|
+
permissions: z7.array(
|
|
5965
|
+
z7.object({
|
|
5966
|
+
key: z7.string().min(1),
|
|
5967
|
+
description: z7.string().min(1)
|
|
5968
|
+
})
|
|
5969
|
+
).optional()
|
|
5970
|
+
});
|
|
5971
|
+
|
|
6039
5972
|
// ../../packages/lib/src/shared/schema-ops.ts
|
|
6040
5973
|
import { z as z8 } from "zod";
|
|
6041
5974
|
var columnSpecSchema = z8.object({
|
|
@@ -7499,6 +7432,9 @@ async function reconcileCompositionArtifacts(context, options = {}) {
|
|
|
7499
7432
|
var HOME_I18N_SUBSTRATE_DIR = `${APP_PACKAGE_DIR}/src/lib/i18n/substrate`;
|
|
7500
7433
|
var HOME_I18N_MESSAGES_DIR = `${APP_PACKAGE_DIR}/src/lib/i18n/messages`;
|
|
7501
7434
|
|
|
7435
|
+
// src/index.ts
|
|
7436
|
+
import ts6 from "typescript";
|
|
7437
|
+
|
|
7502
7438
|
// src/module-boundaries.ts
|
|
7503
7439
|
import fs2 from "fs";
|
|
7504
7440
|
import path2 from "path";
|
|
@@ -7768,6 +7704,41 @@ function assertNoAppLayerImporters(cwd, excluded) {
|
|
|
7768
7704
|
);
|
|
7769
7705
|
}
|
|
7770
7706
|
}
|
|
7707
|
+
var TSCONFIG_PATH = "apps/web/tsconfig.json";
|
|
7708
|
+
var BUILD_TSCONFIG_PATH = "apps/web/tsconfig.build.gen.json";
|
|
7709
|
+
var BUILD_TSCONFIG_HEADER = "// Generated by stardeck-compose \u2014 the tsconfig `next build` type-checks. Do not edit or commit.";
|
|
7710
|
+
function writeBuildTsconfig(cwd, excluded) {
|
|
7711
|
+
const baseFile = path3.join(cwd, TSCONFIG_PATH);
|
|
7712
|
+
if (!fs3.existsSync(path3.join(cwd, MODULES_DIR2)) || !fs3.existsSync(baseFile)) return;
|
|
7713
|
+
const base = ts6.readConfigFile(baseFile, ts6.sys.readFile);
|
|
7714
|
+
if (base.error) {
|
|
7715
|
+
throw new Error(
|
|
7716
|
+
`[compose] cannot read ${TSCONFIG_PATH}: ${ts6.flattenDiagnosticMessageText(base.error.messageText, "\n")}`
|
|
7717
|
+
);
|
|
7718
|
+
}
|
|
7719
|
+
const baseExclude = base.config?.exclude ?? ["node_modules"];
|
|
7720
|
+
const modulesDir = path3.posix.relative("apps/web", MODULES_DIR2);
|
|
7721
|
+
const config = {
|
|
7722
|
+
extends: "./tsconfig.json",
|
|
7723
|
+
exclude: [
|
|
7724
|
+
...baseExclude,
|
|
7725
|
+
...excluded.flatMap((name) => [
|
|
7726
|
+
`${modulesDir}/${name}`,
|
|
7727
|
+
`${modulesDir}/*/enhancements/${name}`
|
|
7728
|
+
])
|
|
7729
|
+
]
|
|
7730
|
+
};
|
|
7731
|
+
const content = `${BUILD_TSCONFIG_HEADER}
|
|
7732
|
+
${JSON.stringify(config, null, 2)}
|
|
7733
|
+
`;
|
|
7734
|
+
const file = path3.join(cwd, BUILD_TSCONFIG_PATH);
|
|
7735
|
+
if (!fs3.existsSync(file) || fs3.readFileSync(file, "utf8") !== content) {
|
|
7736
|
+
fs3.writeFileSync(file, content);
|
|
7737
|
+
}
|
|
7738
|
+
console.log(
|
|
7739
|
+
`[compose] ${BUILD_TSCONFIG_PATH} excludes ${excluded.length} Module(s): ${excluded.join(",") || "none"}`
|
|
7740
|
+
);
|
|
7741
|
+
}
|
|
7771
7742
|
function removeDir(absolute) {
|
|
7772
7743
|
if (!fs3.existsSync(absolute)) return false;
|
|
7773
7744
|
fs3.rmSync(absolute, { recursive: true, force: true });
|
|
@@ -7815,6 +7786,7 @@ async function compose(options) {
|
|
|
7815
7786
|
skipComposeInputs: true
|
|
7816
7787
|
});
|
|
7817
7788
|
const gitignoreEntries = options.enabled ? null : writeStubGitignore(options.cwd, result.artifactPaths);
|
|
7789
|
+
writeBuildTsconfig(options.cwd, result.excludedModules);
|
|
7818
7790
|
let pruned = 0;
|
|
7819
7791
|
if (options.prune) {
|
|
7820
7792
|
for (const name of result.excludedModules) {
|
|
@@ -7836,6 +7808,7 @@ async function compose(options) {
|
|
|
7836
7808
|
};
|
|
7837
7809
|
}
|
|
7838
7810
|
export {
|
|
7811
|
+
BUILD_TSCONFIG_PATH,
|
|
7839
7812
|
COMPOSE_INPUTS_PATH,
|
|
7840
7813
|
assertSupportedTypescript,
|
|
7841
7814
|
compose,
|