@supacloud/compiler 0.26.0 → 0.27.2

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/DELIVERY.md CHANGED
@@ -5,7 +5,8 @@ delivery. It uses the existing source analysis and compiler checks, then groups
5
5
  HTTP routes and declared Jobs into deterministic target previews.
6
6
 
7
7
  `supacloud-compiler build-delivery --json` additionally builds independent local
8
- module factory bundles. It does **not** configure queues or gateways, verify remote
8
+ module factory bundles, or runnable HTTP applications with explicitly configured
9
+ hosts. It does **not** configure queues or gateways, verify remote
9
10
  hosts, deploy functions, or run an unattended AI repair loop.
10
11
  Existing compile/check/dev output remains unchanged.
11
12
 
@@ -136,10 +137,10 @@ delivery/
136
137
  bundle/assets/...
137
138
  ```
138
139
 
139
- `bundle/index.js` exports `createCompiledModules`. Move the whole `bundle` directory,
140
+ By default, `bundle/index.js` exports `createCompiledModules`. Move the whole `bundle` directory,
140
141
  not just its entrypoint. The generated TypeScript is inspection output and still
141
142
  references application sources; the bundle does not require those source files.
142
- This is **not** a default HTTP handler or a ready-to-deploy Function. A compatible
143
+ This default is **not** an HTTP handler or a ready-to-deploy Function. A compatible
143
144
  host must supply HTTP composition, trusted identity, database/governance adapters,
144
145
  and durable Job execution. Route mappings are local metadata, not applied gateway
145
146
  configuration. All results continue to report `deploymentReady: false`.
@@ -165,8 +166,9 @@ traversal, duplicate destinations, and symlinks reject the build. Environment
165
166
  contracts are references, not secret values. Environment values are not inlined.
166
167
  Code doing runtime filesystem reads must use declared assets and the host's
167
168
  documented asset-location convention; automatic discovery is not provided.
168
- Computed `import()` and direct computed `require()` calls are rejected. This is
169
- not a sandbox for arbitrary JavaScript, eval, or filesystem access.
169
+ Unresolved computed `import()` and direct computed `require()` calls are rejected;
170
+ the literal-only import-helper exception is described below. This is not a sandbox
171
+ for arbitrary JavaScript, eval, or filesystem access.
170
172
 
171
173
  Each target includes its conservative module dependency closure, while route and
172
174
  Job descriptors remain exclusive to their owner. Provider pruning is disabled to
@@ -181,6 +183,15 @@ emit-path `rootDir` to the project directory. This does not replace application
181
183
  tests or full release checks. Refresh GraphQL artifacts through normal `compile`
182
184
  before building when GraphQL drift is reported.
183
185
 
186
+ Each target bundles in a fresh Bun subprocess rooted at the application project,
187
+ isolating dependency resolution from the caller's analysis process and working
188
+ directory. The compiler package includes the internal worker entrypoint; do not
189
+ copy only `dist/index.js` or `dist/cli.js`. A typed internal protocol returns the
190
+ artifact bytes and original input hashes. Failure, cancellation or the five-minute
191
+ per-target limit does not publish a new manifest. Cancellation reaps the worker;
192
+ the worker also watches its caller so an abruptly terminated caller does not leave
193
+ it running. These are build-process controls, not application deployment controls.
194
+
184
195
  `inputDigest` includes generated source, captured bundled inputs, compiler and Bun
185
196
  identity, configuration/lockfile hashes, target build options, explicit assets,
186
197
  and environment-contract reference. Shared dependency changes invalidate dependent
@@ -196,12 +207,170 @@ matching hashes are integrity checks, not authorization or authenticity proofs.
196
207
 
197
208
  An exclusive lock protects the owned output directory. Existing unowned output,
198
209
  invalid manifests, and modified immutable objects are rejected without overwrites.
199
- Only an atomic replacement of `delivery.manifest.json` activates a local build.
210
+ Only an atomic replacement of `delivery.manifest.json` publishes the selected local build.
200
211
  Failures preserve the previous active pointer; inactive objects can remain after
201
212
  an interrupted publication. Removed target objects are retained for inspection,
202
213
  not automatically garbage-collected. Inspect stale locks after confirming no
203
214
  writer is active; the builder never removes them automatically.
204
215
 
216
+ ## Runnable HTTP Applications
217
+
218
+ For an HTTP target, explicitly supply a trusted host composition module:
219
+
220
+ ```json
221
+ {
222
+ "version": 1,
223
+ "build": {
224
+ "httpApplications": [
225
+ { "target": "api", "source": "delivery-host.ts" }
226
+ ]
227
+ }
228
+ }
229
+ ```
230
+
231
+ `source` is a TypeScript file relative to the configured source root. It must
232
+ export `createDeliveryApplication(modules, lifecycle)` returning, synchronously
233
+ or asynchronously, `{ fetch(request): Response | Promise<Response>, close() }`.
234
+ The compiler type-checks this contract and bundles the host and its dependencies
235
+ together with that target's compiled modules. Duplicate hosts, unknown targets,
236
+ Job targets, missing files, symlinks and paths into generated output are rejected.
237
+
238
+ For a stateless, public HTTP application:
239
+
240
+ ```ts
241
+ import { createApplication, type CompiledModule } from "@supacloud/elysia";
242
+
243
+ export function createDeliveryApplication(
244
+ modules: CompiledModule[],
245
+ { signal }: { signal: AbortSignal },
246
+ ) {
247
+ signal.throwIfAborted();
248
+ const app = createApplication({ modules });
249
+ return {
250
+ fetch: (request: Request) => app.handle(request),
251
+ close() {},
252
+ };
253
+ }
254
+ ```
255
+
256
+ Business applications must additionally supply their real identity, database,
257
+ governance and other adapters here. No memory or anonymous-identity fallback is
258
+ added by the compiler. Pass the supplied modules through to the runtime; importing
259
+ another generated application or manually adding routes bypasses target ownership.
260
+ The host is trusted application code, not a sandbox, and build success cannot
261
+ prove that its exposed routes or security policy match the plan.
262
+
263
+ Move the **entire** `bundle` directory to the destination and run:
264
+
265
+ ```sh
266
+ HOST=127.0.0.1 PORT=3000 bun --no-env-file bundle/index.js
267
+ ```
268
+
269
+ HTTP objects have `entryKind: "bun-http-application"`; their entry is an executable
270
+ that starts the listener, not an import-only module factory. Targets without a
271
+ host keep `entryKind: "compiled-module-factory"`. All object kinds still report
272
+ `deploymentReady: false`: a local build neither activates a service nor verifies
273
+ its environment, migrations, health, credentials, isolation or recovery.
274
+ HTTP object identities bind their executable discriminator; existing factory
275
+ object hashes remain readable. Old compiler versions reject the new kind.
276
+
277
+ The listener defaults to loopback port 3000; `PORT=0` selects an ephemeral test
278
+ port. It emits a JSON `delivery-http-listening` event with its listener URL, not
279
+ a health or deployment receipt. Environment files are not loaded by the documented
280
+ command. Runtime environment values are not inlined into the bundle.
281
+
282
+ SIGINT/SIGTERM abort `lifecycle.signal`, including during initialization. A host
283
+ that allocates resources before returning must handle cancellation and clean up
284
+ before rejecting; top-level import side effects are outside this lifecycle.
285
+ On shutdown the listener drains requests, then closes the host once. Half of
286
+ `SHUTDOWN_TIMEOUT_MS` (default 10000, range 1-300000) is available for graceful
287
+ draining before force-closing connections. Forced drain is reported as failure,
288
+ even if host cleanup finishes. The full deadline bounds initialization cancellation
289
+ and host cleanup; expiry exits nonzero without claiming cleanup succeeded.
290
+ Startup, listener and shutdown failures use generic messages; the host remains
291
+ responsible for sanitizing its own logging and responses.
292
+
293
+ ## Runnable Workers
294
+
295
+ Job targets can explicitly bind a worker host:
296
+
297
+ ```json
298
+ {
299
+ "version": 1,
300
+ "runtime": {
301
+ "processIsolation": true,
302
+ "durableQueue": true,
303
+ "capabilities": []
304
+ },
305
+ "build": {
306
+ "workerApplications": [
307
+ { "target": "jobs", "source": "worker-host.ts" }
308
+ ]
309
+ }
310
+ }
311
+ ```
312
+
313
+ Runtime capabilities describe the selected infrastructure, not proof that it is
314
+ active or healthy. Only declare a durable queue after selecting and configuring
315
+ the actual queue adapter. The compiler does not create one.
316
+
317
+ The source must export `createDeliveryWorker(modules, lifecycle)` returning
318
+ `{ start(), close() }`, synchronously or asynchronously. Both methods may return
319
+ `void` or `Promise<void>`. The factory prepares the trusted host; `start` begins
320
+ polling; `close` stops new claims, awaits in-flight execution and settlement, and
321
+ releases owned resources. These responsibilities belong to the host, typically
322
+ using the existing `createWorker` API, not to a second compiler-owned queue loop.
323
+ Do not begin consuming work in the factory or a top-level import.
324
+
325
+ Hosts may additionally expose `failure: Promise<never>` for fatal background
326
+ errors consumed by their worker/transport layer. It must stay pending during
327
+ healthy operation and graceful shutdown, and reject when manual recovery or
328
+ process replacement is required. The entry observes it before invoking start,
329
+ performs bounded cleanup and exits nonzero without printing the rejection.
330
+ Unexpected fulfillment also fails the process. Rejecting this channel does not
331
+ settle queue messages: the transport still owns receipt/recovery semantics.
332
+
333
+ The compiler type-checks the host against the target's compiled modules. Worker
334
+ hosts require Job targets; HTTP hosts require HTTP targets. Duplicate bindings,
335
+ invalid source paths, symlinks and generated-output sources fail without replacing
336
+ the previous local manifest. Worker objects bind
337
+ `entryKind: "bun-worker-application"` into their immutable identity and can run
338
+ with `bun --no-env-file bundle/index.js`. Existing factory and HTTP object hash
339
+ formats remain readable; older compilers cannot read the new worker kind.
340
+
341
+ The executable emits `{"event":"delivery-worker-started"}` only after `start`
342
+ resolves. This is neither a queue-health receipt nor activation attestation.
343
+ The process stays alive until shutdown even when the host has no active timers.
344
+ SIGINT/SIGTERM abort `lifecycle.signal`, including during factory/start execution.
345
+ If cancellation happens before `start`, polling is not started. Once the factory
346
+ returns, cancellation calls `close` exactly once, even while `start` is pending.
347
+ The host must support that overlap, stop pending acquisition/polling and await
348
+ its own in-flight work. A successful exit waits for both start and close to settle;
349
+ an unresponsive start still times out even if close has returned. Factories must
350
+ handle cancellation and clean up their resources before rejecting.
351
+ Runtime side effects in imports remain outside this contract.
352
+
353
+ `SHUTDOWN_TIMEOUT_MS` has the same default and range as the HTTP entry. Its deadline
354
+ bounds cancellation and cleanup; expiry exits nonzero, not successful recovery.
355
+ Startup failures attempt bounded cleanup before exiting nonzero. Uncaught host
356
+ exceptions and unhandled promise rejections, including abort-listener failures,
357
+ trigger failed shutdown without printing their contents. The entry yields once
358
+ after cleanup to observe queued abort errors before reporting graceful exit.
359
+ Host-owned logging/error handlers and errors already consumed by a worker
360
+ observer still require their own sanitization and supervision policy.
361
+
362
+ Detached compiler tests and packed starter smoke verify compiled Job execution,
363
+ receipt handling and shutdown using a deterministic test transport. They do not
364
+ prove a durable queue, production credentials, business replay, migrations,
365
+ activation, rollback or data recovery. `deploymentReady` remains `false`.
366
+
367
+ The bundler expands private, single-return import helpers only if every reference
368
+ is a direct call with one literal module specifier. Exported/escaped helpers,
369
+ nonliteral arguments and other computed loads remain rejected. Original source
370
+ bytes stay in the input snapshot. Emitted imports are checked separately from
371
+ input metadata because Bun can mark eliminated re-exports or optional missing
372
+ dependencies as external.
373
+
205
374
  ## Planning Evidence And Limits
206
375
 
207
376
  - Every result has `written: []`. A failure has `ok: false` and `plan: null`.
@@ -221,3 +390,94 @@ writer is active; the builder never removes them automatically.
221
390
  - This version does not reconcile old deployment topology, validate all possible
222
391
  router-specific pattern overlaps, or attest queue adapters. Deployment remains
223
392
  a separate, explicitly authorized step.
393
+
394
+ ## Build-Associated Execution Context
395
+
396
+ New build objects contain `bundle/execution-context.json`, a target-projected,
397
+ sanitized execution snapshot included in their immutable file inventory.
398
+ `context <subject> --delivery-manifest <saved-manifest> --delivery-target <target>
399
+ --events <metadata> --request-id <id> --json` verifies the selected object's
400
+ inventory and correlates observations to that snapshot without loading current
401
+ project configuration or source. The observation envelope must identify the
402
+ same `delivery: { target, objectId }`.
403
+
404
+ Archive the matching manifest alongside its `objects` directory. A mismatched
405
+ identity, missing snapshot, changed file, extra file or symlink fails closed;
406
+ there is no fallback to the current graph. The reader is bounded to 1 MiB JSON,
407
+ 1,024 artifact files, 64 MiB per file and 128 MiB total, with the existing 32 KiB
408
+ context output limit.
409
+
410
+ `artifactVerified: true` establishes local content consistency only. The selected
411
+ manifest and caller-supplied event identity are not authenticated runtime
412
+ attestations; `eventsTrusted` and `deploymentVerified` stay false. Hosts still own
413
+ metadata collection, naming, retention and access control. See
414
+ `docs/execution-context.md` for the envelope and interpretation boundaries.
415
+
416
+ ## Migration Artifact Identity
417
+
418
+ `readDeliveryMigrationArchive(manifestPath, target)` loads a target without source
419
+ checkout. It verifies the entire immutable inventory and hashed target metadata,
420
+ then validates the bounded migration manifest, executor-specific paths and exact
421
+ SQL bytes. Its return value includes SQL for trusted tooling; do not log or expose
422
+ it as an AI context response. An archive without declared migrations returns an
423
+ empty list, not a claim that the application requires no database provisioning.
424
+ Artifact integrity does not attest who built it or where it is deployed.
425
+
426
+ The CLI's `database delivery_migration_plan` uses this reader with the dedicated
427
+ read-only Management API inventory endpoint. It prints identity checks rather
428
+ than SQL, never executes migrations, and keeps operator provisioning separate.
429
+
430
+ `delivery.build.migrations` explicitly declares application SQL inputs. Sources
431
+ are relative to the application project containing `tsconfig.json`, unlike host
432
+ and asset sources which are relative to the configured source root:
433
+
434
+ ```json
435
+ {
436
+ "version": 1,
437
+ "build": {
438
+ "migrations": [
439
+ {
440
+ "source": "migrations/001-review.sql",
441
+ "version": "1",
442
+ "name": "review",
443
+ "executor": "project-migration"
444
+ },
445
+ {
446
+ "source": "migrations/004-review-runtime-roles.sql",
447
+ "version": "4",
448
+ "name": "review_runtime_roles",
449
+ "executor": "operator-provisioning"
450
+ }
451
+ ]
452
+ }
453
+ }
454
+ ```
455
+
456
+ All targets in this project contract carry the same selected application
457
+ migrations. A migration byte, version, name or executor change invalidates their
458
+ immutable identity even when executable bytes do not change. The build does not
459
+ scan migration directories or silently include undeclared SQL.
460
+
461
+ Inputs require unique canonical positive signed-64-bit versions, unique sources,
462
+ portable names and an explicit executor declaration. SQL sources must be regular,
463
+ non-symlinked UTF-8 files inside the project, outside generated output and
464
+ dependency directories. Limits are 128 declarations, 1 MiB per file and 16 MiB
465
+ total. Blank or invalid UTF-8 inputs fail without switching the previous build.
466
+ The SQL is archived verbatim, including line endings; no parser rewrites it.
467
+
468
+ Each object includes `bundle/migrations.json` and files under
469
+ `bundle/migrations/project-migration/` or
470
+ `bundle/migrations/operator-provisioning/`, named `<version>_<name>.sql`.
471
+ The inventory records raw-byte SHA-256 and size, plus `compatibility: "not-proven"`,
472
+ `executionPerformed: false` and `dataRecovery: "separate-required"`.
473
+ The execution flag describes the build operation, not whether a target database
474
+ has already applied any migration; that requires a selected environment's ledger.
475
+
476
+ These hashes are not the canonical platform ledger checksum of normalized
477
+ version/name/statements. Do not compare them as if they were the same identity.
478
+ Reconciliation, risk review, authorization and execution remain owned by the
479
+ existing platform migration APIs. The executor field declares intended handling;
480
+ it cannot bypass platform SQL policy or grant database privileges. Platform
481
+ runtime prerequisites are separately managed, not implicitly bundled.
482
+ Building an archive is not evidence of backward compatibility, applied migrations,
483
+ successful activation, application rollback or recovered data.