@objectstack/runtime 5.1.0 → 6.0.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/index.cjs +1091 -33465
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +356 -118
- package/dist/index.d.ts +356 -118
- package/dist/index.js +1080 -33484
- package/dist/index.js.map +1 -1
- package/package.json +18 -16
package/dist/index.d.ts
CHANGED
|
@@ -1,15 +1,16 @@
|
|
|
1
1
|
import { ObjectKernel, IHttpServer, ObjectKernelConfig, Plugin, PluginContext, RouteHandler, Middleware } from '@objectstack/core';
|
|
2
2
|
export * from '@objectstack/core';
|
|
3
3
|
export { ObjectKernel } from '@objectstack/core';
|
|
4
|
+
import { ClusterServicePluginOptions } from '@objectstack/service-cluster';
|
|
5
|
+
import { ClusterCapabilityConfigInput, ExecutionContext } from '@objectstack/spec/kernel';
|
|
4
6
|
import { z } from 'zod';
|
|
5
7
|
import * as Contracts from '@objectstack/spec/contracts';
|
|
6
8
|
import { ISeedLoaderService, IDataEngine, IMetadataService } from '@objectstack/spec/contracts';
|
|
7
9
|
import { SeedLoaderRequest, SeedLoaderResult, ObjectDependencyGraph, Dataset, SeedLoaderConfigInput, ExpressionBody, ScriptBody, HookBody, Hook } from '@objectstack/spec/data';
|
|
8
10
|
import { MetricsRegistry, ErrorReporter } from '@objectstack/observability';
|
|
9
|
-
export { CapturedError, ErrorReporter, InMemoryErrorReporter, InMemoryMetricsRegistry, MetricSample, MetricsRegistry, NoopErrorReporter, NoopMetricsRegistry, RUNTIME_METRICS } from '@objectstack/observability';
|
|
10
|
-
import { ExecutionContext } from '@objectstack/spec/kernel';
|
|
11
|
+
export { CapturedError, ErrorReporter, InMemoryErrorReporter, InMemoryMetricsRegistry, MetricSample, MetricsRegistry, NoopErrorReporter, NoopMetricsRegistry, OBSERVABILITY_ERRORS_SERVICE, OBSERVABILITY_METRICS_SERVICE, RUNTIME_METRICS } from '@objectstack/observability';
|
|
11
12
|
import { MiddlewareConfig, MiddlewareType } from '@objectstack/spec/system';
|
|
12
|
-
import {
|
|
13
|
+
import { EnvironmentArtifact } from '@objectstack/spec/cloud';
|
|
13
14
|
export { RestApiPluginConfig, RestServer, RouteEntry, RouteGroupBuilder, RouteManager, createRestApiPlugin } from '@objectstack/rest';
|
|
14
15
|
|
|
15
16
|
interface RuntimeConfig {
|
|
@@ -23,6 +24,18 @@ interface RuntimeConfig {
|
|
|
23
24
|
* Kernel Configuration
|
|
24
25
|
*/
|
|
25
26
|
kernel?: ObjectKernelConfig;
|
|
27
|
+
/**
|
|
28
|
+
* Cluster service configuration.
|
|
29
|
+
*
|
|
30
|
+
* - Omit (default): a single-node `memory` cluster is auto-registered.
|
|
31
|
+
* - `false`: skip auto-registration entirely. Register your own
|
|
32
|
+
* `ClusterServicePlugin` if you need it later.
|
|
33
|
+
* - `ClusterCapabilityConfigInput`: forwarded to `defineCluster()`.
|
|
34
|
+
* - `{ cluster: IClusterService }`: bring your own instance.
|
|
35
|
+
*
|
|
36
|
+
* See `content/docs/concepts/cluster-semantics.mdx` for driver options.
|
|
37
|
+
*/
|
|
38
|
+
cluster?: false | ClusterCapabilityConfigInput | ClusterServicePluginOptions;
|
|
26
39
|
}
|
|
27
40
|
/**
|
|
28
41
|
* ObjectStack Runtime
|
|
@@ -41,6 +54,7 @@ interface RuntimeConfig {
|
|
|
41
54
|
declare class Runtime {
|
|
42
55
|
readonly kernel: ObjectKernel;
|
|
43
56
|
constructor(config?: RuntimeConfig);
|
|
57
|
+
private normalizeClusterOptions;
|
|
44
58
|
/**
|
|
45
59
|
* Register a plugin
|
|
46
60
|
*/
|
|
@@ -61,13 +75,14 @@ declare const StandaloneStackConfigSchema: z.ZodObject<{
|
|
|
61
75
|
databaseUrl: z.ZodOptional<z.ZodString>;
|
|
62
76
|
databaseAuthToken: z.ZodOptional<z.ZodString>;
|
|
63
77
|
databaseDriver: z.ZodOptional<z.ZodEnum<{
|
|
64
|
-
sqlite: "sqlite";
|
|
65
|
-
turso: "turso";
|
|
66
78
|
memory: "memory";
|
|
67
79
|
postgres: "postgres";
|
|
80
|
+
sqlite: "sqlite";
|
|
81
|
+
"sqlite-wasm": "sqlite-wasm";
|
|
82
|
+
turso: "turso";
|
|
68
83
|
mongodb: "mongodb";
|
|
69
84
|
}>>;
|
|
70
|
-
|
|
85
|
+
environmentId: z.ZodOptional<z.ZodString>;
|
|
71
86
|
artifactPath: z.ZodOptional<z.ZodString>;
|
|
72
87
|
}, z.core.$strip>;
|
|
73
88
|
type StandaloneStackConfig = z.input<typeof StandaloneStackConfigSchema>;
|
|
@@ -171,7 +186,7 @@ declare class DriverPlugin implements Plugin {
|
|
|
171
186
|
* usages may omit this — no catalog hooks are emitted in that case.
|
|
172
187
|
*/
|
|
173
188
|
interface AppPluginProjectContext {
|
|
174
|
-
|
|
189
|
+
environmentId: string;
|
|
175
190
|
organizationId: string;
|
|
176
191
|
projectName?: string;
|
|
177
192
|
/** When the app comes from a package installation, the source package id. */
|
|
@@ -492,6 +507,75 @@ declare function parseTraceparent(value: unknown): TraceContext | undefined;
|
|
|
492
507
|
*/
|
|
493
508
|
declare function formatTraceparent(ctx: TraceContext): string;
|
|
494
509
|
|
|
510
|
+
/**
|
|
511
|
+
* Options for {@link ObservabilityServicePlugin}.
|
|
512
|
+
*
|
|
513
|
+
* Either or both backends can be omitted; the omitted one resolves to
|
|
514
|
+
* the corresponding no-op exporter so consumers can always rely on the
|
|
515
|
+
* service being present.
|
|
516
|
+
*/
|
|
517
|
+
interface ObservabilityServicePluginOptions {
|
|
518
|
+
/** Metrics backend (e.g. `ConsoleMetricsRegistry`, `OtlpHttpMetricsRegistry`). */
|
|
519
|
+
metrics?: MetricsRegistry;
|
|
520
|
+
/** Error reporter backend (e.g. Sentry adapter). */
|
|
521
|
+
errors?: ErrorReporter;
|
|
522
|
+
}
|
|
523
|
+
/**
|
|
524
|
+
* `ObservabilityServicePlugin` — registers the host's
|
|
525
|
+
* {@link MetricsRegistry} and {@link ErrorReporter} in the kernel
|
|
526
|
+
* service registry under the canonical names so any other plugin can
|
|
527
|
+
* look them up without each host having to thread observability config
|
|
528
|
+
* through every plugin constructor.
|
|
529
|
+
*
|
|
530
|
+
* Resolution chain other plugins should follow:
|
|
531
|
+
*
|
|
532
|
+
* 1. Explicit option on the plugin's own options object (escape
|
|
533
|
+
* hatch for tests / explicit wiring).
|
|
534
|
+
* 2. `ctx.getService(OBSERVABILITY_METRICS_SERVICE)`.
|
|
535
|
+
* 3. `NoopMetricsRegistry()` — never null.
|
|
536
|
+
*
|
|
537
|
+
* Register this plugin **before** any plugin that wants to consume the
|
|
538
|
+
* services (cache, storage, dispatcher), otherwise the consumer's
|
|
539
|
+
* `init` will fall through to the no-op default.
|
|
540
|
+
*
|
|
541
|
+
* @example
|
|
542
|
+
* ```ts
|
|
543
|
+
* import { ObjectKernel } from '@objectstack/core';
|
|
544
|
+
* import {
|
|
545
|
+
* ObservabilityServicePlugin,
|
|
546
|
+
* CacheServicePlugin,
|
|
547
|
+
* } from '@objectstack/runtime';
|
|
548
|
+
* import { ConsoleMetricsRegistry } from '@objectstack/observability';
|
|
549
|
+
*
|
|
550
|
+
* const kernel = new ObjectKernel();
|
|
551
|
+
* kernel.use(new ObservabilityServicePlugin({
|
|
552
|
+
* metrics: new ConsoleMetricsRegistry(),
|
|
553
|
+
* }));
|
|
554
|
+
* kernel.use(new CacheServicePlugin()); // picks metrics up automatically
|
|
555
|
+
* ```
|
|
556
|
+
*/
|
|
557
|
+
declare class ObservabilityServicePlugin implements Plugin {
|
|
558
|
+
name: string;
|
|
559
|
+
version: string;
|
|
560
|
+
type: string;
|
|
561
|
+
private readonly options;
|
|
562
|
+
constructor(options?: ObservabilityServicePluginOptions);
|
|
563
|
+
init(ctx: PluginContext): Promise<void>;
|
|
564
|
+
}
|
|
565
|
+
/**
|
|
566
|
+
* Helper used by consumer plugins to resolve a metrics backend with
|
|
567
|
+
* the canonical fallback chain. Never throws; always returns a usable
|
|
568
|
+
* `MetricsRegistry`.
|
|
569
|
+
*
|
|
570
|
+
* @param ctx the consuming plugin's `PluginContext`
|
|
571
|
+
* @param override explicit option set on the consuming plugin (wins)
|
|
572
|
+
*/
|
|
573
|
+
declare function resolveMetrics(ctx: PluginContext, override?: MetricsRegistry): MetricsRegistry;
|
|
574
|
+
/**
|
|
575
|
+
* Sibling of {@link resolveMetrics} for {@link ErrorReporter}.
|
|
576
|
+
*/
|
|
577
|
+
declare function resolveErrorReporter(ctx: PluginContext, override?: ErrorReporter): ErrorReporter;
|
|
578
|
+
|
|
495
579
|
interface DispatcherPluginConfig {
|
|
496
580
|
/**
|
|
497
581
|
* API path prefix for all endpoints.
|
|
@@ -504,16 +588,16 @@ interface DispatcherPluginConfig {
|
|
|
504
588
|
* routes stay in lockstep with /data and /meta.
|
|
505
589
|
*
|
|
506
590
|
* When `enableProjectScoping` is true and `projectResolution` is:
|
|
507
|
-
* - `required` — only `/
|
|
591
|
+
* - `required` — only `/environments/:environmentId/...` variants are registered.
|
|
508
592
|
* - `optional` / `auto` — both unscoped and scoped variants are registered
|
|
509
|
-
* (the scoped handler forwards `req.params.
|
|
593
|
+
* (the scoped handler forwards `req.params.environmentId` into context).
|
|
510
594
|
*/
|
|
511
595
|
scoping?: {
|
|
512
596
|
enableProjectScoping?: boolean;
|
|
513
597
|
projectResolution?: 'required' | 'optional' | 'auto';
|
|
514
598
|
};
|
|
515
599
|
/**
|
|
516
|
-
* Enforce per-project membership (`
|
|
600
|
+
* Enforce per-project membership (`sys_environment_member`) on scoped
|
|
517
601
|
* data-plane routes. Returns 403 for non-members unless they are
|
|
518
602
|
* staff (platform org) or the project is the well-known system
|
|
519
603
|
* project.
|
|
@@ -588,10 +672,10 @@ declare function createDispatcherPlugin(config?: DispatcherPluginConfig): Plugin
|
|
|
588
672
|
|
|
589
673
|
/**
|
|
590
674
|
* The well-known UUID for the built-in system project.
|
|
591
|
-
* Kept in lockstep with `ProjectProvisioningService.
|
|
675
|
+
* Kept in lockstep with `ProjectProvisioningService.provisionSystemEnvironment`.
|
|
592
676
|
*/
|
|
593
|
-
declare const
|
|
594
|
-
interface
|
|
677
|
+
declare const SYSTEM_ENVIRONMENT_ID = "00000000-0000-0000-0000-000000000001";
|
|
678
|
+
interface SystemEnvironmentPluginConfig {
|
|
595
679
|
/**
|
|
596
680
|
* Service name that resolves to a `ProjectProvisioningService`-shaped
|
|
597
681
|
* object. Defaults to `tenant.provisioning` (convention used by
|
|
@@ -609,8 +693,8 @@ interface SystemProjectPluginConfig {
|
|
|
609
693
|
* System Project Bootstrap Plugin
|
|
610
694
|
*
|
|
611
695
|
* Ensures the built-in system project (well-known UUID
|
|
612
|
-
* {@link
|
|
613
|
-
* runtime starts. Calls are idempotent — `
|
|
696
|
+
* {@link SYSTEM_ENVIRONMENT_ID}) exists on the control plane the first time the
|
|
697
|
+
* runtime starts. Calls are idempotent — `provisionSystemEnvironment()` returns
|
|
614
698
|
* the existing row when the project has already been created.
|
|
615
699
|
*
|
|
616
700
|
* Register AFTER the tenant service is available so the provisioning service
|
|
@@ -619,10 +703,10 @@ interface SystemProjectPluginConfig {
|
|
|
619
703
|
* @example
|
|
620
704
|
* ```ts
|
|
621
705
|
* kernel.use(tenantPlugin);
|
|
622
|
-
* kernel.use(
|
|
706
|
+
* kernel.use(createSystemEnvironmentPlugin());
|
|
623
707
|
* ```
|
|
624
708
|
*/
|
|
625
|
-
declare function
|
|
709
|
+
declare function createSystemEnvironmentPlugin(config?: SystemEnvironmentPluginConfig): Plugin;
|
|
626
710
|
|
|
627
711
|
/**
|
|
628
712
|
* HttpServer - Unified HTTP Server Abstraction
|
|
@@ -711,16 +795,16 @@ declare class HttpServer implements IHttpServer {
|
|
|
711
795
|
/**
|
|
712
796
|
* Factory contract for instantiating a per-project {@link ObjectKernel}.
|
|
713
797
|
*
|
|
714
|
-
* Given a `
|
|
715
|
-
* 1. Read control-plane metadata (`
|
|
798
|
+
* Given a `environmentId`, the factory is expected to:
|
|
799
|
+
* 1. Read control-plane metadata (`sys_environment` + credentials + subscribed packages).
|
|
716
800
|
* 2. Construct a fresh `ObjectKernel` with project-scoped driver + plugins + Apps.
|
|
717
801
|
* 3. Return a **bootstrapped** kernel ready to serve requests.
|
|
718
802
|
*/
|
|
719
|
-
interface
|
|
720
|
-
create(
|
|
803
|
+
interface EnvironmentKernelFactory {
|
|
804
|
+
create(environmentId: string): Promise<ObjectKernel>;
|
|
721
805
|
}
|
|
722
806
|
interface KernelManagerConfig {
|
|
723
|
-
factory:
|
|
807
|
+
factory: EnvironmentKernelFactory;
|
|
724
808
|
/** Maximum number of kernels to keep resident. Defaults to 32. */
|
|
725
809
|
maxSize?: number;
|
|
726
810
|
/**
|
|
@@ -743,7 +827,7 @@ interface KernelManagerConfig {
|
|
|
743
827
|
* Implements ADR-0003 multi-kernel scheduling: each project gets an
|
|
744
828
|
* isolated kernel (App/plugin/metadata namespaces) that is lazily built
|
|
745
829
|
* on first request and evicted under memory / idle pressure. Concurrent
|
|
746
|
-
* `getOrCreate()` calls for the same
|
|
830
|
+
* `getOrCreate()` calls for the same environmentId share a single in-flight
|
|
747
831
|
* factory invocation (singleflight).
|
|
748
832
|
*/
|
|
749
833
|
declare class KernelManager {
|
|
@@ -754,36 +838,36 @@ declare class KernelManager {
|
|
|
754
838
|
private readonly cache;
|
|
755
839
|
private readonly pending;
|
|
756
840
|
constructor(config: KernelManagerConfig);
|
|
757
|
-
/** Returns the currently cached
|
|
841
|
+
/** Returns the currently cached environmentIds (ordered by insertion). */
|
|
758
842
|
keys(): string[];
|
|
759
843
|
/** Cache size for diagnostics. */
|
|
760
844
|
get size(): number;
|
|
761
845
|
/**
|
|
762
|
-
* Resolve or construct the kernel for `
|
|
846
|
+
* Resolve or construct the kernel for `environmentId`.
|
|
763
847
|
*
|
|
764
848
|
* - Cache hit (fresh): bumps `lastAccess` and returns immediately.
|
|
765
849
|
* - Cache hit (TTL expired): evicts then falls through to factory.
|
|
766
850
|
* - Cache miss: dedupes concurrent callers through `pending`.
|
|
767
851
|
*/
|
|
768
|
-
getOrCreate(
|
|
852
|
+
getOrCreate(environmentId: string): Promise<ObjectKernel>;
|
|
769
853
|
/**
|
|
770
|
-
* Evict the kernel for `
|
|
854
|
+
* Evict the kernel for `environmentId` and invoke `kernel.shutdown()`.
|
|
771
855
|
* No-op when the entry is absent.
|
|
772
856
|
*/
|
|
773
|
-
evict(
|
|
857
|
+
evict(environmentId: string): Promise<void>;
|
|
774
858
|
/** Evict all resident kernels. Used on runtime shutdown. */
|
|
775
859
|
evictAll(): Promise<void>;
|
|
776
860
|
private enforceMaxSize;
|
|
777
861
|
}
|
|
778
862
|
|
|
779
|
-
/** Minimal local interface — full
|
|
780
|
-
interface
|
|
781
|
-
touch(
|
|
863
|
+
/** Minimal local interface — full EnvironmentScopeManager was removed in Phase R. */
|
|
864
|
+
interface EnvironmentScopeManager {
|
|
865
|
+
touch(environmentId: string): void;
|
|
782
866
|
}
|
|
783
867
|
interface HttpProtocolContext {
|
|
784
868
|
request: any;
|
|
785
869
|
response?: any;
|
|
786
|
-
|
|
870
|
+
environmentId?: string;
|
|
787
871
|
dataDriver?: any;
|
|
788
872
|
/**
|
|
789
873
|
* Identity envelope resolved by `resolveExecutionContext` and threaded
|
|
@@ -810,17 +894,17 @@ interface HttpDispatcherOptions {
|
|
|
810
894
|
enforceProjectMembership?: boolean;
|
|
811
895
|
/**
|
|
812
896
|
* Optional {@link KernelManager}. When present, the dispatcher resolves
|
|
813
|
-
* `context.
|
|
814
|
-
* project's dedicated kernel via `kernelManager.getOrCreate(
|
|
815
|
-
* Requests that fail to resolve a
|
|
897
|
+
* `context.environmentId` first and then routes the request against the
|
|
898
|
+
* project's dedicated kernel via `kernelManager.getOrCreate(environmentId)`.
|
|
899
|
+
* Requests that fail to resolve a environmentId fall through to the
|
|
816
900
|
* constructor-supplied kernel (self-hosted / legacy behavior).
|
|
817
901
|
*/
|
|
818
902
|
kernelManager?: KernelManager;
|
|
819
903
|
/**
|
|
820
|
-
* Optional {@link
|
|
904
|
+
* Optional {@link EnvironmentScopeManager}. When present, `touch(environmentId)` is
|
|
821
905
|
* called on every scoped request so idle projects are evicted after TTL.
|
|
822
906
|
*/
|
|
823
|
-
scopeManager?:
|
|
907
|
+
scopeManager?: EnvironmentScopeManager;
|
|
824
908
|
}
|
|
825
909
|
/**
|
|
826
910
|
* @deprecated Use `createDispatcherPlugin()` from `@objectstack/runtime` instead.
|
|
@@ -839,22 +923,22 @@ declare class HttpDispatcher {
|
|
|
839
923
|
private scopeManager?;
|
|
840
924
|
/**
|
|
841
925
|
* When `true`, scoped data-plane routes enforce a
|
|
842
|
-
* `
|
|
843
|
-
* Defaults to `true` when a
|
|
926
|
+
* `sys_environment_member` lookup and return 403 for non-members.
|
|
927
|
+
* Defaults to `true` when a environmentId is resolvable — legacy callers
|
|
844
928
|
* can opt out via the third constructor argument (see
|
|
845
929
|
* `DispatcherConfig.enforceProjectMembership`).
|
|
846
930
|
*/
|
|
847
931
|
private enforceMembership;
|
|
848
932
|
/**
|
|
849
933
|
* In-memory cache of positive membership checks, keyed by
|
|
850
|
-
* `${
|
|
934
|
+
* `${environmentId}:${userId}`. Entries expire 60 seconds after insertion
|
|
851
935
|
* — a short TTL is acceptable because a user whose access was just
|
|
852
936
|
* revoked sees stale access for at most one minute.
|
|
853
937
|
*/
|
|
854
938
|
private membershipCache;
|
|
855
939
|
private static readonly MEMBERSHIP_CACHE_TTL_MS;
|
|
856
940
|
/** Well-known system project id — bypassed for any authenticated user. */
|
|
857
|
-
private static readonly
|
|
941
|
+
private static readonly SYSTEM_ENVIRONMENT_ID;
|
|
858
942
|
/** Well-known platform org id — members bypass project membership. */
|
|
859
943
|
private static readonly PLATFORM_ORG_ID;
|
|
860
944
|
constructor(kernel: ObjectKernel, envRegistry?: any, options?: HttpDispatcherOptions);
|
|
@@ -875,22 +959,27 @@ declare class HttpDispatcher {
|
|
|
875
959
|
private callData;
|
|
876
960
|
/**
|
|
877
961
|
* Parse a project UUID out of a scoped URL path such as
|
|
878
|
-
* `/api/v1/
|
|
962
|
+
* `/api/v1/environments/abc-123/data/task` or `/projects/abc-123/meta`.
|
|
963
|
+
* Returns `undefined` when the path does not match the scoped pattern.
|
|
964
|
+
*/
|
|
965
|
+
/**
|
|
966
|
+
* Parse an environment UUID out of a scoped URL path such as
|
|
967
|
+
* `/api/v1/environments/abc-123/data/task` or `/environments/abc-123/meta`.
|
|
879
968
|
* Returns `undefined` when the path does not match the scoped pattern.
|
|
880
969
|
*/
|
|
881
|
-
private
|
|
970
|
+
private extractEnvironmentIdFromPath;
|
|
882
971
|
/**
|
|
883
972
|
* Resolve environment context for incoming request.
|
|
884
973
|
*
|
|
885
974
|
* Precedence:
|
|
886
|
-
* 0. URL path matches `/
|
|
975
|
+
* 0. URL path matches `/environments/:environmentId/...` OR request.params.environmentId set by router
|
|
887
976
|
* → envRegistry.resolveById(id)
|
|
888
977
|
* 1. request.headers.host → envRegistry.resolveByHostname(host)
|
|
889
|
-
* 2. request.headers['x-
|
|
978
|
+
* 2. request.headers['x-environment-id'] → envRegistry.resolveById(id)
|
|
890
979
|
* 3. session.activeEnvironmentId → envRegistry.resolveById(id)
|
|
891
980
|
* 4. session.activeOrganizationId → find default project → envRegistry.resolveById(id)
|
|
892
|
-
* 5. single-
|
|
893
|
-
* → envRegistry.resolveById(defaultProject.
|
|
981
|
+
* 5. single-environment default (registered by `createSingleEnvironmentPlugin`)
|
|
982
|
+
* → envRegistry.resolveById(defaultProject.environmentId). Lets bare
|
|
894
983
|
* `/api/v1/data/...` URLs resolve to the lone project in
|
|
895
984
|
* `cloudUrl: 'local'` deployments.
|
|
896
985
|
*
|
|
@@ -900,13 +989,13 @@ declare class HttpDispatcher {
|
|
|
900
989
|
private resolveEnvironmentContext;
|
|
901
990
|
/**
|
|
902
991
|
* Check whether the authenticated user is a member of
|
|
903
|
-
* `context.
|
|
992
|
+
* `context.environmentId`. Runs after {@link resolveEnvironmentContext}
|
|
904
993
|
* and is a no-op when:
|
|
905
994
|
*
|
|
906
995
|
* - Membership enforcement is disabled via the constructor.
|
|
907
996
|
* - The route is control-plane (`/auth/*`, `/cloud/*`, `/health`,
|
|
908
997
|
* `/discovery`) — already skipped upstream.
|
|
909
|
-
* - No `
|
|
998
|
+
* - No `environmentId` was resolved (e.g. unscoped legacy routes).
|
|
910
999
|
* - The project is the well-known system project (bypassed so any
|
|
911
1000
|
* authenticated user can read platform metadata).
|
|
912
1001
|
* - The user's active organization is the platform org (staff).
|
|
@@ -1240,23 +1329,23 @@ declare class HttpDispatcher {
|
|
|
1240
1329
|
* Cloud / Environment Control-Plane routes.
|
|
1241
1330
|
*
|
|
1242
1331
|
* - GET /cloud/drivers → list registered ObjectQL drivers (for env provisioning)
|
|
1243
|
-
* - GET /cloud/
|
|
1244
|
-
* - POST /cloud/
|
|
1245
|
-
* - GET /cloud/
|
|
1246
|
-
* - PATCH /cloud/
|
|
1247
|
-
* - DELETE /cloud/
|
|
1332
|
+
* - GET /cloud/environments → list
|
|
1333
|
+
* - POST /cloud/environments → provision (driver: memory | turso | <any registered driver>)
|
|
1334
|
+
* - GET /cloud/environments/:id → detail (+ db, credential, membership)
|
|
1335
|
+
* - PATCH /cloud/environments/:id → update displayName / plan / status / isDefault / metadata
|
|
1336
|
+
* - DELETE /cloud/environments/:id[?force=1] → cascade-delete the project (cred/member/package install rows + physical DB)
|
|
1248
1337
|
* - DELETE /cloud/organizations/:id → cascade-delete every project (and its DB) for the org, then drop the org
|
|
1249
|
-
* - POST /cloud/
|
|
1250
|
-
* - POST /cloud/
|
|
1251
|
-
* - POST /cloud/
|
|
1252
|
-
* - GET /cloud/
|
|
1253
|
-
* - GET /cloud/
|
|
1254
|
-
* - POST /cloud/
|
|
1255
|
-
* - GET /cloud/
|
|
1256
|
-
* - PATCH /cloud/
|
|
1257
|
-
* - PATCH /cloud/
|
|
1258
|
-
* - DELETE /cloud/
|
|
1259
|
-
* - POST /cloud/
|
|
1338
|
+
* - POST /cloud/environments/:id/retry → re-run provisioning for a failed environment
|
|
1339
|
+
* - POST /cloud/environments/:id/activate → mark as active for session (stub)
|
|
1340
|
+
* - POST /cloud/environments/:id/credentials/rotate → rotate credential
|
|
1341
|
+
* - GET /cloud/environments/:id/members → list members
|
|
1342
|
+
* - GET /cloud/environments/:id/packages → list installed packages
|
|
1343
|
+
* - POST /cloud/environments/:id/packages → install package into env
|
|
1344
|
+
* - GET /cloud/environments/:id/packages/:pkgId → get installation detail
|
|
1345
|
+
* - PATCH /cloud/environments/:id/packages/:pkgId/enable → enable package
|
|
1346
|
+
* - PATCH /cloud/environments/:id/packages/:pkgId/disable → disable package
|
|
1347
|
+
* - DELETE /cloud/environments/:id/packages/:pkgId → uninstall (scope=platform forbidden)
|
|
1348
|
+
* - POST /cloud/environments/:id/packages/:pkgId/upgrade → upgrade to newer version
|
|
1260
1349
|
*
|
|
1261
1350
|
* Driver binding
|
|
1262
1351
|
* --------------
|
|
@@ -1268,11 +1357,11 @@ declare class HttpDispatcher {
|
|
|
1268
1357
|
* If `driver` is omitted, the dispatcher auto-selects the first available
|
|
1269
1358
|
* in preference order: turso → memory → any other registered driver.
|
|
1270
1359
|
*
|
|
1271
|
-
* Backed by ObjectQL
|
|
1272
|
-
*
|
|
1360
|
+
* Backed by ObjectQL sys_environment / sys_environment_credential /
|
|
1361
|
+
* sys_environment_member tables (registered by
|
|
1273
1362
|
* `@objectstack/service-tenant`'s `createTenantPlugin`).
|
|
1274
1363
|
* Physical database addressing (database_url, database_driver, etc.)
|
|
1275
|
-
* is stored directly on the
|
|
1364
|
+
* is stored directly on the sys_environment row.
|
|
1276
1365
|
*/
|
|
1277
1366
|
/**
|
|
1278
1367
|
* Resolve the calling user id from the request session, if any.
|
|
@@ -1284,7 +1373,7 @@ declare class HttpDispatcher {
|
|
|
1284
1373
|
/**
|
|
1285
1374
|
* Cascade-delete a project: cred / member / package_installation rows,
|
|
1286
1375
|
* then the physical database via the provisioning adapter, then the
|
|
1287
|
-
* `
|
|
1376
|
+
* `sys_environment` row itself. Used by both `DELETE /cloud/environments/:id`
|
|
1288
1377
|
* and the org-cascade in `DELETE /cloud/organizations/:id`.
|
|
1289
1378
|
*
|
|
1290
1379
|
* Idempotent and best-effort: missing rows / unreachable adapters
|
|
@@ -1507,10 +1596,10 @@ declare function mergeRuntimeModule(bundle: any, artifactAbsPath: string, tag?:
|
|
|
1507
1596
|
* The control plane is expected to expose two endpoints:
|
|
1508
1597
|
*
|
|
1509
1598
|
* GET {controlPlaneUrl}/api/v1/cloud/resolve-hostname?host={hostname}
|
|
1510
|
-
* → {
|
|
1599
|
+
* → { environmentId: string, organizationId?: string, runtime?: EnvironmentRuntimeConfig }
|
|
1511
1600
|
*
|
|
1512
|
-
* GET {controlPlaneUrl}/api/v1/cloud/
|
|
1513
|
-
* →
|
|
1601
|
+
* GET {controlPlaneUrl}/api/v1/cloud/environments/:environmentId/artifact
|
|
1602
|
+
* → EnvironmentArtifactResponse (EnvironmentArtifact + optional `runtime` block)
|
|
1514
1603
|
*
|
|
1515
1604
|
* Both endpoints accept an optional `Authorization: Bearer <apiKey>`.
|
|
1516
1605
|
*
|
|
@@ -1525,7 +1614,7 @@ declare function mergeRuntimeModule(bundle: any, artifactAbsPath: string, tag?:
|
|
|
1525
1614
|
* connect to (this is *not* part of the developer-authored compiled
|
|
1526
1615
|
* artifact — the control plane mints it when serving the API).
|
|
1527
1616
|
*/
|
|
1528
|
-
interface
|
|
1617
|
+
interface EnvironmentRuntimeConfig {
|
|
1529
1618
|
organizationId?: string;
|
|
1530
1619
|
hostname?: string;
|
|
1531
1620
|
/** Driver type — e.g. `sqlite`, `postgres`, `turso`, `memory`. */
|
|
@@ -1546,18 +1635,18 @@ interface ProjectRuntimeConfig {
|
|
|
1546
1635
|
* Hostname resolution response.
|
|
1547
1636
|
*/
|
|
1548
1637
|
interface ResolvedHostname {
|
|
1549
|
-
|
|
1638
|
+
environmentId: string;
|
|
1550
1639
|
organizationId?: string;
|
|
1551
1640
|
/** Optional runtime config — when present, callers can skip the artifact fetch's runtime block. */
|
|
1552
|
-
runtime?:
|
|
1641
|
+
runtime?: EnvironmentRuntimeConfig;
|
|
1553
1642
|
}
|
|
1554
1643
|
/**
|
|
1555
|
-
* Artifact response wrapping the spec's `
|
|
1644
|
+
* Artifact response wrapping the spec's `EnvironmentArtifact` envelope plus
|
|
1556
1645
|
* an optional `runtime` block carrying the project's database
|
|
1557
1646
|
* connection details.
|
|
1558
1647
|
*/
|
|
1559
|
-
interface
|
|
1560
|
-
runtime?:
|
|
1648
|
+
interface EnvironmentArtifactResponse extends EnvironmentArtifact {
|
|
1649
|
+
runtime?: EnvironmentRuntimeConfig;
|
|
1561
1650
|
}
|
|
1562
1651
|
interface ArtifactApiClientConfig {
|
|
1563
1652
|
/** Control-plane base URL (no trailing slash). */
|
|
@@ -1603,32 +1692,32 @@ declare class ArtifactApiClient {
|
|
|
1603
1692
|
* independently (the cache key includes the commit id) so the preview
|
|
1604
1693
|
* runtime can hold multiple versions in memory simultaneously.
|
|
1605
1694
|
*/
|
|
1606
|
-
fetchArtifact(
|
|
1695
|
+
fetchArtifact(environmentId: string, opts?: {
|
|
1607
1696
|
commit?: string;
|
|
1608
|
-
}): Promise<
|
|
1697
|
+
}): Promise<EnvironmentArtifactResponse | null>;
|
|
1609
1698
|
/**
|
|
1610
1699
|
* Resolve an 8-hex project short id (first 8 hex chars of the UUID,
|
|
1611
|
-
* dashes stripped) to the full
|
|
1700
|
+
* dashes stripped) to the full environmentId. Used by the preview
|
|
1612
1701
|
* runtime, which encodes project ids in subdomains.
|
|
1613
1702
|
*
|
|
1614
1703
|
* Returns `null` on 404 or ambiguity (the control plane returns 409
|
|
1615
1704
|
* if the prefix matches more than one project).
|
|
1616
1705
|
*/
|
|
1617
1706
|
lookupProjectByShortId(shortId: string): Promise<{
|
|
1618
|
-
|
|
1707
|
+
environmentId: string;
|
|
1619
1708
|
organizationId?: string;
|
|
1620
1709
|
} | null>;
|
|
1621
1710
|
/**
|
|
1622
1711
|
* Fetch the head commit of a branch. Returns the commit id (and the
|
|
1623
1712
|
* matching revision row's `published_at` for cache-validity checks).
|
|
1624
|
-
* Reuses the existing `GET /cloud/
|
|
1713
|
+
* Reuses the existing `GET /cloud/environments/:id/branches` endpoint.
|
|
1625
1714
|
*/
|
|
1626
|
-
fetchBranchHead(
|
|
1715
|
+
fetchBranchHead(environmentId: string, branchName: string): Promise<{
|
|
1627
1716
|
commitId: string;
|
|
1628
1717
|
publishedAt?: string | null;
|
|
1629
1718
|
} | null>;
|
|
1630
1719
|
/** Drop cached entries for a project (and any matching hostname). */
|
|
1631
|
-
invalidate(
|
|
1720
|
+
invalidate(environmentId: string): void;
|
|
1632
1721
|
/** Drop everything. Used on shutdown / hot-reload. */
|
|
1633
1722
|
clear(): void;
|
|
1634
1723
|
private request;
|
|
@@ -1644,9 +1733,9 @@ interface FileArtifactApiClientConfig {
|
|
|
1644
1733
|
artifactPath?: string;
|
|
1645
1734
|
/**
|
|
1646
1735
|
* Project id every hostname maps to. Defaults to
|
|
1647
|
-
* `process.env.
|
|
1736
|
+
* `process.env.OS_ENVIRONMENT_ID` or `'proj_local'`.
|
|
1648
1737
|
*/
|
|
1649
|
-
|
|
1738
|
+
environmentId?: string;
|
|
1650
1739
|
/**
|
|
1651
1740
|
* Organization id surfaced alongside the project. Defaults to
|
|
1652
1741
|
* `process.env.OS_ORGANIZATION_ID` or `'org_local'`.
|
|
@@ -1656,9 +1745,9 @@ interface FileArtifactApiClientConfig {
|
|
|
1656
1745
|
* Override runtime config. When unset, the client tries to derive
|
|
1657
1746
|
* one from the artifact's `datasources` array; if that fails it
|
|
1658
1747
|
* falls back to a local-file SQLite DB at
|
|
1659
|
-
* `<cwd>/.objectstack/data/<
|
|
1748
|
+
* `<cwd>/.objectstack/data/<environmentId>.db`.
|
|
1660
1749
|
*/
|
|
1661
|
-
runtime?:
|
|
1750
|
+
runtime?: EnvironmentRuntimeConfig;
|
|
1662
1751
|
/**
|
|
1663
1752
|
* Reload the artifact on every fetch instead of caching the first
|
|
1664
1753
|
* read. Useful when iterating on a project's metadata without
|
|
@@ -1674,7 +1763,7 @@ interface FileArtifactApiClientConfig {
|
|
|
1674
1763
|
}
|
|
1675
1764
|
declare class FileArtifactApiClient {
|
|
1676
1765
|
private readonly artifactPath;
|
|
1677
|
-
private readonly
|
|
1766
|
+
private readonly environmentId;
|
|
1678
1767
|
private readonly organizationId;
|
|
1679
1768
|
private readonly overrideRuntime?;
|
|
1680
1769
|
private readonly watch;
|
|
@@ -1682,18 +1771,18 @@ declare class FileArtifactApiClient {
|
|
|
1682
1771
|
private cached?;
|
|
1683
1772
|
constructor(config?: FileArtifactApiClientConfig);
|
|
1684
1773
|
resolveHostname(_host: string): Promise<ResolvedHostname | null>;
|
|
1685
|
-
fetchArtifact(
|
|
1774
|
+
fetchArtifact(_environmentId: string, _opts?: {
|
|
1686
1775
|
commit?: string;
|
|
1687
|
-
}): Promise<
|
|
1776
|
+
}): Promise<EnvironmentArtifactResponse | null>;
|
|
1688
1777
|
lookupProjectByShortId(_shortId: string): Promise<{
|
|
1689
|
-
|
|
1778
|
+
environmentId: string;
|
|
1690
1779
|
organizationId?: string;
|
|
1691
1780
|
} | null>;
|
|
1692
|
-
fetchBranchHead(
|
|
1781
|
+
fetchBranchHead(_environmentId: string, _branchName: string): Promise<{
|
|
1693
1782
|
commitId: string;
|
|
1694
1783
|
publishedAt?: string | null;
|
|
1695
1784
|
} | null>;
|
|
1696
|
-
invalidate(
|
|
1785
|
+
invalidate(_environmentId: string): void;
|
|
1697
1786
|
clear(): void;
|
|
1698
1787
|
private loadArtifact;
|
|
1699
1788
|
private readRuntimeFromArtifact;
|
|
@@ -1745,6 +1834,155 @@ interface ObjectOSStackResult {
|
|
|
1745
1834
|
}
|
|
1746
1835
|
declare function createObjectOSStack(config: ObjectOSStackConfig): Promise<ObjectOSStackResult>;
|
|
1747
1836
|
|
|
1837
|
+
/**
|
|
1838
|
+
* MarketplaceProxyPlugin
|
|
1839
|
+
*
|
|
1840
|
+
* Forwards `GET /api/v1/marketplace/*` from a tenant ObjectOS runtime to
|
|
1841
|
+
* the configured ObjectStack Cloud control-plane URL. The cloud endpoint
|
|
1842
|
+
* (`packages/service-cloud/src/routes/marketplace.ts`) is unauthenticated
|
|
1843
|
+
* and only exposes packages whose owner has opted in to the public catalog
|
|
1844
|
+
* (`sys_package.marketplace_listed = true`) — so the proxy passes through
|
|
1845
|
+
* without any credentials.
|
|
1846
|
+
*
|
|
1847
|
+
* Why proxy instead of direct browser → cloud:
|
|
1848
|
+
* - The Console SPA stays on the tenant origin, so no CORS configuration
|
|
1849
|
+
* is required on the cloud side.
|
|
1850
|
+
* - Local-dev `os serve` works regardless of whether the developer's
|
|
1851
|
+
* browser has cookies for cloud.objectos.app.
|
|
1852
|
+
* - Adds a single, easily auditable network seam between tenant and
|
|
1853
|
+
* control plane.
|
|
1854
|
+
*
|
|
1855
|
+
* Install is NOT proxied here. Installing a package mutates control-plane
|
|
1856
|
+
* state and requires a cloud session + active organization context — the
|
|
1857
|
+
* Console SPA performs install by opening the cloud's install dialog in a
|
|
1858
|
+
* new tab so the user authenticates against cloud directly. A future
|
|
1859
|
+
* iteration may introduce a delegated install token; until then, browse
|
|
1860
|
+
* here and install on cloud.
|
|
1861
|
+
*/
|
|
1862
|
+
|
|
1863
|
+
interface MarketplaceProxyPluginConfig {
|
|
1864
|
+
/**
|
|
1865
|
+
* Control-plane base URL (e.g. https://cloud.objectos.app). When the
|
|
1866
|
+
* caller passes nothing AND the runtime has no OS_CLOUD_URL set, the
|
|
1867
|
+
* plugin falls back to the public ObjectStack-operated cloud so that
|
|
1868
|
+
* `objectstack dev` can browse the marketplace out of the box. Set
|
|
1869
|
+
* OS_CLOUD_URL=off (or `local`) to opt out — the plugin then mounts
|
|
1870
|
+
* a stub that responds 503 and the SPA renders an empty-state
|
|
1871
|
+
* explaining marketplace is unavailable in this runtime.
|
|
1872
|
+
*/
|
|
1873
|
+
controlPlaneUrl?: string;
|
|
1874
|
+
}
|
|
1875
|
+
declare class MarketplaceProxyPlugin implements Plugin {
|
|
1876
|
+
readonly name = "com.objectstack.runtime.marketplace-proxy";
|
|
1877
|
+
readonly version = "1.0.0";
|
|
1878
|
+
private readonly cloudUrl;
|
|
1879
|
+
constructor(config?: MarketplaceProxyPluginConfig);
|
|
1880
|
+
init: (_ctx: PluginContext) => Promise<void>;
|
|
1881
|
+
start: (ctx: PluginContext) => Promise<void>;
|
|
1882
|
+
}
|
|
1883
|
+
|
|
1884
|
+
interface MarketplaceInstallLocalPluginConfig {
|
|
1885
|
+
/** Cloud control-plane base URL. When unset, falls back to OS_CLOUD_URL
|
|
1886
|
+
* and then to the public ObjectStack cloud so a fresh `objectstack dev`
|
|
1887
|
+
* can install from the marketplace without configuration. Set
|
|
1888
|
+
* OS_CLOUD_URL=off to disable (the install endpoint then returns 503). */
|
|
1889
|
+
controlPlaneUrl?: string;
|
|
1890
|
+
/** Override the on-disk cache directory. Defaults to
|
|
1891
|
+
* `<cwd>/.objectstack/installed-packages`. */
|
|
1892
|
+
storageDir?: string;
|
|
1893
|
+
}
|
|
1894
|
+
declare class MarketplaceInstallLocalPlugin implements Plugin {
|
|
1895
|
+
readonly name = "com.objectstack.runtime.marketplace-install-local";
|
|
1896
|
+
readonly version = "1.0.0";
|
|
1897
|
+
private readonly cloudUrl;
|
|
1898
|
+
private readonly storageDir;
|
|
1899
|
+
constructor(config?: MarketplaceInstallLocalPluginConfig);
|
|
1900
|
+
init: (_ctx: PluginContext) => Promise<void>;
|
|
1901
|
+
start: (ctx: PluginContext) => Promise<void>;
|
|
1902
|
+
/**
|
|
1903
|
+
* Re-register every cached manifest with the kernel's manifest service.
|
|
1904
|
+
* Safe to call on a kernel that already has the same manifest_id (the
|
|
1905
|
+
* underlying ObjectQL registry overwrites by id, but we still warn so
|
|
1906
|
+
* a developer can spot the dev-time clash between their config.ts and
|
|
1907
|
+
* a marketplace package).
|
|
1908
|
+
*/
|
|
1909
|
+
private rehydrate;
|
|
1910
|
+
private handleInstall;
|
|
1911
|
+
private handleList;
|
|
1912
|
+
private handleUninstall;
|
|
1913
|
+
/**
|
|
1914
|
+
* Detect whether `manifestId` is already known to the kernel and classify
|
|
1915
|
+
* the source so we can refuse vs upgrade gracefully.
|
|
1916
|
+
*
|
|
1917
|
+
* 'none' — fresh install
|
|
1918
|
+
* 'marketplace' — previously installed by this plugin (allow upgrade)
|
|
1919
|
+
* 'user-code' — defined by AppPlugin from objectstack.config.ts
|
|
1920
|
+
* (refuse to avoid silently overwriting authored code)
|
|
1921
|
+
*/
|
|
1922
|
+
private findConflict;
|
|
1923
|
+
/**
|
|
1924
|
+
* Pull a userId out of the request's better-auth session, if any.
|
|
1925
|
+
* Returns null when there is no signed-in user. v1 does not check
|
|
1926
|
+
* admin role — UI gating + the auth requirement is sufficient for
|
|
1927
|
+
* dev / single-tenant runtimes. Stricter checks can be layered on
|
|
1928
|
+
* via a middleware in cloud-hosted multi-tenant deployments.
|
|
1929
|
+
*/
|
|
1930
|
+
/**
|
|
1931
|
+
* Replicate the start-time side-effects that AppPlugin runs for
|
|
1932
|
+
* statically-declared apps but the `manifest` service does NOT:
|
|
1933
|
+
*
|
|
1934
|
+
* 1. Load `manifest.translations` (array of `Record<locale, data>`)
|
|
1935
|
+
* into the i18n service — auto-creating an in-memory fallback if
|
|
1936
|
+
* none is registered, matching AppPlugin's behaviour.
|
|
1937
|
+
*
|
|
1938
|
+
* 2. Merge `manifest.data` (an array of seed datasets) into the
|
|
1939
|
+
* kernel's `seed-datasets` service so SecurityPlugin's per-org
|
|
1940
|
+
* replay middleware picks them up on every future
|
|
1941
|
+
* sys_organization insert.
|
|
1942
|
+
*
|
|
1943
|
+
* 3. When `seedNow=true`, also run the seed immediately so the user
|
|
1944
|
+
* sees demo data without having to create a new org:
|
|
1945
|
+
* • single-tenant: run SeedLoaderService inline (mirrors
|
|
1946
|
+
* AppPlugin single-tenant branch)
|
|
1947
|
+
* • multi-tenant: invoke `seed-replayer` for the caller's
|
|
1948
|
+
* active org (resolved from the request session)
|
|
1949
|
+
*
|
|
1950
|
+
* Errors are logged but never thrown — install succeeds even if
|
|
1951
|
+
* post-register side-effects partially fail (the manifest itself is
|
|
1952
|
+
* already registered + cached). Returns a small summary for the
|
|
1953
|
+
* response envelope.
|
|
1954
|
+
*/
|
|
1955
|
+
private applySideEffects;
|
|
1956
|
+
/**
|
|
1957
|
+
* Best-effort active-org resolution. Reads the better-auth session
|
|
1958
|
+
* (same path as requireAuthenticatedUser) and returns
|
|
1959
|
+
* `session.activeOrganizationId`, falling back to the user's first
|
|
1960
|
+
* org membership.
|
|
1961
|
+
*/
|
|
1962
|
+
private resolveActiveOrgId;
|
|
1963
|
+
private requireAuthenticatedUser;
|
|
1964
|
+
private readAll;
|
|
1965
|
+
}
|
|
1966
|
+
|
|
1967
|
+
/**
|
|
1968
|
+
* Shared marketplace / cloud control-plane defaults.
|
|
1969
|
+
*
|
|
1970
|
+
* Centralised so every plugin + the CLI auto-inject path agree on
|
|
1971
|
+
* "what cloud URL do we mean when the user didn't set OS_CLOUD_URL?".
|
|
1972
|
+
* Until we have a competing public hosted cloud, this points at the
|
|
1973
|
+
* ObjectStack-operated control plane so a vanilla `objectstack dev` can
|
|
1974
|
+
* browse the marketplace out of the box.
|
|
1975
|
+
*/
|
|
1976
|
+
declare const DEFAULT_CLOUD_URL = "https://cloud.objectos.app";
|
|
1977
|
+
/**
|
|
1978
|
+
* Resolve the effective control-plane URL from an explicit constructor
|
|
1979
|
+
* value, the OS_CLOUD_URL env var, or the default. Returns an empty
|
|
1980
|
+
* string when the caller explicitly disabled cloud with
|
|
1981
|
+
* `OS_CLOUD_URL=off` / `local` — callers should treat that as
|
|
1982
|
+
* "marketplace unavailable on this runtime".
|
|
1983
|
+
*/
|
|
1984
|
+
declare function resolveCloudUrl(explicit?: string | null): string;
|
|
1985
|
+
|
|
1748
1986
|
/**
|
|
1749
1987
|
* Per-project driver registry contract.
|
|
1750
1988
|
*
|
|
@@ -1764,22 +2002,22 @@ type IDataDriver$1 = Contracts.IDataDriver;
|
|
|
1764
2002
|
interface EnvironmentDriverRegistry {
|
|
1765
2003
|
/** Resolve a project by hostname. Returns `null` when unknown. */
|
|
1766
2004
|
resolveByHostname(host: string): Promise<{
|
|
1767
|
-
|
|
2005
|
+
environmentId: string;
|
|
1768
2006
|
driver: IDataDriver$1;
|
|
1769
2007
|
} | null>;
|
|
1770
2008
|
/** Resolve a project's driver by ID. Returns `null` when unknown. */
|
|
1771
|
-
resolveById(
|
|
2009
|
+
resolveById(environmentId: string): Promise<IDataDriver$1 | null>;
|
|
1772
2010
|
/**
|
|
1773
2011
|
* Look up the cached project row + driver by ID without triggering a
|
|
1774
2012
|
* remote/file fetch. Returns the full cached entry when fresh.
|
|
1775
2013
|
*/
|
|
1776
|
-
peekById(
|
|
1777
|
-
|
|
2014
|
+
peekById(environmentId: string): {
|
|
2015
|
+
environmentId: string;
|
|
1778
2016
|
driver: IDataDriver$1;
|
|
1779
2017
|
project: any;
|
|
1780
2018
|
} | null;
|
|
1781
2019
|
/** Drop cached entries for the given project. */
|
|
1782
|
-
invalidate(
|
|
2020
|
+
invalidate(environmentId: string): void;
|
|
1783
2021
|
}
|
|
1784
2022
|
|
|
1785
2023
|
/**
|
|
@@ -1788,11 +2026,11 @@ interface EnvironmentDriverRegistry {
|
|
|
1788
2026
|
*
|
|
1789
2027
|
* Mirrors {@link DefaultEnvironmentDriverRegistry} from `environment-registry.ts`
|
|
1790
2028
|
* but does **not** read from a local control-plane database. Hostname →
|
|
1791
|
-
*
|
|
2029
|
+
* environmentId resolution and per-project runtime config (database URL /
|
|
1792
2030
|
* driver) come from the control plane API.
|
|
1793
2031
|
*
|
|
1794
2032
|
* The cached `project` payload exposed by `peekById()` is shaped to look
|
|
1795
|
-
* like a `
|
|
2033
|
+
* like a `sys_environment` row so callers downstream (notably
|
|
1796
2034
|
* `ArtifactKernelFactory`) can read `id`, `organization_id`,
|
|
1797
2035
|
* `database_url` and `database_driver` without branching.
|
|
1798
2036
|
*/
|
|
@@ -1818,16 +2056,16 @@ declare class ArtifactEnvironmentRegistry implements EnvironmentDriverRegistry {
|
|
|
1818
2056
|
private readonly pending;
|
|
1819
2057
|
constructor(config: ArtifactEnvironmentRegistryConfig);
|
|
1820
2058
|
resolveByHostname(host: string): Promise<{
|
|
1821
|
-
|
|
2059
|
+
environmentId: string;
|
|
1822
2060
|
driver: IDataDriver;
|
|
1823
2061
|
} | null>;
|
|
1824
|
-
resolveById(
|
|
1825
|
-
peekById(
|
|
1826
|
-
|
|
2062
|
+
resolveById(environmentId: string): Promise<IDataDriver | null>;
|
|
2063
|
+
peekById(environmentId: string): {
|
|
2064
|
+
environmentId: string;
|
|
1827
2065
|
driver: IDataDriver;
|
|
1828
2066
|
project: any;
|
|
1829
2067
|
} | null;
|
|
1830
|
-
invalidate(
|
|
2068
|
+
invalidate(environmentId: string): void;
|
|
1831
2069
|
private buildCacheEntry;
|
|
1832
2070
|
}
|
|
1833
2071
|
|
|
@@ -1844,19 +2082,19 @@ interface ArtifactKernelFactoryConfig {
|
|
|
1844
2082
|
kernelConfig?: ConstructorParameters<typeof ObjectKernel>[0];
|
|
1845
2083
|
/**
|
|
1846
2084
|
* Base secret used to derive per-project AuthPlugin secrets via
|
|
1847
|
-
* HKDF-style HMAC-SHA256(baseSecret,
|
|
2085
|
+
* HKDF-style HMAC-SHA256(baseSecret, environmentId). Falls back to
|
|
1848
2086
|
* `process.env.OS_AUTH_SECRET` / `AUTH_SECRET` at construction time.
|
|
1849
2087
|
*/
|
|
1850
2088
|
authBaseSecret?: string;
|
|
1851
2089
|
}
|
|
1852
|
-
declare class ArtifactKernelFactory implements
|
|
2090
|
+
declare class ArtifactKernelFactory implements EnvironmentKernelFactory {
|
|
1853
2091
|
private readonly client;
|
|
1854
2092
|
private readonly envRegistry;
|
|
1855
2093
|
private readonly logger;
|
|
1856
2094
|
private readonly kernelConfig?;
|
|
1857
2095
|
private readonly authBaseSecret;
|
|
1858
2096
|
constructor(config: ArtifactKernelFactoryConfig);
|
|
1859
|
-
create(
|
|
2097
|
+
create(environmentId: string): Promise<ObjectKernel>;
|
|
1860
2098
|
}
|
|
1861
2099
|
|
|
1862
2100
|
/**
|
|
@@ -1902,10 +2140,10 @@ declare const PLATFORM_SSO_PROVIDER_ID = "objectstack-cloud";
|
|
|
1902
2140
|
* Derive the per-project OAuth client_id used in `sys_oauth_application`
|
|
1903
2141
|
* (cloud side) and {@link genericOAuth} config (project side).
|
|
1904
2142
|
*/
|
|
1905
|
-
declare function derivePlatformSsoClientId(
|
|
2143
|
+
declare function derivePlatformSsoClientId(environmentId: string): string;
|
|
1906
2144
|
/**
|
|
1907
2145
|
* Derive the per-project OAuth client_secret deterministically from the
|
|
1908
|
-
* shared master secret. HMAC-SHA256(baseSecret, 'oauth-client:' +
|
|
2146
|
+
* shared master secret. HMAC-SHA256(baseSecret, 'oauth-client:' + environmentId)
|
|
1909
2147
|
* yields a 64-char hex string that is:
|
|
1910
2148
|
* - stable across container cold-starts (no DB lookup needed)
|
|
1911
2149
|
* - independent per project (compromising one does not compromise others)
|
|
@@ -1917,7 +2155,7 @@ declare function derivePlatformSsoClientId(projectId: string): string;
|
|
|
1917
2155
|
* defaults to `storeClientSecret: 'hashed'` (SHA-256 + base64url) when the JWT
|
|
1918
2156
|
* plugin is enabled, and looks up the row by hashing the presented secret.
|
|
1919
2157
|
*/
|
|
1920
|
-
declare function derivePlatformSsoClientSecret(baseSecret: string,
|
|
2158
|
+
declare function derivePlatformSsoClientSecret(baseSecret: string, environmentId: string): string;
|
|
1921
2159
|
/**
|
|
1922
2160
|
* Build the redirect_uri better-auth's `genericOAuth` plugin will use
|
|
1923
2161
|
* when the project kernel mounts the provider with id
|
|
@@ -1939,7 +2177,7 @@ interface SeedPlatformSsoClientOptions {
|
|
|
1939
2177
|
update: (object: string, data: any, where: any, opts?: any) => Promise<any>;
|
|
1940
2178
|
};
|
|
1941
2179
|
/** Project id (also used to derive client_id + client_secret). */
|
|
1942
|
-
|
|
2180
|
+
environmentId: string;
|
|
1943
2181
|
/**
|
|
1944
2182
|
* Project hostname (e.g. `acme-crm.objectos.app`). Optional — projects
|
|
1945
2183
|
* may be created before a hostname is assigned, in which case no
|
|
@@ -1962,7 +2200,7 @@ interface SeedPlatformSsoClientOptions {
|
|
|
1962
2200
|
}
|
|
1963
2201
|
/**
|
|
1964
2202
|
* Idempotently upsert a `sys_oauth_application` row for the given project.
|
|
1965
|
-
* Re-running with the same `
|
|
2203
|
+
* Re-running with the same `environmentId` is a no-op (the deterministic
|
|
1966
2204
|
* `client_id` is uniquely indexed and the secret derivation is stable).
|
|
1967
2205
|
* Re-running with a new `hostname` adds the new redirect_uri to the
|
|
1968
2206
|
* existing row's JSON array.
|
|
@@ -1980,7 +2218,7 @@ interface BackfillPlatformSsoClientsOptions {
|
|
|
1980
2218
|
limit?: number;
|
|
1981
2219
|
}
|
|
1982
2220
|
/**
|
|
1983
|
-
* Scan `
|
|
2221
|
+
* Scan `sys_environment` and ensure every active project has a corresponding
|
|
1984
2222
|
* `sys_oauth_application` row. Intended to run once at cloud boot — the
|
|
1985
2223
|
* happy path is dominated by the project-create hook
|
|
1986
2224
|
* ({@link seedPlatformSsoClient}); the backfill exists so projects
|
|
@@ -1992,7 +2230,7 @@ declare function backfillPlatformSsoClients(opts: BackfillPlatformSsoClientsOpti
|
|
|
1992
2230
|
seeded: number;
|
|
1993
2231
|
alreadyExisted: number;
|
|
1994
2232
|
failures: Array<{
|
|
1995
|
-
|
|
2233
|
+
environmentId: string;
|
|
1996
2234
|
error: string;
|
|
1997
2235
|
}>;
|
|
1998
2236
|
}>;
|
|
@@ -2227,4 +2465,4 @@ declare function actionBodyRunnerFactory(runner: ScriptRunner, opts: FactoryOpti
|
|
|
2227
2465
|
timeoutMs?: number;
|
|
2228
2466
|
}) => ((actionCtx: any) => Promise<unknown>) | undefined;
|
|
2229
2467
|
|
|
2230
|
-
export { AppPlugin, ArtifactApiClient, type ArtifactApiClientConfig, ArtifactEnvironmentRegistry, type ArtifactEnvironmentRegistryConfig, ArtifactKernelFactory, type ArtifactKernelFactoryConfig, AuthProxyPlugin, type BackfillPlatformSsoClientsOptions, DEFAULT_RATE_LIMITS, type DefaultHostConfigOptions, type DefaultHostConfigResult, type DispatcherPluginConfig, DriverPlugin, type EnvironmentDriverRegistry, FileArtifactApiClient, type FileArtifactApiClientConfig, HttpDispatcher, type HttpDispatcherResult, type HttpProtocolContext, HttpServer, KernelManager, type KernelManagerConfig, type LoadArtifactBundleOptions,
|
|
2468
|
+
export { AppPlugin, ArtifactApiClient, type ArtifactApiClientConfig, ArtifactEnvironmentRegistry, type ArtifactEnvironmentRegistryConfig, ArtifactKernelFactory, type ArtifactKernelFactoryConfig, AuthProxyPlugin, type BackfillPlatformSsoClientsOptions, DEFAULT_CLOUD_URL, DEFAULT_RATE_LIMITS, type DefaultHostConfigOptions, type DefaultHostConfigResult, type DispatcherPluginConfig, DriverPlugin, type EnvironmentArtifactResponse, type EnvironmentDriverRegistry, type EnvironmentKernelFactory, type EnvironmentRuntimeConfig, FileArtifactApiClient, type FileArtifactApiClientConfig, HttpDispatcher, type HttpDispatcherResult, type HttpProtocolContext, HttpServer, KernelManager, type KernelManagerConfig, type LoadArtifactBundleOptions, MarketplaceInstallLocalPlugin, type MarketplaceInstallLocalPluginConfig, MarketplaceProxyPlugin, type MarketplaceProxyPluginConfig, MiddlewareManager, type ObjectOSStackConfig, type ObjectOSStackResult, ObservabilityServicePlugin, type ObservabilityServicePluginOptions, PLATFORM_SSO_PROVIDER_ID, QuickJSScriptRunner, type QuickJSScriptRunnerOptions, type RateLimitBucketConfig, type RateLimitDecision, type RateLimitDefaults, type RateLimitStore, RateLimiter, type ResolvedHostname, Runtime, type RuntimeConfig, SYSTEM_ENVIRONMENT_ID, SandboxError, type ScriptContext, type ScriptOrigin, type ScriptResult, type ScriptRunOptions, type ScriptRunner, type SecurityHeadersOptions, SeedLoaderService, type SeedPlatformSsoClientOptions, type StandaloneStackConfig, type StandaloneStackResult, type SystemEnvironmentPluginConfig, type TraceContext, UnimplementedScriptRunner, actionBodyRunnerFactory, backfillPlatformSsoClients, buildPlatformSsoRedirectUri, buildSecurityHeaders, collectBundleActions, collectBundleFunctions, collectBundleHooks, createDefaultHostConfig, createDispatcherPlugin, createObjectOSStack, createStandaloneStack, createSystemEnvironmentPlugin, derivePlatformSsoClientId, derivePlatformSsoClientSecret, extractRequestId, formatTraceparent, generateRequestId, hookBodyRunnerFactory, isHttpUrl, loadArtifactBundle, mergeRuntimeModule, parseTraceparent, readArtifactSource, resolveCloudUrl, resolveDefaultArtifactPath, resolveErrorReporter, resolveMetrics, resolveRequestId, seedPlatformSsoClient };
|