@helipod/cli 0.1.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/bin.js ADDED
@@ -0,0 +1,14 @@
1
+ #!/usr/bin/env node
2
+ import {
3
+ runCli
4
+ } from "./chunk-IBFZ2HUR.js";
5
+ import "./chunk-N5J276OX.js";
6
+ import "./chunk-EPHSHGFU.js";
7
+
8
+ // src/bin.ts
9
+ runCli(process.argv.slice(2)).then((code) => process.exit(code)).catch((e) => {
10
+ process.stderr.write(`${e instanceof Error ? e.stack ?? e.message : String(e)}
11
+ `);
12
+ process.exit(1);
13
+ });
14
+ //# sourceMappingURL=bin.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/bin.ts"],"sourcesContent":["#!/usr/bin/env node\nimport { runCli } from \"./cli\";\n\nrunCli(process.argv.slice(2))\n .then((code) => process.exit(code))\n .catch((e) => {\n process.stderr.write(`${e instanceof Error ? e.stack ?? e.message : String(e)}\\n`);\n process.exit(1);\n });\n"],"mappings":";;;;;;;;AAGA,OAAO,QAAQ,KAAK,MAAM,CAAC,CAAC,EACzB,KAAK,CAAC,SAAS,QAAQ,KAAK,IAAI,CAAC,EACjC,MAAM,CAAC,MAAM;AACZ,UAAQ,OAAO,MAAM,GAAG,aAAa,QAAQ,EAAE,SAAS,EAAE,UAAU,OAAO,CAAC,CAAC;AAAA,CAAI;AACjF,UAAQ,KAAK,CAAC;AAChB,CAAC;","names":[]}
@@ -0,0 +1,86 @@
1
+ // src/project.ts
2
+ import { validatorToTsType, assertShardByDeclarations } from "@helipod/codegen";
3
+ import { composeComponents } from "@helipod/component";
4
+ import { STORAGE_TABLE, STORAGE_TABLE_NUMBER, storageTableDefinition } from "@helipod/storage";
5
+ var DEFAULT_INDEX = "by_creation";
6
+ function isRegisteredFunction(x) {
7
+ return typeof x === "object" && x !== null && typeof x.type === "string" && typeof x.handler === "function";
8
+ }
9
+ function loadProject(loaded, components = [], existingTableNumbers) {
10
+ const schemaJson = loaded.schema.export();
11
+ schemaJson.tables[STORAGE_TABLE] = storageTableDefinition.export();
12
+ const appModuleMap = {};
13
+ const manifest = [];
14
+ const shardByDeclarations = [];
15
+ for (const [path, exports] of Object.entries(loaded.modules)) {
16
+ const functions = [];
17
+ for (const [name, value] of Object.entries(exports)) {
18
+ if (!isRegisteredFunction(value)) continue;
19
+ appModuleMap[`${path}:${name}`] = value;
20
+ if (value.type === "query" || value.type === "mutation" || value.type === "action" || value.type === "httpAction") {
21
+ functions.push({
22
+ name,
23
+ type: value.type,
24
+ visibility: "public",
25
+ argsType: value.argsJson ? validatorToTsType(value.argsJson) : void 0,
26
+ // D10: mirrors argsType exactly. A function without `returns` stays `undefined` here,
27
+ // which `generateApi`/`generateInternalApi` (generate.ts:133) fall back to `any` for —
28
+ // the documented gap until the inference follow-on (see functions.ts's returnsJson doc).
29
+ returnsType: value.returnsJson ? validatorToTsType(value.returnsJson) : void 0
30
+ });
31
+ }
32
+ if (value.type === "mutation" && typeof value.shardBy === "string") {
33
+ shardByDeclarations.push({ functionPath: `${path}:${name}`, argName: value.shardBy, argsJson: value.argsJson });
34
+ }
35
+ }
36
+ if (functions.length > 0) {
37
+ functions.sort((a, b) => a.name < b.name ? -1 : a.name > b.name ? 1 : 0);
38
+ manifest.push({ path, functions });
39
+ }
40
+ }
41
+ manifest.sort((a, b) => a.path < b.path ? -1 : a.path > b.path ? 1 : 0);
42
+ assertShardByDeclarations(schemaJson, shardByDeclarations);
43
+ const composed = composeComponents({ schemaJson, moduleMap: appModuleMap }, components, {
44
+ [STORAGE_TABLE]: STORAGE_TABLE_NUMBER,
45
+ ...existingTableNumbers
46
+ });
47
+ const routes = [];
48
+ const router = loaded.modules["http"]?.default;
49
+ if (router?.routes) {
50
+ const pathByFn = /* @__PURE__ */ new Map();
51
+ for (const [path, fn] of Object.entries(appModuleMap)) pathByFn.set(fn, path);
52
+ for (const r of router.routes) {
53
+ const handlerPath = pathByFn.get(r.handler);
54
+ if (!handlerPath) {
55
+ const where = r.path ?? r.pathPrefix ?? "?";
56
+ throw new Error(
57
+ `http.route handler for "${where}" must be an exported httpAction (declare it as a named export of an app module)`
58
+ );
59
+ }
60
+ routes.push({
61
+ method: r.method,
62
+ ...r.path !== void 0 ? { path: r.path } : { pathPrefix: r.pathPrefix },
63
+ handlerPath
64
+ });
65
+ }
66
+ }
67
+ return {
68
+ schemaJson,
69
+ catalog: composed.catalog,
70
+ moduleMap: composed.moduleMap,
71
+ manifest,
72
+ tableNumbers: composed.tableNumbers,
73
+ componentNames: composed.componentNames,
74
+ contextProviders: composed.contextProviders,
75
+ bootSteps: composed.bootSteps,
76
+ drivers: composed.drivers,
77
+ routes,
78
+ componentRoutes: composed.componentRoutes
79
+ };
80
+ }
81
+
82
+ export {
83
+ DEFAULT_INDEX,
84
+ loadProject
85
+ };
86
+ //# sourceMappingURL=chunk-EPHSHGFU.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/project.ts"],"sourcesContent":["/**\n * Turn a loaded project (a live schema + function modules) into the artifacts the engine and\n * codegen need: the schema JSON, an index catalog (with table numbers assigned + an implicit\n * `by_creation` index per table), the `path:name → function` map, and the analyzed manifest.\n */\nimport type { RegisteredFunction, ContextProvider } from \"@helipod/executor\";\nimport type { SchemaDefinition, SchemaDefinitionJSON } from \"@helipod/values\";\nimport type { AnalyzedFunction, AnalyzedFunctionManifest, ShardByDeclaration } from \"@helipod/codegen\";\nimport { validatorToTsType, assertShardByDeclarations } from \"@helipod/codegen\";\nimport { composeComponents, type ComponentDefinition, type BootContext, type Driver, type ResolvedComponentRoute } from \"@helipod/component\";\nimport type { SimpleIndexCatalog } from \"@helipod/executor\";\nimport { STORAGE_TABLE, STORAGE_TABLE_NUMBER, storageTableDefinition } from \"@helipod/storage\";\n\nexport const DEFAULT_INDEX = \"by_creation\";\n\nexport interface LoadedProject {\n schema: SchemaDefinition;\n /** module path (without extension) → its exports (name → value). */\n modules: Record<string, Record<string, unknown>>;\n}\n\nexport interface ProjectArtifacts {\n schemaJson: SchemaDefinitionJSON;\n catalog: SimpleIndexCatalog;\n moduleMap: Record<string, RegisteredFunction>;\n manifest: AnalyzedFunctionManifest;\n tableNumbers: Record<string, number>;\n componentNames: ReadonlySet<string>;\n contextProviders: ContextProvider[];\n /** Component boot steps (e.g. the scheduler's cron reconciler) — must run once at engine create. */\n bootSteps: { name: string; run: (ctx: BootContext) => Promise<void> }[];\n /**\n * Component drivers (e.g. the scheduler's event loop) — must be started at engine create for a\n * composed component's background work to actually run. Omitting this from\n * `createEmbeddedRuntime(...)` silently leaves drivers never started (jobs enqueue but never\n * dispatch) — see `../test/scheduler-e2e.test.ts` for the proof this wiring matters.\n */\n drivers: Driver[];\n /** The app's `http.ts` router, resolved to `path:name` function paths for dispatch. */\n routes: ResolvedRoute[];\n /** Reserved engine routes contributed by composed components (e.g. auth's `/api/auth/oauth/*`). */\n componentRoutes: ResolvedComponentRoute[];\n}\n\n/** A single `http.ts` route, with its handler resolved from a `RegisteredFunction` value to the\n * `path:name` string that `runtime.runHttpAction` looks up in `composed.moduleMap`. */\nexport interface ResolvedRoute {\n method: string;\n path?: string;\n pathPrefix?: string;\n handlerPath: string;\n}\n\nfunction isRegisteredFunction(x: unknown): x is RegisteredFunction {\n return (\n typeof x === \"object\" &&\n x !== null &&\n typeof (x as { type?: unknown }).type === \"string\" &&\n typeof (x as { handler?: unknown }).handler === \"function\"\n );\n}\n\nexport function loadProject(\n loaded: LoadedProject,\n components: ComponentDefinition[] = [],\n existingTableNumbers?: Record<string, number>,\n): ProjectArtifacts {\n const schemaJson = loaded.schema.export();\n\n // File storage is an ALWAYS-ON core feature (not read from `helipod.config.ts`): inject its\n // reserved app-root `_storage` system table into the composed schema so it flows through the same\n // path every other table does — a catalog entry + `by_creation` index (so the `_storage:*`\n // built-ins' `ctx.db` ops resolve) and a stable tableNumber. Seeding the registry with\n // `{ _storage: STORAGE_TABLE_NUMBER }` (below) `preassign`s that number so `_storage` decodes back\n // to the same table forever and never collides with an app/component table. Doing this in the\n // SHARED load path (not just boot) keeps `helipod deploy`'s additive-schema diff consistent:\n // the live schema and every re-pushed schema both carry `_storage`, so a deploy never sees it as\n // a \"dropped table\". Codegen already emits `_storage` from `@helipod/values`' canonical system\n // defs and filters it out of the app schema, so this injection does not double it there.\n schemaJson.tables[STORAGE_TABLE] = storageTableDefinition.export();\n\n // Build the app's moduleMap + manifest from loaded.modules (codegen needs the app manifest).\n const appModuleMap: Record<string, RegisteredFunction> = {};\n const manifest: AnalyzedFunctionManifest = [];\n // Shards B2a (D7): collected alongside the manifest loop below — every mutation whose `shardBy`\n // is a plain arg-name STRING (a resolver function is opaque to codegen; it falls through to the\n // kernel guards at runtime, same as always). Cross-checked against `schemaJson` once the loop\n // finishes (see `assertShardByDeclarations` below).\n const shardByDeclarations: ShardByDeclaration[] = [];\n for (const [path, exports] of Object.entries(loaded.modules)) {\n const functions: AnalyzedFunction[] = [];\n for (const [name, value] of Object.entries(exports)) {\n if (!isRegisteredFunction(value)) continue;\n appModuleMap[`${path}:${name}`] = value;\n if (value.type === \"query\" || value.type === \"mutation\" || value.type === \"action\" || value.type === \"httpAction\") {\n functions.push({\n name,\n type: value.type,\n visibility: \"public\",\n argsType: value.argsJson ? validatorToTsType(value.argsJson) : undefined,\n // D10: mirrors argsType exactly. A function without `returns` stays `undefined` here,\n // which `generateApi`/`generateInternalApi` (generate.ts:133) fall back to `any` for —\n // the documented gap until the inference follow-on (see functions.ts's returnsJson doc).\n returnsType: value.returnsJson ? validatorToTsType(value.returnsJson) : undefined,\n });\n }\n if (value.type === \"mutation\" && typeof value.shardBy === \"string\") {\n shardByDeclarations.push({ functionPath: `${path}:${name}`, argName: value.shardBy, argsJson: value.argsJson });\n }\n }\n if (functions.length > 0) {\n // Sort so codegen output is deterministic regardless of module-namespace key order\n // (which differs between Bun and Node).\n functions.sort((a, b) => (a.name < b.name ? -1 : a.name > b.name ? 1 : 0));\n manifest.push({ path, functions });\n }\n }\n manifest.sort((a, b) => (a.path < b.path ? -1 : a.path > b.path ? 1 : 0));\n assertShardByDeclarations(schemaJson, shardByDeclarations);\n\n // Compose app + components: allocates table numbers, merges module maps, collects context providers.\n // Seed `_storage` at its reserved number BEFORE allocation so `registry.preassign` pins it (an\n // existing deploy's numbers, if any, still win — they carry the same `_storage: 20`).\n const composed = composeComponents({ schemaJson, moduleMap: appModuleMap }, components, {\n [STORAGE_TABLE]: STORAGE_TABLE_NUMBER,\n ...existingTableNumbers,\n });\n\n // Extract + resolve the `http.ts` router (if any): its `default` export is an `HttpRouter` whose\n // route handlers are `RegisteredFunction` VALUES — resolve each to its `path:name` function path\n // by identity over `appModuleMap` (the same objects the router references), for\n // `runtime.runHttpAction` to look up in `composed.moduleMap`.\n const routes: ResolvedRoute[] = [];\n const router = loaded.modules[\"http\"]?.default as\n | { routes?: Array<{ method: string; path?: string; pathPrefix?: string; handler: RegisteredFunction }> }\n | undefined;\n if (router?.routes) {\n const pathByFn = new Map<RegisteredFunction, string>();\n for (const [path, fn] of Object.entries(appModuleMap)) pathByFn.set(fn, path);\n for (const r of router.routes) {\n const handlerPath = pathByFn.get(r.handler);\n if (!handlerPath) {\n const where = r.path ?? r.pathPrefix ?? \"?\";\n throw new Error(\n `http.route handler for \"${where}\" must be an exported httpAction (declare it as a named export of an app module)`,\n );\n }\n routes.push({\n method: r.method,\n ...(r.path !== undefined ? { path: r.path } : { pathPrefix: r.pathPrefix }),\n handlerPath,\n });\n }\n }\n\n return {\n schemaJson,\n catalog: composed.catalog,\n moduleMap: composed.moduleMap,\n manifest,\n tableNumbers: composed.tableNumbers,\n componentNames: composed.componentNames,\n contextProviders: composed.contextProviders,\n bootSteps: composed.bootSteps,\n drivers: composed.drivers,\n routes,\n componentRoutes: composed.componentRoutes,\n };\n}\n"],"mappings":"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","names":[]}