@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.
Files changed (180) hide show
  1. package/dist/chunk-2JU7Y4KU.js +21 -0
  2. package/dist/chunk-46RWK2B5.js +28 -0
  3. package/dist/chunk-4J2QEIUV.js +78 -0
  4. package/dist/chunk-4SEK5ER2.js +8 -0
  5. package/dist/chunk-4ZICQ5PM.js +192 -0
  6. package/dist/chunk-53IPZXDP.js +76 -0
  7. package/dist/chunk-5D63EMO5.js +16 -0
  8. package/dist/chunk-64IH2SMY.js +22 -0
  9. package/dist/chunk-7SDV3QWR.js +67 -0
  10. package/dist/chunk-CPSQXEJ6.js +55 -0
  11. package/dist/chunk-CQP5XAX6.js +173 -0
  12. package/dist/chunk-CROS2GEX.js +49 -0
  13. package/dist/chunk-D4XJTBLB.js +217 -0
  14. package/dist/chunk-D5USD2EX.js +232 -0
  15. package/dist/chunk-DYOJGLIX.js +25 -0
  16. package/dist/chunk-ELBLT2HZ.js +1 -0
  17. package/dist/chunk-EV56K4GB.js +63 -0
  18. package/dist/chunk-EZZYLTWY.js +1 -0
  19. package/dist/chunk-FQ6IZMIU.js +10 -0
  20. package/dist/chunk-FWA5K7Q2.js +48 -0
  21. package/dist/chunk-HC6ERSAH.js +55 -0
  22. package/dist/chunk-HLOUDLPI.js +48 -0
  23. package/dist/chunk-HMK6YMQS.js +135 -0
  24. package/dist/chunk-HNOAZWFH.js +19 -0
  25. package/dist/chunk-IHQLE5M7.js +62 -0
  26. package/dist/chunk-IOPUS6Q5.js +15 -0
  27. package/dist/chunk-JFWFDUTR.js +35 -0
  28. package/dist/chunk-LZIOTBFX.js +1 -0
  29. package/dist/chunk-MHYSHSRG.js +54 -0
  30. package/dist/chunk-MLKGABMK.js +7 -0
  31. package/dist/chunk-MZKIL5IN.js +74 -0
  32. package/dist/chunk-NAECVIAR.js +322 -0
  33. package/dist/chunk-NATGCIVM.js +583 -0
  34. package/dist/chunk-O57GKTYU.js +30 -0
  35. package/dist/chunk-ODJCZ27I.js +50 -0
  36. package/dist/chunk-P53CKOME.js +1 -0
  37. package/dist/chunk-Q2H75UYT.js +92 -0
  38. package/dist/chunk-Q7JK4KY7.js +9 -0
  39. package/dist/chunk-QELZ6TEJ.js +208 -0
  40. package/dist/chunk-QQRDUMB2.js +40 -0
  41. package/dist/chunk-RBUMDYFS.js +681 -0
  42. package/dist/chunk-REPX5QPI.js +57 -0
  43. package/dist/chunk-SAS5KKCR.js +43 -0
  44. package/dist/chunk-SKLMWHQD.js +109 -0
  45. package/dist/chunk-SOQDEPME.js +131 -0
  46. package/dist/chunk-SWPDU752.js +28 -0
  47. package/dist/chunk-T775TUCD.js +18 -0
  48. package/dist/chunk-UBN5JJKZ.js +26 -0
  49. package/dist/chunk-UJHOUZAL.js +36 -0
  50. package/dist/chunk-UP6GGGAN.js +34 -0
  51. package/dist/chunk-VMOBW7RK.js +21 -0
  52. package/dist/chunk-VNMG7NKY.js +69 -0
  53. package/dist/chunk-WNPNNYXY.js +22 -0
  54. package/dist/chunk-XB5GYODW.js +28 -0
  55. package/dist/chunk-XXWNMJI6.js +15 -0
  56. package/dist/chunk-YL2SO5TP.js +334 -0
  57. package/dist/chunk-YO4LWS3I.js +606 -0
  58. package/dist/chunk-ZAQSS47X.js +157 -0
  59. package/dist/chunk-ZCQUUJIF.js +129 -0
  60. package/dist/client/EventTransport.d.ts +131 -0
  61. package/dist/client/EventTransport.js +2 -0
  62. package/dist/client/ServerBridge.d.ts +126 -0
  63. package/dist/client/ServerBridge.js +3 -0
  64. package/dist/client/awaiting.d.ts +28 -0
  65. package/dist/client/awaiting.js +2 -0
  66. package/dist/client/channel-transport.d.ts +69 -0
  67. package/dist/client/channel-transport.js +2 -0
  68. package/dist/client/circuit-store.d.ts +76 -0
  69. package/dist/client/circuit-store.js +4 -0
  70. package/dist/client/client-kernel.d.ts +113 -0
  71. package/dist/client/client-kernel.js +1 -0
  72. package/dist/client/declared-input-dispatch.d.ts +5 -0
  73. package/dist/client/declared-input-dispatch.js +2 -0
  74. package/dist/client/inbound-dispatch.d.ts +5 -0
  75. package/dist/client/inbound-dispatch.js +2 -0
  76. package/dist/client/local-fold.d.ts +26 -0
  77. package/dist/client/local-fold.js +2 -0
  78. package/dist/client/render-sigils.d.ts +24 -0
  79. package/dist/client/render-sigils.js +2 -0
  80. package/dist/client/state-book.d.ts +37 -0
  81. package/dist/client/state-book.js +2 -0
  82. package/dist/client/trait-mount-error.d.ts +9 -0
  83. package/dist/client/trait-mount-error.js +2 -0
  84. package/dist/client/trait-types.d.ts +67 -0
  85. package/dist/client/trait-types.js +1 -0
  86. package/dist/credentials/env-vars.d.ts +14 -0
  87. package/dist/credentials/env-vars.js +3 -0
  88. package/dist/credentials/scope.d.ts +50 -0
  89. package/dist/credentials/scope.js +2 -0
  90. package/dist/credentials/seed.d.ts +21 -0
  91. package/dist/credentials/seed.js +2 -0
  92. package/dist/credentials/store.d.ts +110 -0
  93. package/dist/credentials/store.js +2 -0
  94. package/dist/effects/in-flight-calls.d.ts +36 -0
  95. package/dist/effects/in-flight-calls.js +2 -0
  96. package/dist/effects/on-device-model.d.ts +22 -0
  97. package/dist/effects/on-device-model.js +2 -0
  98. package/dist/events/EventBus.d.ts +90 -0
  99. package/dist/events/EventBus.js +2 -0
  100. package/dist/events/emit-stamp.d.ts +47 -0
  101. package/dist/events/emit-stamp.js +2 -0
  102. package/dist/index-hT1xCdTq.d.ts +46 -0
  103. package/dist/index.d.ts +60 -0
  104. package/dist/index.js +59 -0
  105. package/dist/kernel/beacon.d.ts +32 -0
  106. package/dist/kernel/beacon.js +2 -0
  107. package/dist/kernel/decode.d.ts +15 -0
  108. package/dist/kernel/decode.js +2 -0
  109. package/dist/kernel/engine.d.ts +94 -0
  110. package/dist/kernel/engine.js +11 -0
  111. package/dist/kernel/frame-applier.d.ts +43 -0
  112. package/dist/kernel/frame-applier.js +2 -0
  113. package/dist/kernel/host.d.ts +95 -0
  114. package/dist/kernel/host.js +9 -0
  115. package/dist/kernel/http.d.ts +302 -0
  116. package/dist/kernel/http.js +6 -0
  117. package/dist/kernel/lane.d.ts +28 -0
  118. package/dist/kernel/lane.js +2 -0
  119. package/dist/kernel/oauth-effects.d.ts +25 -0
  120. package/dist/kernel/oauth-effects.js +7 -0
  121. package/dist/kernel/oauth-port.d.ts +31 -0
  122. package/dist/kernel/oauth-port.js +2 -0
  123. package/dist/kernel/os-port.d.ts +133 -0
  124. package/dist/kernel/os-port.js +2 -0
  125. package/dist/kernel/program-effects.d.ts +65 -0
  126. package/dist/kernel/program-effects.js +2 -0
  127. package/dist/kernel/wire.d.ts +66 -0
  128. package/dist/kernel/wire.js +1 -0
  129. package/dist/loader/http-loader.d.ts +111 -0
  130. package/dist/loader/http-loader.js +2 -0
  131. package/dist/loader/lazy-page.d.ts +12 -0
  132. package/dist/loader/lazy-page.js +2 -0
  133. package/dist/loader/schema-loader.d.ts +160 -0
  134. package/dist/loader/schema-loader.js +1 -0
  135. package/dist/persistence/native-memory.d.ts +28 -0
  136. package/dist/persistence/native-memory.js +2 -0
  137. package/dist/runtime/effects/composition/compose-behaviors.d.ts +58 -0
  138. package/dist/runtime/effects/composition/compose-behaviors.js +4 -0
  139. package/dist/runtime/effects/composition/event-wiring.d.ts +38 -0
  140. package/dist/runtime/effects/composition/event-wiring.js +2 -0
  141. package/dist/runtime/effects/composition/index.d.ts +5 -0
  142. package/dist/runtime/effects/composition/index.js +6 -0
  143. package/dist/runtime/effects/composition/layout-strategy.d.ts +35 -0
  144. package/dist/runtime/effects/composition/layout-strategy.js +2 -0
  145. package/dist/runtime/effects/composition/pipe.d.ts +25 -0
  146. package/dist/runtime/effects/composition/pipe.js +2 -0
  147. package/dist/runtime/entities/mockStoreSeed.d.ts +56 -0
  148. package/dist/runtime/entities/mockStoreSeed.js +3 -0
  149. package/dist/runtime/entities/seedBrowserStore.d.ts +28 -0
  150. package/dist/runtime/entities/seedBrowserStore.js +2 -0
  151. package/dist/runtime/entities/std-mock-seed.d.ts +87 -0
  152. package/dist/runtime/entities/std-mock-seed.js +2 -0
  153. package/dist/runtime/evaluation/local-store-transport.d.ts +68 -0
  154. package/dist/runtime/evaluation/local-store-transport.js +18 -0
  155. package/dist/runtime/evaluation/residence-transport.d.ts +15 -0
  156. package/dist/runtime/evaluation/residence-transport.js +2 -0
  157. package/dist/runtime/evaluation/routed-persistence.d.ts +9 -0
  158. package/dist/runtime/evaluation/routed-persistence.js +2 -0
  159. package/dist/runtime/events/identity/routing.d.ts +84 -0
  160. package/dist/runtime/events/identity/routing.js +2 -0
  161. package/dist/runtime/time/TickScheduler.d.ts +77 -0
  162. package/dist/runtime/time/TickScheduler.js +3 -0
  163. package/dist/runtime/time/cron.d.ts +25 -0
  164. package/dist/runtime/time/cron.js +2 -0
  165. package/dist/runtime/time/duration.d.ts +20 -0
  166. package/dist/runtime/time/duration.js +2 -0
  167. package/dist/runtime/traits/OrbitalTraitParsing.d.ts +34 -0
  168. package/dist/runtime/traits/OrbitalTraitParsing.js +2 -0
  169. package/dist/runtime/traits/listen-targets.d.ts +16 -0
  170. package/dist/runtime/traits/listen-targets.js +3 -0
  171. package/dist/runtime/traits/trait-index.d.ts +35 -0
  172. package/dist/runtime/traits/trait-index.js +3 -0
  173. package/dist/runtime/types.d.ts +574 -0
  174. package/dist/runtime/types.js +2 -0
  175. package/dist/service/default-call-service.d.ts +23 -0
  176. package/dist/service/default-call-service.js +3 -0
  177. package/dist/service/service-provider.d.ts +37 -0
  178. package/dist/service/service-provider.js +2 -0
  179. package/package.json +46 -3
  180. 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,2 @@
1
+ export { HANDLER_MANIFEST, isEffectTuple } from '../chunk-WNPNNYXY.js';
2
+ import '../chunk-MLKGABMK.js';
@@ -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,3 @@
1
+ export { defaultCallService } from '../chunk-4SEK5ER2.js';
2
+ import '../chunk-UBN5JJKZ.js';
3
+ import '../chunk-MLKGABMK.js';
@@ -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 };
@@ -0,0 +1,2 @@
1
+ export { ServiceCallError, callRegisteredService, registerServiceProvider, registeredServices, unregisterServiceProvider } from '../chunk-UBN5JJKZ.js';
2
+ import '../chunk-MLKGABMK.js';