@objectstack/runtime 4.0.5 → 4.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.d.cts CHANGED
@@ -2,10 +2,12 @@ import { ObjectKernel, IHttpServer, ObjectKernelConfig, Plugin, PluginContext, R
2
2
  export * from '@objectstack/core';
3
3
  export { ObjectKernel } from '@objectstack/core';
4
4
  import { z } from 'zod';
5
+ import * as Contracts from '@objectstack/spec/contracts';
5
6
  import { ISeedLoaderService, IDataEngine, IMetadataService } from '@objectstack/spec/contracts';
6
7
  import { SeedLoaderRequest, SeedLoaderResult, ObjectDependencyGraph, Dataset, SeedLoaderConfigInput, ExpressionBody, ScriptBody, HookBody, Hook } from '@objectstack/spec/data';
7
8
  import { ExecutionContext } from '@objectstack/spec/kernel';
8
9
  import { MiddlewareConfig, MiddlewareType } from '@objectstack/spec/system';
10
+ import { ProjectArtifact } from '@objectstack/spec/cloud';
9
11
  export { RestApiPluginConfig, RestServer, RouteEntry, RouteGroupBuilder, RouteManager, createRestApiPlugin } from '@objectstack/rest';
10
12
 
11
13
  interface RuntimeConfig {
@@ -73,9 +75,55 @@ interface StandaloneStackResult {
73
75
  enableProjectScoping: false;
74
76
  projectResolution: 'none';
75
77
  };
78
+ /**
79
+ * Top-level metadata copied from the loaded artifact bundle (when an
80
+ * artifact was successfully loaded). These are surfaced so callers
81
+ * that wrap this result as a `defineStack()`-shaped config (e.g. the
82
+ * CLI's `serve` command without a host `objectstack.config.ts`) can
83
+ * still drive tier resolution, capability detection and driver
84
+ * auto-registration off the artifact's declarations.
85
+ */
86
+ requires?: string[];
87
+ objects?: any[];
88
+ manifest?: any;
76
89
  }
77
90
  declare function createStandaloneStack(config?: StandaloneStackConfig): Promise<StandaloneStackResult>;
78
91
 
92
+ interface DefaultHostConfigOptions extends StandaloneStackConfig {
93
+ /**
94
+ * When true (the default), throws if no artifact source can be
95
+ * resolved (no explicit `artifactPath`, no `OS_ARTIFACT_PATH` env,
96
+ * and `<cwd>/dist/objectstack.json` does not exist).
97
+ *
98
+ * Set to false to allow booting an empty kernel — useful for tests
99
+ * that want to assemble plugins manually after the stack is built.
100
+ */
101
+ requireArtifact?: boolean;
102
+ }
103
+ type DefaultHostConfigResult = StandaloneStackResult;
104
+ /**
105
+ * Resolve the artifact source for a default-host boot.
106
+ *
107
+ * Returns the explicit override, then `OS_ARTIFACT_PATH`, then the
108
+ * canonical `<cwd>/dist/objectstack.json` if it exists on disk.
109
+ * Returns `undefined` if none of these are available.
110
+ *
111
+ * URLs (`http(s)://`) are returned as-is — they are validated lazily by
112
+ * the loader, since we cannot stat a remote resource cheaply.
113
+ */
114
+ declare function resolveDefaultArtifactPath(explicitPath?: string, cwd?: string): string | undefined;
115
+ /**
116
+ * Build a `defineStack()`-shaped config from an `objectstack build`
117
+ * artifact, with no `objectstack.config.ts` required.
118
+ *
119
+ * @example
120
+ * // packages/cli/src/commands/serve.ts
121
+ * if (!fs.existsSync(absolutePath)) {
122
+ * config = await createDefaultHostConfig();
123
+ * }
124
+ */
125
+ declare function createDefaultHostConfig(options?: DefaultHostConfigOptions): Promise<DefaultHostConfigResult>;
126
+
79
127
  /**
80
128
  * Driver Plugin
81
129
  *
@@ -247,6 +295,337 @@ declare class SeedLoaderService implements ISeedLoaderService {
247
295
  private buildResult;
248
296
  }
249
297
 
298
+ /**
299
+ * Security response headers builder.
300
+ *
301
+ * Returns the conservative defaults every production API server should
302
+ * send on every response. Designed to be merged with route-specific
303
+ * headers by the dispatcher (`sendResult`) so all adapters (Hono,
304
+ * Fastify, Express, Next.js, …) get them uniformly without each one
305
+ * re-implementing helmet.
306
+ *
307
+ * What we DO opinionate:
308
+ * - Content-Security-Policy (api-default: deny everything but self)
309
+ * - Strict-Transport-Security (HSTS, prod-only — TLS is the caller's
310
+ * responsibility; we just emit the header)
311
+ * - X-Content-Type-Options: nosniff
312
+ * - X-Frame-Options: DENY (anti clickjacking)
313
+ * - Referrer-Policy: no-referrer
314
+ * - Permissions-Policy: geolocation=(), camera=(), microphone=()
315
+ * - Cross-Origin-Resource-Policy: same-origin
316
+ *
317
+ * What we DON'T opinionate:
318
+ * - X-XSS-Protection (deprecated)
319
+ * - CORS — that's an app concern, configure separately
320
+ * - CSP for HTML pages — set a different CSP at the SPA host
321
+ *
322
+ * Every header can be overridden or disabled by config.
323
+ */
324
+ interface SecurityHeadersOptions {
325
+ /**
326
+ * Enable HSTS. Set to `true` in production behind TLS. When `false`
327
+ * the Strict-Transport-Security header is omitted.
328
+ * @default false
329
+ */
330
+ hsts?: boolean | {
331
+ /** Max-age in seconds. @default 15552000 (180 days) */
332
+ maxAge?: number;
333
+ includeSubDomains?: boolean;
334
+ preload?: boolean;
335
+ };
336
+ /**
337
+ * Override the Content-Security-Policy header. Pass `false` to omit.
338
+ * @default "default-src 'none'; frame-ancestors 'none'"
339
+ */
340
+ contentSecurityPolicy?: string | false;
341
+ /**
342
+ * Override X-Frame-Options. @default 'DENY'
343
+ */
344
+ frameOptions?: 'DENY' | 'SAMEORIGIN' | false;
345
+ /**
346
+ * Override Referrer-Policy. @default 'no-referrer'
347
+ */
348
+ referrerPolicy?: string | false;
349
+ /**
350
+ * Override Permissions-Policy. Pass `false` to omit.
351
+ * @default 'geolocation=(), camera=(), microphone=(), payment=()'
352
+ */
353
+ permissionsPolicy?: string | false;
354
+ /**
355
+ * Override Cross-Origin-Resource-Policy. @default 'same-origin'
356
+ */
357
+ corp?: 'same-origin' | 'same-site' | 'cross-origin' | false;
358
+ /**
359
+ * Free-form extra headers merged last.
360
+ */
361
+ extra?: Record<string, string>;
362
+ }
363
+ /**
364
+ * Build a header map ready to be `Object.assign`'d into a response.
365
+ * Idempotent and synchronous — safe to call per-request.
366
+ */
367
+ declare function buildSecurityHeaders(opts?: SecurityHeadersOptions): Record<string, string>;
368
+
369
+ /**
370
+ * In-memory token-bucket rate limiter.
371
+ *
372
+ * Designed to be adapter-agnostic — the dispatcher calls `consume(key)`
373
+ * with a request fingerprint (IP, IP+route bucket, or user id) and
374
+ * short-circuits with 429 if the bucket is empty.
375
+ *
376
+ * For production multi-instance deploys, swap the in-memory store via
377
+ * `RateLimitStore`. The shape is intentionally narrow so a Redis-backed
378
+ * implementation is straightforward.
379
+ */
380
+ interface RateLimitDecision {
381
+ allowed: boolean;
382
+ /** Remaining tokens in the bucket after this consume. */
383
+ remaining: number;
384
+ /** Wall-clock ms until next token is available (when not allowed). */
385
+ retryAfterMs: number;
386
+ /** UNIX ms when the limit window resets. */
387
+ resetAt: number;
388
+ }
389
+ interface RateLimitBucketConfig {
390
+ /** Max tokens (bucket capacity). */
391
+ capacity: number;
392
+ /** Tokens added per second. */
393
+ refillPerSec: number;
394
+ /** Optional cost override for the consume operation. @default 1 */
395
+ defaultCost?: number;
396
+ }
397
+ interface BucketState {
398
+ tokens: number;
399
+ /** Last refill timestamp (ms). */
400
+ lastRefill: number;
401
+ }
402
+ /**
403
+ * Storage interface — swap for Redis/Memcached in clustered deploys.
404
+ * Implementations MUST be safe under concurrent access.
405
+ */
406
+ interface RateLimitStore {
407
+ get(key: string): BucketState | undefined;
408
+ set(key: string, state: BucketState): void;
409
+ /** Cleanup hint — implementations may evict idle entries. */
410
+ prune?(olderThanMs: number): void;
411
+ }
412
+ declare class RateLimiter {
413
+ private config;
414
+ private store;
415
+ private now;
416
+ constructor(config: RateLimitBucketConfig, opts?: {
417
+ store?: RateLimitStore;
418
+ now?: () => number;
419
+ });
420
+ /**
421
+ * Attempt to consume `cost` tokens for `key`. Returns a decision
422
+ * describing whether the request should proceed and, if not, how
423
+ * long the caller should wait before retrying.
424
+ */
425
+ consume(key: string, cost?: number): RateLimitDecision;
426
+ /** Force-reset a key (e.g. after a successful auth flow). */
427
+ reset(key: string): void;
428
+ }
429
+ /**
430
+ * Curated default buckets for the three traffic classes ObjectStack
431
+ * dispatches. Conservative — tune via `DispatcherPluginConfig.rateLimit`
432
+ * for your deployment.
433
+ *
434
+ * - auth: 10 req / minute / IP — guards /auth/* against credential
435
+ * stuffing and password-spray.
436
+ * - write: 60 req / minute / IP — POST/PUT/PATCH/DELETE.
437
+ * - read: 600 req / minute / IP — GET, including discovery and
438
+ * metadata.
439
+ *
440
+ * "Per-IP" is just the suggested key shape; the dispatcher constructs
441
+ * the key from `${ip}:${bucket}` so a single noisy IP can saturate
442
+ * one bucket without blocking the others.
443
+ */
444
+ interface RateLimitDefaults {
445
+ auth: RateLimitBucketConfig;
446
+ write: RateLimitBucketConfig;
447
+ read: RateLimitBucketConfig;
448
+ }
449
+ declare const DEFAULT_RATE_LIMITS: RateLimitDefaults;
450
+
451
+ /**
452
+ * Extract a request id from incoming headers, validating shape. If
453
+ * the header is missing or malformed, returns `undefined` and the
454
+ * caller should mint one via {@link generateRequestId}.
455
+ *
456
+ * Header lookup is case-insensitive — adapters normalize differently.
457
+ */
458
+ declare function extractRequestId(headers: unknown): string | undefined;
459
+ /**
460
+ * Mint a fresh request id. Uses `crypto.randomUUID()` when available
461
+ * (Node 16+, modern browsers, edge runtimes); falls back to a
462
+ * timestamp+random suffix otherwise so the function is universally
463
+ * callable.
464
+ *
465
+ * Format is `req_<hex>`; the prefix makes it obvious in logs that the
466
+ * id was minted by this layer (vs. propagated from a client).
467
+ */
468
+ declare function generateRequestId(): string;
469
+ /**
470
+ * Return the incoming request id if valid, otherwise mint one.
471
+ */
472
+ declare function resolveRequestId(headers: unknown, generate?: () => string): string;
473
+ /**
474
+ * Parsed W3C Trace Context. `sampled` reflects the lowest flag bit.
475
+ */
476
+ interface TraceContext {
477
+ traceId: string;
478
+ spanId: string;
479
+ sampled: boolean;
480
+ }
481
+ /**
482
+ * Parse a `traceparent` header value into its W3C fields. Returns
483
+ * `undefined` for malformed input, the all-zero trace/span ids
484
+ * (spec-mandated invalid), or unknown versions.
485
+ */
486
+ declare function parseTraceparent(value: unknown): TraceContext | undefined;
487
+ /**
488
+ * Build the response header equivalent so downstream services
489
+ * continue the trace.
490
+ */
491
+ declare function formatTraceparent(ctx: TraceContext): string;
492
+
493
+ /**
494
+ * Metrics registry contract.
495
+ *
496
+ * The runtime emits metrics via this interface so the host application
497
+ * can plug in whatever metrics backend it wants (Prometheus via
498
+ * `prom-client`, OTel via `@opentelemetry/api-metrics`, StatsD,
499
+ * CloudWatch, etc.) without the framework taking a hard dep on any of
500
+ * them.
501
+ *
502
+ * Naming follows Prometheus conventions:
503
+ * - snake_case names
504
+ * - unit suffix (`_ms`, `_seconds`, `_bytes`, `_total` for counters)
505
+ *
506
+ * Labels are arbitrary string maps; backends should map them to their
507
+ * native label/tag concept. Keep cardinality low — never label by raw
508
+ * url path or user id.
509
+ *
510
+ * All methods are fire-and-forget; implementations MUST NOT throw on
511
+ * the hot path. Use {@link NoopMetricsRegistry} when metrics are
512
+ * disabled.
513
+ */
514
+ interface MetricsRegistry {
515
+ /** Monotonic counter. `value` defaults to 1. */
516
+ counter(name: string, labels?: Record<string, string>, value?: number): void;
517
+ /** Histogram / timing in arbitrary units (typically ms). */
518
+ histogram(name: string, value: number, labels?: Record<string, string>): void;
519
+ /** Point-in-time gauge. */
520
+ gauge(name: string, value: number, labels?: Record<string, string>): void;
521
+ }
522
+ /**
523
+ * No-op metrics registry — the default. Discards every observation.
524
+ * Production deployments should swap this for a real registry; tests
525
+ * can use {@link InMemoryMetricsRegistry} to assert emissions.
526
+ */
527
+ declare class NoopMetricsRegistry implements MetricsRegistry {
528
+ counter(): void;
529
+ histogram(): void;
530
+ gauge(): void;
531
+ }
532
+ /** Recorded metric sample (in-memory registry). */
533
+ interface MetricSample {
534
+ name: string;
535
+ kind: 'counter' | 'histogram' | 'gauge';
536
+ value: number;
537
+ labels: Record<string, string>;
538
+ /** Wall-clock timestamp; useful for ordering assertions in tests. */
539
+ at: number;
540
+ }
541
+ /**
542
+ * In-memory registry used for tests and local inspection. Stores
543
+ * every observation in insertion order; query via the helpers below
544
+ * or read {@link samples} directly.
545
+ *
546
+ * Not intended for production — unbounded growth.
547
+ */
548
+ declare class InMemoryMetricsRegistry implements MetricsRegistry {
549
+ readonly samples: MetricSample[];
550
+ counter(name: string, labels?: Record<string, string>, value?: number): void;
551
+ histogram(name: string, value: number, labels?: Record<string, string>): void;
552
+ gauge(name: string, value: number, labels?: Record<string, string>): void;
553
+ /**
554
+ * Sum of all counter increments matching `name` (and optionally a
555
+ * label subset). Useful in tests: `metrics.totalCounter('http_requests_total', { status: '500' })`.
556
+ */
557
+ totalCounter(name: string, labelMatch?: Record<string, string>): number;
558
+ /**
559
+ * All histogram observations matching `name` (and optionally a
560
+ * label subset), as raw values.
561
+ */
562
+ histogramValues(name: string, labelMatch?: Record<string, string>): number[];
563
+ /** Clear all recorded samples. */
564
+ reset(): void;
565
+ }
566
+ /**
567
+ * Canonical metric names emitted by the runtime. Hosts may rely on
568
+ * these (e.g., to wire alerts) so they are listed here for reference
569
+ * rather than being string literals scattered through call sites.
570
+ */
571
+ declare const RUNTIME_METRICS: {
572
+ /** Counter, labels: method, route, status. */
573
+ readonly httpRequestsTotal: "http_requests_total";
574
+ /** Histogram (ms), labels: method, route. */
575
+ readonly httpRequestDurationMs: "http_request_duration_ms";
576
+ /** Counter, labels: method, route. Incremented when an in-flight handler throws (after the response is sent). */
577
+ readonly httpRequestErrorsTotal: "http_request_errors_total";
578
+ };
579
+
580
+ /**
581
+ * Error reporter contract.
582
+ *
583
+ * Production deployments wire this to Sentry, Datadog APM, Rollbar,
584
+ * etc. The runtime calls {@link ErrorReporter.captureException} when a
585
+ * route handler results in a 5xx response so the host's APM gets the
586
+ * stack trace without each plugin/route needing to import the SDK.
587
+ *
588
+ * Implementations MUST NOT throw — error reporting failures should be
589
+ * swallowed (or at most logged) so the original error reaches the
590
+ * client unmolested.
591
+ *
592
+ * 4xx responses are intentionally NOT captured here. Client errors
593
+ * (validation failures, auth, not-found) flood APM systems with noise
594
+ * and obscure real bugs. If a deployment wants to track them, do it
595
+ * via the metrics counter (`http_requests_total{status="4xx"}`),
596
+ * not error reporting.
597
+ */
598
+ interface ErrorReporter {
599
+ /**
600
+ * Capture a thrown error with optional context. Context typically
601
+ * includes `requestId`, `method`, `route`, `userId`, `orgId`.
602
+ *
603
+ * The reporter is responsible for redacting sensitive fields from
604
+ * `context` (the runtime does not know what is sensitive in the
605
+ * caller's deployment).
606
+ */
607
+ captureException(error: unknown, context?: Record<string, unknown>): void;
608
+ }
609
+ /** No-op reporter — the default. */
610
+ declare class NoopErrorReporter implements ErrorReporter {
611
+ captureException(): void;
612
+ }
613
+ /** Recorded report (in-memory reporter). */
614
+ interface CapturedError {
615
+ error: unknown;
616
+ context: Record<string, unknown>;
617
+ at: number;
618
+ }
619
+ /**
620
+ * In-memory reporter used in tests to assert that error capture was
621
+ * (or was not) invoked for a given request.
622
+ */
623
+ declare class InMemoryErrorReporter implements ErrorReporter {
624
+ readonly captured: CapturedError[];
625
+ captureException(error: unknown, context?: Record<string, unknown>): void;
626
+ reset(): void;
627
+ }
628
+
250
629
  interface DispatcherPluginConfig {
251
630
  /**
252
631
  * API path prefix for all endpoints.
@@ -278,6 +657,46 @@ interface DispatcherPluginConfig {
278
657
  * where membership has not been seeded.
279
658
  */
280
659
  enforceProjectMembership?: boolean;
660
+ /**
661
+ * Security response headers. When provided, every response routed
662
+ * through this plugin gets the headers merged in (route-specific
663
+ * headers still win on conflict).
664
+ *
665
+ * Pass `false` to disable. Pass `true` (or omit) to enable with
666
+ * conservative API-server defaults (CSP=deny-all, XCTO=nosniff,
667
+ * X-Frame-Options=DENY, etc.). Pass an object to customize — see
668
+ * {@link SecurityHeadersOptions}.
669
+ *
670
+ * @default true
671
+ */
672
+ securityHeaders?: boolean | SecurityHeadersOptions;
673
+ /**
674
+ * Observability wiring. All fields optional; defaults are noop
675
+ * (zero overhead, no behavior change).
676
+ *
677
+ * - `metrics`: registry receiving `http_requests_total`,
678
+ * `http_request_duration_ms`, `http_request_errors_total` for
679
+ * every route this plugin mounts. Plug in `prom-client` /
680
+ * `@opentelemetry/api-metrics` / your own adapter.
681
+ *
682
+ * - `errorReporter`: invoked on 5xx responses with the thrown
683
+ * error and `{ requestId, method, route }`. Plug in Sentry /
684
+ * Datadog / Rollbar.
685
+ *
686
+ * - `generateRequestId`: customize the format of minted request
687
+ * ids (default: `req_<uuid>` via `crypto.randomUUID`). The
688
+ * incoming `X-Request-Id` header is honored when present and
689
+ * well-formed, regardless of this setting.
690
+ *
691
+ * - `requestIdHeader`: response header name to echo the id back
692
+ * on. Defaults to `X-Request-Id`.
693
+ */
694
+ observability?: {
695
+ metrics?: MetricsRegistry;
696
+ errorReporter?: ErrorReporter;
697
+ generateRequestId?: () => string;
698
+ requestIdHeader?: string;
699
+ };
281
700
  }
282
701
  /**
283
702
  * Dispatcher Plugin
@@ -423,58 +842,6 @@ declare class HttpServer implements IHttpServer {
423
842
  getMiddlewares(): Middleware[];
424
843
  }
425
844
 
426
- /**
427
- * ProjectScopeManager
428
- *
429
- * Replaces KernelManager in shared-kernel mode. Instead of managing full
430
- * ObjectKernel instances per project, it manages TTL/LRU eviction of
431
- * SCOPED service instances inside a single shared kernel.
432
- *
433
- * The kernel's PluginLoader already stores scoped instances in:
434
- * scopedServices: Map<scopeId, Map<serviceName, instance>>
435
- *
436
- * This class tracks last-access timestamps and calls kernel.clearScope()
437
- * to release driver connections and metadata caches for idle projects.
438
- */
439
-
440
- interface ProjectScopeManagerConfig {
441
- /** Shared kernel whose scoped services this manager evicts. */
442
- kernel: ObjectKernel;
443
- /** Idle TTL in ms. Scopes not accessed within this window are evicted. Default: 15 min. */
444
- ttlMs?: number;
445
- /** Max number of active scopes. LRU eviction when exceeded. Default: 200. */
446
- maxSize?: number;
447
- /** Eviction check interval in ms. Default: 5 min. */
448
- checkIntervalMs?: number;
449
- }
450
- declare class ProjectScopeManager {
451
- private readonly kernel;
452
- private readonly ttlMs;
453
- private readonly maxSize;
454
- private readonly lastAccess;
455
- private timer?;
456
- constructor(config: ProjectScopeManagerConfig);
457
- /**
458
- * Touch a scope to reset its idle TTL. Call this on every request.
459
- */
460
- touch(scopeId: string): void;
461
- /**
462
- * Evict all scopes not accessed within ttlMs.
463
- */
464
- evictIdle(): void;
465
- /**
466
- * Evict a specific scope immediately.
467
- */
468
- evict(scopeId: string): void;
469
- /**
470
- * Evict all scopes (e.g. on shutdown).
471
- */
472
- evictAll(): void;
473
- destroy(): void;
474
- get activeCount(): number;
475
- private evictLRU;
476
- }
477
-
478
845
  /**
479
846
  * Factory contract for instantiating a per-project {@link ObjectKernel}.
480
847
  *
@@ -543,6 +910,10 @@ declare class KernelManager {
543
910
  private enforceMaxSize;
544
911
  }
545
912
 
913
+ /** Minimal local interface — full ProjectScopeManager was removed in Phase R. */
914
+ interface ProjectScopeManager {
915
+ touch(projectId: string): void;
916
+ }
546
917
  interface HttpProtocolContext {
547
918
  request: any;
548
919
  response?: any;
@@ -1037,6 +1408,12 @@ declare class HttpDispatcher {
1037
1408
  * Physical database addressing (database_url, database_driver, etc.)
1038
1409
  * is stored directly on the sys_project row.
1039
1410
  */
1411
+ /**
1412
+ * Resolve the calling user id from the request session, if any.
1413
+ * Returns `undefined` for anonymous calls or when auth is not wired up.
1414
+ */
1415
+ private resolveActiveOrganizationId;
1416
+ private resolveCallerUserId;
1040
1417
  handleCloud(path: string, method: string, body: any, query: any, _context: HttpProtocolContext): Promise<HttpDispatcherResult>;
1041
1418
  /**
1042
1419
  * Cascade-delete a project: cred / member / package_installation rows,
@@ -1254,6 +1631,506 @@ declare function readArtifactSource(pathOrUrl: string, opts?: {
1254
1631
  declare function loadArtifactBundle(absArtifactPath: string, opts?: LoadArtifactBundleOptions): Promise<any | null>;
1255
1632
  declare function mergeRuntimeModule(bundle: any, artifactAbsPath: string, tag?: string): Promise<void>;
1256
1633
 
1634
+ /**
1635
+ * Artifact API client.
1636
+ *
1637
+ * HTTP client that talks to the ObjectStack control plane (e.g.
1638
+ * `apps/cloud`) to resolve hostnames to projects and to download a
1639
+ * project's compiled artifact.
1640
+ *
1641
+ * The control plane is expected to expose two endpoints:
1642
+ *
1643
+ * GET {controlPlaneUrl}/api/v1/cloud/resolve-hostname?host={hostname}
1644
+ * → { projectId: string, organizationId?: string, runtime?: ProjectRuntimeConfig }
1645
+ *
1646
+ * GET {controlPlaneUrl}/api/v1/cloud/projects/:projectId/artifact
1647
+ * → ProjectArtifactResponse (ProjectArtifact + optional `runtime` block)
1648
+ *
1649
+ * Both endpoints accept an optional `Authorization: Bearer <apiKey>`.
1650
+ *
1651
+ * Responses are cached in-memory with a TTL so each kernel-manager
1652
+ * miss does not produce an extra HTTP round trip. Concurrent callers
1653
+ * for the same key share a single in-flight promise (singleflight).
1654
+ */
1655
+
1656
+ /**
1657
+ * Per-project runtime config injected by the control plane alongside
1658
+ * the artifact. Carries the physical database URL the runtime should
1659
+ * connect to (this is *not* part of the developer-authored compiled
1660
+ * artifact — the control plane mints it when serving the API).
1661
+ */
1662
+ interface ProjectRuntimeConfig {
1663
+ organizationId?: string;
1664
+ hostname?: string;
1665
+ /** Driver type — e.g. `sqlite`, `postgres`, `turso`, `memory`. */
1666
+ databaseDriver: string;
1667
+ /** Driver-specific connection URL. */
1668
+ databaseUrl: string;
1669
+ /** Optional auth token (e.g. for libSQL/Turso). */
1670
+ databaseAuthToken?: string;
1671
+ /**
1672
+ * Project-level metadata captured by the control plane at create time
1673
+ * (e.g. `ownerSeed`, `orgSeed`). Forwarded to the runtime so cold-boot
1674
+ * seed replay can mirror the cloud org + owner into the project DB
1675
+ * before the user's first SSO callback arrives.
1676
+ */
1677
+ metadata?: Record<string, unknown>;
1678
+ }
1679
+ /**
1680
+ * Hostname resolution response.
1681
+ */
1682
+ interface ResolvedHostname {
1683
+ projectId: string;
1684
+ organizationId?: string;
1685
+ /** Optional runtime config — when present, callers can skip the artifact fetch's runtime block. */
1686
+ runtime?: ProjectRuntimeConfig;
1687
+ }
1688
+ /**
1689
+ * Artifact response wrapping the spec's `ProjectArtifact` envelope plus
1690
+ * an optional `runtime` block carrying the project's database
1691
+ * connection details.
1692
+ */
1693
+ interface ProjectArtifactResponse extends ProjectArtifact {
1694
+ runtime?: ProjectRuntimeConfig;
1695
+ }
1696
+ interface ArtifactApiClientConfig {
1697
+ /** Control-plane base URL (no trailing slash). */
1698
+ controlPlaneUrl: string;
1699
+ /** Optional bearer token. */
1700
+ apiKey?: string;
1701
+ /** Cache TTL in ms. Default: 5 min. */
1702
+ cacheTtlMs?: number;
1703
+ /** Timeout for control-plane HTTP calls in ms. Default: 10s. */
1704
+ requestTimeoutMs?: number;
1705
+ /** Optional fetch override (testing). */
1706
+ fetch?: typeof fetch;
1707
+ /** Optional logger. */
1708
+ logger?: {
1709
+ info?: (...a: any[]) => void;
1710
+ warn?: (...a: any[]) => void;
1711
+ error?: (...a: any[]) => void;
1712
+ };
1713
+ }
1714
+ declare class ArtifactApiClient {
1715
+ private readonly base;
1716
+ private readonly apiKey?;
1717
+ private readonly cacheTtlMs;
1718
+ private readonly requestTimeoutMs;
1719
+ private readonly fetchImpl;
1720
+ private readonly logger;
1721
+ private readonly hostnameCache;
1722
+ private readonly artifactCache;
1723
+ private readonly pendingHostname;
1724
+ private readonly pendingArtifact;
1725
+ constructor(config: ArtifactApiClientConfig);
1726
+ /**
1727
+ * Resolve a hostname to its project. Returns `null` on 404 or
1728
+ * malformed responses. Errors (network / 5xx) are thrown so
1729
+ * upstream callers can retry.
1730
+ */
1731
+ resolveHostname(host: string): Promise<ResolvedHostname | null>;
1732
+ /**
1733
+ * Fetch the compiled artifact for a project.
1734
+ *
1735
+ * When `opts.commit` is set, requests that specific revision via the
1736
+ * existing `?commit=` query param. Different commits are cached
1737
+ * independently (the cache key includes the commit id) so the preview
1738
+ * runtime can hold multiple versions in memory simultaneously.
1739
+ */
1740
+ fetchArtifact(projectId: string, opts?: {
1741
+ commit?: string;
1742
+ }): Promise<ProjectArtifactResponse | null>;
1743
+ /**
1744
+ * Resolve an 8-hex project short id (first 8 hex chars of the UUID,
1745
+ * dashes stripped) to the full projectId. Used by the preview
1746
+ * runtime, which encodes project ids in subdomains.
1747
+ *
1748
+ * Returns `null` on 404 or ambiguity (the control plane returns 409
1749
+ * if the prefix matches more than one project).
1750
+ */
1751
+ lookupProjectByShortId(shortId: string): Promise<{
1752
+ projectId: string;
1753
+ organizationId?: string;
1754
+ } | null>;
1755
+ /**
1756
+ * Fetch the head commit of a branch. Returns the commit id (and the
1757
+ * matching revision row's `published_at` for cache-validity checks).
1758
+ * Reuses the existing `GET /cloud/projects/:id/branches` endpoint.
1759
+ */
1760
+ fetchBranchHead(projectId: string, branchName: string): Promise<{
1761
+ commitId: string;
1762
+ publishedAt?: string | null;
1763
+ } | null>;
1764
+ /** Drop cached entries for a project (and any matching hostname). */
1765
+ invalidate(projectId: string): void;
1766
+ /** Drop everything. Used on shutdown / hot-reload. */
1767
+ clear(): void;
1768
+ private request;
1769
+ private buildHeaders;
1770
+ }
1771
+
1772
+ interface FileArtifactApiClientConfig {
1773
+ /**
1774
+ * Path to a compiled artifact JSON file (`dist/objectstack.json`).
1775
+ * Resolved against `process.cwd()` when relative. Defaults to
1776
+ * `<cwd>/dist/objectstack.json`.
1777
+ */
1778
+ artifactPath?: string;
1779
+ /**
1780
+ * Project id every hostname maps to. Defaults to
1781
+ * `process.env.OS_PROJECT_ID` or `'proj_local'`.
1782
+ */
1783
+ projectId?: string;
1784
+ /**
1785
+ * Organization id surfaced alongside the project. Defaults to
1786
+ * `process.env.OS_ORGANIZATION_ID` or `'org_local'`.
1787
+ */
1788
+ organizationId?: string;
1789
+ /**
1790
+ * Override runtime config. When unset, the client tries to derive
1791
+ * one from the artifact's `datasources` array; if that fails it
1792
+ * falls back to a local-file SQLite DB at
1793
+ * `<cwd>/.objectstack/data/<projectId>.db`.
1794
+ */
1795
+ runtime?: ProjectRuntimeConfig;
1796
+ /**
1797
+ * Reload the artifact on every fetch instead of caching the first
1798
+ * read. Useful when iterating on a project's metadata without
1799
+ * restarting objectos. Defaults to `true` for dev ergonomics.
1800
+ */
1801
+ watch?: boolean;
1802
+ /** Optional logger. */
1803
+ logger?: {
1804
+ info?: (...a: any[]) => void;
1805
+ warn?: (...a: any[]) => void;
1806
+ error?: (...a: any[]) => void;
1807
+ };
1808
+ }
1809
+ declare class FileArtifactApiClient {
1810
+ private readonly artifactPath;
1811
+ private readonly projectId;
1812
+ private readonly organizationId;
1813
+ private readonly overrideRuntime?;
1814
+ private readonly watch;
1815
+ private readonly logger;
1816
+ private cached?;
1817
+ constructor(config?: FileArtifactApiClientConfig);
1818
+ resolveHostname(_host: string): Promise<ResolvedHostname | null>;
1819
+ fetchArtifact(_projectId: string, _opts?: {
1820
+ commit?: string;
1821
+ }): Promise<ProjectArtifactResponse | null>;
1822
+ lookupProjectByShortId(_shortId: string): Promise<{
1823
+ projectId: string;
1824
+ organizationId?: string;
1825
+ } | null>;
1826
+ fetchBranchHead(_projectId: string, _branchName: string): Promise<{
1827
+ commitId: string;
1828
+ publishedAt?: string | null;
1829
+ } | null>;
1830
+ invalidate(_projectId: string): void;
1831
+ clear(): void;
1832
+ private loadArtifact;
1833
+ private readRuntimeFromArtifact;
1834
+ private deriveRuntimeFromMetadata;
1835
+ private defaultLocalSqliteRuntime;
1836
+ }
1837
+
1838
+ interface ObjectOSStackConfig {
1839
+ /**
1840
+ * Control-plane base URL (HTTP) or a sentinel of `'file'` for the
1841
+ * local file-backed dev mode. Required unless `client` is supplied.
1842
+ *
1843
+ * - `http(s)://…` — talk to a real ObjectStack Cloud control plane
1844
+ * over HTTP and resolve hostnames via its `/cloud/*` API.
1845
+ * - `'file'` — load a single project from a local
1846
+ * `dist/objectstack.json` (or `fileConfig.artifactPath`). Every
1847
+ * request, regardless of hostname, resolves to the same project.
1848
+ * Intended for `pnpm dev` / smoke tests where standing up a
1849
+ * separate control plane is overkill.
1850
+ */
1851
+ controlPlaneUrl?: string;
1852
+ /** Optional bearer token for the control-plane API. */
1853
+ controlPlaneApiKey?: string;
1854
+ /**
1855
+ * Override the artifact client entirely. When supplied,
1856
+ * `controlPlaneUrl` is ignored — useful for tests or custom transports.
1857
+ */
1858
+ client?: ArtifactApiClient | FileArtifactApiClient;
1859
+ /** Config for the file-backed mode (used when `controlPlaneUrl === 'file'`). */
1860
+ fileConfig?: FileArtifactApiClientConfig;
1861
+ /** KernelManager LRU size. Default: 32. */
1862
+ kernelCacheSize?: number;
1863
+ /** KernelManager idle TTL (ms). Default: 15 min. */
1864
+ kernelTtlMs?: number;
1865
+ /** EnvironmentDriverRegistry cache TTL (ms). Default: 5 min. */
1866
+ envCacheTtlMs?: number;
1867
+ /** Artifact / hostname response cache TTL (ms). Default: 5 min. */
1868
+ artifactCacheTtlMs?: number;
1869
+ /** API prefix (carried for parity with cloud-stack). Default: /api/v1. */
1870
+ apiPrefix?: string;
1871
+ }
1872
+ interface ObjectOSStackResult {
1873
+ plugins: any[];
1874
+ api: {
1875
+ enableProjectScoping: true;
1876
+ projectResolution: 'auto';
1877
+ requireAuth: true;
1878
+ };
1879
+ }
1880
+ declare function createObjectOSStack(config: ObjectOSStackConfig): Promise<ObjectOSStackResult>;
1881
+
1882
+ /**
1883
+ * Per-project driver registry contract.
1884
+ *
1885
+ * Resolves a project (by hostname or ID) and produces an instantiated
1886
+ * `IDataDriver` bound to that project's physical database. Concrete
1887
+ * implementations sit on top of either:
1888
+ * - the ObjectStack Cloud HTTP API (see {@link ArtifactEnvironmentRegistry})
1889
+ * - a local file artifact (see {@link FileArtifactApiClient} +
1890
+ * {@link ArtifactEnvironmentRegistry})
1891
+ *
1892
+ * The contract was extracted from `@objectstack/service-cloud` in Phase R
1893
+ * so the runtime can express "fetch artifact + boot per-project kernel"
1894
+ * without taking a dependency on the cloud control plane.
1895
+ */
1896
+
1897
+ type IDataDriver$1 = Contracts.IDataDriver;
1898
+ interface EnvironmentDriverRegistry {
1899
+ /** Resolve a project by hostname. Returns `null` when unknown. */
1900
+ resolveByHostname(host: string): Promise<{
1901
+ projectId: string;
1902
+ driver: IDataDriver$1;
1903
+ } | null>;
1904
+ /** Resolve a project's driver by ID. Returns `null` when unknown. */
1905
+ resolveById(projectId: string): Promise<IDataDriver$1 | null>;
1906
+ /**
1907
+ * Look up the cached project row + driver by ID without triggering a
1908
+ * remote/file fetch. Returns the full cached entry when fresh.
1909
+ */
1910
+ peekById(projectId: string): {
1911
+ projectId: string;
1912
+ driver: IDataDriver$1;
1913
+ project: any;
1914
+ } | null;
1915
+ /** Drop cached entries for the given project. */
1916
+ invalidate(projectId: string): void;
1917
+ }
1918
+
1919
+ /**
1920
+ * EnvironmentDriverRegistry implementation that talks to the control plane
1921
+ * over HTTP via {@link ArtifactApiClient}.
1922
+ *
1923
+ * Mirrors {@link DefaultEnvironmentDriverRegistry} from `environment-registry.ts`
1924
+ * but does **not** read from a local control-plane database. Hostname →
1925
+ * projectId resolution and per-project runtime config (database URL /
1926
+ * driver) come from the control plane API.
1927
+ *
1928
+ * The cached `project` payload exposed by `peekById()` is shaped to look
1929
+ * like a `sys_project` row so callers downstream (notably
1930
+ * `ArtifactKernelFactory`) can read `id`, `organization_id`,
1931
+ * `database_url` and `database_driver` without branching.
1932
+ */
1933
+
1934
+ type IDataDriver = Contracts.IDataDriver;
1935
+ interface ArtifactEnvironmentRegistryConfig {
1936
+ client: ArtifactApiClient;
1937
+ /** Cache TTL for resolved drivers in ms. Default: 5 min. */
1938
+ cacheTtlMs?: number;
1939
+ /** Optional logger. */
1940
+ logger?: {
1941
+ info?: (...a: any[]) => void;
1942
+ warn?: (...a: any[]) => void;
1943
+ error?: (...a: any[]) => void;
1944
+ };
1945
+ }
1946
+ declare class ArtifactEnvironmentRegistry implements EnvironmentDriverRegistry {
1947
+ private readonly client;
1948
+ private readonly cacheTTL;
1949
+ private readonly logger;
1950
+ private readonly hostnameCache;
1951
+ private readonly idCache;
1952
+ private readonly pending;
1953
+ constructor(config: ArtifactEnvironmentRegistryConfig);
1954
+ resolveByHostname(host: string): Promise<{
1955
+ projectId: string;
1956
+ driver: IDataDriver;
1957
+ } | null>;
1958
+ resolveById(projectId: string): Promise<IDataDriver | null>;
1959
+ peekById(projectId: string): {
1960
+ projectId: string;
1961
+ driver: IDataDriver;
1962
+ project: any;
1963
+ } | null;
1964
+ invalidate(projectId: string): void;
1965
+ private buildCacheEntry;
1966
+ }
1967
+
1968
+ interface ArtifactKernelFactoryConfig {
1969
+ client: ArtifactApiClient;
1970
+ envRegistry: EnvironmentDriverRegistry;
1971
+ /** Optional logger. */
1972
+ logger?: {
1973
+ info?: (...a: any[]) => void;
1974
+ warn?: (...a: any[]) => void;
1975
+ error?: (...a: any[]) => void;
1976
+ };
1977
+ /** Optional kernel constructor config. */
1978
+ kernelConfig?: ConstructorParameters<typeof ObjectKernel>[0];
1979
+ /**
1980
+ * Base secret used to derive per-project AuthPlugin secrets via
1981
+ * HKDF-style HMAC-SHA256(baseSecret, projectId). Falls back to
1982
+ * `process.env.OS_AUTH_SECRET` / `AUTH_SECRET` at construction time.
1983
+ */
1984
+ authBaseSecret?: string;
1985
+ }
1986
+ declare class ArtifactKernelFactory implements ProjectKernelFactory {
1987
+ private readonly client;
1988
+ private readonly envRegistry;
1989
+ private readonly logger;
1990
+ private readonly kernelConfig?;
1991
+ private readonly authBaseSecret;
1992
+ constructor(config: ArtifactKernelFactoryConfig);
1993
+ create(projectId: string): Promise<ObjectKernel>;
1994
+ }
1995
+
1996
+ /**
1997
+ * AuthProxyPlugin
1998
+ *
1999
+ * Mounts a single `/api/v1/auth/*` wildcard route on the host's Hono server
2000
+ * that forwards every request to the per-project `AuthManager` registered
2001
+ * by `ArtifactKernelFactory`.
2002
+ *
2003
+ * Why a dedicated plugin: AuthPlugin (better-auth) registers its routes by
2004
+ * grabbing the host's `http-server` service from its own `PluginContext`.
2005
+ * In objectos runtime mode AuthPlugin lives on a per-project kernel — it
2006
+ * has no access to the host's HTTP server, so its `kernel:ready` route
2007
+ * registration is a no-op. The dispatcher plugin's wildcard registration
2008
+ * via `IHttpServer.post('/auth/*', …)` proved unreliable in practice,
2009
+ * so this plugin uses Hono's raw app directly (same path AuthPlugin took
2010
+ * historically) which is rock solid.
2011
+ *
2012
+ * Routing:
2013
+ * 1. Resolve the project from the request hostname via `env-registry`.
2014
+ * 2. Acquire the project's kernel via `kernel-manager`.
2015
+ * 3. Look up the `auth` service on that kernel — this is the better-auth
2016
+ * handler injected by `ArtifactKernelFactory`.
2017
+ * 4. Build a Web `Request` using the project's canonical baseUrl and
2018
+ * hand it to the better-auth handler.
2019
+ * 5. Stream the response back through Hono.
2020
+ */
2021
+
2022
+ declare class AuthProxyPlugin implements Plugin {
2023
+ readonly name = "com.objectstack.runtime.auth-proxy";
2024
+ readonly version = "1.0.0";
2025
+ init: (_ctx: PluginContext) => Promise<void>;
2026
+ start: (ctx: PluginContext) => Promise<void>;
2027
+ }
2028
+
2029
+ /**
2030
+ * Provider id used in better-auth's `genericOAuth` and as part of the
2031
+ * callback URL: `/api/v1/auth/oauth2/callback/<PROVIDER_ID>`. Keep stable —
2032
+ * changing it invalidates every registered redirect_uri.
2033
+ */
2034
+ declare const PLATFORM_SSO_PROVIDER_ID = "objectstack-cloud";
2035
+ /**
2036
+ * Derive the per-project OAuth client_id used in `sys_oauth_application`
2037
+ * (cloud side) and {@link genericOAuth} config (project side).
2038
+ */
2039
+ declare function derivePlatformSsoClientId(projectId: string): string;
2040
+ /**
2041
+ * Derive the per-project OAuth client_secret deterministically from the
2042
+ * shared master secret. HMAC-SHA256(baseSecret, 'oauth-client:' + projectId)
2043
+ * yields a 64-char hex string that is:
2044
+ * - stable across container cold-starts (no DB lookup needed)
2045
+ * - independent per project (compromising one does not compromise others)
2046
+ * - rotatable via OS_AUTH_SECRET rotation (invalidates all SSO clients)
2047
+ *
2048
+ * This is the **plaintext** value the RP must present at the token endpoint.
2049
+ * The cloud-side `sys_oauth_application.client_secret` column instead stores
2050
+ * {@link hashPlatformSsoClientSecret}(plaintext) — better-auth's oauth-provider
2051
+ * defaults to `storeClientSecret: 'hashed'` (SHA-256 + base64url) when the JWT
2052
+ * plugin is enabled, and looks up the row by hashing the presented secret.
2053
+ */
2054
+ declare function derivePlatformSsoClientSecret(baseSecret: string, projectId: string): string;
2055
+ /**
2056
+ * Build the redirect_uri better-auth's `genericOAuth` plugin will use
2057
+ * when the project kernel mounts the provider with id
2058
+ * {@link PLATFORM_SSO_PROVIDER_ID}. MUST be one of the URIs registered
2059
+ * on the cloud-side oauth client or the authorization server will reject
2060
+ * the callback with `invalid_request`.
2061
+ */
2062
+ declare function buildPlatformSsoRedirectUri(hostname: string, basePath?: string): string;
2063
+ interface SeedPlatformSsoClientOptions {
2064
+ /**
2065
+ * Cloud control-plane ObjectQL engine. Must expose `find(object, query)`,
2066
+ * `insert(object, data)`, and `update(object, data, {where})`. Both the
2067
+ * `apps/cloud` boot kernel (via `kernel.getService('objectql')`) and the
2068
+ * dispatcher's local `ql` reference satisfy this shape.
2069
+ */
2070
+ ql: {
2071
+ find: (object: string, query: any, opts?: any) => Promise<any>;
2072
+ insert: (object: string, data: any, opts?: any) => Promise<any>;
2073
+ update: (object: string, data: any, where: any, opts?: any) => Promise<any>;
2074
+ };
2075
+ /** Project id (also used to derive client_id + client_secret). */
2076
+ projectId: string;
2077
+ /**
2078
+ * Project hostname (e.g. `acme-crm.objectos.app`). Optional — projects
2079
+ * may be created before a hostname is assigned, in which case no
2080
+ * redirect_uri is registered yet and the row is upserted with an
2081
+ * empty `redirect_uris` array. Calling this function again once the
2082
+ * hostname is known will merge the new URI in.
2083
+ */
2084
+ hostname?: string | null;
2085
+ /** Master secret shared between cloud and project containers. */
2086
+ baseSecret: string;
2087
+ /** Optional logger for diagnostics. */
2088
+ logger?: {
2089
+ info?: (...a: any[]) => void;
2090
+ warn?: (...a: any[]) => void;
2091
+ error?: (...a: any[]) => void;
2092
+ };
2093
+ /** When true, rethrow insert/update errors instead of swallowing them.
2094
+ * Backfill uses this to surface real failures via the admin endpoint. */
2095
+ throwOnError?: boolean;
2096
+ }
2097
+ /**
2098
+ * Idempotently upsert a `sys_oauth_application` row for the given project.
2099
+ * Re-running with the same `projectId` is a no-op (the deterministic
2100
+ * `client_id` is uniquely indexed and the secret derivation is stable).
2101
+ * Re-running with a new `hostname` adds the new redirect_uri to the
2102
+ * existing row's JSON array.
2103
+ */
2104
+ declare function seedPlatformSsoClient(opts: SeedPlatformSsoClientOptions): Promise<void>;
2105
+ interface BackfillPlatformSsoClientsOptions {
2106
+ ql: SeedPlatformSsoClientOptions['ql'];
2107
+ baseSecret: string;
2108
+ logger?: {
2109
+ info?: (...a: any[]) => void;
2110
+ warn?: (...a: any[]) => void;
2111
+ error?: (...a: any[]) => void;
2112
+ };
2113
+ /** Hard cap on rows scanned (default: 1000). */
2114
+ limit?: number;
2115
+ }
2116
+ /**
2117
+ * Scan `sys_project` and ensure every active project has a corresponding
2118
+ * `sys_oauth_application` row. Intended to run once at cloud boot — the
2119
+ * happy path is dominated by the project-create hook
2120
+ * ({@link seedPlatformSsoClient}); the backfill exists so projects
2121
+ * created before this feature shipped also get SSO support without an
2122
+ * out-of-band migration.
2123
+ */
2124
+ declare function backfillPlatformSsoClients(opts: BackfillPlatformSsoClientsOptions): Promise<{
2125
+ scanned: number;
2126
+ seeded: number;
2127
+ alreadyExisted: number;
2128
+ failures: Array<{
2129
+ projectId: string;
2130
+ error: string;
2131
+ }>;
2132
+ }>;
2133
+
1257
2134
  /**
1258
2135
  * # Hook & Action Body Sandbox
1259
2136
  *
@@ -1484,4 +2361,4 @@ declare function actionBodyRunnerFactory(runner: ScriptRunner, opts: FactoryOpti
1484
2361
  timeoutMs?: number;
1485
2362
  }) => ((actionCtx: any) => Promise<unknown>) | undefined;
1486
2363
 
1487
- export { AppPlugin, type DispatcherPluginConfig, DriverPlugin, HttpDispatcher, type HttpDispatcherResult, type HttpProtocolContext, HttpServer, type LoadArtifactBundleOptions, MiddlewareManager, QuickJSScriptRunner, type QuickJSScriptRunnerOptions, Runtime, type RuntimeConfig, SYSTEM_PROJECT_ID, SandboxError, type ScriptContext, type ScriptOrigin, type ScriptResult, type ScriptRunOptions, type ScriptRunner, SeedLoaderService, type StandaloneStackConfig, type StandaloneStackResult, type SystemProjectPluginConfig, UnimplementedScriptRunner, actionBodyRunnerFactory, collectBundleActions, collectBundleFunctions, collectBundleHooks, createDispatcherPlugin, createStandaloneStack, createSystemProjectPlugin, hookBodyRunnerFactory, isHttpUrl, loadArtifactBundle, mergeRuntimeModule, readArtifactSource };
2364
+ export { AppPlugin, ArtifactApiClient, type ArtifactApiClientConfig, ArtifactEnvironmentRegistry, type ArtifactEnvironmentRegistryConfig, ArtifactKernelFactory, type ArtifactKernelFactoryConfig, AuthProxyPlugin, type BackfillPlatformSsoClientsOptions, type CapturedError, DEFAULT_RATE_LIMITS, type DefaultHostConfigOptions, type DefaultHostConfigResult, type DispatcherPluginConfig, DriverPlugin, type EnvironmentDriverRegistry, type ErrorReporter, FileArtifactApiClient, type FileArtifactApiClientConfig, HttpDispatcher, type HttpDispatcherResult, type HttpProtocolContext, HttpServer, InMemoryErrorReporter, InMemoryMetricsRegistry, KernelManager, type KernelManagerConfig, type LoadArtifactBundleOptions, type MetricSample, type MetricsRegistry, MiddlewareManager, NoopErrorReporter, NoopMetricsRegistry, type ObjectOSStackConfig, type ObjectOSStackResult, PLATFORM_SSO_PROVIDER_ID, type ProjectArtifactResponse, type ProjectKernelFactory, type ProjectRuntimeConfig, QuickJSScriptRunner, type QuickJSScriptRunnerOptions, RUNTIME_METRICS, type RateLimitBucketConfig, type RateLimitDecision, type RateLimitDefaults, type RateLimitStore, RateLimiter, type ResolvedHostname, Runtime, type RuntimeConfig, SYSTEM_PROJECT_ID, SandboxError, type ScriptContext, type ScriptOrigin, type ScriptResult, type ScriptRunOptions, type ScriptRunner, type SecurityHeadersOptions, SeedLoaderService, type SeedPlatformSsoClientOptions, type StandaloneStackConfig, type StandaloneStackResult, type SystemProjectPluginConfig, type TraceContext, UnimplementedScriptRunner, actionBodyRunnerFactory, backfillPlatformSsoClients, buildPlatformSsoRedirectUri, buildSecurityHeaders, collectBundleActions, collectBundleFunctions, collectBundleHooks, createDefaultHostConfig, createDispatcherPlugin, createObjectOSStack, createStandaloneStack, createSystemProjectPlugin, derivePlatformSsoClientId, derivePlatformSsoClientSecret, extractRequestId, formatTraceparent, generateRequestId, hookBodyRunnerFactory, isHttpUrl, loadArtifactBundle, mergeRuntimeModule, parseTraceparent, readArtifactSource, resolveDefaultArtifactPath, resolveRequestId, seedPlatformSsoClient };