@almadar/shell-node 0.0.0-stage → 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/OrbitalServerRuntime.d.ts +694 -0
- package/dist/OrbitalServerRuntime.js +3 -0
- package/dist/chunk-23YAOI6P.js +42 -0
- package/dist/chunk-A2TIXOLJ.js +1326 -0
- package/dist/chunk-BJA6GYC5.js +2219 -0
- package/dist/chunk-BWMLDDCL.js +21 -0
- package/dist/chunk-QYAPNUBH.js +598 -0
- package/dist/chunk-UBZT5LDW.js +63 -0
- package/dist/chunk-WZFQ7T7V.js +18 -0
- package/dist/createProgramHandlers.d.ts +28 -0
- package/dist/createProgramHandlers.js +6 -0
- package/dist/index.d.ts +265 -0
- package/dist/index.js +217 -0
- package/dist/kernel-loader-24KWM5C7.js +1 -0
- package/dist/kernel-workspace-host-CU56iOlt.d.ts +135 -0
- package/dist/kernelWorkspace.d.ts +3 -0
- package/dist/kernelWorkspace.js +4 -0
- package/dist/program-35OTIG6Y.js +2 -0
- package/package.json +62 -3
- package/README.md +0 -3
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import { createRequire } from 'module';
|
|
2
|
+
import { readFileSync } from 'fs';
|
|
3
|
+
import { join } from 'path';
|
|
4
|
+
import { pathToFileURL } from 'url';
|
|
5
|
+
import { installKernelEvaluator } from '@almadar/core';
|
|
6
|
+
import { readLanguageBundle } from '@almadar/core/language-data';
|
|
7
|
+
import * as installedModule from '@almadar/kernel';
|
|
8
|
+
import { NativeMemoryPersistenceAdapter } from '@almadar/shell-runtime';
|
|
9
|
+
|
|
10
|
+
// src/kernel-loader.ts
|
|
11
|
+
function hasMemoryStore(kernel) {
|
|
12
|
+
return "MemoryStore" in kernel;
|
|
13
|
+
}
|
|
14
|
+
function nativeMemoryOf(kernel) {
|
|
15
|
+
if (!hasMemoryStore(kernel)) throw new Error("this kernel module exports no MemoryStore; install a kernel build that carries it");
|
|
16
|
+
return new NativeMemoryPersistenceAdapter(new kernel.MemoryStore());
|
|
17
|
+
}
|
|
18
|
+
async function loadKernelModule(kernelDir, options) {
|
|
19
|
+
return loadKernel(kernelDir, options);
|
|
20
|
+
}
|
|
21
|
+
var initialised = /* @__PURE__ */ new WeakSet();
|
|
22
|
+
function initOnce(loaded, wasm, languageFrom) {
|
|
23
|
+
if (initialised.has(loaded)) return loaded;
|
|
24
|
+
if (wasm !== void 0) loaded.initSync({ module: wasm });
|
|
25
|
+
loaded.installLanguage(JSON.stringify(readLanguageBundle(languageFrom)));
|
|
26
|
+
installKernelEvaluator(loaded);
|
|
27
|
+
initialised.add(loaded);
|
|
28
|
+
return loaded;
|
|
29
|
+
}
|
|
30
|
+
function initKernelSync(languageFrom) {
|
|
31
|
+
initOnce(installedModule, readFileSync(createRequire(import.meta.url).resolve("@almadar/kernel/kernel.wasm")), languageFrom);
|
|
32
|
+
return installedModule;
|
|
33
|
+
}
|
|
34
|
+
async function loadInstalledKernel(languageFrom) {
|
|
35
|
+
return initKernelSync(languageFrom);
|
|
36
|
+
}
|
|
37
|
+
async function loadHttpKernel(kernelDir, options) {
|
|
38
|
+
return loadKernel(kernelDir, options);
|
|
39
|
+
}
|
|
40
|
+
async function loadKernel(kernelDir, options) {
|
|
41
|
+
const loaded = await import(pathToFileURL(join(kernelDir, "pkg/orbital_wasm.js")).href);
|
|
42
|
+
return initOnce(loaded, initialised.has(loaded) ? void 0 : readFileSync(join(kernelDir, "pkg/orbital_wasm_bg.wasm")), options.languageFrom);
|
|
43
|
+
}
|
|
44
|
+
var NATIVE_PLATFORMS = {
|
|
45
|
+
"darwin-x64": "darwin-x64",
|
|
46
|
+
"darwin-arm64": "darwin-arm64",
|
|
47
|
+
"linux-x64": "linux-x64",
|
|
48
|
+
"linux-arm64": "linux-arm64",
|
|
49
|
+
"win32-x64": "windows-x64"
|
|
50
|
+
};
|
|
51
|
+
function resolveNativeAddon(from) {
|
|
52
|
+
const named = process.env.ALMADAR_KERNEL_NODE;
|
|
53
|
+
if (named !== void 0 && named !== "") return named;
|
|
54
|
+
const platform = NATIVE_PLATFORMS[`${process.platform}-${process.arch}`];
|
|
55
|
+
if (platform === void 0) throw new Error(`no native kernel add-on is shipped for ${process.platform}-${process.arch}`);
|
|
56
|
+
return createRequire(join(from, "resolve.js")).resolve(`@almadar/orb-${platform}/kernel.node`);
|
|
57
|
+
}
|
|
58
|
+
async function loadNativeKernelModule(addonPath, options) {
|
|
59
|
+
const loaded = createRequire(import.meta.url)(addonPath);
|
|
60
|
+
return initOnce(loaded, void 0, options.languageFrom);
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
export { initKernelSync, loadHttpKernel, loadInstalledKernel, loadKernelModule, loadNativeKernelModule, nativeMemoryOf, resolveNativeAddon };
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { workspacesRoot, kernelWorkspaceHost, workspaceBucketFromEnv } from './chunk-BJA6GYC5.js';
|
|
2
|
+
import { runProgramEffect } from './chunk-QYAPNUBH.js';
|
|
3
|
+
import { installedWorkspaceHost, installWorkspaceHost } from './chunk-BWMLDDCL.js';
|
|
4
|
+
|
|
5
|
+
// src/program/createProgramHandlers.ts
|
|
6
|
+
var bucketOf = () => {
|
|
7
|
+
const bucket = workspaceBucketFromEnv(process.env);
|
|
8
|
+
return bucket === void 0 ? {} : { bucket };
|
|
9
|
+
};
|
|
10
|
+
function createProgramHandlers(host) {
|
|
11
|
+
const opts = host.orbBin === void 0 ? { cwd: host.cwd } : { cwd: host.cwd, orbBin: host.orbBin };
|
|
12
|
+
if (installedWorkspaceHost()?.root !== workspacesRoot(host.cwd)) {
|
|
13
|
+
installWorkspaceHost(kernelWorkspaceHost({ projectRoot: host.cwd, ...bucketOf(), ...host.orbBin !== void 0 ? { orb: host.orbBin } : {} }));
|
|
14
|
+
}
|
|
15
|
+
return { programEffect: (op, args, context) => runProgramEffect(op, args, opts, context) };
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export { createProgramHandlers };
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { EffectHandlers } from '@almadar/shell-runtime';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Program host handlers — server-side only.
|
|
5
|
+
*
|
|
6
|
+
* Backs the language trio's effects (behavior/catalog|describe|source,
|
|
7
|
+
* program/read|print|eval) with the one host implementation in
|
|
8
|
+
* `host/program`, which runs the installed `orb` from the
|
|
9
|
+
* project directory. Its workspaces are `std-workspace` run by the kernel
|
|
10
|
+
* (`kernelWorkspaceHost`). Wired by OrbitalServerRuntime
|
|
11
|
+
* (lazy import, merged under user handlers).
|
|
12
|
+
*
|
|
13
|
+
* NOT exported from the main index.ts because it spawns processes.
|
|
14
|
+
*
|
|
15
|
+
* @packageDocumentation
|
|
16
|
+
*/
|
|
17
|
+
|
|
18
|
+
interface ProgramHostConfig {
|
|
19
|
+
/** Project root `orb` resolves behavior packages from. */
|
|
20
|
+
cwd: string;
|
|
21
|
+
/** Explicit `orb` binary; defaults to the host's resolution order. */
|
|
22
|
+
orbBin?: string;
|
|
23
|
+
}
|
|
24
|
+
type ProgramHandlers = Pick<EffectHandlers, 'programEffect'>;
|
|
25
|
+
declare function createProgramHandlers(host: ProgramHostConfig): ProgramHandlers;
|
|
26
|
+
|
|
27
|
+
export { createProgramHandlers };
|
|
28
|
+
export type { ProgramHandlers, ProgramHostConfig };
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,265 @@
|
|
|
1
|
+
import { PinnedFetch, CredentialScopeStorage, NetPort, ResolvedHost, OsAnchors, OsGrantPort, OsHostPort, KernelModule, HttpKernel, CredentialSeedKernel, NativeMemoryPersistenceAdapter, ServiceCallContext, StepRequest, PlayedStep, ProgramValidationReport, ProgramEffectName, ProgramEffectOutcome } from '@almadar/shell-runtime';
|
|
2
|
+
import { JsonValue, KernelMemoryStoreExports, OrbitalSchema, EvaluatedProgram, ProgramValidationIssue, CatalogScope, CatalogEntry, DependencyGraph, TraitValue, TraitDescription, DescribeTarget, BehaviorDescription, BehaviorRef, BehaviorValueMountResult, TraitValueMountResult } from '@almadar/core';
|
|
3
|
+
export { ClientEffectTuple, ClientNavigateBackTuple, ClientNavigateTuple, ClientRenderUITuple, OrbitalEventRequest, OrbitalEventResponse, TransitionRejection } from '@almadar/core';
|
|
4
|
+
import * as installedModule from '@almadar/kernel';
|
|
5
|
+
import { LayoutStrategy } from '@almadar/core/builders';
|
|
6
|
+
export { G as GCS_ENDPOINT, K as KernelProgram, a as KernelProgramOptions, b as KernelWorkspaceBucket, c as KernelWorkspaceHostOptions, P as ProgramRun, W as WORKSPACE_HMAC_KEY_ID, d as WORKSPACE_HMAC_SECRET, e as WorkspaceHost, f as WorkspacePort, g as emitPayload, i as installWorkspaceHost, h as installedWorkspaceHost, k as kernelWorkspaceHost, r as resolveKernelDir, j as resolveProgramFile, u as uninstallWorkspaceHost, w as workspaceBucketFromEnv, l as workspaceOwnerSegment, m as workspacesRoot } from './kernel-workspace-host-CU56iOlt.js';
|
|
7
|
+
export { HostDispatchItem, LiveBroadcastItem, LoaderConfig, OrbitalInfo, OrbitalServerRuntime, OrbitalServerRuntimeConfig, OrbitalSummary, PushItem, RegisterOptions, RegisteredOrbital, RuntimeOrbital, RuntimeOrbitalSchema, RuntimeTrait, RuntimeTraitTick, UnresolvedProgramError, createOrbitalServerRuntime } from './OrbitalServerRuntime.js';
|
|
8
|
+
export { ProgramHandlers, ProgramHostConfig, createProgramHandlers } from './createProgramHandlers.js';
|
|
9
|
+
|
|
10
|
+
declare const pinnedFetchNode: PinnedFetch;
|
|
11
|
+
|
|
12
|
+
declare function resolveHostNode(host: string): Promise<ResolvedHost>;
|
|
13
|
+
declare const nodeNetPort: NetPort;
|
|
14
|
+
declare function nodeCredentialScope(): CredentialScopeStorage;
|
|
15
|
+
/** Install the Node ports `@almadar/shell-runtime` leaves open: the pinned `http` fetch + resolver and per-tenant credential scopes. Idempotent. */
|
|
16
|
+
declare function installNodeHostPorts(): void;
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* A development host's credential-store master key: read from `<dir>/dev-credential-master-key`,
|
|
20
|
+
* generated there (owner-only) on first use. Production must hold its key in the platform secret
|
|
21
|
+
* store, so this refuses under NODE_ENV=production.
|
|
22
|
+
*/
|
|
23
|
+
declare function loadOrCreateDevMasterKey(dir: string): string;
|
|
24
|
+
|
|
25
|
+
/** One program instance's `os` host: its own handle tables, closed by `close`. */
|
|
26
|
+
interface NodeOsHostOptions {
|
|
27
|
+
/** Where `~/` and `./` and the declared grant anchors are placed; absent, the process's own (`OsAnchors::of_process`). */
|
|
28
|
+
anchors?: OsAnchors;
|
|
29
|
+
}
|
|
30
|
+
/** The process's home, working directory, executable directory and environment, read once (`OsAnchors::of_process`). */
|
|
31
|
+
declare function processAnchors(): OsAnchors;
|
|
32
|
+
declare function createNodeOsHost(grants: OsGrantPort, options?: NodeOsHostOptions): OsHostPort;
|
|
33
|
+
|
|
34
|
+
type KvErrorKind = 'denied' | 'invalid' | 'io' | 'timeout' | 'unsupported' | 'closed';
|
|
35
|
+
type KvResult<T> = {
|
|
36
|
+
ok: true;
|
|
37
|
+
value: T;
|
|
38
|
+
} | {
|
|
39
|
+
ok: false;
|
|
40
|
+
error: string;
|
|
41
|
+
kind: KvErrorKind;
|
|
42
|
+
};
|
|
43
|
+
interface KvNamespace {
|
|
44
|
+
app: string;
|
|
45
|
+
locale: string;
|
|
46
|
+
store: string;
|
|
47
|
+
}
|
|
48
|
+
interface KvScanEntry {
|
|
49
|
+
key: string;
|
|
50
|
+
value: JsonValue;
|
|
51
|
+
}
|
|
52
|
+
type KvBatchOp = {
|
|
53
|
+
kind: 'put';
|
|
54
|
+
key: string;
|
|
55
|
+
value: JsonValue;
|
|
56
|
+
} | {
|
|
57
|
+
kind: 'delete';
|
|
58
|
+
key: string;
|
|
59
|
+
};
|
|
60
|
+
declare class KvFailure extends Error {
|
|
61
|
+
readonly kind: KvErrorKind;
|
|
62
|
+
constructor(kind: KvErrorKind, message: string);
|
|
63
|
+
}
|
|
64
|
+
/** A namespace's whole content, key order = UTF-8 byte order. Backends load and commit it whole. */
|
|
65
|
+
type KvTable = Map<string, JsonValue>;
|
|
66
|
+
interface KvBackend {
|
|
67
|
+
load(ns: KvNamespace): Promise<KvTable>;
|
|
68
|
+
/** Replace the namespace content atomically: a failure leaves the previous content. */
|
|
69
|
+
commit(ns: KvNamespace, table: KvTable): Promise<void>;
|
|
70
|
+
}
|
|
71
|
+
declare function namespaceId(ns: KvNamespace): string;
|
|
72
|
+
declare function memoryKvBackend(): KvBackend;
|
|
73
|
+
declare function directoryKvBackend(stateDir: string): KvBackend;
|
|
74
|
+
interface KvHost {
|
|
75
|
+
get(ns: KvNamespace, key: string): Promise<KvResult<{
|
|
76
|
+
found: boolean;
|
|
77
|
+
value?: JsonValue;
|
|
78
|
+
}>>;
|
|
79
|
+
put(ns: KvNamespace, key: string, value: JsonValue): Promise<KvResult<{
|
|
80
|
+
storedKey: string;
|
|
81
|
+
}>>;
|
|
82
|
+
delete(ns: KvNamespace, key: string): Promise<KvResult<{
|
|
83
|
+
existed: boolean;
|
|
84
|
+
}>>;
|
|
85
|
+
scan(ns: KvNamespace, prefix: string, limit?: number): Promise<KvResult<{
|
|
86
|
+
entries: KvScanEntry[];
|
|
87
|
+
}>>;
|
|
88
|
+
batch(ns: KvNamespace, ops: readonly KvBatchOp[]): Promise<KvResult<{
|
|
89
|
+
applied: number;
|
|
90
|
+
}>>;
|
|
91
|
+
}
|
|
92
|
+
declare function createKvHost(backend: KvBackend): KvHost;
|
|
93
|
+
|
|
94
|
+
/** The whole server kernel as Node loads it: the shared module plus the server-only exports the client build omits. */
|
|
95
|
+
interface LoadedKernel extends KernelModule, HttpKernel, CredentialSeedKernel, KernelMemoryStoreExports {
|
|
96
|
+
initSync(input: {
|
|
97
|
+
module: Uint8Array;
|
|
98
|
+
}): object;
|
|
99
|
+
}
|
|
100
|
+
/** A row store the kernel itself holds (its `MemoryStore`), as a host keeps rows with no database. */
|
|
101
|
+
declare function nativeMemoryOf(kernel: KernelModule): NativeMemoryPersistenceAdapter;
|
|
102
|
+
interface LoadKernelOptions {
|
|
103
|
+
/** Where the installed `@almadar/core` and `@almadar/std` are found, node-style. Required: the caller names its own root. */
|
|
104
|
+
languageFrom: string;
|
|
105
|
+
}
|
|
106
|
+
/**
|
|
107
|
+
* Loads the kernel and installs the language data the installed packages declare (the operator table that
|
|
108
|
+
* routes `program/*` and the other host effects), as `orb` reads it. The first install in a process wins.
|
|
109
|
+
*/
|
|
110
|
+
declare function loadKernelModule(kernelDir: string, options: LoadKernelOptions): Promise<LoadedKernel>;
|
|
111
|
+
/**
|
|
112
|
+
* The kernel of the `@almadar/kernel` package this host installs, initialised synchronously with the language data
|
|
113
|
+
* the packages under `languageFrom` declare. `languageFrom` is required; the first call in a process wins.
|
|
114
|
+
*/
|
|
115
|
+
declare function initKernelSync(languageFrom: string): typeof installedModule;
|
|
116
|
+
/**
|
|
117
|
+
* The kernel of the `@almadar/kernel` package this host installs, loaded once per process with the language data
|
|
118
|
+
* the packages under `languageFrom` declare. A host with no package installed rejects, never falls back.
|
|
119
|
+
*/
|
|
120
|
+
declare function loadInstalledKernel(languageFrom: string): Promise<LoadedKernel>;
|
|
121
|
+
/**
|
|
122
|
+
* The `http` effect's builder exports of the same package (`buildHttpRequest`, `isPublicAddress`, …): the
|
|
123
|
+
* interpreter's only way to build a request. A directory that does not hold a built kernel rejects, never falls back.
|
|
124
|
+
*/
|
|
125
|
+
declare function loadHttpKernel(kernelDir: string, options: LoadKernelOptions): Promise<HttpKernel>;
|
|
126
|
+
/**
|
|
127
|
+
* Where the native kernel add-on is: `ALMADAR_KERNEL_NODE`, else `kernel.node` in the `@almadar/orb-<platform>-<arch>`
|
|
128
|
+
* package this platform installs. Rejects when neither exists, so a host can fall back to the wasm kernel by choice.
|
|
129
|
+
*/
|
|
130
|
+
declare function resolveNativeAddon(from: string): string;
|
|
131
|
+
/**
|
|
132
|
+
* Loads the native kernel add-on (the same API as the wasm module, run as machine code) and installs the language data
|
|
133
|
+
* the installed packages declare. The first install in a process wins.
|
|
134
|
+
*/
|
|
135
|
+
declare function loadNativeKernelModule(addonPath: string, options: LoadKernelOptions): Promise<LoadedKernel>;
|
|
136
|
+
|
|
137
|
+
/**
|
|
138
|
+
* The host side of the language trio's server effects (`behavior/catalog`,
|
|
139
|
+
* `behavior/describe`, `behavior/source`, `behavior/resolve`, `behavior/dependencies`, `program/read|print|eval`): a thin
|
|
140
|
+
* caller that runs the installed `orb` from the project directory and parses its
|
|
141
|
+
* JSON. All behavior resolution, reflection, printing and validation is `orb`'s;
|
|
142
|
+
* nothing here re-implements it. Both execution paths (the interpreter's effect
|
|
143
|
+
* executor and the compiled server host) call this module.
|
|
144
|
+
*
|
|
145
|
+
* @packageDocumentation
|
|
146
|
+
*/
|
|
147
|
+
|
|
148
|
+
/** Where the host runs `orb`: the project (workspace) root, so installed behavior packages resolve. */
|
|
149
|
+
interface ProgramHostOptions {
|
|
150
|
+
readonly cwd: string;
|
|
151
|
+
/** Explicit `orb` binary; defaults to {@link resolveOrbBinary}. */
|
|
152
|
+
readonly orbBin?: string;
|
|
153
|
+
}
|
|
154
|
+
/** `behavior/catalog`: installed behaviors under registry folders; `vectors: false` omits the vectors (`--no-vectors`). */
|
|
155
|
+
declare function behaviorCatalog(scope: CatalogScope, opts: ProgramHostOptions, options?: {
|
|
156
|
+
readonly vectors?: boolean;
|
|
157
|
+
}): Promise<CatalogEntry[]>;
|
|
158
|
+
/** {@link behaviorCatalog} for a caller that cannot await. */
|
|
159
|
+
declare function behaviorCatalogSync(scope: CatalogScope, opts: ProgramHostOptions): CatalogEntry[];
|
|
160
|
+
/** `behavior/describe`: a trait value's knobs and events; an orbital value's or a whole behavior's orbitals.
|
|
161
|
+
* `knobVectors: true` attaches a trait's knob vectors (`--knob-vectors`). */
|
|
162
|
+
declare function behaviorDescribe(value: TraitValue, opts: ProgramHostOptions, options?: {
|
|
163
|
+
readonly knobVectors?: boolean;
|
|
164
|
+
}): Promise<TraitDescription>;
|
|
165
|
+
declare function behaviorDescribe(value: DescribeTarget, opts: ProgramHostOptions, options?: {
|
|
166
|
+
readonly knobVectors?: boolean;
|
|
167
|
+
}): Promise<TraitDescription | BehaviorDescription>;
|
|
168
|
+
/** `behavior/source`: the behavior a value belongs to, as a program (`.orb` IR). */
|
|
169
|
+
declare function behaviorSource(value: Pick<TraitValue, 'behavior'>, opts: ProgramHostOptions): Promise<OrbitalSchema>;
|
|
170
|
+
/** `program/read`: `.lolo` text → a program (`.orb` IR). */
|
|
171
|
+
declare function programRead(text: string, opts: ProgramHostOptions): Promise<OrbitalSchema>;
|
|
172
|
+
/** `program/print`: a program (`.orb` IR) → `.lolo` text. */
|
|
173
|
+
declare function programPrint(program: OrbitalSchema, opts: ProgramHostOptions): Promise<string>;
|
|
174
|
+
/** Who runs a program effect: the signed-in caller, as `call-service` receives it. */
|
|
175
|
+
type ProgramCallContext = Pick<ServiceCallContext, 'principal' | 'role'>;
|
|
176
|
+
/**
|
|
177
|
+
* A workspace-backed specifier (`./<workspaces root>/<owner>/…`) is readable
|
|
178
|
+
* only by its owner; every other specifier is unaffected. Returns the refusal,
|
|
179
|
+
* or undefined when the caller may read it.
|
|
180
|
+
*/
|
|
181
|
+
declare function workspaceAccessError(behavior: string, opts: ProgramHostOptions, context: ProgramCallContext | undefined): string | undefined;
|
|
182
|
+
/** Options for {@link programEval}. */
|
|
183
|
+
interface ProgramEvalOptions extends ProgramHostOptions {
|
|
184
|
+
/** Write into this workspace (opened as `context`'s caller) and snapshot it; without one, into `<cwd>/orbitals`. */
|
|
185
|
+
readonly workspace?: {
|
|
186
|
+
readonly id: string;
|
|
187
|
+
readonly context: ProgramCallContext;
|
|
188
|
+
};
|
|
189
|
+
/** A prior version of the program whose ids the re-evaluation keeps. */
|
|
190
|
+
readonly prior?: OrbitalSchema;
|
|
191
|
+
/** The program is a finished app (a generation concludes here): `orb validate --final`. */
|
|
192
|
+
readonly final?: boolean;
|
|
193
|
+
}
|
|
194
|
+
type ProgramEvalResult = {
|
|
195
|
+
readonly ok: true;
|
|
196
|
+
readonly result: EvaluatedProgram;
|
|
197
|
+
} | {
|
|
198
|
+
readonly ok: false;
|
|
199
|
+
readonly errors: readonly ProgramValidationIssue[];
|
|
200
|
+
};
|
|
201
|
+
/**
|
|
202
|
+
* `program/validate`: the same stamp-and-validate call as `program/eval`, at the same
|
|
203
|
+
* 0-error / 0-warning bar, in a temp directory that is removed after. Nothing is written
|
|
204
|
+
* to the workspace or the project.
|
|
205
|
+
*/
|
|
206
|
+
declare function programValidate(program: OrbitalSchema, opts: Pick<ProgramEvalOptions, 'cwd' | 'prior' | 'final'> & ProgramHostOptions): Promise<ProgramValidationReport>;
|
|
207
|
+
/**
|
|
208
|
+
* `program/eval`: validate through {@link stampAndValidate}, and on success write the program to `orbitals/<name>.orb` in its workspace (or `cwd`)
|
|
209
|
+
* and return its traits as values. Failures come back as data.
|
|
210
|
+
*/
|
|
211
|
+
declare function programEval(program: OrbitalSchema, opts: ProgramEvalOptions): Promise<ProgramEvalResult>;
|
|
212
|
+
/** Options for {@link programCompose}. */
|
|
213
|
+
interface ProgramComposeOptions {
|
|
214
|
+
readonly appName: string;
|
|
215
|
+
readonly layout?: LayoutStrategy;
|
|
216
|
+
/** The app's theme (a built-in theme name), set on the composed program. */
|
|
217
|
+
readonly theme?: string;
|
|
218
|
+
}
|
|
219
|
+
/**
|
|
220
|
+
* `program/compose`: assemble programs, in the order given, into one app
|
|
221
|
+
* program — core `composeAppFromFiles` (pages, layout, wiring, the app nav).
|
|
222
|
+
* The composer's registry lookups (an import's source orbital, an atom's trait,
|
|
223
|
+
* an organism's orbital order) are served from `orb behaviors source` for every
|
|
224
|
+
* behavior the programs import, loaded once up front.
|
|
225
|
+
*/
|
|
226
|
+
declare function programCompose(programs: readonly OrbitalSchema[], options: ProgramComposeOptions, opts: ProgramHostOptions): Promise<OrbitalSchema>;
|
|
227
|
+
/**
|
|
228
|
+
* Turn a trait value into a program a host can run: a one-orbital wrapper that
|
|
229
|
+
* imports the value's owning orbital with `only { T }` and the value's overrides
|
|
230
|
+
* as `traits { T { … } }` (LOLO §8b), validated at the 0/0 bar (the binding's
|
|
231
|
+
* admission check) and resolved by `orb`. A project-relative behavior
|
|
232
|
+
* (`./orbitals/X`) is imported relatively from a wrapper written at `cwd`, since
|
|
233
|
+
* `orb`'s loader refuses an absolute import.
|
|
234
|
+
*/
|
|
235
|
+
declare function mountTraitValue(value: TraitValue, opts: ProgramHostOptions, context?: ProgramCallContext): Promise<TraitValueMountResult>;
|
|
236
|
+
/**
|
|
237
|
+
* Make a behavior value runnable: the program as written is validated at the
|
|
238
|
+
* 0/0 bar (the embed's admission check) and resolved by `orb`; the frame opens
|
|
239
|
+
* it on its default page (the one marked `initial`, else the first).
|
|
240
|
+
*/
|
|
241
|
+
declare function mountBehaviorValue(value: BehaviorRef, opts: ProgramHostOptions, context?: ProgramCallContext): Promise<BehaviorValueMountResult>;
|
|
242
|
+
/** A program file resolved by `orb` (every import flattened, every composed trait inlined): what a host registers. */
|
|
243
|
+
declare function programResolve(path: string, opts: ProgramHostOptions): Promise<OrbitalSchema>;
|
|
244
|
+
/** An unresolved program resolved by `orb` from the project root `opts.cwd`, so its relative imports resolve there. */
|
|
245
|
+
declare function programResolveSchema(program: OrbitalSchema, opts: ProgramHostOptions): Promise<OrbitalSchema>;
|
|
246
|
+
/** `behavior/resolve`: the behavior a value belongs to, resolved by `orb` — every import and composed trait inlined, as the runtime runs it. */
|
|
247
|
+
declare function behaviorResolve(value: Pick<TraitValue, 'behavior'>, opts: ProgramHostOptions): Promise<OrbitalSchema | {
|
|
248
|
+
error: string;
|
|
249
|
+
}>;
|
|
250
|
+
/** `behavior/dependencies`: a program's dependency graph — each orbital's imports, then every installed behavior they reach, with its layer and its own imports. */
|
|
251
|
+
declare function behaviorDependencies(program: OrbitalSchema, opts: ProgramHostOptions): Promise<DependencyGraph>;
|
|
252
|
+
declare function programStep(program: OrbitalSchema, requests: readonly StepRequest[], opts: ProgramHostOptions, live?: boolean): Promise<PlayedStep[] | {
|
|
253
|
+
error: string;
|
|
254
|
+
}>;
|
|
255
|
+
type EffectArg = JsonValue;
|
|
256
|
+
/**
|
|
257
|
+
* Parse one program effect's positional arguments (the trailing emit config
|
|
258
|
+
* already removed) and run it. Both execution paths call this — the
|
|
259
|
+
* interpreter's effect executor and the compiled server handlers — so argument
|
|
260
|
+
* validation has one owner. Failures come back as data, never thrown.
|
|
261
|
+
*/
|
|
262
|
+
declare function runProgramEffect(op: ProgramEffectName, args: readonly EffectArg[], opts: ProgramHostOptions, context?: ProgramCallContext): Promise<ProgramEffectOutcome>;
|
|
263
|
+
|
|
264
|
+
export { KvFailure, behaviorCatalog, behaviorCatalogSync, behaviorDependencies, behaviorDescribe, behaviorResolve, behaviorSource, createKvHost, createNodeOsHost, directoryKvBackend, initKernelSync, installNodeHostPorts, loadHttpKernel, loadInstalledKernel, loadKernelModule, loadNativeKernelModule, loadOrCreateDevMasterKey, memoryKvBackend, mountBehaviorValue, mountTraitValue, namespaceId, nativeMemoryOf, nodeCredentialScope, nodeNetPort, pinnedFetchNode, processAnchors, programCompose, programEval, programPrint, programRead, programResolve, programResolveSchema, programStep, programValidate, resolveHostNode, resolveNativeAddon, runProgramEffect, workspaceAccessError };
|
|
265
|
+
export type { KvBackend, KvBatchOp, KvErrorKind, KvHost, KvNamespace, KvResult, KvScanEntry, KvTable, LoadKernelOptions, LoadedKernel, NodeOsHostOptions, ProgramCallContext, ProgramComposeOptions, ProgramEvalOptions, ProgramEvalResult, ProgramHostOptions };
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,217 @@
|
|
|
1
|
+
export { OrbitalServerRuntime, UnresolvedProgramError, createOrbitalServerRuntime } from './chunk-A2TIXOLJ.js';
|
|
2
|
+
export { createProgramHandlers } from './chunk-WZFQ7T7V.js';
|
|
3
|
+
export { GCS_ENDPOINT, KernelProgram, WORKSPACE_HMAC_KEY_ID, WORKSPACE_HMAC_SECRET, createNodeOsHost, emitPayload, kernelWorkspaceHost, processAnchors, resolveKernelDir, resolveProgramFile, workspaceBucketFromEnv, workspacesRoot } from './chunk-BJA6GYC5.js';
|
|
4
|
+
export { installNodeHostPorts, nodeCredentialScope, nodeNetPort, pinnedFetchNode, resolveHostNode } from './chunk-23YAOI6P.js';
|
|
5
|
+
export { initKernelSync, loadHttpKernel, loadInstalledKernel, loadKernelModule, loadNativeKernelModule, nativeMemoryOf, resolveNativeAddon } from './chunk-UBZT5LDW.js';
|
|
6
|
+
export { behaviorCatalog, behaviorCatalogSync, behaviorDependencies, behaviorDescribe, behaviorResolve, behaviorSource, mountBehaviorValue, mountTraitValue, programCompose, programEval, programPrint, programRead, programResolve, programResolveSchema, programStep, programValidate, runProgramEffect, workspaceAccessError } from './chunk-QYAPNUBH.js';
|
|
7
|
+
export { installWorkspaceHost, installedWorkspaceHost, uninstallWorkspaceHost, workspaceOwnerSegment } from './chunk-BWMLDDCL.js';
|
|
8
|
+
import { randomBytes } from 'crypto';
|
|
9
|
+
import { existsSync, readFileSync, mkdirSync, writeFileSync } from 'fs';
|
|
10
|
+
import { join } from 'path';
|
|
11
|
+
import { mkdir, open, rename, rm, readFile } from 'fs/promises';
|
|
12
|
+
|
|
13
|
+
var KEY_FILE = "dev-credential-master-key";
|
|
14
|
+
var HEX_KEY = /^[0-9a-f]{64}$/;
|
|
15
|
+
function loadOrCreateDevMasterKey(dir) {
|
|
16
|
+
if (process.env.NODE_ENV === "production") {
|
|
17
|
+
throw new Error("A generated dev master key is not permitted when NODE_ENV=production \u2014 set ALMADAR_CREDENTIAL_MASTER_KEY");
|
|
18
|
+
}
|
|
19
|
+
const path = join(dir, KEY_FILE);
|
|
20
|
+
if (existsSync(path)) {
|
|
21
|
+
const key2 = readFileSync(path, "utf8").trim();
|
|
22
|
+
if (!HEX_KEY.test(key2)) throw new Error(`${path} is malformed (expected 64 hex characters)`);
|
|
23
|
+
return key2;
|
|
24
|
+
}
|
|
25
|
+
mkdirSync(dir, { recursive: true });
|
|
26
|
+
const key = randomBytes(32).toString("hex");
|
|
27
|
+
writeFileSync(path, `${key}
|
|
28
|
+
`, { mode: 384, flag: "wx" });
|
|
29
|
+
return key;
|
|
30
|
+
}
|
|
31
|
+
var KvFailure = class extends Error {
|
|
32
|
+
constructor(kind, message) {
|
|
33
|
+
super(message);
|
|
34
|
+
this.kind = kind;
|
|
35
|
+
}
|
|
36
|
+
kind;
|
|
37
|
+
};
|
|
38
|
+
var LONE_SURROGATE = /[\ud800-\udbff](?![\udc00-\udfff])|(?<![\ud800-\udbff])[\udc00-\udfff]/;
|
|
39
|
+
var SEGMENT = /^[A-Za-z0-9._-]+$/;
|
|
40
|
+
function namespaceId(ns) {
|
|
41
|
+
return `kv:${ns.app}:${ns.locale}:${ns.store}`;
|
|
42
|
+
}
|
|
43
|
+
function checkNamespace(ns) {
|
|
44
|
+
for (const [what, seg] of [["app", ns.app], ["locale", ns.locale], ["store", ns.store]]) {
|
|
45
|
+
if (!SEGMENT.test(seg) || seg === "." || seg === "..") throw new KvFailure("invalid", `kv ${what} name ${JSON.stringify(seg)} is not [A-Za-z0-9._-]+`);
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
function checkString(what, s) {
|
|
49
|
+
if (typeof s !== "string") throw new KvFailure("invalid", `kv ${what} must be a string`);
|
|
50
|
+
if (LONE_SURROGATE.test(s)) throw new KvFailure("invalid", `kv ${what} is not valid UTF-8`);
|
|
51
|
+
return s;
|
|
52
|
+
}
|
|
53
|
+
function checkJson(value, path) {
|
|
54
|
+
if (value === null || typeof value === "string" || typeof value === "boolean") return value;
|
|
55
|
+
if (typeof value === "number") {
|
|
56
|
+
if (!Number.isFinite(value)) throw new KvFailure("invalid", `kv value at ${path} is not a finite number`);
|
|
57
|
+
return value;
|
|
58
|
+
}
|
|
59
|
+
if (Array.isArray(value)) return value.map((item, i) => checkJson(item, `${path}[${i}]`));
|
|
60
|
+
if (typeof value === "object" && Object.getPrototypeOf(value) === Object.prototype) {
|
|
61
|
+
const out = {};
|
|
62
|
+
for (const [k, v] of Object.entries(value)) Object.defineProperty(out, k, { value: checkJson(v, `${path}.${k}`), enumerable: true, writable: true, configurable: true });
|
|
63
|
+
return out;
|
|
64
|
+
}
|
|
65
|
+
throw new KvFailure("invalid", `kv value at ${path} is not JSON`);
|
|
66
|
+
}
|
|
67
|
+
function byteCompare(a, b) {
|
|
68
|
+
return Buffer.compare(Buffer.from(a, "utf8"), Buffer.from(b, "utf8"));
|
|
69
|
+
}
|
|
70
|
+
function serialize(table) {
|
|
71
|
+
const keys = [...table.keys()].sort(byteCompare);
|
|
72
|
+
return `{${keys.map((k) => `${JSON.stringify(k)}:${JSON.stringify(table.get(k))}`).join(",")}}`;
|
|
73
|
+
}
|
|
74
|
+
function parseTable(text) {
|
|
75
|
+
const parsed = JSON.parse(text);
|
|
76
|
+
if (parsed === null || typeof parsed !== "object" || Array.isArray(parsed)) throw new KvFailure("io", "kv store file is not a JSON object");
|
|
77
|
+
const table = /* @__PURE__ */ new Map();
|
|
78
|
+
for (const [k, v] of Object.entries(parsed)) table.set(k, checkJson(v, k));
|
|
79
|
+
return table;
|
|
80
|
+
}
|
|
81
|
+
function memoryKvBackend() {
|
|
82
|
+
const tables = /* @__PURE__ */ new Map();
|
|
83
|
+
return {
|
|
84
|
+
async load(ns) {
|
|
85
|
+
return new Map(tables.get(namespaceId(ns)) ?? []);
|
|
86
|
+
},
|
|
87
|
+
async commit(ns, table) {
|
|
88
|
+
tables.set(namespaceId(ns), new Map(table));
|
|
89
|
+
}
|
|
90
|
+
};
|
|
91
|
+
}
|
|
92
|
+
function isErrno(e, code) {
|
|
93
|
+
return typeof e === "object" && e !== null && "code" in e && e.code === code;
|
|
94
|
+
}
|
|
95
|
+
function directoryKvBackend(stateDir) {
|
|
96
|
+
const fileOf = (ns) => {
|
|
97
|
+
const dir = join(stateDir, "kv", ns.app, ns.locale);
|
|
98
|
+
return { dir, file: join(dir, `${ns.store}.json`) };
|
|
99
|
+
};
|
|
100
|
+
return {
|
|
101
|
+
async load(ns) {
|
|
102
|
+
const { file } = fileOf(ns);
|
|
103
|
+
let text;
|
|
104
|
+
try {
|
|
105
|
+
text = await readFile(file, "utf8");
|
|
106
|
+
} catch (e) {
|
|
107
|
+
if (isErrno(e, "ENOENT")) return /* @__PURE__ */ new Map();
|
|
108
|
+
throw new KvFailure("io", `kv read failed: ${e instanceof Error ? e.message : String(e)}`);
|
|
109
|
+
}
|
|
110
|
+
try {
|
|
111
|
+
return parseTable(text);
|
|
112
|
+
} catch (e) {
|
|
113
|
+
if (e instanceof KvFailure) throw e;
|
|
114
|
+
throw new KvFailure("io", `kv store file is corrupt: ${e instanceof Error ? e.message : String(e)}`);
|
|
115
|
+
}
|
|
116
|
+
},
|
|
117
|
+
async commit(ns, table) {
|
|
118
|
+
const { dir, file } = fileOf(ns);
|
|
119
|
+
const tmp = `${file}.tmp-${randomBytes(6).toString("hex")}`;
|
|
120
|
+
try {
|
|
121
|
+
await mkdir(dir, { recursive: true });
|
|
122
|
+
const handle = await open(tmp, "w");
|
|
123
|
+
try {
|
|
124
|
+
await handle.writeFile(serialize(table), "utf8");
|
|
125
|
+
await handle.sync();
|
|
126
|
+
} finally {
|
|
127
|
+
await handle.close();
|
|
128
|
+
}
|
|
129
|
+
await rename(tmp, file);
|
|
130
|
+
} catch (e) {
|
|
131
|
+
await rm(tmp, { force: true }).catch(() => void 0);
|
|
132
|
+
throw new KvFailure("io", `kv write failed: ${e instanceof Error ? e.message : String(e)}`);
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
};
|
|
136
|
+
}
|
|
137
|
+
function createKvHost(backend) {
|
|
138
|
+
const tails = /* @__PURE__ */ new Map();
|
|
139
|
+
const serialized = (ns, run) => {
|
|
140
|
+
const id = namespaceId(ns);
|
|
141
|
+
const next = (tails.get(id) ?? Promise.resolve()).then(run, run);
|
|
142
|
+
tails.set(id, next.catch(() => void 0));
|
|
143
|
+
return next;
|
|
144
|
+
};
|
|
145
|
+
const guard = async (run) => {
|
|
146
|
+
try {
|
|
147
|
+
return { ok: true, value: await run() };
|
|
148
|
+
} catch (e) {
|
|
149
|
+
if (e instanceof KvFailure) return { ok: false, error: e.message, kind: e.kind };
|
|
150
|
+
return { ok: false, error: e instanceof Error ? e.message : String(e), kind: "io" };
|
|
151
|
+
}
|
|
152
|
+
};
|
|
153
|
+
return {
|
|
154
|
+
get: (ns, key) => guard(async () => {
|
|
155
|
+
checkNamespace(ns);
|
|
156
|
+
checkString("key", key);
|
|
157
|
+
const table = await backend.load(ns);
|
|
158
|
+
const value = table.get(key);
|
|
159
|
+
return value === void 0 ? { found: false } : { found: true, value };
|
|
160
|
+
}),
|
|
161
|
+
put: (ns, key, value) => guard(() => {
|
|
162
|
+
checkNamespace(ns);
|
|
163
|
+
checkString("key", key);
|
|
164
|
+
const checked = checkJson(value, "value");
|
|
165
|
+
return serialized(ns, async () => {
|
|
166
|
+
const table = await backend.load(ns);
|
|
167
|
+
table.set(key, checked);
|
|
168
|
+
await backend.commit(ns, table);
|
|
169
|
+
return { storedKey: key };
|
|
170
|
+
});
|
|
171
|
+
}),
|
|
172
|
+
delete: (ns, key) => guard(() => {
|
|
173
|
+
checkNamespace(ns);
|
|
174
|
+
checkString("key", key);
|
|
175
|
+
return serialized(ns, async () => {
|
|
176
|
+
const table = await backend.load(ns);
|
|
177
|
+
const existed = table.delete(key);
|
|
178
|
+
if (existed) await backend.commit(ns, table);
|
|
179
|
+
return { existed };
|
|
180
|
+
});
|
|
181
|
+
}),
|
|
182
|
+
scan: (ns, prefix, limit) => guard(async () => {
|
|
183
|
+
checkNamespace(ns);
|
|
184
|
+
checkString("prefix", prefix);
|
|
185
|
+
if (limit !== void 0 && (!Number.isInteger(limit) || limit < 0)) throw new KvFailure("invalid", "kv scan limit must be a non-negative integer");
|
|
186
|
+
const table = await backend.load(ns);
|
|
187
|
+
const wanted = Buffer.from(prefix, "utf8");
|
|
188
|
+
const hits = [...table.keys()].filter((k) => Buffer.from(k, "utf8").subarray(0, wanted.length).equals(wanted)).sort(byteCompare);
|
|
189
|
+
const entries = [];
|
|
190
|
+
for (const key of limit === void 0 ? hits : hits.slice(0, limit)) {
|
|
191
|
+
const value = table.get(key);
|
|
192
|
+
if (value !== void 0) entries.push({ key, value });
|
|
193
|
+
}
|
|
194
|
+
return { entries };
|
|
195
|
+
}),
|
|
196
|
+
batch: (ns, ops) => guard(() => {
|
|
197
|
+
checkNamespace(ns);
|
|
198
|
+
const checked = ops.map((op, i) => {
|
|
199
|
+
const key = checkString(`batch op ${i} key`, op.key);
|
|
200
|
+
if (op.kind === "put") return { kind: "put", key, value: checkJson(op.value, `ops[${i}].value`) };
|
|
201
|
+
if (op.kind === "delete") return { kind: "delete", key };
|
|
202
|
+
throw new KvFailure("invalid", `kv batch op ${i} has unknown kind`);
|
|
203
|
+
});
|
|
204
|
+
return serialized(ns, async () => {
|
|
205
|
+
const table = await backend.load(ns);
|
|
206
|
+
for (const op of checked) {
|
|
207
|
+
if (op.kind === "put") table.set(op.key, op.value);
|
|
208
|
+
else table.delete(op.key);
|
|
209
|
+
}
|
|
210
|
+
await backend.commit(ns, table);
|
|
211
|
+
return { applied: checked.length };
|
|
212
|
+
});
|
|
213
|
+
})
|
|
214
|
+
};
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
export { KvFailure, createKvHost, directoryKvBackend, loadOrCreateDevMasterKey, memoryKvBackend, namespaceId };
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { initKernelSync, loadHttpKernel, loadInstalledKernel, loadKernelModule, loadNativeKernelModule, nativeMemoryOf, resolveNativeAddon } from './chunk-UBZT5LDW.js';
|