@almadar/shell-node 0.0.0-stage → 1.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/OrbitalServerRuntime.d.ts +473 -0
- package/dist/OrbitalServerRuntime.js +3 -0
- package/dist/chunk-3PNZYEZQ.js +844 -0
- package/dist/chunk-7QE32QQR.js +523 -0
- package/dist/chunk-7QG7JGKQ.js +18 -0
- package/dist/chunk-BWMLDDCL.js +21 -0
- package/dist/chunk-EEYGL7AB.js +53 -0
- package/dist/chunk-VQVAHUAX.js +183 -0
- package/dist/chunk-YLFK5OJN.js +2225 -0
- package/dist/createProgramHandlers.d.ts +28 -0
- package/dist/createProgramHandlers.js +6 -0
- package/dist/index.d.ts +301 -0
- package/dist/index.js +217 -0
- package/dist/kernel-loader-3JR6LJV5.js +1 -0
- package/dist/kernel-workspace-host-cT9JGJur.d.ts +130 -0
- package/dist/kernelWorkspace.d.ts +3 -0
- package/dist/kernelWorkspace.js +4 -0
- package/dist/program-6DB6LK5B.js +2 -0
- package/package.json +64 -3
- package/README.md +0 -3
|
@@ -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,301 @@
|
|
|
1
|
+
import { CredentialVaultModule, CredentialVault, CredentialRowsPort, OsAnchors, OsGrantPort, OsHostPort, TokenEndpointPost, KernelModule, 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 } from '@almadar/core';
|
|
3
|
+
export { ClientEffectTuple, ClientNavigateBackTuple, ClientNavigateTuple, ClientRenderUITuple, EventRequest, EventResponse, TransitionRejection } from '@almadar/core';
|
|
4
|
+
import { RequestOptions } from 'node:https';
|
|
5
|
+
import { IncomingMessage, ClientRequest } from 'node:http';
|
|
6
|
+
import { OsGrantsReport, ProveReport, StepRefusal } from '@almadar/core/kernel-wire';
|
|
7
|
+
import { LayoutStrategy } from '@almadar/core/builders';
|
|
8
|
+
export { K as KernelProgram, a as KernelProgramOptions, b as KernelWorkspaceBucket, c as KernelWorkspaceHostOptions, P as ProgramRun, W as WorkspaceHost, d as WorkspacePort, e as emitPayload, i as installWorkspaceHost, f as installedWorkspaceHost, k as kernelWorkspaceHost, r as resolveProgramFile, u as uninstallWorkspaceHost, w as workspaceBucketFromEnv, g as workspaceOwnerSegment, h as workspacesRoot } from './kernel-workspace-host-cT9JGJur.js';
|
|
9
|
+
export { HostDispatchItem, LiveBroadcastItem, LoaderConfig, OrbitalServerRuntime, OrbitalServerRuntimeConfig, PushItem, RegisterOptions, RegisteredOrbital, RuntimeOrbital, RuntimeOrbitalSchema, UnresolvedProgramError } from './OrbitalServerRuntime.js';
|
|
10
|
+
export { ProgramHandlers, ProgramHostConfig, createProgramHandlers } from './createProgramHandlers.js';
|
|
11
|
+
|
|
12
|
+
/** Install the Node ports `@almadar/shell-runtime` leaves open: per-tenant credential scopes. Idempotent. */
|
|
13
|
+
declare function installNodeHostPorts(): void;
|
|
14
|
+
interface NodeCredentialVaultOptions {
|
|
15
|
+
/** The kernel module that carries the vault class (`@almadar/kernel`, initialised). */
|
|
16
|
+
kernel: CredentialVaultModule;
|
|
17
|
+
/** Defaults to the process env, which the native host reads the same keys and file from. */
|
|
18
|
+
env?: Record<string, string | undefined>;
|
|
19
|
+
/** Defaults to the working directory, where the native host looks for `.almadar/dev-credentials.json`. */
|
|
20
|
+
cwd?: string;
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* The durable credential vault of a Node host, as the native host opens it: the key in `ALMADAR_CREDENTIAL_MASTER_KEY`
|
|
24
|
+
* (and `..._PREVIOUS` in a rotation window), the rows in the encrypted file `ALMADAR_CREDENTIALS_FILE` names, else
|
|
25
|
+
* `.almadar/dev-credentials.json`, so one file serves both hosts. With no master key set the host has no store and this
|
|
26
|
+
* answers `null`; a key that is not 64 hex digits, or a row the kernel cannot read, rejects. The vault is installed as the
|
|
27
|
+
* process-wide credential store.
|
|
28
|
+
*/
|
|
29
|
+
declare function installNodeCredentialVault(options: NodeCredentialVaultOptions): Promise<CredentialVault | null>;
|
|
30
|
+
|
|
31
|
+
declare const DEFAULT_CREDENTIALS_FILE = ".almadar/dev-credentials.json";
|
|
32
|
+
/** `ALMADAR_CREDENTIALS_FILE`, else `.almadar/dev-credentials.json` under the working directory, as the native host resolves it. */
|
|
33
|
+
declare function credentialsFilePath(env?: Record<string, string | undefined>, cwd?: string): string;
|
|
34
|
+
/**
|
|
35
|
+
* The kernel's credential rows kept in a JSON file, the layout the native host writes: an array of rows each carrying an
|
|
36
|
+
* `id`, written whole through a temporary file and a rename. A missing file is no rows; a file that cannot be read, is not
|
|
37
|
+
* JSON, is not an array of rows or holds a row without an id is a failure. Operations here run one after another, so the
|
|
38
|
+
* conditional delete is atomic against every other port over the same file in this process; a second process is not
|
|
39
|
+
* covered, as with the native host.
|
|
40
|
+
*/
|
|
41
|
+
declare function fileCredentialRows(path: string): CredentialRowsPort;
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* A development host's credential-store master key: read from `<dir>/dev-credential-master-key`,
|
|
45
|
+
* generated there (owner-only) on first use. Production must hold its key in the platform secret
|
|
46
|
+
* store, so this refuses under NODE_ENV=production.
|
|
47
|
+
*/
|
|
48
|
+
declare function loadOrCreateDevMasterKey(dir: string): string;
|
|
49
|
+
|
|
50
|
+
/** One program instance's `os` host: its own handle tables, closed by `close`. */
|
|
51
|
+
interface NodeOsHostOptions {
|
|
52
|
+
/** Where `~/` and `./` and the declared grant anchors are placed; absent, the process's own (`OsAnchors::of_process`). */
|
|
53
|
+
anchors?: OsAnchors;
|
|
54
|
+
}
|
|
55
|
+
/** The process's home, working directory, executable directory and environment, read once (`OsAnchors::of_process`). */
|
|
56
|
+
declare function processAnchors(): OsAnchors;
|
|
57
|
+
declare function createNodeOsHost(grants: OsGrantPort, options?: NodeOsHostOptions): OsHostPort;
|
|
58
|
+
|
|
59
|
+
type KvErrorKind = 'denied' | 'invalid' | 'io' | 'timeout' | 'unsupported' | 'closed';
|
|
60
|
+
type KvResult<T> = {
|
|
61
|
+
ok: true;
|
|
62
|
+
value: T;
|
|
63
|
+
} | {
|
|
64
|
+
ok: false;
|
|
65
|
+
error: string;
|
|
66
|
+
kind: KvErrorKind;
|
|
67
|
+
};
|
|
68
|
+
interface KvNamespace {
|
|
69
|
+
app: string;
|
|
70
|
+
locale: string;
|
|
71
|
+
store: string;
|
|
72
|
+
}
|
|
73
|
+
interface KvScanEntry {
|
|
74
|
+
key: string;
|
|
75
|
+
value: JsonValue;
|
|
76
|
+
}
|
|
77
|
+
type KvBatchOp = {
|
|
78
|
+
kind: 'put';
|
|
79
|
+
key: string;
|
|
80
|
+
value: JsonValue;
|
|
81
|
+
} | {
|
|
82
|
+
kind: 'delete';
|
|
83
|
+
key: string;
|
|
84
|
+
};
|
|
85
|
+
declare class KvFailure extends Error {
|
|
86
|
+
readonly kind: KvErrorKind;
|
|
87
|
+
constructor(kind: KvErrorKind, message: string);
|
|
88
|
+
}
|
|
89
|
+
/** A namespace's whole content, key order = UTF-8 byte order. Backends load and commit it whole. */
|
|
90
|
+
type KvTable = Map<string, JsonValue>;
|
|
91
|
+
interface KvBackend {
|
|
92
|
+
load(ns: KvNamespace): Promise<KvTable>;
|
|
93
|
+
/** Replace the namespace content atomically: a failure leaves the previous content. */
|
|
94
|
+
commit(ns: KvNamespace, table: KvTable): Promise<void>;
|
|
95
|
+
}
|
|
96
|
+
declare function memoryKvBackend(): KvBackend;
|
|
97
|
+
declare function directoryKvBackend(stateDir: string): KvBackend;
|
|
98
|
+
interface KvHost {
|
|
99
|
+
get(ns: KvNamespace, key: string): Promise<KvResult<{
|
|
100
|
+
found: boolean;
|
|
101
|
+
value?: JsonValue;
|
|
102
|
+
}>>;
|
|
103
|
+
put(ns: KvNamespace, key: string, value: JsonValue): Promise<KvResult<{
|
|
104
|
+
storedKey: string;
|
|
105
|
+
}>>;
|
|
106
|
+
delete(ns: KvNamespace, key: string): Promise<KvResult<{
|
|
107
|
+
existed: boolean;
|
|
108
|
+
}>>;
|
|
109
|
+
scan(ns: KvNamespace, prefix: string, limit?: number): Promise<KvResult<{
|
|
110
|
+
entries: KvScanEntry[];
|
|
111
|
+
}>>;
|
|
112
|
+
batch(ns: KvNamespace, ops: readonly KvBatchOp[]): Promise<KvResult<{
|
|
113
|
+
applied: number;
|
|
114
|
+
}>>;
|
|
115
|
+
}
|
|
116
|
+
declare function createKvHost(backend: KvBackend): KvHost;
|
|
117
|
+
|
|
118
|
+
interface ResolvedAddress {
|
|
119
|
+
address: string;
|
|
120
|
+
family: number;
|
|
121
|
+
}
|
|
122
|
+
interface NodeTokenPostOptions {
|
|
123
|
+
/** The kernel's egress rule over the program's declared origins. */
|
|
124
|
+
egressAllows(url: string): boolean;
|
|
125
|
+
/** The kernel's public-address rule. */
|
|
126
|
+
isPublicAddress(ip: string): boolean;
|
|
127
|
+
request?: (options: RequestOptions, onResponse: (response: IncomingMessage) => void) => ClientRequest;
|
|
128
|
+
resolve?: (host: string) => Promise<ResolvedAddress[]>;
|
|
129
|
+
}
|
|
130
|
+
declare class TokenPostRefusal extends Error {
|
|
131
|
+
constructor(message: string);
|
|
132
|
+
}
|
|
133
|
+
declare function createNodeTokenPost(options: NodeTokenPostOptions): TokenEndpointPost;
|
|
134
|
+
|
|
135
|
+
/** The whole server kernel as Node loads it: the shared module plus the server-only exports the client build omits. */
|
|
136
|
+
interface LoadedKernel extends KernelModule, KernelMemoryStoreExports {
|
|
137
|
+
initSync(input: {
|
|
138
|
+
module: Uint8Array;
|
|
139
|
+
}): object;
|
|
140
|
+
}
|
|
141
|
+
/** A row store the kernel itself holds (its `MemoryStore`), as a host keeps rows with no database. */
|
|
142
|
+
declare function nativeMemoryOf(kernel: KernelModule): NativeMemoryPersistenceAdapter;
|
|
143
|
+
interface LoadKernelOptions {
|
|
144
|
+
/** Where the installed `@almadar/core` and `@almadar/std` are found, node-style. Required: the caller names its own root. */
|
|
145
|
+
languageFrom: string;
|
|
146
|
+
}
|
|
147
|
+
/**
|
|
148
|
+
* The kernel of the `@almadar/kernel` package this host installs, loaded once per process with the language data
|
|
149
|
+
* the packages under `languageFrom` declare. A host with no package installed rejects, never falls back.
|
|
150
|
+
*/
|
|
151
|
+
declare function loadInstalledKernel(languageFrom: string): Promise<LoadedKernel>;
|
|
152
|
+
/**
|
|
153
|
+
* Loads the kernel from `kernelDir` (the one with `pkg/`) and installs the language data the installed packages declare
|
|
154
|
+
* (the operator table that routes `program/*` and the other host effects), as `orb` reads it. The first install in a
|
|
155
|
+
* process wins.
|
|
156
|
+
*/
|
|
157
|
+
declare function loadKernelModule(kernelDir: string, options: LoadKernelOptions): Promise<LoadedKernel>;
|
|
158
|
+
/**
|
|
159
|
+
* Where the native kernel add-on is: `ALMADAR_KERNEL_NODE`, else `kernel.node` in the `@almadar/orb-<platform>-<arch>`
|
|
160
|
+
* package this platform installs. Rejects when neither exists, so a host can fall back to the wasm kernel by choice.
|
|
161
|
+
*/
|
|
162
|
+
declare function resolveNativeAddon(from: string): string;
|
|
163
|
+
/**
|
|
164
|
+
* Loads the native kernel add-on (the same API as the wasm module, run as machine code) and installs the language data
|
|
165
|
+
* the installed packages declare. The first install in a process wins.
|
|
166
|
+
*/
|
|
167
|
+
declare function loadNativeKernelModule(addonPath: string, options: LoadKernelOptions): Promise<LoadedKernel>;
|
|
168
|
+
|
|
169
|
+
/**
|
|
170
|
+
* The host side of the language trio's server effects (`behavior/catalog`,
|
|
171
|
+
* `behavior/describe`, `behavior/source`, `behavior/resolve`, `behavior/dependencies`, `program/read|print|eval`): a thin
|
|
172
|
+
* caller that runs the installed `orb` from the project directory and parses its
|
|
173
|
+
* JSON. All behavior resolution, reflection, printing and validation is `orb`'s;
|
|
174
|
+
* nothing here re-implements it. Both execution paths (the interpreter's effect
|
|
175
|
+
* executor and the compiled server host) call this module.
|
|
176
|
+
*
|
|
177
|
+
* @packageDocumentation
|
|
178
|
+
*/
|
|
179
|
+
|
|
180
|
+
/** Where the host runs `orb`: the project (workspace) root, so installed behavior packages resolve. */
|
|
181
|
+
interface ProgramHostOptions {
|
|
182
|
+
readonly cwd: string;
|
|
183
|
+
/** Explicit `orb` binary; defaults to {@link resolveOrbBinary}. */
|
|
184
|
+
readonly orbBin?: string;
|
|
185
|
+
}
|
|
186
|
+
/** `behavior/catalog`: installed behaviors under registry folders; `traits: false` omits each entry's traits (`--no-traits`). */
|
|
187
|
+
declare function behaviorCatalog(scope: CatalogScope, opts: ProgramHostOptions, options?: {
|
|
188
|
+
readonly traits?: boolean;
|
|
189
|
+
}): Promise<CatalogEntry[]>;
|
|
190
|
+
/** {@link behaviorCatalog} for a caller that cannot await. */
|
|
191
|
+
declare function behaviorCatalogSync(scope: CatalogScope, opts: ProgramHostOptions): CatalogEntry[];
|
|
192
|
+
/** `behavior/describe`: a trait value's knobs and events; an orbital value's or a whole behavior's orbitals. */
|
|
193
|
+
declare function behaviorDescribe(value: TraitValue, opts: ProgramHostOptions): Promise<TraitDescription>;
|
|
194
|
+
declare function behaviorDescribe(value: DescribeTarget, opts: ProgramHostOptions): Promise<TraitDescription | BehaviorDescription>;
|
|
195
|
+
/** `behavior/source`: the behavior a value belongs to, as a program (`.orb` IR). */
|
|
196
|
+
declare function behaviorSource(value: Pick<TraitValue, 'behavior'>, opts: ProgramHostOptions): Promise<OrbitalSchema>;
|
|
197
|
+
/** `program/read`: `.lolo` text → a program (`.orb` IR). */
|
|
198
|
+
declare function programRead(text: string, opts: ProgramHostOptions): Promise<OrbitalSchema>;
|
|
199
|
+
/** `program/print`: a program (`.orb` IR) → `.lolo` text. */
|
|
200
|
+
declare function programPrint(program: OrbitalSchema, opts: ProgramHostOptions): Promise<string>;
|
|
201
|
+
/** What `program/os-grants` returns: the static `os/` grant check's typed findings. */
|
|
202
|
+
type ProgramOsGrantsReport = OsGrantsReport;
|
|
203
|
+
/** What `program/prove` returns: every spec proposition the program cannot be shown to keep. */
|
|
204
|
+
type ProgramProveReport = ProveReport;
|
|
205
|
+
/** Who runs a program effect: the signed-in caller, as `call-service` receives it. */
|
|
206
|
+
type ProgramCallContext = Pick<ServiceCallContext, 'principal' | 'role'>;
|
|
207
|
+
/**
|
|
208
|
+
* A workspace-backed specifier (`./<workspaces root>/<owner>/…`) is readable
|
|
209
|
+
* only by its owner; every other specifier is unaffected. Returns the refusal,
|
|
210
|
+
* or undefined when the caller may read it.
|
|
211
|
+
*/
|
|
212
|
+
declare function workspaceAccessError(behavior: string, opts: ProgramHostOptions, context: ProgramCallContext | undefined): string | undefined;
|
|
213
|
+
/** Options for {@link programEval}. */
|
|
214
|
+
interface ProgramEvalOptions extends ProgramHostOptions {
|
|
215
|
+
/** Write into this workspace (opened as `context`'s caller) and snapshot it; without one, into `<cwd>/orbitals`. */
|
|
216
|
+
readonly workspace?: {
|
|
217
|
+
readonly id: string;
|
|
218
|
+
readonly context: ProgramCallContext;
|
|
219
|
+
};
|
|
220
|
+
/** A prior version of the program whose ids the re-evaluation keeps. */
|
|
221
|
+
readonly prior?: OrbitalSchema;
|
|
222
|
+
/** The program is a finished app (a generation concludes here): `orb validate --final`. */
|
|
223
|
+
readonly final?: boolean;
|
|
224
|
+
}
|
|
225
|
+
type ProgramEvalResult = {
|
|
226
|
+
readonly ok: true;
|
|
227
|
+
readonly result: EvaluatedProgram;
|
|
228
|
+
} | {
|
|
229
|
+
readonly ok: false;
|
|
230
|
+
readonly errors: readonly ProgramValidationIssue[];
|
|
231
|
+
};
|
|
232
|
+
/**
|
|
233
|
+
* `program/validate`: the same stamp-and-validate call as `program/eval`, at the same
|
|
234
|
+
* 0-error / 0-warning bar, in a temp directory that is removed after. Nothing is written
|
|
235
|
+
* to the workspace or the project.
|
|
236
|
+
*/
|
|
237
|
+
declare function programValidate(program: OrbitalSchema, opts: Pick<ProgramEvalOptions, 'cwd' | 'prior' | 'final'> & ProgramHostOptions): Promise<ProgramValidationReport>;
|
|
238
|
+
/**
|
|
239
|
+
* `program/prove`: the kernel prover's findings on a program, asked of `orb prove` (the prover is the kernel's, so the
|
|
240
|
+
* node host carries no copy of it). A program value is written to a temp file and resolved like any file; `path` names
|
|
241
|
+
* the file directly.
|
|
242
|
+
*/
|
|
243
|
+
declare function programProve(target: {
|
|
244
|
+
readonly program: OrbitalSchema;
|
|
245
|
+
} | {
|
|
246
|
+
readonly path: string;
|
|
247
|
+
}, opts: ProgramHostOptions): Promise<ProgramProveReport>;
|
|
248
|
+
/**
|
|
249
|
+
* `program/os-grants`: the kernel's static `os/` grant findings on a program, asked of `orb os-grants` (the check is the
|
|
250
|
+
* kernel's, so the node host carries no copy of it). `final` checks the finished program, where a config-fed target is a
|
|
251
|
+
* literal. A program value is written to a temp file and resolved like any file; `path` names the file directly.
|
|
252
|
+
*/
|
|
253
|
+
declare function programOsGrants(target: {
|
|
254
|
+
readonly program: OrbitalSchema;
|
|
255
|
+
} | {
|
|
256
|
+
readonly path: string;
|
|
257
|
+
}, opts: ProgramHostOptions & {
|
|
258
|
+
readonly final?: boolean;
|
|
259
|
+
}): Promise<ProgramOsGrantsReport>;
|
|
260
|
+
/**
|
|
261
|
+
* `program/eval`: validate through {@link stampAndValidate}, and on success write the program to `orbitals/<name>.orb` in its workspace (or `cwd`)
|
|
262
|
+
* and return its traits as values. Failures come back as data.
|
|
263
|
+
*/
|
|
264
|
+
declare function programEval(program: OrbitalSchema, opts: ProgramEvalOptions): Promise<ProgramEvalResult>;
|
|
265
|
+
/** Options for {@link programCompose}. */
|
|
266
|
+
interface ProgramComposeOptions {
|
|
267
|
+
readonly appName: string;
|
|
268
|
+
readonly layout?: LayoutStrategy;
|
|
269
|
+
/** The app's theme (a built-in theme name), set on the composed program. */
|
|
270
|
+
readonly theme?: string;
|
|
271
|
+
}
|
|
272
|
+
/**
|
|
273
|
+
* `program/compose`: assemble programs, in the order given, into one app
|
|
274
|
+
* program. The composer is `orb compose` (the Rust composer, `program/compose`
|
|
275
|
+
* of the kernel's program host): the programs are written to a scratch folder
|
|
276
|
+
* and handed to it, and its JSON is the answer. Pages, layout, wiring, the app
|
|
277
|
+
* nav and every registry read are `orb`'s.
|
|
278
|
+
*/
|
|
279
|
+
declare function programCompose(programs: readonly OrbitalSchema[], options: ProgramComposeOptions, opts: ProgramHostOptions): Promise<OrbitalSchema>;
|
|
280
|
+
/** A program file resolved by `orb` (every import flattened, every composed trait inlined): what a host registers. */
|
|
281
|
+
declare function programResolve(path: string, opts: ProgramHostOptions): Promise<OrbitalSchema>;
|
|
282
|
+
/** An unresolved program resolved by `orb` from the project root `opts.cwd`, so its relative imports resolve there. */
|
|
283
|
+
declare function programResolveSchema(program: OrbitalSchema, opts: ProgramHostOptions): Promise<OrbitalSchema>;
|
|
284
|
+
/** `behavior/resolve`: the behavior a value belongs to, resolved by `orb` — every import and composed trait inlined, as the runtime runs it. */
|
|
285
|
+
declare function behaviorResolve(value: Pick<TraitValue, 'behavior'>, opts: ProgramHostOptions): Promise<OrbitalSchema | {
|
|
286
|
+
error: string;
|
|
287
|
+
}>;
|
|
288
|
+
/** `behavior/dependencies`: a program's dependency graph — each orbital's imports, then every installed behavior they reach, with its layer and its own imports. */
|
|
289
|
+
declare function behaviorDependencies(program: OrbitalSchema, opts: ProgramHostOptions): Promise<DependencyGraph>;
|
|
290
|
+
declare function programStep(program: OrbitalSchema, requests: readonly StepRequest[], opts: ProgramHostOptions, live?: boolean): Promise<PlayedStep[] | StepRefusal>;
|
|
291
|
+
type EffectArg = JsonValue;
|
|
292
|
+
/**
|
|
293
|
+
* Parse one program effect's positional arguments (the trailing emit config
|
|
294
|
+
* already removed) and run it. Both execution paths call this — the
|
|
295
|
+
* interpreter's effect executor and the compiled server handlers — so argument
|
|
296
|
+
* validation has one owner. Failures come back as data, never thrown.
|
|
297
|
+
*/
|
|
298
|
+
declare function runProgramEffect(op: ProgramEffectName, args: readonly EffectArg[], opts: ProgramHostOptions, context?: ProgramCallContext): Promise<ProgramEffectOutcome>;
|
|
299
|
+
|
|
300
|
+
export { DEFAULT_CREDENTIALS_FILE, KvFailure, TokenPostRefusal, behaviorCatalog, behaviorCatalogSync, behaviorDependencies, behaviorDescribe, behaviorResolve, behaviorSource, createKvHost, createNodeOsHost, createNodeTokenPost, credentialsFilePath, directoryKvBackend, fileCredentialRows, installNodeCredentialVault, installNodeHostPorts, loadInstalledKernel, loadKernelModule, loadNativeKernelModule, loadOrCreateDevMasterKey, memoryKvBackend, nativeMemoryOf, processAnchors, programCompose, programEval, programOsGrants, programPrint, programProve, programRead, programResolve, programResolveSchema, programStep, programValidate, resolveNativeAddon, runProgramEffect, workspaceAccessError };
|
|
301
|
+
export type { KvBackend, KvBatchOp, KvErrorKind, KvHost, KvNamespace, KvResult, LoadKernelOptions, LoadedKernel, NodeCredentialVaultOptions, NodeOsHostOptions, NodeTokenPostOptions, ProgramCallContext, ProgramComposeOptions, ProgramEvalOptions, ProgramEvalResult, ProgramHostOptions, ProgramOsGrantsReport, ProgramProveReport, ResolvedAddress };
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,217 @@
|
|
|
1
|
+
export { OrbitalServerRuntime, UnresolvedProgramError } from './chunk-3PNZYEZQ.js';
|
|
2
|
+
export { createProgramHandlers } from './chunk-7QG7JGKQ.js';
|
|
3
|
+
export { KernelProgram, createNodeOsHost, emitPayload, kernelWorkspaceHost, processAnchors, resolveProgramFile, workspaceBucketFromEnv, workspacesRoot } from './chunk-YLFK5OJN.js';
|
|
4
|
+
export { DEFAULT_CREDENTIALS_FILE, TokenPostRefusal, createNodeTokenPost, credentialsFilePath, fileCredentialRows, installNodeCredentialVault, installNodeHostPorts } from './chunk-VQVAHUAX.js';
|
|
5
|
+
export { loadInstalledKernel, loadKernelModule, loadNativeKernelModule, nativeMemoryOf, resolveNativeAddon } from './chunk-EEYGL7AB.js';
|
|
6
|
+
export { behaviorCatalog, behaviorCatalogSync, behaviorDependencies, behaviorDescribe, behaviorResolve, behaviorSource, programCompose, programEval, programOsGrants, programPrint, programProve, programRead, programResolve, programResolveSchema, programStep, programValidate, runProgramEffect, workspaceAccessError } from './chunk-7QE32QQR.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 };
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { loadInstalledKernel, loadKernelModule, loadNativeKernelModule, nativeMemoryOf, resolveNativeAddon } from './chunk-EEYGL7AB.js';
|