@almadar/shell-runtime 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/chunk-2JU7Y4KU.js +21 -0
- package/dist/chunk-46RWK2B5.js +28 -0
- package/dist/chunk-4J2QEIUV.js +78 -0
- package/dist/chunk-4SEK5ER2.js +8 -0
- package/dist/chunk-4ZICQ5PM.js +192 -0
- package/dist/chunk-53IPZXDP.js +76 -0
- package/dist/chunk-5D63EMO5.js +16 -0
- package/dist/chunk-64IH2SMY.js +22 -0
- package/dist/chunk-7SDV3QWR.js +67 -0
- package/dist/chunk-CPSQXEJ6.js +55 -0
- package/dist/chunk-CQP5XAX6.js +173 -0
- package/dist/chunk-CROS2GEX.js +49 -0
- package/dist/chunk-D4XJTBLB.js +217 -0
- package/dist/chunk-D5USD2EX.js +232 -0
- package/dist/chunk-DYOJGLIX.js +25 -0
- package/dist/chunk-ELBLT2HZ.js +1 -0
- package/dist/chunk-EV56K4GB.js +63 -0
- package/dist/chunk-EZZYLTWY.js +1 -0
- package/dist/chunk-FQ6IZMIU.js +10 -0
- package/dist/chunk-FWA5K7Q2.js +48 -0
- package/dist/chunk-HC6ERSAH.js +55 -0
- package/dist/chunk-HLOUDLPI.js +48 -0
- package/dist/chunk-HMK6YMQS.js +135 -0
- package/dist/chunk-HNOAZWFH.js +19 -0
- package/dist/chunk-IHQLE5M7.js +62 -0
- package/dist/chunk-IOPUS6Q5.js +15 -0
- package/dist/chunk-JFWFDUTR.js +35 -0
- package/dist/chunk-LZIOTBFX.js +1 -0
- package/dist/chunk-MHYSHSRG.js +54 -0
- package/dist/chunk-MLKGABMK.js +7 -0
- package/dist/chunk-MZKIL5IN.js +74 -0
- package/dist/chunk-NAECVIAR.js +322 -0
- package/dist/chunk-NATGCIVM.js +583 -0
- package/dist/chunk-O57GKTYU.js +30 -0
- package/dist/chunk-ODJCZ27I.js +50 -0
- package/dist/chunk-P53CKOME.js +1 -0
- package/dist/chunk-Q2H75UYT.js +92 -0
- package/dist/chunk-Q7JK4KY7.js +9 -0
- package/dist/chunk-QELZ6TEJ.js +208 -0
- package/dist/chunk-QQRDUMB2.js +40 -0
- package/dist/chunk-RBUMDYFS.js +681 -0
- package/dist/chunk-REPX5QPI.js +57 -0
- package/dist/chunk-SAS5KKCR.js +43 -0
- package/dist/chunk-SKLMWHQD.js +109 -0
- package/dist/chunk-SOQDEPME.js +131 -0
- package/dist/chunk-SWPDU752.js +28 -0
- package/dist/chunk-T775TUCD.js +18 -0
- package/dist/chunk-UBN5JJKZ.js +26 -0
- package/dist/chunk-UJHOUZAL.js +36 -0
- package/dist/chunk-UP6GGGAN.js +34 -0
- package/dist/chunk-VMOBW7RK.js +21 -0
- package/dist/chunk-VNMG7NKY.js +69 -0
- package/dist/chunk-WNPNNYXY.js +22 -0
- package/dist/chunk-XB5GYODW.js +28 -0
- package/dist/chunk-XXWNMJI6.js +15 -0
- package/dist/chunk-YL2SO5TP.js +334 -0
- package/dist/chunk-YO4LWS3I.js +606 -0
- package/dist/chunk-ZAQSS47X.js +157 -0
- package/dist/chunk-ZCQUUJIF.js +129 -0
- package/dist/client/EventTransport.d.ts +131 -0
- package/dist/client/EventTransport.js +2 -0
- package/dist/client/ServerBridge.d.ts +126 -0
- package/dist/client/ServerBridge.js +3 -0
- package/dist/client/awaiting.d.ts +28 -0
- package/dist/client/awaiting.js +2 -0
- package/dist/client/channel-transport.d.ts +69 -0
- package/dist/client/channel-transport.js +2 -0
- package/dist/client/circuit-store.d.ts +76 -0
- package/dist/client/circuit-store.js +4 -0
- package/dist/client/client-kernel.d.ts +113 -0
- package/dist/client/client-kernel.js +1 -0
- package/dist/client/declared-input-dispatch.d.ts +5 -0
- package/dist/client/declared-input-dispatch.js +2 -0
- package/dist/client/inbound-dispatch.d.ts +5 -0
- package/dist/client/inbound-dispatch.js +2 -0
- package/dist/client/local-fold.d.ts +26 -0
- package/dist/client/local-fold.js +2 -0
- package/dist/client/render-sigils.d.ts +24 -0
- package/dist/client/render-sigils.js +2 -0
- package/dist/client/state-book.d.ts +37 -0
- package/dist/client/state-book.js +2 -0
- package/dist/client/trait-mount-error.d.ts +9 -0
- package/dist/client/trait-mount-error.js +2 -0
- package/dist/client/trait-types.d.ts +67 -0
- package/dist/client/trait-types.js +1 -0
- package/dist/credentials/env-vars.d.ts +14 -0
- package/dist/credentials/env-vars.js +3 -0
- package/dist/credentials/scope.d.ts +50 -0
- package/dist/credentials/scope.js +2 -0
- package/dist/credentials/seed.d.ts +21 -0
- package/dist/credentials/seed.js +2 -0
- package/dist/credentials/store.d.ts +110 -0
- package/dist/credentials/store.js +2 -0
- package/dist/effects/in-flight-calls.d.ts +36 -0
- package/dist/effects/in-flight-calls.js +2 -0
- package/dist/effects/on-device-model.d.ts +22 -0
- package/dist/effects/on-device-model.js +2 -0
- package/dist/events/EventBus.d.ts +90 -0
- package/dist/events/EventBus.js +2 -0
- package/dist/events/emit-stamp.d.ts +47 -0
- package/dist/events/emit-stamp.js +2 -0
- package/dist/index-hT1xCdTq.d.ts +46 -0
- package/dist/index.d.ts +60 -0
- package/dist/index.js +59 -0
- package/dist/kernel/beacon.d.ts +32 -0
- package/dist/kernel/beacon.js +2 -0
- package/dist/kernel/decode.d.ts +15 -0
- package/dist/kernel/decode.js +2 -0
- package/dist/kernel/engine.d.ts +94 -0
- package/dist/kernel/engine.js +11 -0
- package/dist/kernel/frame-applier.d.ts +43 -0
- package/dist/kernel/frame-applier.js +2 -0
- package/dist/kernel/host.d.ts +95 -0
- package/dist/kernel/host.js +9 -0
- package/dist/kernel/http.d.ts +302 -0
- package/dist/kernel/http.js +6 -0
- package/dist/kernel/lane.d.ts +28 -0
- package/dist/kernel/lane.js +2 -0
- package/dist/kernel/oauth-effects.d.ts +25 -0
- package/dist/kernel/oauth-effects.js +7 -0
- package/dist/kernel/oauth-port.d.ts +31 -0
- package/dist/kernel/oauth-port.js +2 -0
- package/dist/kernel/os-port.d.ts +133 -0
- package/dist/kernel/os-port.js +2 -0
- package/dist/kernel/program-effects.d.ts +65 -0
- package/dist/kernel/program-effects.js +2 -0
- package/dist/kernel/wire.d.ts +66 -0
- package/dist/kernel/wire.js +1 -0
- package/dist/loader/http-loader.d.ts +111 -0
- package/dist/loader/http-loader.js +2 -0
- package/dist/loader/lazy-page.d.ts +12 -0
- package/dist/loader/lazy-page.js +2 -0
- package/dist/loader/schema-loader.d.ts +160 -0
- package/dist/loader/schema-loader.js +1 -0
- package/dist/persistence/native-memory.d.ts +28 -0
- package/dist/persistence/native-memory.js +2 -0
- package/dist/runtime/effects/composition/compose-behaviors.d.ts +58 -0
- package/dist/runtime/effects/composition/compose-behaviors.js +4 -0
- package/dist/runtime/effects/composition/event-wiring.d.ts +38 -0
- package/dist/runtime/effects/composition/event-wiring.js +2 -0
- package/dist/runtime/effects/composition/index.d.ts +5 -0
- package/dist/runtime/effects/composition/index.js +6 -0
- package/dist/runtime/effects/composition/layout-strategy.d.ts +35 -0
- package/dist/runtime/effects/composition/layout-strategy.js +2 -0
- package/dist/runtime/effects/composition/pipe.d.ts +25 -0
- package/dist/runtime/effects/composition/pipe.js +2 -0
- package/dist/runtime/entities/mockStoreSeed.d.ts +56 -0
- package/dist/runtime/entities/mockStoreSeed.js +3 -0
- package/dist/runtime/entities/seedBrowserStore.d.ts +28 -0
- package/dist/runtime/entities/seedBrowserStore.js +2 -0
- package/dist/runtime/entities/std-mock-seed.d.ts +87 -0
- package/dist/runtime/entities/std-mock-seed.js +2 -0
- package/dist/runtime/evaluation/local-store-transport.d.ts +68 -0
- package/dist/runtime/evaluation/local-store-transport.js +18 -0
- package/dist/runtime/evaluation/residence-transport.d.ts +15 -0
- package/dist/runtime/evaluation/residence-transport.js +2 -0
- package/dist/runtime/evaluation/routed-persistence.d.ts +9 -0
- package/dist/runtime/evaluation/routed-persistence.js +2 -0
- package/dist/runtime/events/identity/routing.d.ts +84 -0
- package/dist/runtime/events/identity/routing.js +2 -0
- package/dist/runtime/time/TickScheduler.d.ts +77 -0
- package/dist/runtime/time/TickScheduler.js +3 -0
- package/dist/runtime/time/cron.d.ts +25 -0
- package/dist/runtime/time/cron.js +2 -0
- package/dist/runtime/time/duration.d.ts +20 -0
- package/dist/runtime/time/duration.js +2 -0
- package/dist/runtime/traits/OrbitalTraitParsing.d.ts +34 -0
- package/dist/runtime/traits/OrbitalTraitParsing.js +2 -0
- package/dist/runtime/traits/listen-targets.d.ts +16 -0
- package/dist/runtime/traits/listen-targets.js +3 -0
- package/dist/runtime/traits/trait-index.d.ts +35 -0
- package/dist/runtime/traits/trait-index.js +3 -0
- package/dist/runtime/types.d.ts +574 -0
- package/dist/runtime/types.js +2 -0
- package/dist/service/default-call-service.d.ts +23 -0
- package/dist/service/default-call-service.js +3 -0
- package/dist/service/service-provider.d.ts +37 -0
- package/dist/service/service-provider.js +2 -0
- package/package.json +46 -3
- package/README.md +0 -3
|
@@ -0,0 +1,574 @@
|
|
|
1
|
+
import { CallServiceHandler } from '../service/default-call-service.js';
|
|
2
|
+
import { ServiceCallContext } from '../service/service-provider.js';
|
|
3
|
+
import { EventPayload, BusEventSource, BusEventListener, Unsubscribe as Unsubscribe$1, BusEvent, EntityRow, TraitConfig, UserContext, NavItem, RuntimeValue, TraitId, OrbitalId, EventId, FieldValue, SExpr, FetchResult, RowSetRef, PatternConfig, OrbitalDefinition, PageFactField, BrowserPageFacts, JsonValue, ServiceHostPorts, AgentContext, LlmContext, WorkspaceContext, SessionContext, MemoryContext, TraceContext, ResolvedPatternProps } from '@almadar/core';
|
|
4
|
+
export { EntityRow, EventPayload, FetchResult, ServiceParams } from '@almadar/core';
|
|
5
|
+
import { ProgramEffectName, ProgramEffectOutcome } from '../kernel/program-effects.js';
|
|
6
|
+
import { ComposeBehaviorsInput, ComposeBehaviorsResult } from './effects/composition/compose-behaviors.js';
|
|
7
|
+
import { EventWiringEntry } from './effects/composition/event-wiring.js';
|
|
8
|
+
import { LayoutStrategy } from './effects/composition/layout-strategy.js';
|
|
9
|
+
import { PipeStep } from './effects/composition/pipe.js';
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Unified Runtime Types
|
|
13
|
+
*
|
|
14
|
+
* Platform-agnostic interfaces for trait execution on client or server.
|
|
15
|
+
*
|
|
16
|
+
* @packageDocumentation
|
|
17
|
+
*/
|
|
18
|
+
|
|
19
|
+
/** Alias for ResolvedPatternProps to avoid breaking internal consumers */
|
|
20
|
+
type PatternProps = ResolvedPatternProps;
|
|
21
|
+
/**
|
|
22
|
+
* Value a render-ui pattern prop can carry AFTER interpolation. Mirrors
|
|
23
|
+
* `FieldValue` but extends with `RuntimeRenderPattern` so nested pattern
|
|
24
|
+
* configs (children, slot props that are themselves render-ui nodes)
|
|
25
|
+
* round-trip without an `unknown` escape hatch.
|
|
26
|
+
*/
|
|
27
|
+
type RuntimePatternValue = string | number | boolean | null | undefined | EntityRow | EntityRow[] | readonly RuntimePatternValue[] | RuntimeRenderPattern;
|
|
28
|
+
/**
|
|
29
|
+
* Shape of a render-ui pattern AFTER interpolation, as the runtime hands
|
|
30
|
+
* it to `EffectHandlers.renderUI`. Different from `ResolvedPatternProps`
|
|
31
|
+
* (`@almadar/core`) because the post-interpolation pattern carries
|
|
32
|
+
* resolved EntityRow values (e.g. `{ entity: <row> }` from `@payload.row`)
|
|
33
|
+
* not just primitives. Used by render-ui observability helpers to narrow
|
|
34
|
+
* safely without `unknown` casts.
|
|
35
|
+
*/
|
|
36
|
+
interface RuntimeRenderPattern {
|
|
37
|
+
readonly [prop: string]: RuntimePatternValue;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
type ConfigContext = TraitConfig;
|
|
41
|
+
/**
|
|
42
|
+
* Event structure for cross-trait communication.
|
|
43
|
+
* Re-export of `BusEvent` from `@almadar/core` so runtime + ui + codegen
|
|
44
|
+
* all agree on the bus envelope shape. `RuntimeEvent` is kept as a type
|
|
45
|
+
* alias for anyone importing by the old name.
|
|
46
|
+
*/
|
|
47
|
+
type RuntimeEvent = BusEvent;
|
|
48
|
+
type EventListener = BusEventListener;
|
|
49
|
+
type Unsubscribe = Unsubscribe$1;
|
|
50
|
+
/**
|
|
51
|
+
* Event bus interface for pub/sub communication
|
|
52
|
+
*/
|
|
53
|
+
interface IEventBus {
|
|
54
|
+
/** Emit an event. `routingKey` (V4) keys delivery by event-id when the
|
|
55
|
+
* schema carries ids; absent → keyed by `type` (name, legacy). */
|
|
56
|
+
emit(type: string, payload?: EventPayload, source?: BusEventSource, routingKey?: string): void;
|
|
57
|
+
/** Subscribe to an event */
|
|
58
|
+
on(type: string, listener: EventListener): Unsubscribe;
|
|
59
|
+
/** Subscribe to ALL events (wildcard listener) */
|
|
60
|
+
onAny(listener: EventListener): Unsubscribe;
|
|
61
|
+
/** Check if there are listeners for an event */
|
|
62
|
+
hasListeners(type: string): boolean;
|
|
63
|
+
/** Get all registered event types */
|
|
64
|
+
getRegisteredEvents(): string[];
|
|
65
|
+
/** Clear all listeners */
|
|
66
|
+
clear(): void;
|
|
67
|
+
}
|
|
68
|
+
/**
|
|
69
|
+
* Result of processing an event through a state machine
|
|
70
|
+
*/
|
|
71
|
+
interface TransitionResult {
|
|
72
|
+
/** Whether a transition was executed */
|
|
73
|
+
executed: boolean;
|
|
74
|
+
/** New state after transition (same as current if not executed) */
|
|
75
|
+
newState: string;
|
|
76
|
+
/** Previous state before transition */
|
|
77
|
+
previousState: string;
|
|
78
|
+
/** Effects to execute (empty if guard failed or no transition found) */
|
|
79
|
+
effects: SExpr[];
|
|
80
|
+
/** The transition that was executed (undefined if none) */
|
|
81
|
+
transition?: {
|
|
82
|
+
from: string;
|
|
83
|
+
to: string;
|
|
84
|
+
event: string;
|
|
85
|
+
};
|
|
86
|
+
/** Guard evaluation result (undefined if no guard) */
|
|
87
|
+
guardResult?: boolean;
|
|
88
|
+
}
|
|
89
|
+
/**
|
|
90
|
+
* Effect handlers interface - platform-specific implementations
|
|
91
|
+
*
|
|
92
|
+
* Client: React hooks, DOM, router
|
|
93
|
+
* Server: Express, database, integrators
|
|
94
|
+
*/
|
|
95
|
+
/** What one `http` effect came to: the `<METHOD> <origin><path>` it addressed and, on failure, the declared `emit.failure` event the program routed it to. */
|
|
96
|
+
interface HttpEffectReport {
|
|
97
|
+
success: boolean;
|
|
98
|
+
target: string;
|
|
99
|
+
error?: string;
|
|
100
|
+
routed?: string;
|
|
101
|
+
}
|
|
102
|
+
interface EffectHandlers {
|
|
103
|
+
/**
|
|
104
|
+
* Emit an event to the event bus.
|
|
105
|
+
*
|
|
106
|
+
* `source` carries the emitter's identity (orbital + trait) so that
|
|
107
|
+
* source-scoped listeners (`TraitName EVENT -> TRIGGER` and
|
|
108
|
+
* `Orbital.TraitName EVENT -> TRIGGER` in .lolo) can filter incoming
|
|
109
|
+
* events by their originating trait. Omitted when the emit is
|
|
110
|
+
* synthesized by a non-trait context (e.g. test harness).
|
|
111
|
+
*
|
|
112
|
+
* `fromPersistSuccess` is set only by `EffectExecutor`'s `persist` case
|
|
113
|
+
* (batch and single-op), never inferred from the event name — the
|
|
114
|
+
* positional signal a server-side implementation uses to also fan this
|
|
115
|
+
* emit out to other connected clients (live-broadcast). Absent/false
|
|
116
|
+
* for every other emit source (plain `emit` effect, `set`/`call-service`/
|
|
117
|
+
* `fetch` success envelopes, cascade re-emits).
|
|
118
|
+
*/
|
|
119
|
+
emit: (event: string, payload?: EventPayload, source?: RuntimeEvent['source'], fromPersistSuccess?: boolean) => void;
|
|
120
|
+
/**
|
|
121
|
+
* Persist data (create/update/delete/batch).
|
|
122
|
+
*
|
|
123
|
+
* Returns the persisted ROW — for a create that is the submitted data
|
|
124
|
+
* plus the store-minted `id`, which the caller's `emit:{success}`
|
|
125
|
+
* envelope carries. Without it a `*_CREATED` listener sees no id (the
|
|
126
|
+
* compiled path emits the created row), so anything routing on the new
|
|
127
|
+
* row's identity — navigating to the page just created — worked in one
|
|
128
|
+
* execution path only.
|
|
129
|
+
*
|
|
130
|
+
* `create`/`update`/`delete` (batch is separate — see `PersistBatchSummary`)
|
|
131
|
+
* return `undefined` ONLY to signal the write was DENIED or otherwise
|
|
132
|
+
* failed (a policy rejection, a missing row key, a no-op stub) — never
|
|
133
|
+
* a genuine success with nothing to report, since every real success
|
|
134
|
+
* branch sets a row. The caller (`EffectExecutor`'s `persist` case)
|
|
135
|
+
* treats `undefined` as a failure: it skips the declared `success`
|
|
136
|
+
* emit entirely rather than falling back to the submitted data, which
|
|
137
|
+
* previously made a denied delete indistinguishable from a completed
|
|
138
|
+
* one.
|
|
139
|
+
*/
|
|
140
|
+
persist: (action: 'create' | 'upsert' | 'update' | 'delete' | 'batch', entityType: string, data?: EntityRow) => Promise<EntityRow | undefined>;
|
|
141
|
+
/**
|
|
142
|
+
* Runs a run of consecutive plain persists as stop-mode requests (one when nothing is refused) when the store declares it. Answers the
|
|
143
|
+
* per-op results in order (`undefined` = that persist failed, a handled outcome, and the ones after it still run).
|
|
144
|
+
* Answers `null` when the run cannot be pushed, and the executor then runs the effects one by one.
|
|
145
|
+
*/
|
|
146
|
+
persistRun?: (ops: Array<{
|
|
147
|
+
action: 'create' | 'upsert' | 'update' | 'delete';
|
|
148
|
+
entityType: string;
|
|
149
|
+
data: EntityRow | string | undefined;
|
|
150
|
+
}>) => Promise<Array<EntityRow | undefined> | null>;
|
|
151
|
+
/**
|
|
152
|
+
* Bridge mode: the SERVER executes every persist of this dispatch and
|
|
153
|
+
* returns the real outcome in its response (`effectResults`), so the
|
|
154
|
+
* client's `persist` member is a placeholder that must never be read as
|
|
155
|
+
* a denial. When `true`, `EffectExecutor` skips the persist locally —
|
|
156
|
+
* no `persist:denied` error, no client-side `failure` emit (which fired
|
|
157
|
+
* the declared failure event in the browser while the server had
|
|
158
|
+
* succeeded), no `success` emit either (the server's cascade carries it).
|
|
159
|
+
* Set by `@almadar/ui`'s `createClientEffectHandlers` when no live
|
|
160
|
+
* client entity is supplied; absent everywhere a handler really writes.
|
|
161
|
+
*/
|
|
162
|
+
persistDelegated?: true;
|
|
163
|
+
/**
|
|
164
|
+
* Bridge mode: the SERVER runs every `call-service` of this dispatch and
|
|
165
|
+
* its cascade carries the success/failure emits, so the client's mock
|
|
166
|
+
* `callService` must not also run one. Set by `@almadar/ui`'s
|
|
167
|
+
* `createClientEffectHandlers` when no consumer `callService` is wired.
|
|
168
|
+
*/
|
|
169
|
+
callServiceDelegated?: true;
|
|
170
|
+
/**
|
|
171
|
+
* Set a field value on an entity. `void` for a client-side/in-memory
|
|
172
|
+
* handler (synchronous mutation); `Promise<void>` for a server-side
|
|
173
|
+
* handler backed by real persistence (e.g. `createServerEffectHandlers`,
|
|
174
|
+
* Firestore) — callers MUST `await` this, not just call it, or the
|
|
175
|
+
* write (and any telemetry it records) can still be in flight when the
|
|
176
|
+
* caller moves on. Verified 2026-09-15: `EffectExecutor.dispatch`'s
|
|
177
|
+
* 'set' case called this without `await`, invisible against every
|
|
178
|
+
* existing (synchronous, in-memory) test but a real dropped-write race
|
|
179
|
+
* the instant a real async persistence backend (Firestore) was wired in.
|
|
180
|
+
*/
|
|
181
|
+
set: (entityId: string, field: string, value: FieldValue) => void | Promise<void>;
|
|
182
|
+
/** Report the outcome of an `http` effect to the host's effect trace. */
|
|
183
|
+
httpResult?: (report: HttpEffectReport) => void;
|
|
184
|
+
/** Call an external service. `context` carries the caller's identity
|
|
185
|
+
* (the same viewer entity ACL enforces against) so role-gated services
|
|
186
|
+
* can enforce server-side; hosts forward it to the integration factory. */
|
|
187
|
+
callService: CallServiceHandler;
|
|
188
|
+
/** Fetch entity data (server only) - returns data for client-side rendering.
|
|
189
|
+
*
|
|
190
|
+
* Always returns a `FetchResult` (`{rows, total}`) on success. `total`
|
|
191
|
+
* is the count of rows matching the `filter` BEFORE `offset`/`limit`
|
|
192
|
+
* are applied so a paginating caller can compute totalPages without
|
|
193
|
+
* a second round-trip. Single-id fetches return `total: 1`. `null`
|
|
194
|
+
* means "not found / failed".
|
|
195
|
+
*/
|
|
196
|
+
fetch?: (entityType: string, options?: {
|
|
197
|
+
id?: string;
|
|
198
|
+
filter?: SExpr | Record<string, RuntimeValue>;
|
|
199
|
+
limit?: number;
|
|
200
|
+
offset?: number;
|
|
201
|
+
/** `"field"` or `"field:asc|desc"` — ordered before offset/limit */
|
|
202
|
+
orderBy?: string;
|
|
203
|
+
/** `none`: the store need not count every match; the success payload carries no `totalCount`. */
|
|
204
|
+
total?: 'exact' | 'none';
|
|
205
|
+
/** Relation fields to include (populate) in the response */
|
|
206
|
+
include?: string[];
|
|
207
|
+
}) => Promise<FetchResult | null>;
|
|
208
|
+
/** A collection fetch delivered by reference (`fetch … { deliver: ids }`, server only): the window's ids, the
|
|
209
|
+
* count of every match and the query that re-counts it at resolve time. Rejects when the fetch cannot be
|
|
210
|
+
* expressed as a row query, which the executor routes to `emit.failure`. */
|
|
211
|
+
fetchRowSet?: (entityType: string, options?: {
|
|
212
|
+
filter?: SExpr | Record<string, RuntimeValue>;
|
|
213
|
+
limit?: number;
|
|
214
|
+
offset?: number;
|
|
215
|
+
/** `"field"` or `"field:asc|desc"` — ordered before offset/limit */
|
|
216
|
+
orderBy?: string;
|
|
217
|
+
/** `none`: the store need not count every match; the success payload carries no `totalCount`. */
|
|
218
|
+
total?: 'exact' | 'none';
|
|
219
|
+
}) => Promise<RowSetRef>;
|
|
220
|
+
/** Stream an LLM or HTTP response (server only).
|
|
221
|
+
*
|
|
222
|
+
* Calls `onChunk` per incoming chunk; resolves with the final aggregated
|
|
223
|
+
* result on completion. The executor fires `emit.on_message` per chunk and
|
|
224
|
+
* `emit.success` on resolution. `null` means stream failed before any chunk.
|
|
225
|
+
*/
|
|
226
|
+
fetchStream?: (entityType: string, options: {
|
|
227
|
+
id?: string;
|
|
228
|
+
filter?: SExpr | Record<string, RuntimeValue>;
|
|
229
|
+
} | undefined, onChunk: (chunk: RuntimeValue) => void) => Promise<RuntimeValue>;
|
|
230
|
+
/** Spawn a new entity instance */
|
|
231
|
+
spawn?: (entityType: string, props?: EntityRow) => void;
|
|
232
|
+
/** Despawn (delete) an entity instance */
|
|
233
|
+
despawn?: (entityId: string) => void;
|
|
234
|
+
/** Send an orbital event to the server over WebSocket (client-only).
|
|
235
|
+
*
|
|
236
|
+
* Produces the wire message `{ type: 'ORBITAL_EVENT', payload: { orbital, event, payload, entityId? } }`
|
|
237
|
+
* which `setupEventBroadcast` decodes → server bus → `processOrbitalEvent`.
|
|
238
|
+
*/
|
|
239
|
+
sendServer?: (event: string, payload?: EventPayload) => void;
|
|
240
|
+
/** Render UI to a slot (client only). `pattern` is the post-interpolation
|
|
241
|
+
* `PatternConfig` from the trait's `(render-ui slot pattern)` SExpr, or
|
|
242
|
+
* `null` when the trait clears the slot (`render-ui slot null`).
|
|
243
|
+
* May be async: the server runtime injects relation option data
|
|
244
|
+
* (relationsData) read from the persistence adapter before pushing —
|
|
245
|
+
* the interpreter's mirror of codegen's build-time relationsData. */
|
|
246
|
+
renderUI?: (slot: string, pattern: PatternConfig | null) => void | Promise<void>;
|
|
247
|
+
/** Navigate to a route (client only). `crumb` labels the navigation-stack
|
|
248
|
+
* entry the client pushes for the target page (from the effect's
|
|
249
|
+
* `{ crumb: … }` options). */
|
|
250
|
+
navigate?: (path: string, params?: {
|
|
251
|
+
[key: string]: string;
|
|
252
|
+
}, crumb?: string) => void;
|
|
253
|
+
/** Pop the orbital-scoped navigation stack and return to the previous
|
|
254
|
+
* entry (client only). */
|
|
255
|
+
navigateBack?: () => void;
|
|
256
|
+
/** Log a message */
|
|
257
|
+
log?: (message: string, level?: 'log' | 'warn' | 'error', data?: RuntimeValue) => void;
|
|
258
|
+
/** Ref: declarative data subscription (server: same as fetch) */
|
|
259
|
+
ref?: (entityType: string, options?: {
|
|
260
|
+
id?: string;
|
|
261
|
+
filter?: SExpr | Record<string, RuntimeValue>;
|
|
262
|
+
limit?: number;
|
|
263
|
+
offset?: number;
|
|
264
|
+
include?: string[];
|
|
265
|
+
}) => Promise<FetchResult | null>;
|
|
266
|
+
/** Deref: one-shot data read (server: same as fetch) */
|
|
267
|
+
deref?: (entityType: string, options?: {
|
|
268
|
+
id?: string;
|
|
269
|
+
filter?: SExpr | Record<string, RuntimeValue>;
|
|
270
|
+
}) => Promise<FetchResult | null>;
|
|
271
|
+
/** Swap!: atomic read-modify-write on an entity */
|
|
272
|
+
swap?: (entityType: string, entityId: string, transform: SExpr) => Promise<EntityRow | null>;
|
|
273
|
+
/** Watch: client-side reactive subscription (no-op on server) */
|
|
274
|
+
watch?: (entityType: string, options?: {
|
|
275
|
+
id?: string;
|
|
276
|
+
filter?: SExpr | Record<string, RuntimeValue>;
|
|
277
|
+
limit?: number;
|
|
278
|
+
}) => void;
|
|
279
|
+
/** Atomic: execute inner effects as a transaction */
|
|
280
|
+
atomic?: (effects: SExpr[]) => Promise<void>;
|
|
281
|
+
/** Compose multiple orbitals into one schema. Compile-time only. */
|
|
282
|
+
composeBehaviors?: (input: ComposeBehaviorsInput) => ComposeBehaviorsResult;
|
|
283
|
+
/** Apply cross-orbital event wiring. Compile-time only. */
|
|
284
|
+
applyEventWiring?: (orbitals: OrbitalDefinition[], wiring: EventWiringEntry[]) => OrbitalDefinition[];
|
|
285
|
+
/** Auto-detect layout strategy. Compile-time only. */
|
|
286
|
+
detectLayoutStrategy?: (orbitals: OrbitalDefinition[], wiring?: EventWiringEntry[]) => LayoutStrategy;
|
|
287
|
+
/** Left-to-right behavior pipeline. Compile-time only. */
|
|
288
|
+
pipeBehaviors?: <T>(seed: T, ...steps: Array<PipeStep<T, T>>) => T;
|
|
289
|
+
/** browser/open-file-picker — resolves with `{ files }` inside `result` */
|
|
290
|
+
browserOpenFilePicker?: (options?: BrowserFilePickerOptions) => Promise<{
|
|
291
|
+
files: BrowserFileMeta[];
|
|
292
|
+
}>;
|
|
293
|
+
/** browser/clipboard-read — resolves with `{ text }` inside `result` */
|
|
294
|
+
browserClipboardRead?: () => Promise<{
|
|
295
|
+
text: string;
|
|
296
|
+
}>;
|
|
297
|
+
/** browser/clipboard-write — resolves with `{ text }` (echo) inside `result` */
|
|
298
|
+
browserClipboardWrite?: (text: string) => Promise<{
|
|
299
|
+
text: string;
|
|
300
|
+
}>;
|
|
301
|
+
/** browser/geolocation-current — resolves with the position inside `result` */
|
|
302
|
+
browserGeolocationCurrent?: (options?: BrowserGeolocationOptions) => Promise<BrowserGeolocationPosition>;
|
|
303
|
+
/**
|
|
304
|
+
* browser/page-facts — reads the requested facts in the order given and resolves with the flat facts
|
|
305
|
+
* (`PAGE_FACTS_SHAPE`). No page resolves `available: false`; a getter that throws rejects, which is not no-page.
|
|
306
|
+
*/
|
|
307
|
+
browserPageFacts?: (fields: readonly PageFactField[]) => Promise<BrowserPageFacts>;
|
|
308
|
+
/**
|
|
309
|
+
* browser/prompt — the on-device model's raw reply text for `text` under the JSON Schema text; rejects with an
|
|
310
|
+
* `OnDeviceModelFailure` (`unconfigured`, `unavailable` or `failed`), and stops on an aborted `signal`.
|
|
311
|
+
*/
|
|
312
|
+
browserPrompt?: (text: string, schemaText: string, key: string | null, signal?: AbortSignal) => Promise<string>;
|
|
313
|
+
/** browser/embed — one vector per text, in input order; rejects as `browserPrompt` does. */
|
|
314
|
+
browserEmbed?: (texts: readonly string[], key: string | null, signal?: AbortSignal) => Promise<number[][]>;
|
|
315
|
+
/** browser/push-subscribe — resolves with the flat Web Push subscription credentials inside `result` */
|
|
316
|
+
browserPushSubscribe?: () => Promise<{
|
|
317
|
+
endpoint: string;
|
|
318
|
+
p256dh: string;
|
|
319
|
+
auth: string;
|
|
320
|
+
}>;
|
|
321
|
+
programEffect?: (op: ProgramEffectName, args: readonly JsonValue[], context?: Pick<ServiceCallContext, 'principal' | 'role'>) => Promise<ProgramEffectOutcome>;
|
|
322
|
+
agentPorts?: () => ServiceHostPorts | undefined;
|
|
323
|
+
}
|
|
324
|
+
/**
|
|
325
|
+
* What a `batch` persist hands back — the shape `canonical-operators.json`
|
|
326
|
+
* declares for persist's batch branch, so the `emit: { success }` envelope
|
|
327
|
+
* carries exactly what the type system promises. Before this existed the
|
|
328
|
+
* envelope emitted the raw INPUT array, so `?completedCount` / `?totalCount`
|
|
329
|
+
* read `undefined` at runtime.
|
|
330
|
+
*
|
|
331
|
+
* Structurally an {@link EntityRow} — `operations` is an array of rows and the
|
|
332
|
+
* counts are numbers, all valid `FieldValue`s — so `EffectHandlers.persist`
|
|
333
|
+
* needs no widened return type and no cast: a batch summary reaches the bus by
|
|
334
|
+
* the same path a create/update row does.
|
|
335
|
+
*
|
|
336
|
+
* Declared as a `type` alias, NOT an `interface`, deliberately: only an object
|
|
337
|
+
* type alias gets TypeScript's implicit index signature, which is what makes it
|
|
338
|
+
* assignable to `EntityRow`'s `Record<string, FieldValue | undefined>` half. As
|
|
339
|
+
* an interface it fails that assignment (TS2322) and the only way to ship it
|
|
340
|
+
* would be a cast — which the type-safety rule forbids, and rightly: the cast
|
|
341
|
+
* would have hidden that the contract, not the value, was wrong.
|
|
342
|
+
*/
|
|
343
|
+
type PersistBatchSummary = {
|
|
344
|
+
/** One result row per attempted operation, in submission order. */
|
|
345
|
+
operations: EntityRow[];
|
|
346
|
+
/** How many operations completed before the batch stopped. */
|
|
347
|
+
completedCount: number;
|
|
348
|
+
/** How many were submitted. */
|
|
349
|
+
totalCount: number;
|
|
350
|
+
};
|
|
351
|
+
/** Options for `browser/open-file-picker`. */
|
|
352
|
+
interface BrowserFilePickerOptions {
|
|
353
|
+
/** Allow selecting multiple files. */
|
|
354
|
+
multiple?: boolean;
|
|
355
|
+
/** MIME type filter (e.g. "image/*"). Best-effort; host may ignore. */
|
|
356
|
+
accept?: string;
|
|
357
|
+
}
|
|
358
|
+
/** Metadata for a file chosen via `browser/open-file-picker`. */
|
|
359
|
+
interface BrowserFileMeta {
|
|
360
|
+
name: string;
|
|
361
|
+
size: number;
|
|
362
|
+
type: string;
|
|
363
|
+
lastModified: number;
|
|
364
|
+
}
|
|
365
|
+
/** Options for `browser/geolocation-current` (subset of PositionOptions). */
|
|
366
|
+
interface BrowserGeolocationOptions {
|
|
367
|
+
enableHighAccuracy?: boolean;
|
|
368
|
+
timeout?: number;
|
|
369
|
+
maximumAge?: number;
|
|
370
|
+
}
|
|
371
|
+
/** Position returned by `browser/geolocation-current`. */
|
|
372
|
+
interface BrowserGeolocationPosition {
|
|
373
|
+
latitude: number;
|
|
374
|
+
longitude: number;
|
|
375
|
+
accuracy: number;
|
|
376
|
+
}
|
|
377
|
+
/**
|
|
378
|
+
* Context for resolving bindings like @entity.field, @payload.value
|
|
379
|
+
*/
|
|
380
|
+
interface BindingContext {
|
|
381
|
+
/** Current entity data */
|
|
382
|
+
entity?: EntityRow;
|
|
383
|
+
/** Event payload data */
|
|
384
|
+
payload?: EventPayload;
|
|
385
|
+
/** Current state name */
|
|
386
|
+
state?: string;
|
|
387
|
+
/** Trait-level state/config */
|
|
388
|
+
config?: ConfigContext;
|
|
389
|
+
/** Authenticated viewer behind `@user.x` — ownership (`@user.id`) and role gates. */
|
|
390
|
+
user?: UserContext;
|
|
391
|
+
/** The dispatch's one `now` stamp (ms epoch) — every guard, effect and time operator in it reads this. */
|
|
392
|
+
now?: number;
|
|
393
|
+
/** `@locale`: the viewer's locale (`OrbitalEventRequest.locale`, else the program's first declared locale). */
|
|
394
|
+
locale?: string;
|
|
395
|
+
/** That locale's catalog — `i18n/t` reads it. */
|
|
396
|
+
messages?: Readonly<Record<string, string>>;
|
|
397
|
+
/** `@event`: the delivery being processed (`deliveryRecordValue`, Runtime Spec Clause 5.5). */
|
|
398
|
+
event?: EventPayload;
|
|
399
|
+
/** `@prevEvents`: deliveries this trait already received this dispatch. */
|
|
400
|
+
prevEvents?: EventPayload[];
|
|
401
|
+
/** `@prevStates`: states this trait left this dispatch. */
|
|
402
|
+
prevStates?: string[];
|
|
403
|
+
/** `@fromState` / `@toState`: the transition's ends. */
|
|
404
|
+
fromState?: string;
|
|
405
|
+
toState?: string;
|
|
406
|
+
/**
|
|
407
|
+
* The host orbital's pages for the `@pages` render sigil (`href`/`label`
|
|
408
|
+
* per inline page). Seeded onto the render binding context only — never
|
|
409
|
+
* present on a guard/tick context. Mirrors the compiler's
|
|
410
|
+
* `OirBindingRoot::Pages`.
|
|
411
|
+
*/
|
|
412
|
+
pages?: NavItem[];
|
|
413
|
+
/**
|
|
414
|
+
* The `data-theme` key string for the `@currentTheme` render sigil,
|
|
415
|
+
* derived from the host orbital's `Orbital.theme`. Render-context only.
|
|
416
|
+
*/
|
|
417
|
+
currentTheme?: string;
|
|
418
|
+
/**
|
|
419
|
+
* Local variables introduced by a `let` form, keyed by bare name and
|
|
420
|
+
* referenced via `@<name>` (the canonical evaluator convention — same as
|
|
421
|
+
* `createChildContext` in `@almadar/evaluator`). Carried on the context so
|
|
422
|
+
* a `let` body's effects resolve their value expressions against the
|
|
423
|
+
* `let`-bound locals.
|
|
424
|
+
*/
|
|
425
|
+
locals?: Map<string, RuntimeValue>;
|
|
426
|
+
/**
|
|
427
|
+
* The composing effect's triggering payload, for a trait embedded via
|
|
428
|
+
* `@trait.X` inline into a parent's render-ui. Set when re-running an
|
|
429
|
+
* embedded child's lifecycle transition under its embedder's payload
|
|
430
|
+
* (see `OrbitalServerRuntime.executeEffects` / the client's
|
|
431
|
+
* `useTraitStateMachine`), so `@callsitePayload.<field>` resolves on the
|
|
432
|
+
* child's evaluation context — mirrors the compiled path's
|
|
433
|
+
* `CALLSITE_PAYLOAD_PREFIX` capture.
|
|
434
|
+
*/
|
|
435
|
+
callsitePayload?: EventPayload;
|
|
436
|
+
/** Additional custom bindings */
|
|
437
|
+
[key: string]: RuntimeValue | undefined;
|
|
438
|
+
}
|
|
439
|
+
/**
|
|
440
|
+
* Executable effect tuple: operator name plus already-resolved arguments.
|
|
441
|
+
*
|
|
442
|
+
* Runtime-local on purpose — NOT `@almadar/core`'s `Effect` (`TypedEffect`),
|
|
443
|
+
* which is a CLOSED union of authoring-time tuples. The runtime's operator
|
|
444
|
+
* set is extensible (custom handlers, `os/*`, substrate ops), so the executor
|
|
445
|
+
* input is this open tuple. The wire-level type for effect lists stays
|
|
446
|
+
* `SExpr[]` (`TransitionResult.effects`, `TraitDefinition.transitions[].effects`);
|
|
447
|
+
* narrow it to `Effect[]` at the executor boundary with {@link isEffectTuple}.
|
|
448
|
+
*/
|
|
449
|
+
type Effect = [string, ...RuntimeValue[]];
|
|
450
|
+
/**
|
|
451
|
+
* Type guard: is this value an executable effect tuple (operator + args)?
|
|
452
|
+
* Narrows wire-level `SExpr` effect lists to the executor-input `Effect`
|
|
453
|
+
* without a cast. (Parameter is `RuntimeValue`, not `SExpr`, because a type
|
|
454
|
+
* predicate's type must be assignable to its parameter's type — `Effect`'s
|
|
455
|
+
* `RuntimeValue` tail is wider than `SExpr`. Every `SExpr` is a `RuntimeValue`,
|
|
456
|
+
* so call sites pass either.)
|
|
457
|
+
*/
|
|
458
|
+
declare function isEffectTuple(value: RuntimeValue): value is Effect;
|
|
459
|
+
/**
|
|
460
|
+
* Effect execution context
|
|
461
|
+
*/
|
|
462
|
+
interface EffectContext {
|
|
463
|
+
/** Trait name */
|
|
464
|
+
traitName: string;
|
|
465
|
+
/** Orbital that owns the firing trait. Used to stamp the source
|
|
466
|
+
* metadata on emits so source-scoped listens (`TraitName EVENT` for
|
|
467
|
+
* intra-orbital, `Orbital.TraitName EVENT` for cross-orbital) can
|
|
468
|
+
* filter by emitter identity. */
|
|
469
|
+
orbitalName?: string;
|
|
470
|
+
/**
|
|
471
|
+
* V4 dual-carry id sibling of `traitName` — stamped onto emit sources
|
|
472
|
+
* so id-scoped `listens` (`buildSourceMatcher`) match by id,
|
|
473
|
+
* rename-proof. The matcher compares ids ONLY when the listen source
|
|
474
|
+
* carries one, so a name-only stamp never matches a `traitId`-carrying
|
|
475
|
+
* listen (the chat SAVE → DO_CREATE relay died on the stateful path,
|
|
476
|
+
* 2026-09-22). Parity with `OrbitalServerRuntime`'s emit stamp.
|
|
477
|
+
*/
|
|
478
|
+
traitId?: TraitId;
|
|
479
|
+
/**
|
|
480
|
+
* V4 dual-carry id sibling of `orbitalName` — same contract as
|
|
481
|
+
* `traitId`, for `kind: 'orbital'` listen sources.
|
|
482
|
+
*/
|
|
483
|
+
orbitalId?: OrbitalId;
|
|
484
|
+
/**
|
|
485
|
+
* The trait's emit contracts — the emit-source stamp reads `eventId`
|
|
486
|
+
* from the matching contract (parity with `OrbitalServerRuntime`'s
|
|
487
|
+
* `emitContract?.eventId`).
|
|
488
|
+
*/
|
|
489
|
+
emits?: ReadonlyArray<{
|
|
490
|
+
event: string;
|
|
491
|
+
eventId?: EventId;
|
|
492
|
+
}>;
|
|
493
|
+
/** Current state */
|
|
494
|
+
state: string;
|
|
495
|
+
/** Transition description */
|
|
496
|
+
transition: string;
|
|
497
|
+
/** Linked entity name */
|
|
498
|
+
linkedEntity?: string;
|
|
499
|
+
/** Entity ID (if available) */
|
|
500
|
+
entityId?: string;
|
|
501
|
+
}
|
|
502
|
+
/**
|
|
503
|
+
* Result of executing a single effect, with status tracking.
|
|
504
|
+
*/
|
|
505
|
+
interface EffectResult {
|
|
506
|
+
/** Effect operator (e.g., "persist", "render-ui") */
|
|
507
|
+
type: string;
|
|
508
|
+
/** Effect arguments */
|
|
509
|
+
args: RuntimeValue[];
|
|
510
|
+
/** Whether the effect executed successfully */
|
|
511
|
+
status: "executed" | "failed" | "skipped";
|
|
512
|
+
/** Error message if failed */
|
|
513
|
+
error?: string;
|
|
514
|
+
/** Execution duration in milliseconds */
|
|
515
|
+
durationMs?: number;
|
|
516
|
+
/** Refused before the effect's handler ran (e.g. a `persist create` missing a
|
|
517
|
+
* required field), so no handler recorded it — the host reports it. */
|
|
518
|
+
refusedBeforeHandler?: boolean;
|
|
519
|
+
}
|
|
520
|
+
/**
|
|
521
|
+
* Runtime configuration for strictness and safety modes.
|
|
522
|
+
*
|
|
523
|
+
* These options control how the runtime handles edge cases:
|
|
524
|
+
* - `strictBindings`: Log warnings when bindings resolve to undefined (RCG-01)
|
|
525
|
+
* - `maxEventDepth`: Prevent infinite event loops (RCG-05)
|
|
526
|
+
*/
|
|
527
|
+
interface RuntimeConfig {
|
|
528
|
+
/**
|
|
529
|
+
* When true, log warnings when bindings like @entity.field resolve to undefined.
|
|
530
|
+
* Helps detect typos and missing fields early. (RCG-01)
|
|
531
|
+
* @default false
|
|
532
|
+
*/
|
|
533
|
+
strictBindings?: boolean;
|
|
534
|
+
/**
|
|
535
|
+
* Maximum event emission depth before triggering circuit breaker. (RCG-05)
|
|
536
|
+
* Prevents infinite loops from circular emit/listen chains.
|
|
537
|
+
* @default 10
|
|
538
|
+
*/
|
|
539
|
+
maxEventDepth?: number;
|
|
540
|
+
/**
|
|
541
|
+
* Additional fields to spread onto every EvaluationContext.
|
|
542
|
+
* Used to inject module contexts (e.g., { agent: AgentContext }).
|
|
543
|
+
* The evaluator dispatches agent/* operators to ctx.agent.
|
|
544
|
+
*/
|
|
545
|
+
contextExtensions?: EvaluationContextExtensions;
|
|
546
|
+
}
|
|
547
|
+
/**
|
|
548
|
+
* Typed extensions that get spread onto every EvaluationContext.
|
|
549
|
+
* Each field here corresponds to an optional field on EvaluationContext.
|
|
550
|
+
*/
|
|
551
|
+
interface EvaluationContextExtensions {
|
|
552
|
+
/** Agent context for agent/* operators (memory, LLM, tools, session) */
|
|
553
|
+
agent?: AgentContext;
|
|
554
|
+
/** Substrate contexts for the new operator namespaces */
|
|
555
|
+
llm?: LlmContext;
|
|
556
|
+
workspace?: WorkspaceContext;
|
|
557
|
+
session?: SessionContext;
|
|
558
|
+
memory?: MemoryContext;
|
|
559
|
+
trace?: TraceContext;
|
|
560
|
+
}
|
|
561
|
+
/**
|
|
562
|
+
* Execution context for handler manifest validation.
|
|
563
|
+
* Defines which effect handlers should be available in each environment.
|
|
564
|
+
*/
|
|
565
|
+
type ExecutionEnvironment = "client" | "server" | "test" | "ssr";
|
|
566
|
+
/**
|
|
567
|
+
* Effect handlers each execution environment is expected to carry. `client`
|
|
568
|
+
* and `server` derive from the registry's `runsOn`; `ssr` is a render mode
|
|
569
|
+
* (one server-side page render), not an execution site, so it stays listed.
|
|
570
|
+
*/
|
|
571
|
+
declare const HANDLER_MANIFEST: Record<ExecutionEnvironment, string[]>;
|
|
572
|
+
|
|
573
|
+
export { HANDLER_MANIFEST, isEffectTuple };
|
|
574
|
+
export type { BindingContext, BrowserFileMeta, BrowserFilePickerOptions, BrowserGeolocationOptions, BrowserGeolocationPosition, ConfigContext, Effect, EffectContext, EffectHandlers, EffectResult, EvaluationContextExtensions, EventListener, ExecutionEnvironment, HttpEffectReport, IEventBus, PatternProps, PersistBatchSummary, RuntimeConfig, RuntimeEvent, RuntimePatternValue, RuntimeRenderPattern, TransitionResult, Unsubscribe };
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { ServiceParams, BusEventSource, EventPayload } from '@almadar/core';
|
|
2
|
+
import { ServiceCallContext } from './service-provider.js';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* The runtime's own `call-service` answerer when the host injects none: the services a host plugged in with
|
|
6
|
+
* `registerServiceProvider`. A call to a service nobody plugged in fails by name, so the trait's declared failure event fires.
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Where a running `call-service`'s live messages go: the call site's
|
|
11
|
+
* `emit.onMessage` event, stamped as the calling trait. Absent when the call
|
|
12
|
+
* site declares no `onMessage`.
|
|
13
|
+
*/
|
|
14
|
+
interface ServiceMessageRoute {
|
|
15
|
+
event: string;
|
|
16
|
+
source?: BusEventSource;
|
|
17
|
+
}
|
|
18
|
+
/** Call an external service. `context` carries the caller's identity (the same viewer entity ACL enforces against) so role-gated services can enforce server-side; hosts forward it to the integration factory. */
|
|
19
|
+
type CallServiceHandler = (service: string, action: string, params?: ServiceParams, context?: ServiceCallContext, message?: ServiceMessageRoute) => Promise<EventPayload | null>;
|
|
20
|
+
declare function defaultCallService(service: string, action: string, params: ServiceParams | undefined, context?: ServiceCallContext): Promise<EventPayload | null>;
|
|
21
|
+
|
|
22
|
+
export { defaultCallService };
|
|
23
|
+
export type { CallServiceHandler, ServiceMessageRoute };
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { ServiceHostPorts, ServiceParams, EventPayload } from '@almadar/core';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Caller identity forwarded with a call-service dispatch (I-25) — the id and
|
|
5
|
+
* roster role of the SAME normalized viewer entity ACL enforces against.
|
|
6
|
+
* Absent when no viewer is bound (ticks, anonymous); role-gated services
|
|
7
|
+
* fail closed on absence.
|
|
8
|
+
*/
|
|
9
|
+
interface ServiceCallContext {
|
|
10
|
+
principal?: string;
|
|
11
|
+
role?: string;
|
|
12
|
+
/** The running app, lent for this call as the caller (`page watch`). */
|
|
13
|
+
host?: ServiceHostPorts;
|
|
14
|
+
/** Aborted when `cancel-call` cancels this call; a provider stops its work on it. */
|
|
15
|
+
signal?: AbortSignal;
|
|
16
|
+
/** No request awaits this call (a follow-on step's call): the host holds no request's event queue around it. */
|
|
17
|
+
outsideRequest?: true;
|
|
18
|
+
}
|
|
19
|
+
/** Why a service call failed, for a provider to name: bad params, no host installed, no signed-in caller, an action it does not have. */
|
|
20
|
+
type ServiceCallErrorCode = 'VALIDATION_ERROR' | 'NOT_CONFIGURED' | 'AUTH_ERROR' | 'UNKNOWN_ACTION';
|
|
21
|
+
declare class ServiceCallError extends Error {
|
|
22
|
+
readonly code: ServiceCallErrorCode;
|
|
23
|
+
constructor(message: string, code: ServiceCallErrorCode);
|
|
24
|
+
}
|
|
25
|
+
/** A host's answerer for the `call-service` calls of one named service: resolves the payload, throws to fail the call. */
|
|
26
|
+
type ServiceProvider = (action: string, params: ServiceParams, context?: ServiceCallContext) => Promise<EventPayload | null>;
|
|
27
|
+
/** Plug a service's answerer into this process's `call-service`; a later registration of the same name replaces it. */
|
|
28
|
+
declare function registerServiceProvider(service: string, provider: ServiceProvider): void;
|
|
29
|
+
/** Testing/reset hook. */
|
|
30
|
+
declare function unregisterServiceProvider(service: string): void;
|
|
31
|
+
/** The names of the services a host has plugged in. */
|
|
32
|
+
declare function registeredServices(): string[];
|
|
33
|
+
/** Calls `service.action` through the registered provider; a service no host plugged in is a named failure. */
|
|
34
|
+
declare function callRegisteredService(service: string, action: string, params: ServiceParams | undefined, context?: ServiceCallContext): Promise<EventPayload | null>;
|
|
35
|
+
|
|
36
|
+
export { ServiceCallError, callRegisteredService, registerServiceProvider, registeredServices, unregisterServiceProvider };
|
|
37
|
+
export type { ServiceCallContext, ServiceCallErrorCode, ServiceProvider };
|