@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 +14 -0
- package/dist/bin.js.map +1 -0
- package/dist/chunk-EPHSHGFU.js +86 -0
- package/dist/chunk-EPHSHGFU.js.map +1 -0
- package/dist/chunk-IBFZ2HUR.js +2653 -0
- package/dist/chunk-IBFZ2HUR.js.map +1 -0
- package/dist/chunk-N5J276OX.js +218 -0
- package/dist/chunk-N5J276OX.js.map +1 -0
- package/dist/http-handler-BFprdo3f.d.ts +133 -0
- package/dist/http-handler.d.ts +8 -0
- package/dist/http-handler.js +7 -0
- package/dist/http-handler.js.map +1 -0
- package/dist/index.d.ts +366 -0
- package/dist/index.js +120 -0
- package/dist/index.js.map +1 -0
- package/dist/project.d.ts +53 -0
- package/dist/project.js +9 -0
- package/dist/project.js.map +1 -0
- package/package.json +92 -0
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,366 @@
|
|
|
1
|
+
import { ProjectArtifacts, LoadedProject, ResolvedRoute } from './project.js';
|
|
2
|
+
export { DEFAULT_INDEX, loadProject } from './project.js';
|
|
3
|
+
import { GeneratedBundle } from '@helipod/codegen';
|
|
4
|
+
export { writeGenerated } from '@helipod/codegen';
|
|
5
|
+
import { ComponentDefinition, HelipodConfig, WakeHost } from '@helipod/component';
|
|
6
|
+
export { HelipodConfig } from '@helipod/component';
|
|
7
|
+
import { D as DeployWireResult, F as FleetHandles } from './http-handler-BFprdo3f.js';
|
|
8
|
+
export { H as HttpRequest, a as HttpResponse, S as ServerInfo, h as handleHttpRequest } from './http-handler-BFprdo3f.js';
|
|
9
|
+
import { ServerHandle, ServeOptions, RuntimeHost, EmbeddedRuntime, WriteRouter, EmbeddedWriteFanoutAdapter } from '@helipod/runtime-embedded';
|
|
10
|
+
import { AdminApi } from '@helipod/admin';
|
|
11
|
+
import { StorageRoute } from '@helipod/storage';
|
|
12
|
+
import { DocStore } from '@helipod/docstore';
|
|
13
|
+
import { InMemoryLogSink, RegisteredFunction } from '@helipod/executor';
|
|
14
|
+
import { BlobStore } from '@helipod/blobstore';
|
|
15
|
+
import { S3Config } from '@helipod/blobstore-s3';
|
|
16
|
+
import '@helipod/values';
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* The push pipeline: load the project → run codegen → return artifacts. `helipod dev` runs
|
|
20
|
+
* this on startup and on every file change (hot reload re-runs `push` and re-registers the
|
|
21
|
+
* module map with the running engine — no restart).
|
|
22
|
+
*/
|
|
23
|
+
|
|
24
|
+
interface PushResult {
|
|
25
|
+
project: ProjectArtifacts;
|
|
26
|
+
generated: GeneratedBundle;
|
|
27
|
+
}
|
|
28
|
+
declare function push(loaded: LoadedProject, components?: ComponentDefinition[], existingTableNumbers?: Record<string, number>): PushResult;
|
|
29
|
+
|
|
30
|
+
type RuntimeKind = "bun" | "node" | "auto";
|
|
31
|
+
interface DevOptions {
|
|
32
|
+
port?: number;
|
|
33
|
+
ip?: string;
|
|
34
|
+
functionsDir?: string;
|
|
35
|
+
dataPath?: string;
|
|
36
|
+
runtime?: RuntimeKind;
|
|
37
|
+
/** Optional static web UI directory to serve alongside the API/WebSocket. */
|
|
38
|
+
webDir?: string;
|
|
39
|
+
/** Postgres connection string (flag wins over `HELIPOD_DATABASE_URL`); unset → SQLite. */
|
|
40
|
+
databaseUrl?: string;
|
|
41
|
+
/** File-storage backend flag overrides (`--storage-bucket`/`--storage-endpoint`; win over env). */
|
|
42
|
+
storageBucket?: string;
|
|
43
|
+
storageEndpoint?: string;
|
|
44
|
+
}
|
|
45
|
+
interface ResolvedDevOptions {
|
|
46
|
+
port: number;
|
|
47
|
+
ip: string;
|
|
48
|
+
functionsDir: string;
|
|
49
|
+
dataPath: string;
|
|
50
|
+
runtime: RuntimeKind;
|
|
51
|
+
webDir: string | undefined;
|
|
52
|
+
databaseUrl: string | undefined;
|
|
53
|
+
storageBucket: string | undefined;
|
|
54
|
+
storageEndpoint: string | undefined;
|
|
55
|
+
}
|
|
56
|
+
declare function resolveDevOptions(options?: DevOptions): ResolvedDevOptions;
|
|
57
|
+
/** Detect the active JS runtime (Bun is primary; Node is supported). */
|
|
58
|
+
declare function detectRuntime(): "bun" | "node";
|
|
59
|
+
|
|
60
|
+
type DevServer = ServerHandle<ResolvedRoute>;
|
|
61
|
+
type DevServerOptions = ServeOptions<ResolvedRoute, AdminApi, StorageRoute, DeployWireResult, FleetHandles>;
|
|
62
|
+
/** Start the dev server using the best backend for the current runtime. */
|
|
63
|
+
declare function startDevServer(runtime: EmbeddedRuntime, options: DevServerOptions): Promise<DevServer>;
|
|
64
|
+
/**
|
|
65
|
+
* The process {@link RuntimeHost}: binds a runtime to a real TCP port via `Bun.serve` (primary) or
|
|
66
|
+
* `node:http` + `ws`. This class is the ONLY place in the CLI that owns those host primitives — the
|
|
67
|
+
* `detectRuntime()` bun/node split is its private internal (in {@link startDevServer}). Production
|
|
68
|
+
* entrypoints (`dev`/`serve`/`binary`) reach serving exclusively through `host.serve(...)`; a
|
|
69
|
+
* Durable Object host (Slice 3) will implement the same seam without touching any of the above.
|
|
70
|
+
* `serve` is a thin delegation to {@link startDevServer}, which stays exported for tests/benches.
|
|
71
|
+
*/
|
|
72
|
+
declare class ProcessRuntimeHost implements RuntimeHost<ResolvedRoute, AdminApi, StorageRoute, DeployWireResult, FleetHandles> {
|
|
73
|
+
serve(runtime: EmbeddedRuntime, options: DevServerOptions): Promise<DevServer>;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
/**
|
|
77
|
+
* A small debounced watch loop. The fs-watch wiring is injected so the debounce/dispatch
|
|
78
|
+
* logic is testable without touching the filesystem.
|
|
79
|
+
*/
|
|
80
|
+
type WatchTriggerReason = "initial" | "change";
|
|
81
|
+
interface WatchLoopOptions {
|
|
82
|
+
/** Subscribe to raw change events; return an unsubscribe. */
|
|
83
|
+
subscribe: (onChange: () => void) => () => void;
|
|
84
|
+
/** Called (debounced) to rebuild; reason "initial" fires once up front. */
|
|
85
|
+
onTrigger: (reason: WatchTriggerReason) => void | Promise<void>;
|
|
86
|
+
debounceMs?: number;
|
|
87
|
+
/** Injectable timer for tests. */
|
|
88
|
+
setTimer?: (fn: () => void, ms: number) => unknown;
|
|
89
|
+
clearTimer?: (handle: unknown) => void;
|
|
90
|
+
}
|
|
91
|
+
interface WatchLoop {
|
|
92
|
+
start(): void;
|
|
93
|
+
stop(): void;
|
|
94
|
+
}
|
|
95
|
+
declare function createWatchLoop(options: WatchLoopOptions): WatchLoop;
|
|
96
|
+
|
|
97
|
+
declare function loadFunctionsDir(dir: string): Promise<LoadedProject>;
|
|
98
|
+
|
|
99
|
+
declare function loadConfig(projectDir: string): Promise<HelipodConfig>;
|
|
100
|
+
|
|
101
|
+
/** The default backend functions directory name. */
|
|
102
|
+
declare const DEFAULT_FUNCTIONS_DIR = "helipod";
|
|
103
|
+
interface ResolvedFunctionsDir {
|
|
104
|
+
/** Absolute path to the functions directory. */
|
|
105
|
+
functionsDir: string;
|
|
106
|
+
/** Absolute path to the project root (where helipod.config.ts lives). */
|
|
107
|
+
projectRoot: string;
|
|
108
|
+
}
|
|
109
|
+
/**
|
|
110
|
+
* Resolve the functions directory. Precedence, highest first:
|
|
111
|
+
* 1. an explicit `--dir` value
|
|
112
|
+
* 2. `functionsDir` in helipod.config.ts
|
|
113
|
+
* 3. DEFAULT_FUNCTIONS_DIR
|
|
114
|
+
*
|
|
115
|
+
* There is deliberately NO implicit fallback to `convex/`: a Convex layout is
|
|
116
|
+
* converted by `helipod migrate`, never adopted silently. See
|
|
117
|
+
* docs_old/superpowers/specs/2026-06-06-functions-dir-rename-design.md.
|
|
118
|
+
*
|
|
119
|
+
* With an explicit flag the project root is that path's parent, so a caller can point at a
|
|
120
|
+
* functions directory anywhere. Without one the root is the cwd, which is what makes it safe
|
|
121
|
+
* to read the config before the directory name is known: helipod.config.ts always sits at
|
|
122
|
+
* the root and never inside the functions directory.
|
|
123
|
+
*/
|
|
124
|
+
declare function resolveFunctionsDir(flagValue: string | undefined, cwd: string): Promise<ResolvedFunctionsDir>;
|
|
125
|
+
/** The failure message when the resolved directory does not exist. The one Convex-aware string in the CLI. */
|
|
126
|
+
declare function functionsDirNotFoundMessage(functionsDir: string): string;
|
|
127
|
+
|
|
128
|
+
declare function devCommand(args: string[]): Promise<number>;
|
|
129
|
+
declare function codegenCommand(args: string[]): Promise<number>;
|
|
130
|
+
declare function runCli(argv: string[]): Promise<number>;
|
|
131
|
+
|
|
132
|
+
/** Resolved storage config. A `bucket` selects the S3 backend; everything else is FS. */
|
|
133
|
+
type StorageConfig = Partial<S3Config> & {
|
|
134
|
+
bucket?: string;
|
|
135
|
+
};
|
|
136
|
+
|
|
137
|
+
interface BootResult {
|
|
138
|
+
runtime: EmbeddedRuntime;
|
|
139
|
+
adminApi: AdminApi;
|
|
140
|
+
project: ProjectArtifacts;
|
|
141
|
+
generated: GeneratedBundle;
|
|
142
|
+
store: DocStore;
|
|
143
|
+
logSink: InMemoryLogSink;
|
|
144
|
+
/** The boot-time component set (from helipod.config.ts) — `applyDeploy` re-composes against it. */
|
|
145
|
+
components: ComponentDefinition[];
|
|
146
|
+
/** The always-on file-storage byte backend (FS or S3), shared by the provider/reaper/routes. */
|
|
147
|
+
blobStore: BlobStore;
|
|
148
|
+
/**
|
|
149
|
+
* The engine-owned `/api/storage/*` handlers (upload/confirm/serve). Reserved-path routes the
|
|
150
|
+
* server splices into its dispatch (NOT user `http.ts` routes) — see `server.ts`.
|
|
151
|
+
*/
|
|
152
|
+
storageRoutes: StorageRoute[];
|
|
153
|
+
/**
|
|
154
|
+
* Reserved engine routes contributed by composed components (e.g. `@helipod/auth`'s
|
|
155
|
+
* `/api/auth/oauth/*`), each bound to `runtime.runHttpAction` and shaped as an engine-owned
|
|
156
|
+
* `StorageRoute` `{method,pathPrefix,handler}` so `server.ts` dispatches them exactly like the
|
|
157
|
+
* always-on storage routes. Fixed at boot (the component set is fixed at boot — only functions/
|
|
158
|
+
* schema hot-swap), so no `setRoutes` live-swap is needed. Empty when no component declares routes.
|
|
159
|
+
*/
|
|
160
|
+
componentRoutes: StorageRoute[];
|
|
161
|
+
/**
|
|
162
|
+
* Set only when `objectStoreUrl` was given — the object-store node's graceful-shutdown handle.
|
|
163
|
+
* `serve.ts`'s shutdown calls this AFTER `server.close()` and BEFORE `store.close()`. Two shapes,
|
|
164
|
+
* mutually exclusive by construction (at most one of `replica`/writer ever built this boot):
|
|
165
|
+
* - Writer (Tier 3 Slice 6, Task 6.5): `store.relinquish()`, which best-effort CAS-clears the
|
|
166
|
+
* lease IN THE BUCKET, not just in-process — see `ObjectStoreDocStore.relinquish()`'s doc —
|
|
167
|
+
* so a challenger takes over immediately instead of waiting out the full TTL.
|
|
168
|
+
* - Replica (Tier 3 Slice 8, Task 8.2): stops the reactive-tailer wiring helper (Task 8.1) and
|
|
169
|
+
* `removeConsumer`s this replica's watermark, so a departed replica stops pinning the
|
|
170
|
+
* writer's gc — see `buildObjectStoreReplicaNode`'s doc.
|
|
171
|
+
*/
|
|
172
|
+
objectStoreRelease?: () => Promise<void>;
|
|
173
|
+
/**
|
|
174
|
+
* Tier 3 Slice 8 follow-on (replica write-forwarding): set only when this boot is a
|
|
175
|
+
* `--replica` configured with `--writer-url` (i.e. a `ReplicaWriteForwarder` was wired in as
|
|
176
|
+
* the runtime's `writeRouter`). `serve.ts` threads this straight through to
|
|
177
|
+
* `startDevServer`'s `replicaWriterUrl` option, which arms `/api/run`'s single-hop defensive
|
|
178
|
+
* guard (`http-handler.ts`). Absent whenever `--writer-url` is unset (the pre-existing
|
|
179
|
+
* reject-with-message replica behavior, unchanged) or this isn't a replica boot at all.
|
|
180
|
+
*/
|
|
181
|
+
replicaWriterUrl?: string;
|
|
182
|
+
}
|
|
183
|
+
/**
|
|
184
|
+
* Merge the always-on `_storage:*` privileged built-ins into a function map. The `_storage` modules
|
|
185
|
+
* must live in the runtime's `modules` map (not just `systemModules`) because the action-mode
|
|
186
|
+
* `ctx.storage.store` reaches them through the trusted `invoke`, and the reaper driver through
|
|
187
|
+
* `runFunction` — both resolve `modules`. Since `setModules` (dev reload / `helipod deploy`)
|
|
188
|
+
* REPLACES `modules` wholesale, every such swap must re-apply this so storage survives a hot-swap.
|
|
189
|
+
*/
|
|
190
|
+
declare function withStorageModules(map: Record<string, RegisteredFunction>): Record<string, RegisteredFunction>;
|
|
191
|
+
/**
|
|
192
|
+
* Every input the boot core takes. `bootProject` DERIVES its own options from this type (rather than
|
|
193
|
+
* re-declaring them) and forwards them with a spread — see `BootProjectOptions`'s doc for why that
|
|
194
|
+
* matters. Adding an option here therefore reaches `bootProject`'s public surface automatically; the
|
|
195
|
+
* only keys that don't are the two `bootProject` produces itself (`loaded`/`components`).
|
|
196
|
+
*/
|
|
197
|
+
interface BootLoadedOptions {
|
|
198
|
+
loaded: LoadedProject;
|
|
199
|
+
components: ComponentDefinition[];
|
|
200
|
+
dataPath: string;
|
|
201
|
+
adminKey: string;
|
|
202
|
+
/** Postgres connection string; when unset, falls back to the zero-config SQLite file store. */
|
|
203
|
+
databaseUrl?: string;
|
|
204
|
+
/** File-storage backend overrides (CLI flags win over env, resolved via `resolveStorageConfig`). */
|
|
205
|
+
storage?: StorageConfig;
|
|
206
|
+
/**
|
|
207
|
+
* Override the pending-upload TTL (ms) the `ctx.storage` provider stamps on `expiresAt`. Unset →
|
|
208
|
+
* the provider default (1h). Exists so tests can force a short reap deadline; production leaves
|
|
209
|
+
* it at the default.
|
|
210
|
+
*/
|
|
211
|
+
storageUploadTtlMs?: number;
|
|
212
|
+
/**
|
|
213
|
+
* Override the orphan-reaper's sweep interval (ms). Unset → the reaper default (60s). Same
|
|
214
|
+
* test-only motivation as `storageUploadTtlMs`.
|
|
215
|
+
*/
|
|
216
|
+
storageReaperSweepMs?: number;
|
|
217
|
+
/**
|
|
218
|
+
* Tier 2 fleet wiring (from `@helipod/fleet`'s `prepareFleetNode`). When set, `store` is the
|
|
219
|
+
* pre-constructed (read-only-until-promoted) Postgres store — used INSTEAD of `makeStore` — and
|
|
220
|
+
* the runtime is built as a fleet node: writes route through `writeRouter` when this node isn't
|
|
221
|
+
* the writer, drivers are deferred until promotion (`deferDrivers`), and a promoted writer's
|
|
222
|
+
* commits fan out via `fanoutAdapter` (pg_notify). Absent for dev / non-fleet serve.
|
|
223
|
+
*/
|
|
224
|
+
fleet?: {
|
|
225
|
+
store: DocStore;
|
|
226
|
+
writeRouter?: WriteRouter;
|
|
227
|
+
deferDrivers?: boolean;
|
|
228
|
+
fanoutAdapter?: EmbeddedWriteFanoutAdapter;
|
|
229
|
+
/** Shards B2a: shard count — >1 builds a ShardedTransactor (per-shard parallel commits). */
|
|
230
|
+
numShards?: number;
|
|
231
|
+
/** Fleet B3 hybrid (multi-writer): the replica-backed query store (queries route here; mutations
|
|
232
|
+
* commit to `store`). Threaded straight into `createEmbeddedRuntime`. */
|
|
233
|
+
queryStore?: DocStore;
|
|
234
|
+
/** Receipted Outbox (verdict §(c) placement): the authoritative receipts store the Connect handshake
|
|
235
|
+
* classifies/prunes against — the PRIMARY on a sync node (whose `store` is the receipt-less replica),
|
|
236
|
+
* so the handshake never spuriously resets. Threaded straight into `createEmbeddedRuntime`. */
|
|
237
|
+
receiptsStore?: DocStore;
|
|
238
|
+
/** Fleet B3 hybrid RYOW: awaited in the runtime fan-out drain before a local commit's re-runs. */
|
|
239
|
+
beforeNotify?: (commitTs: bigint) => Promise<void>;
|
|
240
|
+
/** Fleet B4: group commit — resolved by `@helipod/fleet`'s `node.ts` from its OWN
|
|
241
|
+
* `HELIPOD_GROUP_COMMIT` read (mirrors how `numShards` is resolved fleet-side, before
|
|
242
|
+
* `bootLoaded` runs) and threaded straight into `createEmbeddedRuntime`. Unset → `false`. */
|
|
243
|
+
groupCommit?: boolean;
|
|
244
|
+
/** Triggers D1: the stable-prefix accessor for `DriverContext.readLog` (`min(shard_leases.frontier_ts)`
|
|
245
|
+
* in a fleet). Threaded straight into `createEmbeddedRuntime`; absent outside a fleet. */
|
|
246
|
+
stablePrefix?: () => Promise<bigint | null>;
|
|
247
|
+
/** Receipted Outbox: fleet owns the `clientReceiptsGuard()` registration on the concrete Postgres
|
|
248
|
+
* store (in `armWriter`, before the fence) — so `createEmbeddedRuntime` must SKIP its own, which
|
|
249
|
+
* would land on a sync node's `SwitchableDocStore` and vanish on the promotion swapTo. Threaded
|
|
250
|
+
* straight into `createEmbeddedRuntime`; absent outside a fleet (the runtime owns it there). */
|
|
251
|
+
externalReceiptsGuard?: boolean;
|
|
252
|
+
};
|
|
253
|
+
/**
|
|
254
|
+
* Tier 3 Slice 6: object-storage substrate writer node. When set, `store` (at the `opts.fleet?.
|
|
255
|
+
* store ?? … ?? makeStore(...)` seam below) becomes an `ObjectStoreDocStore` over this URL's
|
|
256
|
+
* bucket (shard "0") instead of the usual SQLite/Postgres store — see `buildObjectStoreWriterNode`'s
|
|
257
|
+
* doc comment. Mutually exclusive with `fleet` (Tier 2 and Tier 3 are alternative write-scaling
|
|
258
|
+
* stories); combining both throws.
|
|
259
|
+
*/
|
|
260
|
+
objectStoreUrl?: string;
|
|
261
|
+
/** Called once, synchronously, the moment the lease-heartbeat driver detects this node has been
|
|
262
|
+
* fenced (lost the shard-0 lease to a challenger). `serve.ts` wires this to trigger graceful
|
|
263
|
+
* shutdown. Ignored when `objectStoreUrl` is unset. */
|
|
264
|
+
objectStoreOnFenced?: (e: Error) => void;
|
|
265
|
+
/** Test-only overrides (mirrors `storageUploadTtlMs`'s pattern) — unset → the production defaults
|
|
266
|
+
* (`DEFAULT_OBJECTSTORE_LEASE_TTL_MS`/`DEFAULT_OBJECTSTORE_HEARTBEAT_MS`/`leaseTtlMs + 5000`). */
|
|
267
|
+
objectStoreLeaseTtlMs?: number;
|
|
268
|
+
objectStoreHeartbeatMs?: number;
|
|
269
|
+
objectStoreAcquireTimeoutMs?: number;
|
|
270
|
+
objectStoreAcquirePollIntervalMs?: number;
|
|
271
|
+
/** Test-only: force a deterministic writer id instead of a fresh `randomUUID()` per boot. */
|
|
272
|
+
objectStoreWriterId?: string;
|
|
273
|
+
/** Tier 3 Slice 7, Task 7.3: the gc-driver's sweep cadence (ms). Unset → `DEFAULT_OBJECTSTORE_GC_MS`
|
|
274
|
+
* (~60s). `serve.ts` threads `HELIPOD_OBJECTSTORE_GC_MS` in here; tests can also set it directly
|
|
275
|
+
* to force an observable reclamation on a short timescale. Ignored when `objectStoreUrl` is unset. */
|
|
276
|
+
objectStoreGcMs?: number;
|
|
277
|
+
/** Tier 3 multi-shard single-node serve: the number of object-storage lanes a `--object-store`
|
|
278
|
+
* WRITER node owns (`serve.ts` threads `--shards`/`HELIPOD_FLEET_SHARDS` in here). Unset / `1`
|
|
279
|
+
* → the shipped single-shard path (shard "0"), byte-identical. `> 1` → this node opens+acquires
|
|
280
|
+
* all `shardIdList(N)` lanes and composes a `ShardedObjectStoreDocStore`; the runtime's
|
|
281
|
+
* `numShards` is sized to N so the `ShardedTransactor` routes writes to the owning lane. Ignored
|
|
282
|
+
* for a `--replica` boot (a replica reads its lane count from the bucket's `globals.numShards`, not
|
|
283
|
+
* this flag — it has no `--shards` of its own) and when `objectStoreUrl` is unset. */
|
|
284
|
+
objectStoreShards?: number;
|
|
285
|
+
/** Tier 3 Slice 8, Task 8.2: boot this node as a READ-ONLY REPLICA of `objectStoreUrl`'s shard
|
|
286
|
+
* instead of a writer — materializes + tails, NEVER acquires the write lease (every mutation is
|
|
287
|
+
* rejected with `REPLICA_WRITE_REJECTED_MESSAGE`), and runs no heartbeat/gc drivers. Requires
|
|
288
|
+
* `objectStoreUrl` (throws if set without it — `serve.ts` also validates this at the CLI-flag
|
|
289
|
+
* level, before ever reaching here). Ignored (no-op) when `objectStoreUrl` is unset. */
|
|
290
|
+
replica?: boolean;
|
|
291
|
+
/** Test-only: force a deterministic consumer-watermark id for the replica's tailer. Ignored
|
|
292
|
+
* unless `replica` is set. See `buildObjectStoreReplicaNode`'s `consumerId`. */
|
|
293
|
+
objectStoreReplicaConsumerId?: string;
|
|
294
|
+
/** Test-only: shorten the replica's reactive-tailer poll cadence so a materialize-and-fan-out
|
|
295
|
+
* round is observable within a test's timescale. Unset → `DEFAULT_OBJECTSTORE_REPLICA_POLL_MS`
|
|
296
|
+
* (1000ms). Ignored unless `replica` is set. */
|
|
297
|
+
objectStoreReplicaPollMs?: number;
|
|
298
|
+
/**
|
|
299
|
+
* Tier 3 Slice 8 follow-on: the writer node's URL, from `--writer-url`/`HELIPOD_WRITER_URL`.
|
|
300
|
+
* When set on a `replica` boot, every mutation/action is FORWARDED here (`ReplicaWriteForwarder`,
|
|
301
|
+
* wired in as `createEmbeddedRuntime`'s `writeRouter`) instead of being rejected locally.
|
|
302
|
+
* Ignored unless `replica` is also set. Unset (the default) → today's unchanged reject-with-
|
|
303
|
+
* `REPLICA_WRITE_REJECTED_MESSAGE` behavior.
|
|
304
|
+
*/
|
|
305
|
+
writerUrl?: string;
|
|
306
|
+
/**
|
|
307
|
+
* The wake seam: the host's single alarm, for a host that STOPS THE PROCESS between requests (so
|
|
308
|
+
* `setTimeout` never fires and every driver silently goes dead). `serve.ts` builds this from
|
|
309
|
+
* `--wake-url`/`HELIPOD_WAKE_URL` (`httpWakeHost`); the runtime then multiplexes every driver
|
|
310
|
+
* timer down to one arm. Threaded straight into `createEmbeddedRuntime`. Unset (every existing
|
|
311
|
+
* deployment) → plain `setTimeout`, byte-for-byte unchanged.
|
|
312
|
+
*/
|
|
313
|
+
wakeHost?: WakeHost;
|
|
314
|
+
/**
|
|
315
|
+
* The wake seam's other half: answers `DriverContext.backstopMs`, the floor/stretch applied to a
|
|
316
|
+
* driver's BACKSTOP poll cadence only (never a next-work wake). `serve.ts` builds this from
|
|
317
|
+
* `--backstop-min-ms`/`HELIPOD_BACKSTOP_MIN_MS`. Threaded straight into `createEmbeddedRuntime`.
|
|
318
|
+
* Unset → identity (the drivers' own 30s/60s), byte-for-byte unchanged.
|
|
319
|
+
*/
|
|
320
|
+
backstopMs?: (defaultMs: number) => number;
|
|
321
|
+
}
|
|
322
|
+
/**
|
|
323
|
+
* `bootProject`'s options: everything `bootLoaded` takes, MINUS the two things `bootProject` exists
|
|
324
|
+
* to produce itself, PLUS the `functionsDir` it produces them from. Derived deliberately — never
|
|
325
|
+
* re-declared.
|
|
326
|
+
*
|
|
327
|
+
* WHY (a trap this has already cost a full debug cycle — do not re-introduce it): `bootProject` used to
|
|
328
|
+
* re-declare its own option type and forward every key BY HAND into a fresh object literal. That
|
|
329
|
+
* shape drops options SILENTLY. TypeScript's excess-property check does not apply through a spread,
|
|
330
|
+
* and every caller passes optional options via conditional spread
|
|
331
|
+
* (`...(x !== undefined ? { k: v } : {})`, see `serve.ts`) — so a caller could hand `bootProject` a
|
|
332
|
+
* key its type never declared, get ZERO diagnostics, and have the value vanish before it ever
|
|
333
|
+
* reached `createEmbeddedRuntime`. That is exactly how the wake seam shipped dead: `serve.ts` built
|
|
334
|
+
* a valid `httpWakeHost(--wake-url)`, `bootProject` dropped it, the runtime silently took the
|
|
335
|
+
* `setTimeout` branch, and scheduled work never fired on a host that stops the process between
|
|
336
|
+
* requests — with the whole suite green, because nothing type-checked or tested the seam BETWEEN
|
|
337
|
+
* the two functions.
|
|
338
|
+
*
|
|
339
|
+
* Deriving from `BootLoadedOptions` + forwarding with a spread makes the drop structurally
|
|
340
|
+
* impossible rather than merely caught: a new `bootLoaded` option is part of this type, and is
|
|
341
|
+
* forwarded, the moment it is declared. The `Omit` is the ONLY exclusion list, and it is deliberate:
|
|
342
|
+
* `loaded`/`components` are `bootProject`'s own outputs (`loadFunctionsDir`/`loadConfig`), so
|
|
343
|
+
* accepting them from a caller would be meaningless. Anything else belongs here automatically.
|
|
344
|
+
*/
|
|
345
|
+
type BootProjectOptions = Omit<BootLoadedOptions, "loaded" | "components"> & {
|
|
346
|
+
functionsDir: string;
|
|
347
|
+
};
|
|
348
|
+
declare function bootProject(opts: BootProjectOptions): Promise<BootResult>;
|
|
349
|
+
|
|
350
|
+
interface BinaryOptions {
|
|
351
|
+
port: number;
|
|
352
|
+
ip: string;
|
|
353
|
+
dataDir: string;
|
|
354
|
+
adminKey: string;
|
|
355
|
+
/** Postgres connection string (flag wins over `HELIPOD_DATABASE_URL`); unset → SQLite. */
|
|
356
|
+
databaseUrl?: string;
|
|
357
|
+
}
|
|
358
|
+
declare function resolveBinaryOptions(argv: string[], env: Record<string, string | undefined>): BinaryOptions;
|
|
359
|
+
declare function startBinaryServer(loaded: LoadedProject, components: ComponentDefinition[], opts: BinaryOptions, dashboard?: Record<string, string>): Promise<{
|
|
360
|
+
server: DevServer;
|
|
361
|
+
store: DocStore;
|
|
362
|
+
runtime: EmbeddedRuntime;
|
|
363
|
+
}>;
|
|
364
|
+
declare function runBinaryServer(loaded: LoadedProject, components: ComponentDefinition[], dashboard?: Record<string, string>): Promise<void>;
|
|
365
|
+
|
|
366
|
+
export { type BootLoadedOptions, type BootProjectOptions, type BootResult, DEFAULT_FUNCTIONS_DIR, type DevOptions, type DevServer, type DevServerOptions, LoadedProject, ProcessRuntimeHost, ProjectArtifacts, type PushResult, type ResolvedDevOptions, type ResolvedFunctionsDir, type RuntimeKind, type WatchLoop, type WatchLoopOptions, type WatchTriggerReason, bootProject, codegenCommand, createWatchLoop, detectRuntime, devCommand, functionsDirNotFoundMessage, loadConfig, loadFunctionsDir, push, resolveBinaryOptions, resolveDevOptions, resolveFunctionsDir, runBinaryServer, runCli, startBinaryServer, startDevServer, withStorageModules };
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
import {
|
|
2
|
+
DEFAULT_FUNCTIONS_DIR,
|
|
3
|
+
ProcessRuntimeHost,
|
|
4
|
+
bootLoaded,
|
|
5
|
+
bootProject,
|
|
6
|
+
codegenCommand,
|
|
7
|
+
createWatchLoop,
|
|
8
|
+
detectRuntime,
|
|
9
|
+
devCommand,
|
|
10
|
+
functionsDirNotFoundMessage,
|
|
11
|
+
loadConfig,
|
|
12
|
+
loadFunctionsDir,
|
|
13
|
+
push,
|
|
14
|
+
resolveDevOptions,
|
|
15
|
+
resolveFunctionsDir,
|
|
16
|
+
runCli,
|
|
17
|
+
startDevServer,
|
|
18
|
+
withStorageModules
|
|
19
|
+
} from "./chunk-IBFZ2HUR.js";
|
|
20
|
+
import {
|
|
21
|
+
handleHttpRequest
|
|
22
|
+
} from "./chunk-N5J276OX.js";
|
|
23
|
+
import {
|
|
24
|
+
DEFAULT_INDEX,
|
|
25
|
+
loadProject
|
|
26
|
+
} from "./chunk-EPHSHGFU.js";
|
|
27
|
+
|
|
28
|
+
// src/index.ts
|
|
29
|
+
import { writeGenerated } from "@helipod/codegen";
|
|
30
|
+
|
|
31
|
+
// src/binary-main.ts
|
|
32
|
+
import { join } from "path";
|
|
33
|
+
function resolveBinaryOptions(argv, env) {
|
|
34
|
+
let port = env.PORT ? Number(env.PORT) : 3e3;
|
|
35
|
+
let ip = "0.0.0.0";
|
|
36
|
+
let dataDir = "./data";
|
|
37
|
+
let databaseUrl = env.HELIPOD_DATABASE_URL;
|
|
38
|
+
const adminKey = (env.HELIPOD_ADMIN_KEY ?? "").trim();
|
|
39
|
+
for (let i = 0; i < argv.length; i++) {
|
|
40
|
+
const a = argv[i];
|
|
41
|
+
if (a === "--port" && argv[i + 1] !== void 0) port = Number(argv[++i]);
|
|
42
|
+
else if (a === "--hostname" && argv[i + 1] !== void 0) ip = argv[++i];
|
|
43
|
+
else if (a === "--data-dir" && argv[i + 1] !== void 0) dataDir = argv[++i];
|
|
44
|
+
else if (a === "--database-url" && argv[i + 1] !== void 0) databaseUrl = argv[++i];
|
|
45
|
+
}
|
|
46
|
+
return { port, ip, dataDir, adminKey, databaseUrl };
|
|
47
|
+
}
|
|
48
|
+
async function startBinaryServer(loaded, components, opts, dashboard) {
|
|
49
|
+
const boot = await bootLoaded({
|
|
50
|
+
loaded,
|
|
51
|
+
components,
|
|
52
|
+
dataPath: join(opts.dataDir, "db.sqlite"),
|
|
53
|
+
adminKey: opts.adminKey,
|
|
54
|
+
databaseUrl: opts.databaseUrl
|
|
55
|
+
});
|
|
56
|
+
let dash;
|
|
57
|
+
if (dashboard) {
|
|
58
|
+
const bun = globalThis.Bun;
|
|
59
|
+
if (!bun) throw new Error("Bun runtime not available to read the embedded dashboard");
|
|
60
|
+
const indexPath = dashboard["/"];
|
|
61
|
+
if (!indexPath) throw new Error('embedded dashboard map is missing its "/" (index.html) entry');
|
|
62
|
+
const html = await bun.file(indexPath).text();
|
|
63
|
+
dash = { html, assets: dashboard };
|
|
64
|
+
}
|
|
65
|
+
const server = await new ProcessRuntimeHost().serve(boot.runtime, {
|
|
66
|
+
port: opts.port,
|
|
67
|
+
ip: opts.ip,
|
|
68
|
+
admin: { api: boot.adminApi, key: opts.adminKey },
|
|
69
|
+
routes: boot.project.routes,
|
|
70
|
+
storageRoutes: boot.storageRoutes,
|
|
71
|
+
componentRoutes: boot.componentRoutes,
|
|
72
|
+
dashboard: dash
|
|
73
|
+
});
|
|
74
|
+
return { server, store: boot.store, runtime: boot.runtime };
|
|
75
|
+
}
|
|
76
|
+
async function runBinaryServer(loaded, components, dashboard) {
|
|
77
|
+
const opts = resolveBinaryOptions(process.argv.slice(2), process.env);
|
|
78
|
+
if (!opts.adminKey) {
|
|
79
|
+
process.stderr.write("\u2717 HELIPOD_ADMIN_KEY is required \u2014 set it to a strong secret.\n");
|
|
80
|
+
process.exit(1);
|
|
81
|
+
}
|
|
82
|
+
const { server, store } = await startBinaryServer(loaded, components, opts, dashboard);
|
|
83
|
+
process.stdout.write(JSON.stringify({ ready: true, port: opts.port, url: `http://${opts.ip}:${opts.port}` }) + "\n");
|
|
84
|
+
let closing = false;
|
|
85
|
+
const shutdown = async () => {
|
|
86
|
+
if (closing) return;
|
|
87
|
+
closing = true;
|
|
88
|
+
await server.close();
|
|
89
|
+
await store.close();
|
|
90
|
+
process.exit(0);
|
|
91
|
+
};
|
|
92
|
+
process.on("SIGTERM", () => void shutdown());
|
|
93
|
+
process.on("SIGINT", () => void shutdown());
|
|
94
|
+
}
|
|
95
|
+
export {
|
|
96
|
+
DEFAULT_FUNCTIONS_DIR,
|
|
97
|
+
DEFAULT_INDEX,
|
|
98
|
+
ProcessRuntimeHost,
|
|
99
|
+
bootProject,
|
|
100
|
+
codegenCommand,
|
|
101
|
+
createWatchLoop,
|
|
102
|
+
detectRuntime,
|
|
103
|
+
devCommand,
|
|
104
|
+
functionsDirNotFoundMessage,
|
|
105
|
+
handleHttpRequest,
|
|
106
|
+
loadConfig,
|
|
107
|
+
loadFunctionsDir,
|
|
108
|
+
loadProject,
|
|
109
|
+
push,
|
|
110
|
+
resolveBinaryOptions,
|
|
111
|
+
resolveDevOptions,
|
|
112
|
+
resolveFunctionsDir,
|
|
113
|
+
runBinaryServer,
|
|
114
|
+
runCli,
|
|
115
|
+
startBinaryServer,
|
|
116
|
+
startDevServer,
|
|
117
|
+
withStorageModules,
|
|
118
|
+
writeGenerated
|
|
119
|
+
};
|
|
120
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/index.ts","../src/binary-main.ts"],"sourcesContent":["/**\n * `@helipod/cli` — the `helipod` dev tooling: project loading, the push pipeline (load →\n * codegen → register), the HTTP dev server, hot-reload watch loop, and the command dispatch.\n */\nexport type { LoadedProject, ProjectArtifacts } from \"./project\";\nexport { loadProject, DEFAULT_INDEX } from \"./project\";\n\nexport type { PushResult } from \"./push-pipeline\";\nexport { push } from \"./push-pipeline\";\n\nexport type { DevOptions, ResolvedDevOptions, RuntimeKind } from \"./dev-options\";\nexport { resolveDevOptions, detectRuntime } from \"./dev-options\";\n\nexport type { HttpRequest, HttpResponse, ServerInfo } from \"./http-handler\";\nexport { handleHttpRequest } from \"./http-handler\";\n\nexport type { DevServer, DevServerOptions } from \"./server\";\nexport { startDevServer, ProcessRuntimeHost } from \"./server\";\n\nexport type { WatchLoop, WatchLoopOptions, WatchTriggerReason } from \"./watch\";\nexport { createWatchLoop } from \"./watch\";\n\nexport { loadFunctionsDir } from \"./load-modules\";\nexport type { HelipodConfig } from \"@helipod/component\";\nexport { loadConfig } from \"./load-config\";\nexport type { ResolvedFunctionsDir } from \"./functions-dir\";\nexport { resolveFunctionsDir, functionsDirNotFoundMessage, DEFAULT_FUNCTIONS_DIR } from \"./functions-dir\";\nexport { runCli, devCommand, codegenCommand } from \"./cli\";\n\n// The shared boot core + codegen writer, re-exported so an out-of-CLI host (e.g. `@helipod/vite`'s\n// in-process embed mode) can boot the engine and write `_generated` through the package boundary\n// rather than reaching into deep source paths. All already-existing internals — purely additive.\nexport { bootProject, withStorageModules } from \"./boot\";\nexport type { BootResult, BootProjectOptions, BootLoadedOptions } from \"./boot\";\nexport { writeGenerated } from \"@helipod/codegen\";\n\nexport { runBinaryServer, startBinaryServer, resolveBinaryOptions } from \"./binary-main\";\n","/**\n * The runtime entry a `helipod build` binary calls. It is compiled `serve`: boot an already-loaded\n * project (static imports, not a dir scan), start the shared server, print a machine-readable ready\n * line, and shut down gracefully. `startBinaryServer` is the testable core (no signals/exit).\n */\nimport { join } from \"node:path\";\nimport type { ComponentDefinition } from \"@helipod/component\";\nimport type { EmbeddedRuntime } from \"@helipod/runtime-embedded\";\nimport type { DocStore } from \"@helipod/docstore\";\nimport type { LoadedProject } from \"./project\";\nimport { bootLoaded } from \"./boot\";\nimport { ProcessRuntimeHost, type DevServer } from \"./server\";\n\nexport interface BinaryOptions {\n port: number;\n ip: string;\n dataDir: string;\n adminKey: string;\n /** Postgres connection string (flag wins over `HELIPOD_DATABASE_URL`); unset → SQLite. */\n databaseUrl?: string;\n}\n\n/** The materialized embedded dashboard: key-injected HTML plus the urlPath→embedded-path asset map. */\nexport interface EmbeddedDashboard { html: string; assets: Record<string, string> }\n\n/** Minimal structural surface of `Bun.file(path)`, reached only inside a compiled binary. */\ninterface BunFileLike {\n text(): Promise<string>;\n}\ninterface BunFileRuntime {\n file(path: string): BunFileLike;\n}\n\nexport function resolveBinaryOptions(argv: string[], env: Record<string, string | undefined>): BinaryOptions {\n let port = env.PORT ? Number(env.PORT) : 3000;\n let ip = \"0.0.0.0\";\n let dataDir = \"./data\";\n let databaseUrl = env.HELIPOD_DATABASE_URL;\n const adminKey = (env.HELIPOD_ADMIN_KEY ?? \"\").trim();\n for (let i = 0; i < argv.length; i++) {\n const a = argv[i];\n if (a === \"--port\" && argv[i + 1] !== undefined) port = Number(argv[++i]);\n else if (a === \"--hostname\" && argv[i + 1] !== undefined) ip = argv[++i] as string;\n else if (a === \"--data-dir\" && argv[i + 1] !== undefined) dataDir = argv[++i] as string;\n else if (a === \"--database-url\" && argv[i + 1] !== undefined) databaseUrl = argv[++i] as string;\n }\n return { port, ip, dataDir, adminKey, databaseUrl };\n}\n\nexport async function startBinaryServer(\n loaded: LoadedProject,\n components: ComponentDefinition[],\n opts: BinaryOptions,\n dashboard?: Record<string, string>,\n): Promise<{ server: DevServer; store: DocStore; runtime: EmbeddedRuntime }> {\n const boot = await bootLoaded({\n loaded,\n components,\n dataPath: join(opts.dataDir, \"db.sqlite\"),\n adminKey: opts.adminKey,\n databaseUrl: opts.databaseUrl,\n });\n let dash: EmbeddedDashboard | undefined;\n if (dashboard) {\n const bun = (globalThis as { Bun?: BunFileRuntime }).Bun;\n if (!bun) throw new Error(\"Bun runtime not available to read the embedded dashboard\");\n const indexPath = dashboard[\"/\"];\n if (!indexPath) throw new Error(\"embedded dashboard map is missing its \\\"/\\\" (index.html) entry\");\n const html = await bun.file(indexPath).text();\n dash = { html, assets: dashboard };\n }\n const server = await new ProcessRuntimeHost().serve(boot.runtime, {\n port: opts.port,\n ip: opts.ip,\n admin: { api: boot.adminApi, key: opts.adminKey },\n routes: boot.project.routes,\n storageRoutes: boot.storageRoutes,\n componentRoutes: boot.componentRoutes,\n dashboard: dash,\n });\n return { server, store: boot.store, runtime: boot.runtime };\n}\n\nexport async function runBinaryServer(\n loaded: LoadedProject,\n components: ComponentDefinition[],\n dashboard?: Record<string, string>,\n): Promise<void> {\n const opts = resolveBinaryOptions(process.argv.slice(2), process.env);\n if (!opts.adminKey) {\n process.stderr.write(\"✗ HELIPOD_ADMIN_KEY is required — set it to a strong secret.\\n\");\n process.exit(1);\n }\n const { server, store } = await startBinaryServer(loaded, components, opts, dashboard);\n process.stdout.write(JSON.stringify({ ready: true, port: opts.port, url: `http://${opts.ip}:${opts.port}` }) + \"\\n\");\n let closing = false;\n const shutdown = async (): Promise<void> => {\n if (closing) return;\n closing = true;\n await server.close();\n await store.close();\n process.exit(0);\n };\n process.on(\"SIGTERM\", () => void shutdown());\n process.on(\"SIGINT\", () => void shutdown());\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;AAkCA,SAAS,sBAAsB;;;AC7B/B,SAAS,YAAY;AA4Bd,SAAS,qBAAqB,MAAgB,KAAwD;AAC3G,MAAI,OAAO,IAAI,OAAO,OAAO,IAAI,IAAI,IAAI;AACzC,MAAI,KAAK;AACT,MAAI,UAAU;AACd,MAAI,cAAc,IAAI;AACtB,QAAM,YAAY,IAAI,qBAAqB,IAAI,KAAK;AACpD,WAAS,IAAI,GAAG,IAAI,KAAK,QAAQ,KAAK;AACpC,UAAM,IAAI,KAAK,CAAC;AAChB,QAAI,MAAM,YAAY,KAAK,IAAI,CAAC,MAAM,OAAW,QAAO,OAAO,KAAK,EAAE,CAAC,CAAC;AAAA,aAC/D,MAAM,gBAAgB,KAAK,IAAI,CAAC,MAAM,OAAW,MAAK,KAAK,EAAE,CAAC;AAAA,aAC9D,MAAM,gBAAgB,KAAK,IAAI,CAAC,MAAM,OAAW,WAAU,KAAK,EAAE,CAAC;AAAA,aACnE,MAAM,oBAAoB,KAAK,IAAI,CAAC,MAAM,OAAW,eAAc,KAAK,EAAE,CAAC;AAAA,EACtF;AACA,SAAO,EAAE,MAAM,IAAI,SAAS,UAAU,YAAY;AACpD;AAEA,eAAsB,kBACpB,QACA,YACA,MACA,WAC2E;AAC3E,QAAM,OAAO,MAAM,WAAW;AAAA,IAC5B;AAAA,IACA;AAAA,IACA,UAAU,KAAK,KAAK,SAAS,WAAW;AAAA,IACxC,UAAU,KAAK;AAAA,IACf,aAAa,KAAK;AAAA,EACpB,CAAC;AACD,MAAI;AACJ,MAAI,WAAW;AACb,UAAM,MAAO,WAAwC;AACrD,QAAI,CAAC,IAAK,OAAM,IAAI,MAAM,0DAA0D;AACpF,UAAM,YAAY,UAAU,GAAG;AAC/B,QAAI,CAAC,UAAW,OAAM,IAAI,MAAM,8DAAgE;AAChG,UAAM,OAAO,MAAM,IAAI,KAAK,SAAS,EAAE,KAAK;AAC5C,WAAO,EAAE,MAAM,QAAQ,UAAU;AAAA,EACnC;AACA,QAAM,SAAS,MAAM,IAAI,mBAAmB,EAAE,MAAM,KAAK,SAAS;AAAA,IAChE,MAAM,KAAK;AAAA,IACX,IAAI,KAAK;AAAA,IACT,OAAO,EAAE,KAAK,KAAK,UAAU,KAAK,KAAK,SAAS;AAAA,IAChD,QAAQ,KAAK,QAAQ;AAAA,IACrB,eAAe,KAAK;AAAA,IACpB,iBAAiB,KAAK;AAAA,IACtB,WAAW;AAAA,EACb,CAAC;AACD,SAAO,EAAE,QAAQ,OAAO,KAAK,OAAO,SAAS,KAAK,QAAQ;AAC5D;AAEA,eAAsB,gBACpB,QACA,YACA,WACe;AACf,QAAM,OAAO,qBAAqB,QAAQ,KAAK,MAAM,CAAC,GAAG,QAAQ,GAAG;AACpE,MAAI,CAAC,KAAK,UAAU;AAClB,YAAQ,OAAO,MAAM,0EAAgE;AACrF,YAAQ,KAAK,CAAC;AAAA,EAChB;AACA,QAAM,EAAE,QAAQ,MAAM,IAAI,MAAM,kBAAkB,QAAQ,YAAY,MAAM,SAAS;AACrF,UAAQ,OAAO,MAAM,KAAK,UAAU,EAAE,OAAO,MAAM,MAAM,KAAK,MAAM,KAAK,UAAU,KAAK,EAAE,IAAI,KAAK,IAAI,GAAG,CAAC,IAAI,IAAI;AACnH,MAAI,UAAU;AACd,QAAM,WAAW,YAA2B;AAC1C,QAAI,QAAS;AACb,cAAU;AACV,UAAM,OAAO,MAAM;AACnB,UAAM,MAAM,MAAM;AAClB,YAAQ,KAAK,CAAC;AAAA,EAChB;AACA,UAAQ,GAAG,WAAW,MAAM,KAAK,SAAS,CAAC;AAC3C,UAAQ,GAAG,UAAU,MAAM,KAAK,SAAS,CAAC;AAC5C;","names":[]}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import { SimpleIndexCatalog, RegisteredFunction, ContextProvider } from '@helipod/executor';
|
|
2
|
+
import { SchemaDefinition, SchemaDefinitionJSON } from '@helipod/values';
|
|
3
|
+
import { AnalyzedFunctionManifest } from '@helipod/codegen';
|
|
4
|
+
import { BootContext, Driver, ResolvedComponentRoute, ComponentDefinition } from '@helipod/component';
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Turn a loaded project (a live schema + function modules) into the artifacts the engine and
|
|
8
|
+
* codegen need: the schema JSON, an index catalog (with table numbers assigned + an implicit
|
|
9
|
+
* `by_creation` index per table), the `path:name → function` map, and the analyzed manifest.
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
declare const DEFAULT_INDEX = "by_creation";
|
|
13
|
+
interface LoadedProject {
|
|
14
|
+
schema: SchemaDefinition;
|
|
15
|
+
/** module path (without extension) → its exports (name → value). */
|
|
16
|
+
modules: Record<string, Record<string, unknown>>;
|
|
17
|
+
}
|
|
18
|
+
interface ProjectArtifacts {
|
|
19
|
+
schemaJson: SchemaDefinitionJSON;
|
|
20
|
+
catalog: SimpleIndexCatalog;
|
|
21
|
+
moduleMap: Record<string, RegisteredFunction>;
|
|
22
|
+
manifest: AnalyzedFunctionManifest;
|
|
23
|
+
tableNumbers: Record<string, number>;
|
|
24
|
+
componentNames: ReadonlySet<string>;
|
|
25
|
+
contextProviders: ContextProvider[];
|
|
26
|
+
/** Component boot steps (e.g. the scheduler's cron reconciler) — must run once at engine create. */
|
|
27
|
+
bootSteps: {
|
|
28
|
+
name: string;
|
|
29
|
+
run: (ctx: BootContext) => Promise<void>;
|
|
30
|
+
}[];
|
|
31
|
+
/**
|
|
32
|
+
* Component drivers (e.g. the scheduler's event loop) — must be started at engine create for a
|
|
33
|
+
* composed component's background work to actually run. Omitting this from
|
|
34
|
+
* `createEmbeddedRuntime(...)` silently leaves drivers never started (jobs enqueue but never
|
|
35
|
+
* dispatch) — see `../test/scheduler-e2e.test.ts` for the proof this wiring matters.
|
|
36
|
+
*/
|
|
37
|
+
drivers: Driver[];
|
|
38
|
+
/** The app's `http.ts` router, resolved to `path:name` function paths for dispatch. */
|
|
39
|
+
routes: ResolvedRoute[];
|
|
40
|
+
/** Reserved engine routes contributed by composed components (e.g. auth's `/api/auth/oauth/*`). */
|
|
41
|
+
componentRoutes: ResolvedComponentRoute[];
|
|
42
|
+
}
|
|
43
|
+
/** A single `http.ts` route, with its handler resolved from a `RegisteredFunction` value to the
|
|
44
|
+
* `path:name` string that `runtime.runHttpAction` looks up in `composed.moduleMap`. */
|
|
45
|
+
interface ResolvedRoute {
|
|
46
|
+
method: string;
|
|
47
|
+
path?: string;
|
|
48
|
+
pathPrefix?: string;
|
|
49
|
+
handlerPath: string;
|
|
50
|
+
}
|
|
51
|
+
declare function loadProject(loaded: LoadedProject, components?: ComponentDefinition[], existingTableNumbers?: Record<string, number>): ProjectArtifacts;
|
|
52
|
+
|
|
53
|
+
export { DEFAULT_INDEX, type LoadedProject, type ProjectArtifacts, type ResolvedRoute, loadProject };
|
package/dist/project.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":[],"sourcesContent":[],"mappings":"","names":[]}
|
package/package.json
ADDED
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@helipod/cli",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"type": "module",
|
|
5
|
+
"license": "FSL-1.1-Apache-2.0",
|
|
6
|
+
"bin": {
|
|
7
|
+
"helipod": "./dist/bin.js"
|
|
8
|
+
},
|
|
9
|
+
"main": "./dist/index.js",
|
|
10
|
+
"module": "./dist/index.js",
|
|
11
|
+
"types": "./dist/index.d.ts",
|
|
12
|
+
"exports": {
|
|
13
|
+
".": {
|
|
14
|
+
"types": "./dist/index.d.ts",
|
|
15
|
+
"default": "./dist/index.js"
|
|
16
|
+
},
|
|
17
|
+
"./http-handler": {
|
|
18
|
+
"types": "./dist/http-handler.d.ts",
|
|
19
|
+
"default": "./dist/http-handler.js"
|
|
20
|
+
},
|
|
21
|
+
"./project": {
|
|
22
|
+
"types": "./dist/project.d.ts",
|
|
23
|
+
"default": "./dist/project.js"
|
|
24
|
+
}
|
|
25
|
+
},
|
|
26
|
+
"files": [
|
|
27
|
+
"dist"
|
|
28
|
+
],
|
|
29
|
+
"scripts": {
|
|
30
|
+
"build": "tsup",
|
|
31
|
+
"test": "vitest run --exclude 'test/*-e2e.test.ts'",
|
|
32
|
+
"test:e2e": "vitest run test/*-e2e.test.ts",
|
|
33
|
+
"typecheck": "tsc --noEmit",
|
|
34
|
+
"clean": "rm -rf dist .turbo"
|
|
35
|
+
},
|
|
36
|
+
"dependencies": {
|
|
37
|
+
"@helipod/admin": "0.1.0",
|
|
38
|
+
"@helipod/blobstore": "0.1.0",
|
|
39
|
+
"@helipod/blobstore-fs": "0.1.0",
|
|
40
|
+
"@helipod/blobstore-s3": "0.1.0",
|
|
41
|
+
"@helipod/codegen": "0.1.0",
|
|
42
|
+
"@helipod/component": "0.1.0",
|
|
43
|
+
"@helipod/deploy": "0.1.0",
|
|
44
|
+
"@helipod/docstore": "0.1.0",
|
|
45
|
+
"@helipod/docstore-postgres": "0.1.0",
|
|
46
|
+
"@helipod/docstore-sqlite": "0.1.0",
|
|
47
|
+
"@helipod/errors": "0.1.0",
|
|
48
|
+
"@helipod/executor": "0.1.0",
|
|
49
|
+
"@helipod/id-codec": "0.1.0",
|
|
50
|
+
"@helipod/objectstore": "0.1.0",
|
|
51
|
+
"@helipod/objectstore-fs": "0.1.0",
|
|
52
|
+
"@helipod/objectstore-s3": "0.1.0",
|
|
53
|
+
"@helipod/query-engine": "0.1.0",
|
|
54
|
+
"@helipod/receipts": "0.1.0",
|
|
55
|
+
"@helipod/runtime-embedded": "0.1.0",
|
|
56
|
+
"@helipod/storage": "0.1.0",
|
|
57
|
+
"@helipod/sync": "0.1.0",
|
|
58
|
+
"@helipod/values": "0.1.0",
|
|
59
|
+
"esbuild": "^0.27.0",
|
|
60
|
+
"ws": "^8.18.0",
|
|
61
|
+
"@helipod/dashboard": "0.1.0"
|
|
62
|
+
},
|
|
63
|
+
"devDependencies": {
|
|
64
|
+
"@electric-sql/pglite": "^0.2.17",
|
|
65
|
+
"@levischuck/tiny-cbor": "0.2.11",
|
|
66
|
+
"@simplewebauthn/server": "13.3.2",
|
|
67
|
+
"@helipod/auth": "0.1.0",
|
|
68
|
+
"@helipod/client": "0.1.0",
|
|
69
|
+
"@helipod/fleet": "0.0.0",
|
|
70
|
+
"@helipod/notifications": "0.1.0",
|
|
71
|
+
"@helipod/objectstore-substrate": "0.0.0",
|
|
72
|
+
"@helipod/scheduler": "0.1.0",
|
|
73
|
+
"@helipod/triggers": "0.1.0",
|
|
74
|
+
"@helipod/workflow": "0.1.0",
|
|
75
|
+
"@types/node": "^22.10.5",
|
|
76
|
+
"@types/ws": "^8.5.13",
|
|
77
|
+
"fake-indexeddb": "^6.0.0",
|
|
78
|
+
"jose": "6.2.3",
|
|
79
|
+
"tsup": "^8.3.5",
|
|
80
|
+
"typescript": "^5.7.2",
|
|
81
|
+
"vitest": "^2.1.8"
|
|
82
|
+
},
|
|
83
|
+
"publishConfig": {
|
|
84
|
+
"access": "public"
|
|
85
|
+
},
|
|
86
|
+
"repository": {
|
|
87
|
+
"type": "git",
|
|
88
|
+
"url": "git+https://github.com/helipod-sh/helipod.git",
|
|
89
|
+
"directory": "packages/cli"
|
|
90
|
+
},
|
|
91
|
+
"homepage": "https://github.com/helipod-sh/helipod"
|
|
92
|
+
}
|