@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,157 @@
1
+ import { base64Standard, isOAuthReason, isOAuthCode } from './chunk-YO4LWS3I.js';
2
+ import { isJsonObject } from '@almadar/core';
3
+
4
+ var PENDING_GRANT_TTL_MS = 10 * 60 * 1e3;
5
+ var MOCK_PENDING_TTL_MS = Number.MAX_SAFE_INTEGER;
6
+ var PROVIDERS = ["google", "github", "auth0"];
7
+ var OAuthEffectFailure = class extends Error {
8
+ constructor(payload) {
9
+ super(payload.error);
10
+ this.payload = payload;
11
+ }
12
+ payload;
13
+ };
14
+ function parsed(text) {
15
+ return JSON.parse(text);
16
+ }
17
+ function objectOf(value, what) {
18
+ if (value === void 0 || !isJsonObject(value)) throw new Error(`${what} is malformed`);
19
+ return value;
20
+ }
21
+ function failureOf(kernel, reason) {
22
+ if (kernel.oauthFailure === void 0) throw new Error("this kernel build has no OAuth failure messages");
23
+ const payload = objectOf(parsed(kernel.oauthFailure(reason)), "the oauth failure");
24
+ const { error, code } = payload;
25
+ if (typeof error !== "string" || !isOAuthCode(code)) throw new Error("the oauth failure is malformed");
26
+ return new OAuthEffectFailure({ error, code, reason });
27
+ }
28
+ async function ask(ports, kernel, request, principal) {
29
+ if (ports.oauth === void 0) throw failureOf(kernel, "store-unavailable");
30
+ try {
31
+ const reply = await ports.oauth.answer(request, principal);
32
+ if (!isReplyOf(request, reply)) throw new Error("wrong reply");
33
+ return reply;
34
+ } catch {
35
+ throw failureOf(kernel, "store-unavailable");
36
+ }
37
+ }
38
+ function isReplyOf(request, reply) {
39
+ switch (request.ask) {
40
+ case "pendingPut":
41
+ case "subjectRemember":
42
+ case "subjectForget":
43
+ case "metadataPut":
44
+ return reply.reply === "done";
45
+ case "pendingTake":
46
+ return reply.reply === "taken";
47
+ case "connectionAvailable":
48
+ return reply.reply === "flag";
49
+ case "connectionSave":
50
+ case "connectionStatus":
51
+ case "connectionRemove":
52
+ return reply.reply === "row";
53
+ case "subjectLookup":
54
+ return reply.reply === "subject";
55
+ case "metadataGet":
56
+ return reply.reply === "metadata";
57
+ case "clock":
58
+ return reply.reply === "millis";
59
+ case "mockTokenPut":
60
+ return reply.reply === "done";
61
+ case "mockTokenRefresh":
62
+ case "mockTokenRevoke":
63
+ return reply.reply === "flag";
64
+ case "mockTokenCheck":
65
+ return reply.reply === "mockToken";
66
+ case "consent":
67
+ return reply.reply === "code";
68
+ }
69
+ }
70
+ async function oauthAuthorizePayload(ports, client, options, principal, key) {
71
+ if (key !== void 0 && (typeof key !== "string" || key === "")) {
72
+ throw new Error(`call key must evaluate to a non-empty string, got ${String(key)}`);
73
+ }
74
+ const echoed = typeof key === "string" ? key : null;
75
+ const kernel = await ports.kernel();
76
+ if (kernel.oauthAuthorizePlan === void 0 || kernel.oauthAuthorizeBuild === void 0) {
77
+ throw new Error("oauth-authorize: this kernel build cannot run it");
78
+ }
79
+ const planned = objectOf(parsed(kernel.oauthAuthorizePlan(JSON.stringify(client ?? null), JSON.stringify(options ?? null))), "the authorize plan");
80
+ if (planned.mode === "mock") {
81
+ if (kernel.oauthAuthorizeMockBuild === void 0) throw new Error("oauth-authorize: this kernel build cannot run it");
82
+ const mock = objectOf(parsed(kernel.oauthAuthorizeMockBuild(JSON.stringify(planned.plan ?? null), base64Standard(ports.random(16)))), "the authorization");
83
+ return keepGrant(ports, kernel, mock, MOCK_PENDING_TTL_MS, principal, echoed, false);
84
+ }
85
+ const slot = objectOf(planned.clientId, "the client id slot");
86
+ if (typeof slot.name !== "string") throw new Error("the client id slot is malformed");
87
+ let owner;
88
+ if (slot.scope === "user") {
89
+ if (principal === void 0) throw failureOf(kernel, "not-signed-in");
90
+ owner = principal;
91
+ }
92
+ const clientId = await ports.secrets.get(slot.name, owner);
93
+ if (clientId === void 0) throw failureOf(kernel, "unconfigured-client");
94
+ let metadata = planned.metadata ?? null;
95
+ if (typeof planned.issuer === "string") {
96
+ const reply = await ask(ports, kernel, { ask: "metadataGet", issuer: planned.issuer }, principal);
97
+ metadata = reply.reply === "metadata" ? reply.metadata : null;
98
+ }
99
+ if (metadata === null) throw failureOf(kernel, "metadata-invalid");
100
+ const state = ports.random(32);
101
+ const verifier = ports.random(32);
102
+ const built = objectOf(
103
+ parsed(kernel.oauthAuthorizeBuild(JSON.stringify(planned.plan ?? null), clientId, JSON.stringify(metadata), base64Standard(state), base64Standard(verifier))),
104
+ "the authorization"
105
+ );
106
+ if (typeof built.refused === "string") throw new Error(built.refused);
107
+ if (built.failure !== void 0) {
108
+ const failure = objectOf(built.failure, "the failure");
109
+ const reason = failure.reason;
110
+ if (!isOAuthReason(reason)) throw new Error("the oauth failure is malformed");
111
+ throw failureOf(kernel, reason);
112
+ }
113
+ return keepGrant(ports, kernel, objectOf(built.ok, "the authorization"), PENDING_GRANT_TTL_MS, principal, echoed, true);
114
+ }
115
+ async function keepGrant(ports, kernel, ok, ttlMs, principal, key, consent) {
116
+ const grant = objectOf(ok.grant, "the pending grant");
117
+ if (typeof ok.authUrl !== "string" || typeof ok.state !== "string") throw new Error("the authorization is malformed");
118
+ const scopes = Array.isArray(grant.scopes) ? grant.scopes.flatMap((scope) => typeof scope === "string" ? [scope] : []) : [];
119
+ await ask(
120
+ ports,
121
+ kernel,
122
+ {
123
+ ask: "pendingPut",
124
+ state: ok.state,
125
+ ttlMs,
126
+ grant: {
127
+ provider: String(grant.provider),
128
+ redirectUri: String(grant.redirectUri),
129
+ verifier: String(grant.verifier),
130
+ subject: typeof grant.subject === "string" ? grant.subject : null,
131
+ scopes
132
+ }
133
+ },
134
+ principal
135
+ );
136
+ let code = "";
137
+ if (consent) {
138
+ const reply = await ask(ports, kernel, { ask: "consent", authUrl: ok.authUrl, state: ok.state, redirectUri: String(grant.redirectUri) }, principal);
139
+ code = reply.reply === "code" ? reply.code ?? "" : "";
140
+ }
141
+ return { authUrl: ok.authUrl, state: ok.state, code, key };
142
+ }
143
+ async function oauthConnectionPayload(ports, head, provider, principal) {
144
+ const word = PROVIDERS.find((known) => known === provider);
145
+ if (word === void 0) {
146
+ throw new Error(typeof provider === "string" ? `${head}: provider must be google, github or auth0, not \`${provider}\`` : `${head}: provider must be a provider word`);
147
+ }
148
+ const kernel = await ports.kernel();
149
+ const available = await ask(ports, kernel, { ask: "connectionAvailable" }, principal);
150
+ if (available.reply !== "flag" || !available.value) throw failureOf(kernel, "store-unavailable");
151
+ if (principal === void 0 || principal === "") throw failureOf(kernel, "not-signed-in");
152
+ const reply = await ask(ports, kernel, head === "oauth-connection-status" ? { ask: "connectionStatus", provider: word } : { ask: "connectionRemove", provider: word }, principal);
153
+ if (reply.reply !== "row") throw failureOf(kernel, "store-unavailable");
154
+ return reply.row;
155
+ }
156
+
157
+ export { OAuthEffectFailure, oauthAuthorizePayload, oauthConnectionPayload };
@@ -0,0 +1,129 @@
1
+ import { detectLayoutStrategy } from './chunk-EV56K4GB.js';
2
+ import { applyEventWiring } from './chunk-MHYSHSRG.js';
3
+
4
+ // src/runtime/effects/composition/compose-behaviors.ts
5
+ function isSchema(input) {
6
+ return "orbitals" in input && Array.isArray(input.orbitals);
7
+ }
8
+ function asDefinitions(inputs) {
9
+ return inputs.flatMap(
10
+ (input) => isSchema(input) ? input.orbitals : [input]
11
+ );
12
+ }
13
+ function mergeLedgers(inputs) {
14
+ const merged = /* @__PURE__ */ new Map();
15
+ let sawLedger = false;
16
+ for (const input of inputs) {
17
+ if (!isSchema(input) || input.ledger === void 0) continue;
18
+ sawLedger = true;
19
+ for (const [id, entry] of Object.entries(input.ledger.entries)) {
20
+ if (!merged.has(id)) merged.set(id, entry);
21
+ }
22
+ }
23
+ if (!sawLedger) return void 0;
24
+ const entries = {};
25
+ for (const [id, entry] of [...merged.entries()].sort(
26
+ ([a], [b]) => a < b ? -1 : a > b ? 1 : 0
27
+ )) {
28
+ entries[id] = entry;
29
+ }
30
+ return { schemaVersion: 1, entries };
31
+ }
32
+ function mergeSchemaVersions(inputs) {
33
+ let max;
34
+ for (const input of inputs) {
35
+ if (!isSchema(input) || input.schemaVersion === void 0) continue;
36
+ max = max === void 0 ? input.schemaVersion : Math.max(max, input.schemaVersion);
37
+ }
38
+ return max;
39
+ }
40
+ function toKebabCase(name) {
41
+ return name.replace(/([a-z])([A-Z])/g, "$1-$2").replace(/[\s_]+/g, "-").toLowerCase();
42
+ }
43
+ function generatePages(orbitals, strategy) {
44
+ switch (strategy) {
45
+ case "single": {
46
+ const orbital = orbitals[0];
47
+ const name = orbital?.name ?? "Main";
48
+ return [
49
+ {
50
+ name: `${name}Page`,
51
+ path: "/",
52
+ isInitial: true,
53
+ primaryEntity: getEntityName(orbital)
54
+ }
55
+ ];
56
+ }
57
+ case "dashboard": {
58
+ return [
59
+ {
60
+ name: "DashboardPage",
61
+ path: "/",
62
+ viewType: "dashboard",
63
+ isInitial: true
64
+ }
65
+ ];
66
+ }
67
+ case "sidebar":
68
+ case "tabs":
69
+ case "wizard-flow": {
70
+ return orbitals.map((orbital, index) => ({
71
+ name: `${orbital.name}Page`,
72
+ path: index === 0 ? "/" : `/${toKebabCase(orbital.name)}`,
73
+ isInitial: index === 0,
74
+ primaryEntity: getEntityName(orbital)
75
+ }));
76
+ }
77
+ }
78
+ }
79
+ function getEntityName(orbital) {
80
+ if (!orbital) return void 0;
81
+ const entity = orbital.entity;
82
+ if (typeof entity === "string") {
83
+ return entity.replace(".entity", "");
84
+ }
85
+ return entity.name;
86
+ }
87
+ function composeBehaviors(input) {
88
+ const {
89
+ appName,
90
+ orbitals: rawInputs,
91
+ layoutStrategy: strategyInput,
92
+ eventWiring
93
+ } = input;
94
+ const rawOrbitals = asDefinitions(rawInputs);
95
+ const wiredOrbitals = eventWiring && eventWiring.length > 0 ? applyEventWiring(rawOrbitals, eventWiring) : rawOrbitals;
96
+ const strategy = !strategyInput || strategyInput === "auto" ? detectLayoutStrategy(wiredOrbitals, eventWiring) : strategyInput;
97
+ const pages = generatePages(wiredOrbitals, strategy);
98
+ const orbitalsWithPages = wiredOrbitals.map((orbital, index) => {
99
+ if (orbital.pages && orbital.pages.length > 0) {
100
+ return orbital;
101
+ }
102
+ const page = strategy === "dashboard" || strategy === "single" ? pages[0] : pages[index];
103
+ return {
104
+ ...orbital,
105
+ pages: page ? [page] : []
106
+ };
107
+ });
108
+ const ledger = mergeLedgers(rawInputs);
109
+ const schemaVersion = mergeSchemaVersions(rawInputs);
110
+ const schema = {
111
+ name: appName,
112
+ version: "1.0.0",
113
+ orbitals: orbitalsWithPages,
114
+ ...schemaVersion !== void 0 ? { schemaVersion } : {},
115
+ ...ledger !== void 0 ? { ledger } : {}
116
+ };
117
+ return {
118
+ schema,
119
+ layout: {
120
+ strategy,
121
+ pageCount: pages.length
122
+ },
123
+ wiring: {
124
+ connections: eventWiring?.length ?? 0
125
+ }
126
+ };
127
+ }
128
+
129
+ export { composeBehaviors };
@@ -0,0 +1,131 @@
1
+ import { OrbitalSchema, OrbitalEventRequest, OrbitalEventResponse, RowSetRef, RowQueryPage, EmittedEvent, ServerTopology } from '@almadar/core';
2
+
3
+ /**
4
+ * EventTransport — the client → orbital event transport port (plan P5,
5
+ * `docs/Almadar_Runtime_Stateless_Stateful_PLAN.md` §4.2).
6
+ *
7
+ * Promotes `@almadar/ui`'s `ServerBridgeTransport` interface +
8
+ * `createHttpTransport` into `@almadar/runtime` so there is ONE owner of
9
+ * the HTTP request/response leg instead of two (this package's own
10
+ * `ServerBridge` class and the ui provider). `@almadar/ui`'s provider will
11
+ * be switched onto this port at the W5b build checkpoint (see the plan);
12
+ * until then this file has no consumers outside this package.
13
+ *
14
+ * The wire shapes are `@almadar/core`'s existing `OrbitalEventRequest` /
15
+ * `OrbitalEventResponse` — no shadow types.
16
+ *
17
+ * @packageDocumentation
18
+ */
19
+
20
+ /**
21
+ * `true` = stateless topology: the server holds no circuit state between
22
+ * requests, so every `send()` request must carry `traits`/`entityByTrait`.
23
+ * `false` = the server (or an in-process evaluator) holds the state itself.
24
+ *
25
+ * Derivation mirrors `@almadar/ui`'s `ServerBridgeProvider` EXACTLY
26
+ * (`providers/ServerBridge.tsx`, both the initial-state fallback and the
27
+ * post-register `.then` callback — the same mapping was duplicated at two
28
+ * call sites there, which is the `stateSource` string-branching this port
29
+ * retires): `'stateful'` → false, `'stateless'` OR an absent/undeclared
30
+ * topology (older servers) → true. An absent topology defaulting to
31
+ * "stateless" is the ui's existing assumption, carried over unchanged, not
32
+ * a new judgment call made here.
33
+ */
34
+ declare function deriveCarriesCircuitState(topology: ServerTopology | undefined): boolean;
35
+ interface EventTransportRegisterResult {
36
+ success: boolean;
37
+ /** See `deriveCarriesCircuitState`. Computed once here, not re-derived by callers. */
38
+ carriesCircuitState: boolean;
39
+ }
40
+ /**
41
+ * Who a server push was addressed to: `peers` — another client's change
42
+ * (live push); `origin` — this client's own running request, live (a
43
+ * call-service's `emit.onMessage`).
44
+ */
45
+ type PushTarget = 'peers' | 'origin';
46
+ interface EventTransport {
47
+ /** Register a schema with the transport's target (server, or an in-process evaluator). */
48
+ register(schema: OrbitalSchema): Promise<EventTransportRegisterResult>;
49
+ unregister(): Promise<void>;
50
+ /** Play one event through the orbital named `orbitalName`. */
51
+ send(orbitalName: string, request: OrbitalEventRequest): Promise<OrbitalEventResponse>;
52
+ /**
53
+ * A row-set reference resolved by the host that holds the rows, for the viewer the transport is signed in as (the
54
+ * host applies `@read`): the rows that still match, in the reference's order. Absent when the transport has no
55
+ * such route (an in-process evaluator resolves against its own store).
56
+ */
57
+ resolveRows?(reference: RowSetRef): Promise<RowQueryPage>;
58
+ /**
59
+ * Subscribe to server-pushed cascade events (e.g. another client's
60
+ * persist-envelope emits, Almadar_Live_Push.md). Absent when the
61
+ * transport has no server to push from (in-process). `params` augments
62
+ * the push channel's query string (e.g. a caller-supplied per-tab
63
+ * `clientId` for the server's origin-exclusion) — the transport itself
64
+ * carries no notion of "tab identity", that is a client-role concern
65
+ * (plan P4).
66
+ */
67
+ subscribe?(onPush: (emitted: EmittedEvent, target: PushTarget) => void, params?: Record<string, string>): () => void;
68
+ /**
69
+ * The host runs the whole program, browser-stored entities included (an extension's worker): a
70
+ * view of it keeps no browser store of its own and sends every leg to the host.
71
+ */
72
+ readonly hostsBrowserStore?: boolean;
73
+ /**
74
+ * Hear the results of dispatches the host ran without any view asking (a declared input, a
75
+ * follow-on call's outcome), so an open view shows them. The view applies the result; it never
76
+ * runs the dispatch again. `params` addresses this view on a push channel, as for `subscribe`.
77
+ */
78
+ subscribeHostDispatches?(onDispatch: HostDispatchListener, params?: Record<string, string>): () => void;
79
+ }
80
+ /** A dispatch the host ran on its own, with its result. */
81
+ type HostDispatchListener = (orbitalName: string, request: OrbitalEventRequest, response: OrbitalEventResponse) => void;
82
+ /**
83
+ * Supplies the bearer token the hosting server authenticates with. Resolved
84
+ * per request (tokens expire); `undefined` sends the request unauthenticated
85
+ * (dev servers with an auth bypass, standalone playground). Moved verbatim
86
+ * from `@almadar/ui`'s `providers/ServerBridge.tsx`.
87
+ */
88
+ type AccessTokenProvider = () => Promise<string | undefined>;
89
+ interface HttpTransportOptions {
90
+ serverUrl: string;
91
+ getAccessToken?: AccessTokenProvider;
92
+ /** Custom fetch function (for testing or custom auth). */
93
+ fetch?: typeof fetch;
94
+ /**
95
+ * Gzip JSON request bodies of at least `COMPRESSED_BODY_MIN_BYTES` (`Content-Encoding: gzip`).
96
+ * Browsers never compress request bodies, so a registered schema otherwise goes up raw. Only
97
+ * for servers that inflate request bodies (Express's JSON parser does).
98
+ */
99
+ compressRequests?: boolean;
100
+ }
101
+ /** Bodies below this stay plain: compressing them costs more than it saves. */
102
+ declare const COMPRESSED_BODY_MIN_BYTES: number;
103
+ /** A JSON request body, gzipped (`encoding: 'gzip'`) when `compress` is set and it is large enough to be worth it. */
104
+ declare function encodeJsonBody(value: object, compress: boolean): Promise<{
105
+ body: string | Uint8Array<ArrayBuffer>;
106
+ encoding?: 'gzip';
107
+ }>;
108
+ /** HTTP transport — POSTs to a server speaking the canonical playground-runtime contract. */
109
+ declare function createHttpTransport(options: HttpTransportOptions): EventTransport;
110
+ /** Evaluates one event against an orbital with no wire in between — the unified `evaluateOrbitalEvent` (a separate, in-progress unit) is a valid `OrbitalEvaluator`. */
111
+ type OrbitalEvaluator = (orbitalName: string, request: OrbitalEventRequest) => Promise<OrbitalEventResponse>;
112
+ interface InProcessTransportOptions {
113
+ onRegister?: (schema: OrbitalSchema) => Promise<void> | void;
114
+ onUnregister?: () => Promise<void> | void;
115
+ /**
116
+ * In-process evaluation never crosses a wire, so nothing about circuit
117
+ * state is "carried" in the stateless-topology sense — `false` by
118
+ * default, mirroring `@almadar/ui`'s `BrowserPlayground` today: its
119
+ * in-process `register` never declares a `topology`, and the provider's
120
+ * fallback for a custom transport is `'in-process'` (not
121
+ * `'stateless-http'`).
122
+ */
123
+ carriesCircuitState?: boolean;
124
+ /** Resolves a row-set reference on the in-process kernel (`KernelEngine.resolveRows`), `@read` applied there. */
125
+ resolveRows?: (reference: RowSetRef) => Promise<RowQueryPage>;
126
+ }
127
+ /** In-process transport — the evaluator is INJECTED (e.g. the unified `evaluateOrbitalEvent`, owned elsewhere). */
128
+ declare function createInProcessTransport(evaluate: OrbitalEvaluator, options?: InProcessTransportOptions): EventTransport;
129
+
130
+ export { COMPRESSED_BODY_MIN_BYTES, createHttpTransport, createInProcessTransport, deriveCarriesCircuitState, encodeJsonBody };
131
+ export type { AccessTokenProvider, EventTransport, EventTransportRegisterResult, HostDispatchListener, HttpTransportOptions, InProcessTransportOptions, OrbitalEvaluator, PushTarget };
@@ -0,0 +1,2 @@
1
+ export { COMPRESSED_BODY_MIN_BYTES, createHttpTransport, createInProcessTransport, deriveCarriesCircuitState, encodeJsonBody } from '../chunk-QELZ6TEJ.js';
2
+ import '../chunk-MLKGABMK.js';
@@ -0,0 +1,126 @@
1
+ import { IEventBus } from '../runtime/types.js';
2
+ import { EventPayload, EmittedEvent } from '@almadar/core';
3
+ import '../service/default-call-service.js';
4
+ import '../service/service-provider.js';
5
+ import '../kernel/program-effects.js';
6
+ import '../runtime/effects/composition/compose-behaviors.js';
7
+ import '../runtime/effects/composition/event-wiring.js';
8
+ import '../runtime/effects/composition/layout-strategy.js';
9
+ import '../runtime/effects/composition/pipe.js';
10
+
11
+ /**
12
+ * ServerBridge - Client-Server Trait Communication
13
+ *
14
+ * Bridges the client EventBus with the server OrbitalRuntime:
15
+ * 1. Forwards specified events from client to server
16
+ * 2. Receives events from server (via polling or WebSocket)
17
+ * 3. Puts server events onto client EventBus
18
+ *
19
+ * This enables cross-orbital communication between client and server traits.
20
+ *
21
+ * @example
22
+ * ```typescript
23
+ * import { ServerBridge } from '@kflow-builder/shared/runtime';
24
+ * import { useEventBus } from './hooks/useEventBus';
25
+ *
26
+ * // In your app initialization
27
+ * const eventBus = useEventBus();
28
+ * const bridge = new ServerBridge({
29
+ * eventBus,
30
+ * serverUrl: '/api/orbitals',
31
+ * // Events to forward from client to server
32
+ * forwardEvents: ['ORDER_PLACED', 'PAYMENT_COMPLETED'],
33
+ * });
34
+ *
35
+ * bridge.connect();
36
+ *
37
+ * // Now when client emits ORDER_PLACED, server traits receive it
38
+ * eventBus.emit('ORDER_PLACED', { orderId: '123' });
39
+ * ```
40
+ *
41
+ * @packageDocumentation
42
+ */
43
+
44
+ interface ServerBridgeConfig {
45
+ /** Client EventBus to bridge */
46
+ eventBus: IEventBus;
47
+ /** Base URL for orbital server API */
48
+ serverUrl: string;
49
+ /** Events to forward from client to server */
50
+ forwardEvents?: string[];
51
+ /** Forward all events matching pattern (e.g., 'Order*', '*') */
52
+ forwardPattern?: string;
53
+ /** Target orbital for forwarded events (or 'broadcast' for all) */
54
+ targetOrbital?: string;
55
+ /** Enable WebSocket for real-time server events */
56
+ useWebSocket?: boolean;
57
+ /** Polling interval in ms (if not using WebSocket) */
58
+ pollInterval?: number;
59
+ /** Enable debug logging */
60
+ debug?: boolean;
61
+ /** Custom fetch function (for testing or custom auth) */
62
+ fetch?: typeof fetch;
63
+ }
64
+ interface ServerBridgeState {
65
+ connected: boolean;
66
+ lastError?: string;
67
+ eventsForwarded: number;
68
+ eventsReceived: number;
69
+ }
70
+ /**
71
+ * Bridges client EventBus with server OrbitalRuntime
72
+ */
73
+ declare class ServerBridge {
74
+ private config;
75
+ private state;
76
+ private unsubscribes;
77
+ private pollTimer?;
78
+ private ws?;
79
+ private fetchFn;
80
+ /** The one HTTP request/response leg — shared with `@almadar/ui`'s transport (P5, EventTransport.ts). */
81
+ private transport;
82
+ constructor(config: ServerBridgeConfig);
83
+ /**
84
+ * Connect the bridge - start forwarding events
85
+ */
86
+ connect(): void;
87
+ /**
88
+ * Disconnect the bridge
89
+ */
90
+ disconnect(): void;
91
+ /**
92
+ * Get current bridge state
93
+ */
94
+ getState(): ServerBridgeState;
95
+ private setupEventForwarding;
96
+ private forwardToServer;
97
+ private sendEventToOrbital;
98
+ private fetchOrbitals;
99
+ private setupPolling;
100
+ private setupWebSocket;
101
+ /**
102
+ * Send an event directly to a specific orbital (bypassing EventBus)
103
+ */
104
+ sendEvent(orbitalName: string, event: string, payload?: EventPayload): Promise<{
105
+ success: boolean;
106
+ states?: Record<string, string>;
107
+ emittedEvents?: EmittedEvent[];
108
+ error?: string;
109
+ }>;
110
+ /**
111
+ * Get current state of an orbital's traits
112
+ */
113
+ getOrbitalState(orbitalName: string): Promise<{
114
+ success: boolean;
115
+ states?: Record<string, string>;
116
+ error?: string;
117
+ }>;
118
+ private log;
119
+ }
120
+ /**
121
+ * Create a ServerBridge instance
122
+ */
123
+ declare function createServerBridge(config: ServerBridgeConfig): ServerBridge;
124
+
125
+ export { ServerBridge, createServerBridge };
126
+ export type { ServerBridgeConfig, ServerBridgeState };
@@ -0,0 +1,3 @@
1
+ export { ServerBridge, createServerBridge } from '../chunk-D5USD2EX.js';
2
+ import '../chunk-QELZ6TEJ.js';
3
+ import '../chunk-MLKGABMK.js';
@@ -0,0 +1,28 @@
1
+ import { AwaitingTrait } from '@almadar/core';
2
+
3
+ /**
4
+ * Which traits are awaiting a server round trip right now — the kernel contract
5
+ * behind awaiting-server skeletons (`AwaitingTrait`, `@almadar/core`). The
6
+ * client kernel begins an entry right before a server leg's send and ends it
7
+ * when the leg folds or fails; local/hybrid traits and tick legs never enter.
8
+ * Subscriptions are per trait, so only the slots that trait owns re-render.
9
+ */
10
+
11
+ declare class AwaitingRegistry {
12
+ private readonly entries;
13
+ private readonly listeners;
14
+ private readonly anyListeners;
15
+ private version;
16
+ begin(list: readonly AwaitingTrait[]): void;
17
+ end(traits: readonly string[]): void;
18
+ get(trait: string): AwaitingTrait | undefined;
19
+ list(): AwaitingTrait[];
20
+ subscribe(trait: string, listener: () => void): () => void;
21
+ /** Any trait's awaiting change (an empty slot does not know which trait will fill it). */
22
+ subscribeAll(listener: () => void): () => void;
23
+ /** Bumped on every change — a stable snapshot key for `useSyncExternalStore`. */
24
+ getVersion(): number;
25
+ private emit;
26
+ }
27
+
28
+ export { AwaitingRegistry };
@@ -0,0 +1,2 @@
1
+ export { AwaitingRegistry } from '../chunk-HC6ERSAH.js';
2
+ import '../chunk-MLKGABMK.js';
@@ -0,0 +1,69 @@
1
+ import { OrbitalEventRequest, OrbitalEventResponse, EmittedEvent } from '@almadar/core';
2
+ import { PushTarget, EventTransport } from './EventTransport.js';
3
+
4
+ /**
5
+ * An EventTransport over a message channel, for a program hosted in another browser context (an
6
+ * extension's service worker, a web worker, an iframe). The view half plays events and receives
7
+ * pushes; the host half serves any EventTransport on the channel and pushes to its views. The
8
+ * channel is two functions, so any postMessage-style port fits behind it.
9
+ */
10
+
11
+ type ChannelMessage = {
12
+ almadarChannel: 'register';
13
+ id: number;
14
+ schemaName: string;
15
+ } | {
16
+ almadarChannel: 'registered';
17
+ id: number;
18
+ held: boolean;
19
+ } | {
20
+ almadarChannel: 'send';
21
+ id: number;
22
+ orbitalName: string;
23
+ request: OrbitalEventRequest;
24
+ } | {
25
+ almadarChannel: 'reply';
26
+ id: number;
27
+ response: OrbitalEventResponse;
28
+ } | {
29
+ almadarChannel: 'push';
30
+ emitted: EmittedEvent;
31
+ target: PushTarget;
32
+ } | {
33
+ almadarChannel: 'dispatched';
34
+ orbitalName: string;
35
+ request: OrbitalEventRequest;
36
+ response: OrbitalEventResponse;
37
+ };
38
+ interface TransportChannel {
39
+ post(message: ChannelMessage): void;
40
+ onMessage(listener: (message: ChannelMessage) => void): () => void;
41
+ /** The other end went away for good (a stopped extension worker's port); absent for channels that cannot close. */
42
+ onClose?(listener: () => void): () => void;
43
+ }
44
+ interface ChannelTransportOptions {
45
+ /** The host on the other end keeps the program's browser-stored entities (see `EventTransport.hostsBrowserStore`). */
46
+ hostsBrowserStore?: boolean;
47
+ }
48
+ /** The view half: an EventTransport whose program lives on the other end of the channel. */
49
+ declare function createChannelTransport(channel: TransportChannel, options?: ChannelTransportOptions): EventTransport;
50
+ interface ServedChannel {
51
+ /** Push a host-side event to the view (e.g. one a declared input caused while no view was asking). */
52
+ push(emitted: EmittedEvent, target: PushTarget): void;
53
+ /** Send the view the result of a dispatch the host ran on its own. */
54
+ pushDispatch(orbitalName: string, request: OrbitalEventRequest, response: OrbitalEventResponse): void;
55
+ stop(): void;
56
+ }
57
+ /** The host half: serve `transport` on `channel` for the program named `schemaName`. */
58
+ declare function serveChannel(channel: TransportChannel, transport: EventTransport, options: {
59
+ schemaName: string;
60
+ }): ServedChannel;
61
+ /**
62
+ * A channel that listens from the moment it is wrapped and keeps what arrives until something
63
+ * subscribes, then hands it over in order: a host that is still starting (an extension worker
64
+ * waking up) serves the channel late without losing the view's first messages.
65
+ */
66
+ declare function holdUntilServed(channel: TransportChannel): TransportChannel;
67
+
68
+ export { createChannelTransport, holdUntilServed, serveChannel };
69
+ export type { ChannelMessage, ChannelTransportOptions, ServedChannel, TransportChannel };
@@ -0,0 +1,2 @@
1
+ export { createChannelTransport, holdUntilServed, serveChannel } from '../chunk-SKLMWHQD.js';
2
+ import '../chunk-MLKGABMK.js';