@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.
@@ -0,0 +1,694 @@
1
+ import { EventPayload, EffectHandlers, EvaluationContextExtensions, KernelModule, HttpPortsOptions, OsGrantPort, OsHostPort, EntityRow, EventBus, TransitionObserver, TraitState } from '@almadar/shell-runtime';
2
+ import { OrbitalEventRequest, OrbitalEventResponse, BusEventSource, Entity, OrbitalDefinition, Trait, TraitConfig, PersistenceAdapter, UserContext, OrbitalSchema, MessageCatalogs, RowSetRef, RowQueryPage, ExternalInput, ServiceHostPorts, DispatchRequestOutcome, ExternalInputRequest, ClientEffectTuple, InboundDelivery, InboundAnswer, TraitTick } from '@almadar/core';
3
+ export { ClientEffectTuple, ClientNavigateBackTuple, ClientNavigateTuple, ClientRenderUITuple, OrbitalEventRequest, OrbitalEventResponse, TransitionRejection } from '@almadar/core';
4
+
5
+ /**
6
+ * OrbitalServerRuntime: the Node host that runs a registered program on the kernel. It answers the kernel's asks
7
+ * (rows, services, `http`, `os` through the given os host, live streams), drives its ticks and mounts; it serves no
8
+ * HTTP routes (a served program composes std-http-server for that).
9
+ *
10
+ * @packageDocumentation
11
+ */
12
+
13
+ /** @deprecated Use OrbitalSchema from @almadar/core */
14
+ type RuntimeOrbitalSchema = OrbitalSchema;
15
+ /** @deprecated Use OrbitalDefinition from @almadar/core */
16
+ type RuntimeOrbital = OrbitalDefinition;
17
+ /** @deprecated Use Trait from @almadar/core */
18
+ type RuntimeTrait = Trait;
19
+ /** @deprecated Use TraitTick from @almadar/core */
20
+ type RuntimeTraitTick = TraitTick;
21
+ /**
22
+ * Incremental-push item streamed to an SSE client mid-dispatch (an emitted
23
+ * event or a client effect), before the response resolves.
24
+ */
25
+ type PushItem = {
26
+ type: 'event';
27
+ data: {
28
+ event: string;
29
+ payload?: EventPayload;
30
+ source?: BusEventSource;
31
+ };
32
+ timestamp?: number;
33
+ } | {
34
+ type: 'effect';
35
+ data: ClientEffectTuple;
36
+ timestamp?: number;
37
+ };
38
+ /**
39
+ * Registered orbital with runtime state
40
+ */
41
+ /** One registered orbital as the API lists it. */
42
+ interface OrbitalSummary {
43
+ name: string;
44
+ entity: string | undefined;
45
+ traits: string[];
46
+ }
47
+ /** One registered orbital as the API describes it: its entity and each trait's current state, states and events. */
48
+ interface OrbitalInfo {
49
+ name: string;
50
+ entity: Entity;
51
+ traits: {
52
+ name: string;
53
+ currentState: string | undefined;
54
+ states: string[];
55
+ events: string[];
56
+ }[];
57
+ }
58
+ interface RegisteredOrbital {
59
+ schema: OrbitalDefinition;
60
+ /** Resolved entity (never a string ref at runtime) */
61
+ entity: Entity;
62
+ /** Resolved inline traits (string refs filtered out) */
63
+ traits: Trait[];
64
+ /**
65
+ * Call-site `config: { ... }` attached to each trait ref, keyed by trait
66
+ * name. Used to populate the `@config.X` binding when running that trait's
67
+ * effects. Preserved from the preprocessed schema's trait-ref wrapper
68
+ * (`{ ref, config, linkedEntity, _resolved }`) before the wrapper is
69
+ * unwrapped to its inline form.
70
+ */
71
+ configByTrait: Map<string, TraitConfig>;
72
+ }
73
+ /**
74
+ * One persist-envelope success emit, handed to the live-broadcast sink
75
+ * (`setLiveBroadcastSink`). Fired only from the `persist` effect's
76
+ * `emit:{success}` envelope (batch and single-op) — never from the generic
77
+ * emit funnel — so transport layers can fan it out to every OTHER
78
+ * connected client without matching on event names.
79
+ */
80
+ interface LiveBroadcastItem {
81
+ event: string;
82
+ payload?: EventPayload;
83
+ source: BusEventSource;
84
+ /** `clientId` of the request that produced this emit. */
85
+ originClientId?: string;
86
+ /**
87
+ * `peers`: every OTHER client (persist envelopes, tick relay). `origin`:
88
+ * only the requesting client, while its request is still running (a
89
+ * `call-service`'s live `emit.onMessage`).
90
+ */
91
+ target: 'peers' | 'origin';
92
+ }
93
+ /**
94
+ * The result of a dispatch the host ran on its own — a follow-on step's `call-service`
95
+ * outcome, run after the request that started the call had answered — for the tab that
96
+ * asked (`originClientId`). Handed to the host-dispatch sink (`setHostDispatchSink`).
97
+ */
98
+ interface HostDispatchItem {
99
+ orbitalName: string;
100
+ request: OrbitalEventRequest;
101
+ response: OrbitalEventResponse;
102
+ originClientId?: string;
103
+ }
104
+ /**
105
+ * Loader configuration for resolving `uses` imports
106
+ */
107
+ interface LoaderConfig {
108
+ /** Where `orb` resolves a registered program's imports from, when no `programHost` names it. */
109
+ basePath: string;
110
+ }
111
+ /**
112
+ * Runtime configuration
113
+ */
114
+ interface OrbitalServerRuntimeConfig {
115
+ /** Enable debug logging */
116
+ debug?: boolean;
117
+ /**
118
+ * Snapshot cadence (ms) for relaying tick-stamped broadcasts to other
119
+ * clients — newest-per-(client, orbital, event) wins between flushes
120
+ * (T6, docs/Almadar_Tick_Loop.md §3a). Default 50 (≈20Hz).
121
+ */
122
+ tickRelayIntervalMs?: number;
123
+ /** Custom effect handlers (for integrating with your data layer) */
124
+ effectHandlers?: Partial<EffectHandlers>;
125
+ /** Persistence adapter for entity data */
126
+ persistence?: PersistenceAdapter;
127
+ /**
128
+ * Data mode:
129
+ * - 'mock': mock service answers and the std mock-seed dataset
130
+ * - 'real': the actual persistence layer and services
131
+ * Required: whoever starts the runtime states it; there is no default (EXEC-BOUND-2).
132
+ */
133
+ mode: 'mock' | 'real';
134
+ /** Where a registered program with imports is resolved from (`orb resolve`). */
135
+ loaderConfig?: LoaderConfig;
136
+ /**
137
+ * Additional fields to spread onto every EvaluationContext.
138
+ * Use this to inject module contexts (e.g., { agent: AgentContext }).
139
+ * The evaluator dispatches agent/* operators to ctx.agent.
140
+ */
141
+ contextExtensions?: EvaluationContextExtensions;
142
+ /**
143
+ * The program host behind behavior/catalog|describe|source and
144
+ * program/read|print|eval: the project root `orb` runs from. Absent means
145
+ * those effects fail explicitly ("no program host configured").
146
+ */
147
+ programHost?: {
148
+ cwd: string;
149
+ orbBin?: string;
150
+ };
151
+ /**
152
+ * The persona a preview or verification run is looking at the app AS.
153
+ *
154
+ * `@user.id` / `@user.role` are what an app's ownership scoping and role
155
+ * gates resolve against, so with no user every predicate takes its negative
156
+ * branch and every owner filter matches nothing. A dev host (playground,
157
+ * runtime-verify) sets it to make both branches reachable.
158
+ *
159
+ * Never an HTTP request's identity: `router()` resolves every request from
160
+ * its verified token (or anonymous). It is the viewer for in-process calls,
161
+ * ticks and the mock seeder's owner stamps.
162
+ */
163
+ defaultUser?: UserContext;
164
+ /**
165
+ * The initialised `@almadar/kernel` module that decides execution and whose I/O this runtime answers with its
166
+ * persistence, service and program-host adapters. Absent, the runtime loads the installed `@almadar/kernel` itself
167
+ * (`loadInstalledKernel`) when a program is first registered.
168
+ */
169
+ kernel?: KernelModule;
170
+ /**
171
+ * What the `http` effect runs on: the kernel's request driver (`loadHttpKernel`), and optionally the secret store,
172
+ * pinned fetch and resolver. The program's `egress` is read from the registered schema. Absent, an `http` effect
173
+ * fails with `HTTP_KERNEL_UNAVAILABLE`.
174
+ */
175
+ http?: Omit<HttpPortsOptions, 'egress'>;
176
+ /**
177
+ * Builds the `os` host of the kernel engine from the grant port backed by the kernel (`createNodeOsHost` from
178
+ * `@almadar/shell-node`). Absent, every `os` ask is denied, as the native host does with none.
179
+ */
180
+ osHost?: (grants: OsGrantPort) => OsHostPort;
181
+ /** The clock the kernel's `clock` ask is answered from, in epoch milliseconds; absent, the system clock. */
182
+ clock?: () => number;
183
+ }
184
+
185
+ /**
186
+ * Check whether a schema needs preprocessing (has `uses` declarations or
187
+ * un-inlined cross-orbital trait references).
188
+ *
189
+ * Cross-orbital refs are trait entries like
190
+ * `{ ref: "Modal.traits.ModalRecordModal", ... }` with no inline
191
+ * `stateMachine`. If these aren't resolved before `register()` runs, the
192
+ * trait binder produces an empty state machine and all interactions
193
+ * targeting the trait are silently dropped.
194
+ */
195
+ /**
196
+ * Walk a trait's DECLARED config schema (`{ icon: { type, default }, ... }`)
197
+ * and collect a flat `{ icon: <default>, ... }` map of just the default
198
+ * values. Used to seed the `@config.X` binding context with the atom's
199
+ * own declared defaults before any call-site override is applied. Mirrors
200
+ * the compiled path's `DEFAULT_<TRAIT>_CONFIG` constant emitted by
201
+ * backend.rs's Solution-1 plumbing.
202
+ *
203
+ * Returns `undefined` when the trait has no config schema or none of its
204
+ * fields declare a default — keeps the caller's existing fast-path.
205
+ */
206
+ /**
207
+ * Structural shape that both `@almadar/core`'s `Trait` and
208
+ * `ResolvedTrait` satisfy: a `config?` map keyed by field name whose
209
+ * values either carry a `default` (the declared-schema form loaded
210
+ * from `.orb`) or are bare values (the runtime-resolved form).
211
+ *
212
+ * Widening to a structural parameter lets callers from the resolved
213
+ * side (e.g., `@almadar/ui`'s `useTraitStateMachine`) pass their own
214
+ * `ResolvedTrait` without an `as unknown as` cast.
215
+ */
216
+ /**
217
+ * Read the `default` from each field of a trait's declared
218
+ * `config { }` schema and return the flat `{ key: default, ... }`
219
+ * map. Used to seed `@config.X` binding context with the atom's
220
+ * own declared defaults before any call-site override is applied.
221
+ *
222
+ * Mirrors the compiled path's `DEFAULT_<TRAIT>_CONFIG` constant
223
+ * emitted by `backend.rs` Solution-1.
224
+ */
225
+ /** A program with imports registered where `orb` cannot run (a browser): resolve it first (`orb resolve`). */
226
+ declare class UnresolvedProgramError extends Error {
227
+ constructor(schemaName: string);
228
+ }
229
+ /** What `register` takes beside the schema: the program's catalogs and the `uses lazy` behaviors the server runs alongside it. */
230
+ interface RegisterOptions {
231
+ messages?: MessageCatalogs;
232
+ lazy?: readonly OrbitalSchema[];
233
+ }
234
+ declare class OrbitalServerRuntime {
235
+ protected orbitals: Map<string, RegisteredOrbital>;
236
+ private eventBus;
237
+ private config;
238
+ /** The row store a host-supplied `persistence` replaces: the kernel's own `MemoryStore`, opened by the first `register()`. */
239
+ private ownedStore;
240
+ /** The owner cells the mock seed stamped, kept for a persona restamp. */
241
+ private mockJournal;
242
+ /** The std seed program resolved from the installed packages, once per runtime. */
243
+ private seedProgram;
244
+ /** Store writes (seed, reseed, restamp) run one after another. */
245
+ private storeOps;
246
+ /**
247
+ * The bound persistence adapter (host-supplied, else the kernel's own memory store). Public so a test can
248
+ * inspect committed rows honestly. A runtime that owns its store has one from the first `register()`.
249
+ */
250
+ get persistence(): PersistenceAdapter;
251
+ /** Whether this runtime seeds generated mock rows: mock mode over the store it owns. */
252
+ private seedsMock;
253
+ private tickBindings;
254
+ /** The kernel running the registered program; null before a program is registered. */
255
+ private kernelEngine;
256
+ /** The `os` handles of the program the kernel runs; closed when that program is replaced, reset or dropped. */
257
+ private kernelOs;
258
+ /** `orbital::trait` → the clients that have it mounted (Runtime Spec Clause 8.3). */
259
+ private readonly mountedBy;
260
+ private readonly tickScheduler;
261
+ private readonly transitionObservers;
262
+ private readonly transitionFanout;
263
+ private programHandlersPromise;
264
+ private resolvedSchema;
265
+ /** The program's declared `locales`, in declared order; the first is the default. */
266
+ private appLocales;
267
+ /** Merged message catalogs of every registered program (keys are behavior-qualified). */
268
+ private messages;
269
+ /** Wired by the hosting server (e.g. the playground SSE endpoint) via `setLiveBroadcastSink`. */
270
+ private readonly liveSubscribers;
271
+ private liveBroadcastSink;
272
+ private hostDispatchSink;
273
+ /**
274
+ * Tick-broadcast relay (T6): newest pending item per
275
+ * (originClientId, orbital, event), flushed to the live-broadcast sink on
276
+ * the `tickRelayIntervalMs` cadence — other tabs get the latest position
277
+ * at snapshot rate, never 1:1 with emissions.
278
+ */
279
+ private readonly tickRelayPending;
280
+ private tickRelayTimer;
281
+ constructor(config: OrbitalServerRuntimeConfig);
282
+ /**
283
+ * Lazily wire the program host handlers (behavior/* and program/* effects),
284
+ * merging them UNDER any user-provided handlers. Only when `programHost`
285
+ * is configured; otherwise the effects fail explicitly.
286
+ */
287
+ private ensureProgramHandlers;
288
+ /**
289
+ * Register an OrbitalSchema for execution.
290
+ *
291
+ * Auto-preprocesses the schema when it contains `uses` declarations or
292
+ * unresolved cross-orbital trait references (e.g. a trait with
293
+ * `ref: "Modal.traits.ModalRecordModal"` and no inline `stateMachine`).
294
+ * Without preprocessing, those refs arrive empty at the state machine and
295
+ * button clicks silently do nothing — see Phase 9.5.H.
296
+ *
297
+ * Preprocessing needs a loader. If `loaderConfig` is set, that loader is
298
+ * used. Otherwise, a default loader is constructed that points at
299
+ * `<cwd>` (for `basePath`) and the nearest `node_modules/@almadar/std` (for
300
+ * `stdLibPath`), which matches how every caller in this monorepo has the
301
+ * std registry on disk.
302
+ */
303
+ /**
304
+ * The in-flight (or last-completed) app mutation — `register()` chains its
305
+ * body onto this, and `unregisterAll()` stamps a marker after clearing.
306
+ * `processOrbitalEvent` consults it when the requested orbital is missing:
307
+ * during a catalog-style app swap the new schema's registration is already
308
+ * in flight while a client's first events arrive, and answering those with
309
+ * an immediate `Orbital not found` 404 (the pre-fix behavior) races the
310
+ * swap — big multi-orbital organisms lost their mount INITs intermittently
311
+ * while single-orbital ones almost always won. Awaiting the epoch and
312
+ * re-reading the map turns the race into a brief wait. `BrowserPlayground`
313
+ * gated dispatches on registration ad hoc for the same race; the epoch is
314
+ * the canonical, host-wide fix.
315
+ */
316
+ private registrationEpoch;
317
+ /**
318
+ * Reentrancy guard for `withRegistrationMutation`. While a bracket is
319
+ * open, `register()`/`unregisterAll()` must NOT chain/stamp the epoch:
320
+ * the callback's sequential awaits already order them, and chaining a
321
+ * `register()` awaited by the callback onto the bracket's gate would
322
+ * deadlock (callback → register → epoch → gate → callback's finally).
323
+ */
324
+ private registrationMutationDepth;
325
+ register(schema: OrbitalSchema, options?: RegisterOptions): Promise<void>;
326
+ private doRegister;
327
+ /** The kernel's own row store, opened once in the register phase when the host supplied none. */
328
+ private openOwnedStore;
329
+ /**
330
+ * Returns the schema that this runtime is currently executing, post-
331
+ * preprocessing. Safe to expose from an HTTP `/api/schema` endpoint — every
332
+ * cross-orbital trait ref will have an inline `stateMachine` already, which
333
+ * is what the browser's `schema-to-ir` resolver needs to wire button clicks
334
+ * back to state transitions.
335
+ *
336
+ * Returns `null` if `register()` hasn't run yet.
337
+ */
338
+ /** The registered program's name, or null when nothing is registered (none yet, or after `unregisterAll`). */
339
+ registeredSchemaName(): string | null;
340
+ getResolvedSchema(): OrbitalSchema | null;
341
+ /** The registered program's message catalogs (locale → qualified key → message), for a host's client. */
342
+ getMessages(): MessageCatalogs;
343
+ /**
344
+ * One-call entry point: read an `.orb` file from disk, parse it, preprocess
345
+ * cross-orbital imports, and register the result. Callers never touch raw
346
+ * `.orb` bytes — `register()` handles preprocessing internally.
347
+ *
348
+ * Node only. Browsers must receive already-resolved schemas from their
349
+ * server (see `getResolvedSchema()`).
350
+ */
351
+ registerFromFile(path: string): Promise<void>;
352
+ /** A program with imports resolved by `orb` from the configured base path (Node only: the one resolver is the compiler). */
353
+ private resolveWithOrb;
354
+ /**
355
+ * Register a single orbital
356
+ */
357
+ private registerOrbitalAsync;
358
+ /** The adapters the kernel's I/O is answered with: this runtime's persistence, services and program host. */
359
+ private httpPorts;
360
+ private kernelPorts;
361
+ /** One live message of a running `call-service`, stamped as its calling trait, to the requesting tab only. */
362
+ private deliverLiveMessage;
363
+ /** The project root this runtime hands `orb` and the kernel's language data: the program host's cwd, else the loader base path. */
364
+ private programRoot;
365
+ /** The kernel module this runtime runs on: the one the host handed in, else the installed `@almadar/kernel`. */
366
+ private kernelModule;
367
+ /** (Re)open the kernel on the program just registered. */
368
+ private openKernel;
369
+ /** Run the kernel's boot mounts for the server side (EXEC-ENDPOINT-3): the host sends what the kernel lists and chooses nothing. */
370
+ private mountBootEndpoints;
371
+ /** The program whose rows the store holds, once seeded; absent before the first seed and after `unregisterAll`. */
372
+ private seededProgram;
373
+ /** The std mock-seed program, resolved by `orb` from the installed packages. */
374
+ private resolveSeedProgram;
375
+ /** Run `use` with the seed program forked off the kernel just opened; the fork is released after. */
376
+ private withSeeder;
377
+ /** Store writes (seed, reseed, restamp) run one after another, so a persona switch never interleaves a reseed. */
378
+ private enqueueStoreOp;
379
+ /**
380
+ * Fill the store from the program, in the register phase: a mock runtime seeds every entity for the viewer, any
381
+ * other runtime seeds the rows the program writes out and its browser-stored entities.
382
+ */
383
+ private seedStores;
384
+ private managedProgram;
385
+ /**
386
+ * Name the program whose declared credentials this runtime's credential effects manage beside its own: an
387
+ * integrations console serving the app a host shows saves and tests that app's keys. Naming another replaces it.
388
+ */
389
+ manageCredentialsOf(program: OrbitalSchema): void;
390
+ /** A mock store seeds every entity; the `[runtime]` rows the kernel holds itself are seeded in the kernel. */
391
+ private seedKernelRuntimeMock;
392
+ private requireKernelEngine;
393
+ /**
394
+ * Set up scheduled ticks for all traits
395
+ */
396
+ private setupTicks;
397
+ /**
398
+ * Register a single tick
399
+ */
400
+ private registerTick;
401
+ /** A tick: the host owns the timer, the kernel decides whether and over which rows it fires. */
402
+ private executeTick;
403
+ /** Tell the kernel which traits some client has mounted, so it can pause the other traits' ticks. */
404
+ private syncTickMount;
405
+ /**
406
+ * Clean up all active ticks
407
+ */
408
+ private cleanupTicks;
409
+ /**
410
+ * Unregister all orbitals and clean up
411
+ */
412
+ /** A client mounts a trait by dispatching its lifecycle event and releases it with `$UNMOUNT`. */
413
+ private recordMount;
414
+ /** Drop every mount a disconnected client held, so its traits' mount-scoped ticks pause. */
415
+ releaseClient(clientId: string): void;
416
+ /** True while at least one client has `traitName` mounted. */
417
+ isTraitMounted(orbitalName: string, traitName: string): boolean;
418
+ unregisterAll(): void;
419
+ /**
420
+ * Bracket a multi-step app mutation (the classic swap is
421
+ * `unregisterAll()` → resolve next schema → `register()`) as ONE
422
+ * registration epoch. `register()` alone chains only its own body onto
423
+ * the epoch, so between `unregisterAll()` and the `register()` call the
424
+ * runtime's map is empty while the epoch marker has already resolved —
425
+ * any `processOrbitalEvent` that lands in that gap (the resolve of a big
426
+ * organism takes real time) 404s `Orbital not found` even though the
427
+ * requested orbital is milliseconds away from landing. Inside this
428
+ * bracket the epoch stays pending for the WHOLE callback, so mid-swap
429
+ * dispatches await the completed swap and then resolve against the new
430
+ * app. A failed callback still releases the epoch (chained on both
431
+ * branches), so a failed swap falls through to the honest 404 instead of
432
+ * wedging the queue. Callbacks SERIALIZE: each bracket awaits the previous
433
+ * epoch before running `fn`, so two hosts swapping at once (a catalog
434
+ * select racing a preview remount's `/register`) cannot interleave their
435
+ * unregister/register sequences into a mixed registry. A bracket opened
436
+ * from INSIDE another bracket's callback runs `fn` directly — detected
437
+ * via the AsyncLocalStorage context below (a depth counter alone can't
438
+ * tell a true nest from a concurrent caller) — because the outer
439
+ * callback's awaits already serialize it and queueing on the outer gate
440
+ * would deadlock. Deadlock-free otherwise: `doRegister` never dispatches
441
+ * events, so awaiting dispatches never block registration progress.
442
+ */
443
+ /**
444
+ * Reentrancy context for `withRegistrationMutation`. A depth counter alone
445
+ * cannot distinguish "called from inside a bracket callback" (must run
446
+ * directly — queueing on the outer gate would deadlock) from "called
447
+ * concurrently while another bracket is in flight" (must queue — running
448
+ * directly would interleave two swaps). The ALS marks the callback's async
449
+ * context, which separates the two exactly.
450
+ */
451
+ private bracketAls;
452
+ private ensureBracketAls;
453
+ withRegistrationMutation<T>(fn: () => Promise<T>): Promise<T>;
454
+ /**
455
+ * Reset the mock persistence store to a clean-slate re-seed without
456
+ * unregistering orbitals. Exposed for verifier tools that want to
457
+ * start each test with deterministic seeded rows, not the residue of
458
+ * the previous walk's persist-creates. No-op when the runtime does not
459
+ * seed a mock store of its own.
460
+ */
461
+ resetMockPersistence(): Promise<void>;
462
+ /**
463
+ * Return every registered orbital's circuit to boot: trait states to their
464
+ * initial states, frames and row cache emptied, and a fresh mount (no trait
465
+ * awaiting INIT, nothing held). The hermetic-reset twin of
466
+ * `resetMockPersistence`: a reset walk must not inherit the previous walk's
467
+ * circuit any more than its rows.
468
+ */
469
+ resetCircuitState(): void;
470
+ /**
471
+ * Wire a live-broadcast sink. Called only from a `persist` effect's
472
+ * `emit:{success}` envelope firing site (batch and single-op) — see
473
+ * `docs/Almadar_Live_Push.md`. The hosting server (e.g. the playground's
474
+ * `/api/events` SSE endpoint) uses this to fan persist mutations out to
475
+ * every OTHER connected client; a fresh call replaces the previous sink.
476
+ */
477
+ setLiveBroadcastSink(sink: (item: LiveBroadcastItem) => void): void;
478
+ private publishLiveItem;
479
+ /** Wire where a host-run dispatch's result goes (see `HostDispatchItem`); a fresh call replaces the previous sink. */
480
+ setHostDispatchSink(sink: (item: HostDispatchItem) => void): void;
481
+ /** Run a follow-on step's call outcome as its own dispatch, and hand its result to the host-dispatch sink. */
482
+ private runDeferredOutcome;
483
+ /**
484
+ * Switch the viewer a dev host presents the app as — see
485
+ * `OrbitalServerRuntimeConfig.defaultUser`. Pass `undefined` for an
486
+ * unauthenticated viewer. Takes effect on the next event; an authenticated
487
+ * request still overrides it.
488
+ *
489
+ * Mock mode stamps the seeded owner columns for whichever id was `defaultUser`
490
+ * at register time. Switching to a different id re-points those cells with
491
+ * `restampMockOwner` instead of re-seeding, so an ownership-scoped view for
492
+ * the new viewer has rows. The returned promise settles when the restamp has
493
+ * landed (immediately when there is nothing seeded yet; register flushes it).
494
+ */
495
+ setDefaultUser(user: UserContext | undefined): Promise<void>;
496
+ /** Whether the host named the viewer (constructor or `setDefaultUser`). If not, the viewer is
497
+ * the app's first declared persona, resolved as soon as its roster is seeded. */
498
+ private viewerNamedByHost;
499
+ /** setDefaultUser can land before register() finishes resolving the schema
500
+ * (a dev host pins a persona right after boot). An ungated restamp there
501
+ * would hand a read-only persona authorship of drafts, so the restamp is
502
+ * DEFERRED until the schema exists — register()/registerSync() flush it. */
503
+ private pendingOwnerRestamp;
504
+ /**
505
+ * Re-point the seeded owner cells at `user` (a persona switch never reseeds). The seed program's policy gates decide
506
+ * per row whether the persona could have created it. Deferred when the program is not seeded yet.
507
+ */
508
+ private restampOwnerGated;
509
+ /** Flush a persona switch that arrived before the schema was resolved. */
510
+ private flushPendingOwnerRestamp;
511
+ /** The viewer a dev host is currently presenting the app as. */
512
+ getDefaultUser(): UserContext | undefined;
513
+ /**
514
+ * Queue a tick-stamped dispatch for coalesced snapshot relay (T6). Newest
515
+ * per (originClientId, orbital, event) wins between flushes — the standard
516
+ * netcode position-broadcast discipline.
517
+ */
518
+ private queueTickRelay;
519
+ private flushTickRelay;
520
+ /**
521
+ * The registered app's declared persona roster: the live rows of its
522
+ * `[identity]` entity, mapped onto viewers (`Almadar_LOLO_Identity.md` §4.3).
523
+ * Live-store rows rather than a re-derivation, so the roster carries the ids
524
+ * ownership scoping actually compares `@user.id` against. Empty when no
525
+ * schema is registered or the app declares no `[identity]` entity — there is
526
+ * no global fallback roster by design.
527
+ */
528
+ /**
529
+ * `reference` resolved for `user` against the store as it is now: the rows that still match its query and the
530
+ * viewer's `@read`, in the reference's order, `total` re-counted. The kernel resolves through its server
531
+ * resolve flight. A client reaches it with
532
+ * `POST /:orbital/../resolve-rows` as the signed-in viewer.
533
+ */
534
+ resolveRows(reference: RowSetRef, user: UserContext): Promise<RowQueryPage>;
535
+ getIdentityRoster(): Promise<UserContext[]>;
536
+ /**
537
+ * Process an event for an orbital — the stateful host's thin shell over
538
+ * the unified `evaluateOrbitalEvent` composition (design:
539
+ * docs/Almadar_Runtime_Stateless_Stateful_PLAN.md §4.1). This method owns
540
+ * ONLY session concerns: orbital lookup, viewer normalization, the lazy
541
+ * OS/substrate handler wiring, the per-request relay mask
542
+ * (G-RUNTIME-031 — the client's mounted set as DATA, replacing the
543
+ * deleted blanket `originClientId` skip), the tick snapshot relay, and
544
+ * the cross-orbital listens relay (a listener registered under a
545
+ * DIFFERENT orbital than the emitter — the per-orbital composition's
546
+ * in-band fan-out covers the rest). Target resolution, payload
547
+ * validation, the cascade, the fan-out, structured rejections, and
548
+ * response assembly are the composition's, identical to the stateless
549
+ * path.
550
+ *
551
+ * Serialization: the whole evaluation runs on ONE runtime-wide async
552
+ * queue. The composition commits manager state directly (no per-trait
553
+ * actor queue), so concurrent requests against the long-lived session
554
+ * manager would otherwise both evaluate from the same held state and
555
+ * lose a transition. Coarser than the old per-(trait, entityId) actor
556
+ * queues — a deliberate W4 tradeoff, recorded in the plan doc.
557
+ *
558
+ * @param onPush - Optional incremental-push callback. Called immediately
559
+ * when an event is emitted or a client effect fires, before the promise
560
+ * resolves. Used by the SSE streaming path to write items to the
561
+ * response as they arrive rather than buffering and flushing at the end.
562
+ */
563
+ /**
564
+ * Read an orbital by name, awaiting an in-flight registration mutation
565
+ * first when the lookup misses (G-RUNTIME-038): mid-swap lookups 404ed
566
+ * against the emptied map even though the requested orbital was
567
+ * milliseconds from landing. A failed mutation falls through to the miss.
568
+ */
569
+ private resolveRegisteredOrbital;
570
+ /** The registered orbitals as `GET /` lists them. */
571
+ listOrbitalSummaries(): OrbitalSummary[];
572
+ /** One orbital as `GET /:orbital` describes it, awaiting an in-flight swap first (G-RUNTIME-038); `undefined` when it is not registered. */
573
+ describeOrbital(orbitalName: string): Promise<OrbitalInfo | undefined>;
574
+ /** An entity's full row set as `GET /:orbital/entities/:entityType` answers it (verification and tooling only); `undefined` when the orbital is not registered. */
575
+ entityRows(orbitalName: string, entityType: string): Promise<EntityRow[] | undefined>;
576
+ /** The program's declared external inputs: what an outside client may send which trait. */
577
+ listExternalInputs(): ExternalInput[];
578
+ /**
579
+ * The outside-client input channel: an API caller, an agent acting as the
580
+ * user, an MCP client. Only a declared external input of the target trait is
581
+ * dispatched — through `processOrbitalEvent`, so guards, entity policies and
582
+ * cascades apply exactly as for a click. Anything else is refused with
583
+ * `not-an-external-input`. The app's own UI keeps using `processOrbitalEvent`.
584
+ */
585
+ /**
586
+ * The running app lent to one `call-service` provider as the caller: the
587
+ * declared inputs, the input channel as `user`, and the rows `user` may read
588
+ * (the entity's `@read` policy, the same rule a `fetch` effect applies).
589
+ */
590
+ servicePorts(caller: {
591
+ orbital: string;
592
+ trait: string;
593
+ }, user: UserContext | undefined, message?: (payload: EventPayload) => void, assertReentry?: () => void): ServiceHostPorts;
594
+ /**
595
+ * A `program/dispatch` event request, as the events route (or with `input`, the inputs route) runs it: the
596
+ * request's own `user` is its viewer, else the caller's. An unknown orbital is `ORBITAL_NOT_FOUND`, an undeclared
597
+ * locale `LOCALE_NOT_DECLARED`; an inbound-only event and an undeclared input are the routes' refusals.
598
+ */
599
+ dispatchEventRequest(orbital: string, request: OrbitalEventRequest, input: boolean, caller: UserContext | undefined, stream?: boolean): Promise<DispatchRequestOutcome>;
600
+ dispatchExternalInput(orbitalName: string, request: ExternalInputRequest, onPush?: (item: PushItem) => void): Promise<OrbitalEventResponse>;
601
+ /**
602
+ * An inbound delivery (`/api/hooks/<name>`): the runtime decides whether the name is served, runs
603
+ * the handler through `processOrbitalEvent` and answers; the host only carries the bytes.
604
+ */
605
+ /**
606
+ * An event that is an inbound hook's is delivered only by `deliverInbound`: the app's own event
607
+ * route refuses it, as the input channel refuses an event that is no declared input.
608
+ */
609
+ refuseInboundOnly(orbitalName: string, request: Pick<OrbitalEventRequest, 'event' | 'targetTrait'>): OrbitalEventResponse | undefined;
610
+ deliverInbound(name: string, delivery: InboundDelivery, onPush?: (item: PushItem) => void): Promise<InboundAnswer>;
611
+ processOrbitalEvent(orbitalName: string, request: OrbitalEventRequest, onPush?: (item: PushItem) => void): Promise<OrbitalEventResponse>;
612
+ /**
613
+ * The enqueued critical section behind `processOrbitalEvent`: evaluate
614
+ * one request through the composition, then relay its emits to
615
+ * cross-orbital listeners. MUST only run holding the event queue.
616
+ */
617
+ private evaluateForOrbital;
618
+ /**
619
+ * Feed the host sinks from a kernel response: the kernel answers a dispatch whole, so each emit reaches the
620
+ * event bus (the public firehose) and `onPush` once the dispatch is done, in the order the response carries them.
621
+ */
622
+ private publishKernelResponse;
623
+ /**
624
+ * The runtime-wide event queue — ONE async serialization point for every
625
+ * composition run (requests, cross-orbital relays, external emits, tick
626
+ * relays). The composition commits manager state directly rather than
627
+ * through the manager's per-(trait, entityId) actor queues, so without
628
+ * this, two concurrent requests against the session manager could both
629
+ * evaluate from the same held state and lose a transition. `run` sees
630
+ * the caller's result (or throw); the queue itself never wedges on a
631
+ * failure.
632
+ */
633
+ private eventQueue;
634
+ /** This app's in-flight keyed `call-service`s, shared by every transition it runs (`cancel-call`). */
635
+ private readonly inFlightCalls;
636
+ /** Wait for the queue, then hold it until the returned release is called. FIFO. */
637
+ private acquireEventQueue;
638
+ /**
639
+ * Hold the queue for `run`, handing it the hold so the work it reaches can
640
+ * release it (`outsideEventQueue`). The hold is passed explicitly rather than
641
+ * carried in async context: this runtime also runs in the browser (the orb
642
+ * website), which has no AsyncLocalStorage.
643
+ */
644
+ private enqueueEvent;
645
+ /**
646
+ * Run `work` with this context's queue hold released, then re-acquire it (in
647
+ * FIFO order behind whatever queued meanwhile). Dispatches that land while
648
+ * released run as their own dispatches; their commits and the held run's
649
+ * later commit follow server-arrival last-write-wins. Outside a hold, `work`
650
+ * just runs.
651
+ */
652
+ private outsideEventQueue;
653
+ /**
654
+ * Get the event bus for manual event emission
655
+ */
656
+ getEventBus(): EventBus;
657
+ /** Observe every executed hop (listener deliveries included) on every orbital; returns the unsubscribe. */
658
+ observeTransitions(observer: TransitionObserver): () => void;
659
+ /**
660
+ * Get state for a specific orbital/trait
661
+ */
662
+ getState(orbitalName: string, traitName?: string): TraitState | Record<string, TraitState> | undefined;
663
+ /**
664
+ * List registered orbitals
665
+ */
666
+ listOrbitals(): string[];
667
+ /**
668
+ * Check if an orbital is registered
669
+ */
670
+ hasOrbital(name: string): boolean;
671
+ /**
672
+ * Get information about active ticks
673
+ */
674
+ getActiveTicks(): Array<{
675
+ orbital: string;
676
+ trait: string;
677
+ tick: string;
678
+ interval: number | string;
679
+ hasGuard: boolean;
680
+ }>;
681
+ /** Halt every registered tick's shared clock. Delegates to `TickScheduler.pause`. */
682
+ pauseTicks(): void;
683
+ /** Resume ticks halted by `pauseTicks()`. Delegates to `TickScheduler.resume`. */
684
+ resumeTicks(): void;
685
+ /** True while ticks are paused. Delegates to `TickScheduler.isPaused`. */
686
+ areTicksPaused(): boolean;
687
+ }
688
+ /**
689
+ * Factory function to create a runtime instance
690
+ */
691
+ declare function createOrbitalServerRuntime(config: OrbitalServerRuntimeConfig): OrbitalServerRuntime;
692
+
693
+ export { OrbitalServerRuntime, UnresolvedProgramError, createOrbitalServerRuntime };
694
+ export type { HostDispatchItem, LiveBroadcastItem, LoaderConfig, OrbitalInfo, OrbitalServerRuntimeConfig, OrbitalSummary, PushItem, RegisterOptions, RegisteredOrbital, RuntimeOrbital, RuntimeOrbitalSchema, RuntimeTrait, RuntimeTraitTick };