@almadar/shell-runtime 0.1.0 → 1.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 (167) hide show
  1. package/dist/chunk-2WCVOMZ2.js +112 -0
  2. package/dist/chunk-57SBCUSM.js +62 -0
  3. package/dist/{chunk-Q2H75UYT.js → chunk-A2JJT4GA.js} +1 -37
  4. package/dist/chunk-BAS26HBN.js +10 -0
  5. package/dist/{chunk-REPX5QPI.js → chunk-BOVU4TCQ.js} +11 -3
  6. package/dist/chunk-BY5G4225.js +6 -0
  7. package/dist/chunk-DFDNHVDW.js +284 -0
  8. package/dist/{chunk-NATGCIVM.js → chunk-JVSREWQO.js} +378 -130
  9. package/dist/{chunk-DYOJGLIX.js → chunk-LKWYCYX5.js} +2 -5
  10. package/dist/chunk-LYFIQPXX.js +1 -0
  11. package/dist/{chunk-ODJCZ27I.js → chunk-N7HYNKK6.js} +35 -2
  12. package/dist/{chunk-4J2QEIUV.js → chunk-NTFQ36UN.js} +4 -30
  13. package/dist/chunk-NU6LVKGS.js +15 -0
  14. package/dist/{chunk-VNMG7NKY.js → chunk-OQVSN7DP.js} +21 -26
  15. package/dist/chunk-P2N6K2IV.js +20 -0
  16. package/dist/{chunk-QQRDUMB2.js → chunk-QCJWPXLH.js} +11 -11
  17. package/dist/{chunk-QELZ6TEJ.js → chunk-UD2CXYSJ.js} +39 -3
  18. package/dist/{chunk-UJHOUZAL.js → chunk-V4EMDPCO.js} +2 -5
  19. package/dist/chunk-VKQA2DJX.js +409 -0
  20. package/dist/chunk-VNGXRYFF.js +9 -0
  21. package/dist/{chunk-HNOAZWFH.js → chunk-WGCWJOT2.js} +2 -0
  22. package/dist/chunk-XZGVOBY6.js +33 -0
  23. package/dist/chunk-ZUSM4VW4.js +197 -0
  24. package/dist/client/EventTransport.d.ts +23 -7
  25. package/dist/client/EventTransport.js +1 -2
  26. package/dist/client/awaiting.js +0 -1
  27. package/dist/client/channel-transport.d.ts +6 -6
  28. package/dist/client/channel-transport.js +0 -1
  29. package/dist/client/circuit-store.d.ts +16 -5
  30. package/dist/client/circuit-store.js +2 -3
  31. package/dist/client/client-kernel.d.ts +36 -15
  32. package/dist/client/declared-input-dispatch.d.ts +19 -2
  33. package/dist/client/declared-input-dispatch.js +1 -2
  34. package/dist/client/inbound-dispatch.d.ts +21 -2
  35. package/dist/client/inbound-dispatch.js +1 -2
  36. package/dist/client/local-fold.d.ts +15 -8
  37. package/dist/client/local-fold.js +1 -2
  38. package/dist/client/render-sigils.js +0 -1
  39. package/dist/client/state-book.d.ts +9 -16
  40. package/dist/client/state-book.js +1 -2
  41. package/dist/client/trait-mount-error.js +0 -1
  42. package/dist/credentials/env-vars.d.ts +5 -1
  43. package/dist/credentials/env-vars.js +1 -3
  44. package/dist/credentials/scope.d.ts +8 -7
  45. package/dist/credentials/scope.js +0 -1
  46. package/dist/credentials/vault.d.ts +142 -0
  47. package/dist/credentials/vault.js +1 -0
  48. package/dist/effects/in-flight-calls.js +0 -1
  49. package/dist/effects/on-device-model.js +0 -1
  50. package/dist/events/EventBus.d.ts +1 -4
  51. package/dist/events/EventBus.js +0 -1
  52. package/dist/events/emit-stamp.js +0 -1
  53. package/dist/index.d.ts +25 -42
  54. package/dist/index.js +27 -45
  55. package/dist/kernel/decode.d.ts +10 -10
  56. package/dist/kernel/decode.js +1 -2
  57. package/dist/kernel/engine.d.ts +133 -31
  58. package/dist/kernel/engine.js +7 -9
  59. package/dist/kernel/frame-applier.d.ts +8 -7
  60. package/dist/kernel/frame-applier.js +1 -2
  61. package/dist/kernel/host.d.ts +148 -16
  62. package/dist/kernel/host.js +4 -7
  63. package/dist/kernel/lane.d.ts +1 -22
  64. package/dist/kernel/lane.js +1 -2
  65. package/dist/kernel/os-fetch-port.d.ts +7 -0
  66. package/dist/kernel/os-fetch-port.js +3 -0
  67. package/dist/kernel/os-port.d.ts +30 -8
  68. package/dist/kernel/os-port.js +1 -2
  69. package/dist/kernel/program-effects.d.ts +11 -28
  70. package/dist/kernel/program-effects.js +1 -2
  71. package/dist/kernel/secret-ports.d.ts +139 -0
  72. package/dist/kernel/secret-ports.js +2 -0
  73. package/dist/kernel/wire.d.ts +113 -12
  74. package/dist/loader/fetch-loader.d.ts +26 -0
  75. package/dist/loader/fetch-loader.js +1 -0
  76. package/dist/loader/lazy-page.js +0 -1
  77. package/dist/loader/schema-loader.d.ts +1 -17
  78. package/dist/persistence/native-memory.js +0 -1
  79. package/dist/runtime/entities/declaredCollections.d.ts +6 -0
  80. package/dist/runtime/entities/declaredCollections.js +1 -0
  81. package/dist/runtime/evaluation/local-store-transport.d.ts +16 -23
  82. package/dist/runtime/evaluation/local-store-transport.js +9 -13
  83. package/dist/runtime/evaluation/residence-transport.d.ts +3 -3
  84. package/dist/runtime/evaluation/residence-transport.js +1 -2
  85. package/dist/runtime/evaluation/routed-persistence.js +0 -1
  86. package/dist/runtime/events/identity/routing.d.ts +2 -53
  87. package/dist/runtime/events/identity/routing.js +1 -2
  88. package/dist/runtime/types.d.ts +5 -205
  89. package/dist/runtime/types.js +1 -2
  90. package/dist/service/default-call-service.js +0 -1
  91. package/dist/service/service-provider.js +0 -1
  92. package/package.json +8 -5
  93. package/dist/chunk-2JU7Y4KU.js +0 -21
  94. package/dist/chunk-46RWK2B5.js +0 -28
  95. package/dist/chunk-4ZICQ5PM.js +0 -192
  96. package/dist/chunk-53IPZXDP.js +0 -76
  97. package/dist/chunk-5D63EMO5.js +0 -16
  98. package/dist/chunk-CPSQXEJ6.js +0 -55
  99. package/dist/chunk-CQP5XAX6.js +0 -173
  100. package/dist/chunk-CROS2GEX.js +0 -49
  101. package/dist/chunk-D4XJTBLB.js +0 -217
  102. package/dist/chunk-D5USD2EX.js +0 -232
  103. package/dist/chunk-EV56K4GB.js +0 -63
  104. package/dist/chunk-FQ6IZMIU.js +0 -10
  105. package/dist/chunk-HMK6YMQS.js +0 -135
  106. package/dist/chunk-IHQLE5M7.js +0 -62
  107. package/dist/chunk-JFWFDUTR.js +0 -35
  108. package/dist/chunk-MHYSHSRG.js +0 -54
  109. package/dist/chunk-MLKGABMK.js +0 -7
  110. package/dist/chunk-NAECVIAR.js +0 -322
  111. package/dist/chunk-Q7JK4KY7.js +0 -9
  112. package/dist/chunk-RBUMDYFS.js +0 -681
  113. package/dist/chunk-SAS5KKCR.js +0 -43
  114. package/dist/chunk-SWPDU752.js +0 -28
  115. package/dist/chunk-T775TUCD.js +0 -18
  116. package/dist/chunk-VMOBW7RK.js +0 -21
  117. package/dist/chunk-WNPNNYXY.js +0 -22
  118. package/dist/chunk-XB5GYODW.js +0 -28
  119. package/dist/chunk-YL2SO5TP.js +0 -334
  120. package/dist/chunk-YO4LWS3I.js +0 -606
  121. package/dist/chunk-ZAQSS47X.js +0 -157
  122. package/dist/chunk-ZCQUUJIF.js +0 -129
  123. package/dist/client/ServerBridge.d.ts +0 -126
  124. package/dist/client/ServerBridge.js +0 -3
  125. package/dist/credentials/seed.d.ts +0 -21
  126. package/dist/credentials/seed.js +0 -2
  127. package/dist/credentials/store.d.ts +0 -110
  128. package/dist/credentials/store.js +0 -2
  129. package/dist/index-hT1xCdTq.d.ts +0 -46
  130. package/dist/kernel/beacon.d.ts +0 -32
  131. package/dist/kernel/beacon.js +0 -2
  132. package/dist/kernel/http.d.ts +0 -302
  133. package/dist/kernel/http.js +0 -6
  134. package/dist/kernel/oauth-effects.d.ts +0 -25
  135. package/dist/kernel/oauth-effects.js +0 -7
  136. package/dist/kernel/oauth-port.d.ts +0 -31
  137. package/dist/kernel/oauth-port.js +0 -2
  138. package/dist/loader/http-loader.d.ts +0 -111
  139. package/dist/loader/http-loader.js +0 -2
  140. package/dist/runtime/effects/composition/compose-behaviors.d.ts +0 -58
  141. package/dist/runtime/effects/composition/compose-behaviors.js +0 -4
  142. package/dist/runtime/effects/composition/event-wiring.d.ts +0 -38
  143. package/dist/runtime/effects/composition/event-wiring.js +0 -2
  144. package/dist/runtime/effects/composition/index.d.ts +0 -5
  145. package/dist/runtime/effects/composition/index.js +0 -6
  146. package/dist/runtime/effects/composition/layout-strategy.d.ts +0 -35
  147. package/dist/runtime/effects/composition/layout-strategy.js +0 -2
  148. package/dist/runtime/effects/composition/pipe.d.ts +0 -25
  149. package/dist/runtime/effects/composition/pipe.js +0 -2
  150. package/dist/runtime/entities/mockStoreSeed.d.ts +0 -56
  151. package/dist/runtime/entities/mockStoreSeed.js +0 -3
  152. package/dist/runtime/entities/seedBrowserStore.d.ts +0 -28
  153. package/dist/runtime/entities/seedBrowserStore.js +0 -2
  154. package/dist/runtime/entities/std-mock-seed.d.ts +0 -87
  155. package/dist/runtime/entities/std-mock-seed.js +0 -2
  156. package/dist/runtime/time/TickScheduler.d.ts +0 -77
  157. package/dist/runtime/time/TickScheduler.js +0 -3
  158. package/dist/runtime/time/cron.d.ts +0 -25
  159. package/dist/runtime/time/cron.js +0 -2
  160. package/dist/runtime/time/duration.d.ts +0 -20
  161. package/dist/runtime/time/duration.js +0 -2
  162. package/dist/runtime/traits/OrbitalTraitParsing.d.ts +0 -34
  163. package/dist/runtime/traits/OrbitalTraitParsing.js +0 -2
  164. package/dist/runtime/traits/listen-targets.d.ts +0 -16
  165. package/dist/runtime/traits/listen-targets.js +0 -3
  166. package/dist/runtime/traits/trait-index.d.ts +0 -35
  167. package/dist/runtime/traits/trait-index.js +0 -3
@@ -1,9 +1,12 @@
1
- import { isProgramEffect } from './chunk-HNOAZWFH.js';
2
- import { systemRandom, base64Standard, sendBeaconRequest, streamHttp, sendHttp, checkOAuthReply } from './chunk-YO4LWS3I.js';
3
- import { untilAborted } from './chunk-MZKIL5IN.js';
1
+ import { isProgramEffect } from './chunk-WGCWJOT2.js';
2
+ import { systemRandom, base64Standard } from './chunk-ZUSM4VW4.js';
4
3
  import { OnDeviceModelFailure, promptOnDevice, embedOnDevice } from './chunk-FWA5K7Q2.js';
5
- import { WriteDeclinedError, isJsonObject, QueryDeclinedError, TabHostFailure, OrbitalEventRequestSchema, credentialStatusConnected } from '@almadar/core';
4
+ import { untilAborted } from './chunk-MZKIL5IN.js';
5
+ import { isJsonObject, WriteDeclinedError, QueryDeclinedError, TabHostFailure, RowSetRefSchema, toPayloadValue, credentialStatusConnected } from '@almadar/core';
6
6
 
7
+ function callerViewer(caller) {
8
+ return caller === void 0 ? void 0 : { id: caller.principal, ...caller.role !== void 0 ? { role: caller.role } : {} };
9
+ }
7
10
  function issuePayload(issue) {
8
11
  const payload = { code: issue.code, message: issue.message };
9
12
  if (issue.path !== void 0) payload.path = issue.path;
@@ -11,8 +14,24 @@ function issuePayload(issue) {
11
14
  if (issue.column !== void 0) payload.column = issue.column;
12
15
  return payload;
13
16
  }
14
- function toJson(value) {
15
- return JSON.parse(JSON.stringify(value));
17
+ var HostAskError = class extends Error {
18
+ constructor(kind, message) {
19
+ super(message);
20
+ this.kind = kind;
21
+ }
22
+ kind;
23
+ };
24
+ function programDocumentJson(document) {
25
+ return typeof document === "string" ? document : toPayloadValue(document);
26
+ }
27
+ function kernelEventRequestParser(kernel) {
28
+ return (payload, options) => {
29
+ try {
30
+ return { ok: kernel.parseEventRequest(JSON.stringify(payload), JSON.stringify(options)) };
31
+ } catch (error) {
32
+ return { error: error instanceof Error ? error.message : String(error) };
33
+ }
34
+ };
16
35
  }
17
36
  async function settle(work) {
18
37
  try {
@@ -39,10 +58,10 @@ async function callService(ports, request, scope) {
39
58
  ports.deliverLive({ orbital, trait: site.trait, event: onMessage }, payload, scope.originClientId);
40
59
  };
41
60
  const call = async (signal, outsideRequest) => {
42
- const host = site !== void 0 ? ports.servicePorts({ orbital, trait: site.trait }, scope.user, message, outsideRequest === true ? void 0 : scope.assertReentry) : void 0;
61
+ const host = site !== void 0 ? ports.servicePorts({ orbital, trait: site.trait }, callerViewer(caller), message, outsideRequest === true ? void 0 : scope.assertReentry) : void 0;
43
62
  const context = caller !== void 0 || signal !== void 0 || host !== void 0 || outsideRequest !== void 0 ? { ...identity, ...host !== void 0 ? { host } : {}, ...signal !== void 0 ? { signal } : {}, ...outsideRequest !== void 0 ? { outsideRequest } : {} } : void 0;
44
63
  const result = await ports.callService(service, method, serviceParams(args), context);
45
- return result === null ? null : toJson(result);
64
+ return result;
46
65
  };
47
66
  const deferred = site?.followOn === true ? ports.deferCallOutcome() : void 0;
48
67
  if (site !== void 0 && deferred !== void 0) {
@@ -55,7 +74,7 @@ async function callService(ports, request, scope) {
55
74
  return outcome.cancelled ? { kind: "serviceCancelled" } : { kind: "service", result: { ok: outcome.value } };
56
75
  };
57
76
  try {
58
- return await (scope.outsideEventQueue !== void 0 ? scope.outsideEventQueue(run) : run());
77
+ return await run();
59
78
  } catch (error) {
60
79
  return { kind: "service", result: { error: failureMessage(error) } };
61
80
  }
@@ -69,7 +88,6 @@ function startDeferredCall(defer, site, key, call, context) {
69
88
  payload,
70
89
  entityId: scope.entityId,
71
90
  originClientId: scope.originClientId,
72
- user: scope.user,
73
91
  locale: scope.locale
74
92
  });
75
93
  const outcome = key === void 0 ? call(void 0, true).then((value) => ({ cancelled: false, value })) : ports.inFlightCalls.run(key, (signal) => untilAborted(signal, call(signal, true)));
@@ -100,7 +118,7 @@ async function substrate(ports, request, scope) {
100
118
  const source = site.emit.onMessage !== void 0 ? ports.substrateStream?.(request.op, request.args, scope) : void 0;
101
119
  if (ports.inFlightCalls.inFlight(key)) return { kind: "substrate", result: { error: { message: source !== void 0 ? `key ${key} already has a stream open` : `key ${key} already has a completion pending`, errors: [] } } };
102
120
  const deliver = (fired) => {
103
- if (fired !== null) sink({ orbital: site.orbital ?? scope.orbital, traitName: site.trait, event: fired.event, payload: isJsonObject(fired.payload) ? fired.payload : void 0, entityId: site.entityId, originClientId: scope.originClientId, user: scope.user, locale: scope.locale });
121
+ if (fired !== null) sink({ orbital: site.orbital ?? scope.orbital, traitName: site.trait, event: fired.event, payload: isJsonObject(fired.payload) ? fired.payload : void 0, entityId: site.entityId, originClientId: scope.originClientId, locale: scope.locale });
104
122
  };
105
123
  const failed = (error) => deliver(complete(site, key, request.op, request.args, { error: { message: failureMessage(error), errors: [] } }));
106
124
  if (source !== void 0 && ports.substrateMessage !== void 0) {
@@ -131,18 +149,168 @@ async function substrate(ports, request, scope) {
131
149
  }, failed);
132
150
  return { kind: "serviceDeferred" };
133
151
  }
152
+ function optionalKey(op, args) {
153
+ if (args.length === 0) return { key: void 0 };
154
+ const [key] = args;
155
+ if (args.length === 1 && typeof key === "string" && key !== "") return { key };
156
+ return { error: `${op}: the key must be one non-empty text` };
157
+ }
158
+ async function performHostAsk(actions, op, args) {
159
+ const fail = (message) => ({ error: message });
160
+ if (op === "auth/sign-out") {
161
+ if (args.length !== 0) return fail("auth/sign-out takes no arguments");
162
+ if (actions?.signOut === void 0) return fail("no host sign-out is configured for auth/sign-out");
163
+ try {
164
+ await actions.signOut();
165
+ return { ok: null };
166
+ } catch (error) {
167
+ return fail(error instanceof Error ? error.message : String(error));
168
+ }
169
+ }
170
+ const audio = actions?.audio;
171
+ if (audio === void 0) return fail(`no host audio is configured for ${op}`);
172
+ let ask;
173
+ if (op === "audio/stop-music") {
174
+ if (args.length !== 0) return fail("audio/stop-music takes no arguments");
175
+ ask = { op };
176
+ } else {
177
+ const parsed = optionalKey(op, args);
178
+ if ("error" in parsed) return fail(parsed.error);
179
+ if (op === "audio/play-sound") {
180
+ if (parsed.key === void 0) return fail("audio/play-sound: the key must be one non-empty text");
181
+ ask = { op, key: parsed.key };
182
+ } else if (op === "audio/stop-sound" || op === "audio/change-music") {
183
+ ask = { op, key: parsed.key };
184
+ } else {
185
+ return fail(`no host action is configured for ${op}`);
186
+ }
187
+ }
188
+ try {
189
+ audio(ask);
190
+ return { ok: null };
191
+ } catch (error) {
192
+ return fail(error instanceof Error ? error.message : String(error));
193
+ }
194
+ }
195
+ var SIGN_IN_FIELDS = {
196
+ google: ["method"],
197
+ email: ["method", "email", "password"],
198
+ emailLink: ["method", "email", "continueUrl", "link"],
199
+ customToken: ["method", "token"]
200
+ };
201
+ function parseSignInRequest(args) {
202
+ const [request] = args;
203
+ if (args.length !== 1 || !isJsonObject(request)) return { error: "auth/sign-in takes one request object" };
204
+ const method = request.method;
205
+ const allowed = typeof method === "string" ? SIGN_IN_FIELDS[method] : void 0;
206
+ if (typeof method !== "string" || allowed === void 0) return { error: "auth/sign-in: method must be google, email, emailLink or customToken" };
207
+ const text = (field) => {
208
+ const value = request[field];
209
+ return typeof value === "string" && value !== "" ? value : void 0;
210
+ };
211
+ for (const field of Object.keys(request)) {
212
+ if (!allowed.includes(field)) return { error: `auth/sign-in: ${field} is not a field of the ${method} method` };
213
+ }
214
+ if (method === "google") return { request: { method } };
215
+ if (method === "email") {
216
+ const email2 = text("email");
217
+ const password = text("password");
218
+ return email2 !== void 0 && password !== void 0 ? { request: { method, email: email2, password } } : { error: "auth/sign-in: email takes an email and a password" };
219
+ }
220
+ if (method === "customToken") {
221
+ const token = text("token");
222
+ return token !== void 0 ? { request: { method, token } } : { error: "auth/sign-in: customToken takes a token" };
223
+ }
224
+ const email = text("email");
225
+ const continueUrl = text("continueUrl");
226
+ const link = text("link");
227
+ if (email === void 0 || continueUrl === void 0 === (link === void 0)) {
228
+ return { error: "auth/sign-in: emailLink takes an email and exactly one of continueUrl (send the link) or link (complete the sign-in)" };
229
+ }
230
+ return continueUrl !== void 0 ? { request: { method: "emailLink", email, continueUrl } } : { request: { method: "emailLink", email, link } };
231
+ }
232
+ function parseConsentRequest(args) {
233
+ const [request] = args;
234
+ if (args.length !== 1 || !isJsonObject(request)) return { error: "auth/consent takes one request object" };
235
+ for (const field of Object.keys(request)) {
236
+ if (field !== "authorizeUrl") return { error: `auth/consent: ${field} is not a field of the request` };
237
+ }
238
+ const authorizeUrl = request.authorizeUrl;
239
+ return typeof authorizeUrl === "string" && authorizeUrl !== "" ? { request: { authorizeUrl } } : { error: "auth/consent: authorizeUrl must be one non-empty text" };
240
+ }
241
+ function consentFromRedirect(redirectUrl) {
242
+ let params;
243
+ try {
244
+ params = new URL(redirectUrl).searchParams;
245
+ } catch {
246
+ throw new HostAskError("invalid", "the consent redirect is not a URL");
247
+ }
248
+ const code = params.get("code");
249
+ const state = params.get("state");
250
+ if (code === null || code === "" || state === null || state === "") throw new HostAskError("denied", "the consent redirect carried no code and state");
251
+ return { code, state };
252
+ }
253
+ async function performConsent(actions, args) {
254
+ const parsed = parseConsentRequest(args);
255
+ if ("error" in parsed) return { error: parsed.error, kind: "invalid" };
256
+ if (actions?.consent === void 0) return { error: "no host consent is configured for auth/consent", kind: "unavailable" };
257
+ try {
258
+ const { code, state } = await actions.consent(parsed.request);
259
+ return { ok: { code, state } };
260
+ } catch (error) {
261
+ if (error instanceof HostAskError) return { error: error.message, kind: error.kind };
262
+ return { error: error instanceof Error ? error.message : String(error), kind: "unavailable" };
263
+ }
264
+ }
265
+ async function performHostAnswer(actions, op, args) {
266
+ if (op === "auth/consent") return performConsent(actions, args);
267
+ if (op !== "auth/sign-in") {
268
+ const outcome = await performHostAsk(actions, op, args);
269
+ return "error" in outcome ? { error: outcome.error, kind: "unavailable" } : { ok: {} };
270
+ }
271
+ const parsed = parseSignInRequest(args);
272
+ if ("error" in parsed) return { error: parsed.error, kind: "invalid" };
273
+ if (actions?.signIn === void 0) return { error: "no host sign-in is configured for auth/sign-in", kind: "unavailable" };
274
+ try {
275
+ const answer = await actions.signIn(parsed.request);
276
+ const fields = {};
277
+ if ("sent" in answer) fields.sent = true;
278
+ else {
279
+ fields.uid = answer.uid;
280
+ if (answer.email !== void 0) fields.email = answer.email;
281
+ if (answer.displayName !== void 0) fields.displayName = answer.displayName;
282
+ }
283
+ return { ok: fields };
284
+ } catch (error) {
285
+ if (error instanceof HostAskError) return { error: error.message, kind: error.kind };
286
+ return { error: error instanceof Error ? error.message : String(error), kind: "unavailable" };
287
+ }
288
+ }
289
+ function hostAskReturn(completion, outcome) {
290
+ const keyed2 = completion.key !== void 0 ? { key: completion.key } : {};
291
+ const event = "ok" in outcome ? completion.success : completion.failure;
292
+ if (event === void 0) return void 0;
293
+ const payload = "ok" in outcome ? { ...outcome.ok, ...keyed2 } : { error: outcome.error, kind: outcome.kind, ...keyed2 };
294
+ return { trait: completion.trait, ...completion.entityId !== void 0 ? { entityId: completion.entityId } : {}, event, payload };
295
+ }
296
+ async function hostAction(ports, request) {
297
+ const outcome = await performHostAsk(ports.hostActions, request.op, request.args);
298
+ return "error" in outcome ? { kind: "substrate", result: { error: { message: outcome.error, errors: [] } } } : { kind: "substrate", result: { ok: null } };
299
+ }
134
300
  async function substrateInPlace(ports, request, scope) {
301
+ if (request.op === "auth/sign-in" || request.op === "auth/consent") return { kind: "substrate", result: { error: { message: `${request.op} runs on the client host: a server-role kernel cannot ask it`, errors: [] } } };
302
+ if (request.op.startsWith("audio/") || request.op === "auth/sign-out") return hostAction(ports, request);
135
303
  if (request.op === "program/live") return { kind: "substrate", result: { error: { message: "program/live streams to its onMessage route: give it a key and an onMessage route", errors: [] } } };
136
304
  const handler = ports.programEffect();
137
305
  const failure = (message, errors = []) => {
138
306
  const detail = { message, errors };
139
307
  return { kind: "substrate", result: { error: detail } };
140
308
  };
141
- if (request.op === "program/dispatch" || request.op === "program/inputs") {
142
- const lent = ports.servicePorts({ orbital: scope.orbital, trait: "" }, scope.user, () => {
309
+ if (request.op === "program/dispatch" || request.op === "program/inputs" || request.op === "program/resolve-rows") {
310
+ const lent = ports.servicePorts({ orbital: scope.orbital, trait: "" }, void 0, () => {
143
311
  }, scope.assertReentry);
144
312
  try {
145
- const delivered = await deliverAgentAsk(request.op, request.args, lent);
313
+ const delivered = await deliverAgentAsk(request.op, request.args, lent, ports, scope.originClientId);
146
314
  if (delivered.ok) return { kind: "substrate", result: { ok: delivered.result } };
147
315
  return failure(delivered.error, delivered.errors ?? []);
148
316
  } catch (error) {
@@ -152,22 +320,27 @@ async function substrateInPlace(ports, request, scope) {
152
320
  if (handler === void 0) return failure(`no program host configured for ${request.op}`);
153
321
  if (!isProgramEffect(request.op)) return failure(`no program host configured for ${request.op}`);
154
322
  try {
155
- const user = scope.user;
156
- const outcome = await handler(request.op, request.args, user !== void 0 ? { principal: user.id, ...user.role !== void 0 ? { role: user.role } : {} } : void 0);
157
- if (outcome.ok) return { kind: "substrate", result: { ok: toJson(outcome.result) } };
158
- return failure(outcome.error, (outcome.errors ?? []).map((issue) => toJson(issuePayload(issue))));
323
+ const outcome = await handler(request.op, request.args, void 0);
324
+ if (outcome.ok) return { kind: "substrate", result: { ok: programDocumentJson(outcome.result) } };
325
+ return failure(outcome.error, (outcome.errors ?? []).map((issue) => issuePayload(issue)));
159
326
  } catch (error) {
160
327
  return failure(error instanceof Error ? error.message : String(error));
161
328
  }
162
329
  }
163
- function present(value) {
164
- if (value === void 0 || value === null || value === "") return false;
165
- if (Array.isArray(value)) return value.length > 0;
166
- if (isJsonObject(value)) return Object.keys(value).length > 0;
167
- return true;
168
- }
169
- async function deliverAgentAsk(op, args, host) {
330
+ async function deliverAgentAsk(op, args, host, ports, clientId) {
170
331
  const [first, second, third] = args;
332
+ if (op === "program/resolve-rows") {
333
+ if (args.length !== 2 || first === void 0 || second === void 0) return { ok: false, error: "program/resolve-rows: the host is asked for a row-set reference and the viewer slot, which is null: a program names no viewer" };
334
+ const reference = RowSetRefSchema.safeParse(first);
335
+ if (!reference.success) {
336
+ const error = `program/resolve-rows: not a row-set reference: ${reference.error.message}`;
337
+ return { ok: false, error, errors: [{ code: "INVALID_REQUEST", message: error, status: 400 }] };
338
+ }
339
+ if (second !== null) return { ok: false, error: "program/resolve-rows: rows resolve for the requesting session's identity (EXEC-IDENTITY-1); a program names no viewer, so the viewer argument is null" };
340
+ if (host.resolveRows === void 0) return { ok: false, error: "program/resolve-rows: this host resolves no row sets" };
341
+ const page = await host.resolveRows(reference.data, clientId);
342
+ return { ok: true, result: toPayloadValue(page) };
343
+ }
171
344
  if (op === "program/inputs") {
172
345
  const steps = args.length === 1 && isJsonObject(first) ? first["trace"] : void 0;
173
346
  if (typeof steps !== "number") return { ok: false, error: "program/inputs: the host is asked for { trace } only" };
@@ -189,74 +362,25 @@ async function deliverAgentAsk(op, args, host) {
189
362
  if (host.dispatchRequest === void 0) return { ok: false, error: "program/dispatch: this host does not serve event requests" };
190
363
  const stream = third["stream"] === true;
191
364
  if (stream && host.supportsDispatchStream !== true) return { ok: false, error: "program/dispatch: this host does not answer stream items" };
192
- const fields = { payload };
193
- for (const key of ["event", "entityId", "targetTrait", "clientId", "locale", "delivery", "dispatchLog", "mount"]) {
194
- const value = third[key];
195
- if (present(value)) fields[key] = value;
196
- }
197
- const traits = third["traits"];
198
- if (traits !== void 0 && traits !== null) fields["traits"] = traits;
199
- if (isJsonObject(third["viewer"])) fields["user"] = third["viewer"];
200
- const parsed = OrbitalEventRequestSchema.safeParse(fields);
201
- if (!parsed.success) {
202
- const message = `program/dispatch: not an event request: ${parsed.error.message}`;
203
- return { ok: false, error: message, errors: [{ code: "INVALID_REQUEST", message, status: 400 }] };
204
- }
365
+ const parse = ports.parseEventRequest;
366
+ if (parse === void 0) return { ok: false, error: "program/dispatch: this host has no kernel to parse an event request" };
367
+ const parsed = parse(payload, third);
368
+ if ("error" in parsed) return { ok: false, error: parsed.error, errors: [{ code: "INVALID_REQUEST", message: parsed.error, status: 400 }] };
205
369
  const orbital = typeof third["orbital"] === "string" ? third["orbital"] : "";
206
- const answered = await host.dispatchRequest(orbital, parsed.data, third["input"] === true, stream);
370
+ const answered = await host.dispatchRequest(orbital, parsed.ok, third["input"] === true, stream);
207
371
  if (!answered.ok) return { ok: false, error: answered.error, errors: [{ code: answered.code, message: answered.error, status: answered.status }] };
208
- if (!stream) return { ok: true, result: toJson(answered.response) };
372
+ if (!stream) return { ok: true, result: answered.response };
209
373
  if (answered.streamItems === void 0) return { ok: false, error: "program/dispatch: this host does not answer stream items" };
210
- return { ok: true, result: toJson({ ...answered.response, items: answered.streamItems }) };
374
+ return { ok: true, result: { ...answered.response, items: answered.streamItems } };
211
375
  }
212
376
  const event = first.lastIndexOf(".");
213
377
  const trait = first.lastIndexOf(".", event - 1);
214
378
  if (event < 0 || trait < 0) return { ok: false, error: `program/dispatch: '${first}' is not a qualified address` };
215
379
  const response = await host.dispatchInput(first.slice(0, trait), { targetTrait: first.slice(trait + 1, event), event: first.slice(event + 1), payload });
216
- return { ok: true, result: toJson(response) };
217
- }
218
- var HTTP_UNAVAILABLE = "HTTP_KERNEL_UNAVAILABLE: this host was given no http ports";
219
- function httpAnswer(exchange) {
220
- return { kind: "http", result: exchange.kind === "reply" ? { ok: exchange.response } : { error: exchange.failure } };
221
- }
222
- async function http(ports, request, scope) {
223
- const exchangePorts = ports.http;
224
- if (exchangePorts === void 0) return { kind: "http", result: { error: { kind: "failed", message: HTTP_UNAVAILABLE } } };
225
- const { key, site } = request;
226
- const orbital = site?.orbital ?? scope.orbital;
227
- const onMessage = site?.emit.onMessage;
228
- const onEvent = (event) => {
229
- if (site === void 0 || onMessage === void 0) return;
230
- ports.deliverLive({ orbital, trait: site.trait, event: onMessage }, { ...event }, scope.originClientId);
231
- };
232
- const send = (signal) => request.kind === "httpStream" ? streamHttp(exchangePorts, request.request, { framing: request.framing, key: key ?? null }, onEvent, signal) : sendHttp(exchangePorts, request.request, signal, request.delayMs);
233
- const run = async () => {
234
- if (key === void 0) return httpAnswer(await send());
235
- const outcome = await ports.inFlightCalls.run(key, (signal) => untilAborted(signal, send(signal)));
236
- return outcome.cancelled ? { kind: "serviceCancelled" } : httpAnswer(outcome.value);
237
- };
238
- try {
239
- return await (scope.outsideEventQueue !== void 0 ? scope.outsideEventQueue(run) : run());
240
- } catch (error) {
241
- return { kind: "http", result: { error: { kind: "failed", message: failureMessage(error) } } };
242
- }
243
- }
244
- async function httpBeacon(ports, request, scope) {
245
- const exchangePorts = ports.http;
246
- if (exchangePorts === void 0) return { kind: "httpBeacon", result: { ok: { via: "unavailable", message: HTTP_UNAVAILABLE } } };
247
- const { key } = request;
248
- const send = async (signal) => ({ kind: "httpBeacon", result: await sendBeaconRequest(exchangePorts, request.request, signal) });
249
- const run = async () => {
250
- if (key === void 0) return send();
251
- const outcome = await ports.inFlightCalls.run(key, (signal) => untilAborted(signal, send(signal)));
252
- return outcome.cancelled ? { kind: "serviceCancelled" } : outcome.value;
253
- };
254
- try {
255
- return await (scope.outsideEventQueue !== void 0 ? scope.outsideEventQueue(run) : run());
256
- } catch (error) {
257
- return { kind: "httpBeacon", result: { error: { kind: "failed", message: failureMessage(error) } } };
258
- }
380
+ return { ok: true, result: response };
259
381
  }
382
+ var CREDENTIAL_CONNECT_UNAVAILABLE = "this host holds no credential store that can connect";
383
+ var SECRET_PORTS_UNAVAILABLE = "SECRET_PORTS_UNAVAILABLE: this host was given no secret ports";
260
384
  async function onDeviceModel(ports, request, scope) {
261
385
  const { key } = request;
262
386
  const ask = async (signal) => request.kind === "prompt" ? { kind: "prompt", result: { ok: await promptOnDevice(ports.onDevice, request.text, request.schema, key ?? null, signal) } } : { kind: "embed", result: { ok: await embedOnDevice(ports.onDevice, request.texts, key ?? null, signal) } };
@@ -266,7 +390,7 @@ async function onDeviceModel(ports, request, scope) {
266
390
  return outcome.cancelled ? { kind: "serviceCancelled" } : outcome.value;
267
391
  };
268
392
  try {
269
- return await (scope.outsideEventQueue !== void 0 ? scope.outsideEventQueue(run) : run());
393
+ return await run();
270
394
  } catch (error) {
271
395
  const failure = error instanceof OnDeviceModelFailure ? { kind: error.kind, message: error.message } : { kind: "failed", message: failureMessage(error) };
272
396
  return request.kind === "prompt" ? { kind: "prompt", result: { error: failure } } : { kind: "embed", result: { error: failure } };
@@ -280,7 +404,7 @@ async function tab(ports, request, scope) {
280
404
  const deliver = (payload) => {
281
405
  if (ask.kind !== "watch") return;
282
406
  const target = ask.deliver;
283
- const lent = ports.servicePorts({ orbital: target.orbital, trait: target.trait }, scope.user, () => {
407
+ const lent = ports.servicePorts({ orbital: target.orbital, trait: target.trait }, void 0, () => {
284
408
  });
285
409
  void lent.dispatchInput(target.orbital, { targetTrait: target.trait, event: target.event, payload });
286
410
  };
@@ -297,22 +421,103 @@ async function tab(ports, request, scope) {
297
421
  const outcome = await ports.inFlightCalls.run(key, (signal) => untilAborted(signal, perform(signal)));
298
422
  return outcome.cancelled ? { kind: "serviceCancelled" } : outcome.value;
299
423
  };
300
- return scope.outsideEventQueue !== void 0 ? scope.outsideEventQueue(run) : run();
424
+ return run();
301
425
  }
302
426
  async function pageFacts(ports, request) {
303
- return { kind: "pageFacts", result: await settle(async () => ports.pageFacts?.(request.fields) ?? { available: false, hostname: "", referrer: "", screenWidth: null }) };
427
+ return { kind: "pageFacts", result: await settle(async () => ports.pageFacts?.(request.fields) ?? { available: false, hostname: "", referrer: "", screenWidth: null, href: "" }) };
428
+ }
429
+ function finishTls(ports, os, key, raw) {
430
+ return new Promise((resolve) => completeTls(ports, os, key, raw, resolve));
431
+ }
432
+ function completeTls(ports, os, key, raw, finish) {
433
+ const tls = ports.osTls;
434
+ if (tls === void 0) {
435
+ finish(raw);
436
+ return;
437
+ }
438
+ const step = (outcome, parked) => {
439
+ const next = tls.complete(key, outcome);
440
+ if (next === null) {
441
+ finish(parked ? { error: { kind: "tls", message: "the TLS operation vanished" } } : outcome);
442
+ return;
443
+ }
444
+ if ("done" in next) {
445
+ finish(next.done);
446
+ return;
447
+ }
448
+ void os.answer(next.ask.op, next.ask.args).then((answered) => step(answered, true));
449
+ };
450
+ step(raw, false);
451
+ }
452
+ var CANONICAL_BASE64 = /^(?:[A-Za-z0-9+/]{4})*(?:[A-Za-z0-9+/]{2}==|[A-Za-z0-9+/]{3}=)?$/;
453
+ var SEGMENT_ENCODERS = {
454
+ base64: (value) => base64Standard(new TextEncoder().encode(value)),
455
+ uri: (value) => encodeURIComponent(value),
456
+ form: (value) => encodeURIComponent(value).replace(/[!'()~]/g, (c) => `%${c.charCodeAt(0).toString(16).toUpperCase()}`).replace(/%20/g, "+")
457
+ };
458
+ async function withCredentialSegments(ports, op, args, principal) {
459
+ const segments = args[1];
460
+ if (op !== "os/send" || !Array.isArray(segments)) return { args };
461
+ const parts = [];
462
+ for (const [at, segment] of segments.entries()) {
463
+ const invalid = (what) => ({ error: { kind: "invalid", message: `${op}: segment ${at + 1} ${what}` } });
464
+ if (!isJsonObject(segment)) return invalid("is not a { bytes, credential } object");
465
+ const text = segment["bytes"];
466
+ const name = segment["credential"];
467
+ if (typeof text !== "string" || typeof name !== "string") return invalid("needs a bytes text and a credential name");
468
+ if (!CANONICAL_BASE64.test(text)) return invalid("bytes are not standard base64");
469
+ parts.push(Uint8Array.from(atob(text), (c) => c.charCodeAt(0)));
470
+ const requested = segment["encode"];
471
+ const encoder = requested === void 0 ? void 0 : typeof requested === "string" && Object.hasOwn(SEGMENT_ENCODERS, requested) ? SEGMENT_ENCODERS[requested] : null;
472
+ if (encoder === null) return invalid(`encode must be one of ${Object.keys(SEGMENT_ENCODERS).join(", ")}`);
473
+ const requestedScope = segment["scope"];
474
+ if (requestedScope !== void 0 && requestedScope !== "app" && requestedScope !== "user") return invalid("scope must be one of app, user");
475
+ if (name === "") continue;
476
+ if (requestedScope === "user" && principal === void 0) return { error: { kind: "denied", message: `${op}: segment ${at + 1} needs a signed-in viewer` } };
477
+ const store = ports.secretPorts?.secrets;
478
+ if (store === void 0) return { error: { kind: "denied", message: `${op}: no credential source is configured` } };
479
+ let held;
480
+ try {
481
+ held = await store.get(name, requestedScope === "user" ? principal : void 0);
482
+ } catch (error) {
483
+ return { error: { kind: "io", message: `${op}: credential ${name}: ${error instanceof Error ? error.message : String(error)}` } };
484
+ }
485
+ if (held === void 0 || held === null) return { error: { kind: "denied", message: `${op}: credential ${name} is not held` } };
486
+ parts.push(new TextEncoder().encode(encoder === void 0 ? held : encoder(held)));
487
+ }
488
+ const bytes = new Uint8Array(parts.reduce((total, part) => total + part.length, 0));
489
+ let offset = 0;
490
+ for (const part of parts) {
491
+ bytes.set(part, offset);
492
+ offset += part.length;
493
+ }
494
+ return { args: [args[0] ?? null, base64Standard(bytes), ...args.slice(2)] };
304
495
  }
305
496
  async function osAnswer(ports, request, scope) {
306
497
  const { os } = ports;
307
- if (os === void 0) return { kind: "os", result: { error: { kind: "denied", message: `${request.op}: no os host configured` } } };
308
- const { op, args, key, site } = request;
498
+ if (os === void 0) return { kind: "os", result: { error: { kind: "unsupported", message: `${request.op}: no os host configured` } } };
499
+ const { op, key, site, orbital: asking } = request;
309
500
  const completions = ports.osCompletions;
310
501
  const sink = ports.deferCallOutcome();
311
502
  const message = ports.substrateMessage;
312
- if (key !== void 0 && site !== void 0 && completions !== void 0 && sink !== void 0 && message !== void 0 && os.stream !== void 0 && completions.streams(op)) {
503
+ const streaming = key !== void 0 && site !== void 0 && completions !== void 0 && sink !== void 0 && message !== void 0 && os.stream !== void 0 && completions.streams(op);
504
+ const deferring = !streaming && key !== void 0 && site !== void 0 && completions !== void 0 && sink !== void 0 && os.defer !== void 0 && completions.defers(op);
505
+ const lease = (streaming || deferring) && key !== void 0 ? ports.inFlightCalls.reserve(key) : void 0;
506
+ if ((streaming || deferring) && lease === void 0) {
507
+ return { kind: "os", result: { error: { kind: "invalid", message: `${op}: key ${key} already has ${streaming ? "a stream open" : "a completion pending"}` } } };
508
+ }
509
+ const segmented = await withCredentialSegments(ports, op, request.args, request.principal);
510
+ if ("error" in segmented) {
511
+ lease?.release();
512
+ return { kind: "os", result: segmented };
513
+ }
514
+ if (lease?.signal.aborted === true) {
515
+ lease.release();
516
+ return { kind: "serviceCancelled" };
517
+ }
518
+ const { args } = segmented;
519
+ if (lease !== void 0 && streaming && key !== void 0 && site !== void 0 && completions !== void 0 && sink !== void 0 && message !== void 0 && os.stream !== void 0) {
313
520
  const orbital = site.orbital ?? scope.orbital;
314
- const lease = ports.inFlightCalls.reserve(key);
315
- if (lease === void 0) return { kind: "os", result: { error: { kind: "invalid", message: `${op}: key ${key} already has a stream open` } } };
316
521
  const stop = () => {
317
522
  os.cancel?.(key);
318
523
  lease.release();
@@ -320,30 +525,28 @@ async function osAnswer(ports, request, scope) {
320
525
  lease.signal.addEventListener("abort", stop, { once: true });
321
526
  const deliver = (fired) => {
322
527
  if (fired === null || lease.signal.aborted) return false;
323
- sink({ orbital, traitName: site.trait, event: fired.event, payload: isJsonObject(fired.payload) ? fired.payload : void 0, entityId: site.entityId, originClientId: scope.originClientId, user: scope.user, locale: scope.locale });
528
+ sink({ orbital, traitName: site.trait, event: fired.event, payload: isJsonObject(fired.payload) ? fired.payload : void 0, entityId: site.entityId, originClientId: scope.originClientId, locale: scope.locale });
324
529
  return true;
325
530
  };
326
531
  const started = await os.stream(op, args, key, (value) => deliver(message(site, key, value)), (error) => {
327
532
  lease.release();
328
533
  lease.signal.removeEventListener("abort", stop);
329
534
  deliver(completions.event(site, key, { error }));
330
- });
535
+ }, asking);
331
536
  if ("error" in started) {
332
537
  lease.release();
333
538
  lease.signal.removeEventListener("abort", stop);
334
539
  }
335
540
  return { kind: "os", result: started };
336
541
  }
337
- if (key !== void 0 && site !== void 0 && completions !== void 0 && sink !== void 0 && os.defer !== void 0 && completions.defers(op)) {
542
+ if (lease !== void 0 && deferring && key !== void 0 && site !== void 0 && completions !== void 0 && sink !== void 0 && os.defer !== void 0) {
338
543
  const orbital = site.orbital ?? scope.orbital;
339
- const lease = ports.inFlightCalls.reserve(key);
340
- if (lease === void 0) return { kind: "os", result: { error: { kind: "invalid", message: `${op}: key ${key} already has a completion pending` } } };
341
544
  const cancel = () => {
342
545
  os.cancel?.(key);
343
546
  lease.release();
344
547
  };
345
548
  lease.signal.addEventListener("abort", cancel, { once: true });
346
- const started = os.defer(op, args, key, (outcome) => {
549
+ const finish = (outcome) => {
347
550
  lease.release();
348
551
  lease.signal.removeEventListener("abort", cancel);
349
552
  if (lease.signal.aborted) return;
@@ -356,34 +559,67 @@ async function osAnswer(ports, request, scope) {
356
559
  payload: isJsonObject(fired.payload) ? fired.payload : void 0,
357
560
  entityId: site.entityId,
358
561
  originClientId: scope.originClientId,
359
- user: scope.user,
360
562
  locale: scope.locale
361
563
  });
362
- });
564
+ };
565
+ const started = os.defer(op, args, key, (raw) => {
566
+ completeTls(ports, os, key, raw, finish);
567
+ }, asking);
363
568
  if ("error" in started) {
364
569
  lease.release();
365
570
  lease.signal.removeEventListener("abort", cancel);
366
571
  }
367
572
  return "error" in started ? { kind: "os", result: started } : { kind: "serviceDeferred" };
368
573
  }
369
- return { kind: "os", result: await os.answer(op, args) };
574
+ return { kind: "os", result: await os.answer(op, args, asking) };
575
+ }
576
+ async function heldGpuAnswer(ports, request, scope) {
577
+ const held = ports.heldGpu;
578
+ if (held === void 0) return { kind: "os", result: { error: { kind: "unsupported", message: `${request.op}: this host installed no gpu answerer` } } };
579
+ const { key } = request;
580
+ const lease = key === void 0 ? void 0 : ports.inFlightCalls.reserve(key);
581
+ if (key !== void 0 && lease === void 0) {
582
+ return { kind: "os", result: { error: { kind: "invalid", message: `${request.op}: key ${key} already has a completion pending` } } };
583
+ }
584
+ const answer = await held.answer(request.ticket, (completion) => {
585
+ const aborted = lease?.signal.aborted === true;
586
+ lease?.release();
587
+ if (completion === null) return;
588
+ const sink = ports.deferCallOutcome();
589
+ if (aborted || sink === void 0) {
590
+ held.drop(completion.heldPayload);
591
+ return;
592
+ }
593
+ sink({
594
+ orbital: completion.orbital ?? scope.orbital,
595
+ traitName: completion.traitName,
596
+ event: completion.event,
597
+ payload: void 0,
598
+ heldPayload: completion.heldPayload,
599
+ entityId: completion.entityId,
600
+ originClientId: scope.originClientId,
601
+ locale: scope.locale
602
+ });
603
+ });
604
+ if (answer.kind !== "serviceDeferred") lease?.release();
605
+ return answer;
370
606
  }
371
607
  async function secret(ports, request) {
372
- const store = ports.http?.secrets;
373
- if (store === void 0) return { kind: "secret", result: { error: HTTP_UNAVAILABLE } };
608
+ const store = ports.secretPorts?.secrets;
609
+ if (store === void 0) return { kind: "secret", result: { error: SECRET_PORTS_UNAVAILABLE } };
374
610
  return { kind: "secret", result: await settle(async () => await store.get(request.name, request.principal) ?? null) };
375
611
  }
376
612
  async function secretSet(ports, request) {
377
- const store = ports.http?.secrets;
378
- if (store === void 0) return { kind: "secretSet", result: { error: HTTP_UNAVAILABLE } };
613
+ const store = ports.secretPorts?.secrets;
614
+ if (store === void 0) return { kind: "secretSet", result: { error: SECRET_PORTS_UNAVAILABLE } };
379
615
  return { kind: "secretSet", result: await settle(async () => {
380
616
  await store.set(request.name, request.value, request.ttlMs, request.principal);
381
617
  return null;
382
618
  }) };
383
619
  }
384
620
  async function secretRotate(ports, request) {
385
- const store = ports.http?.secrets;
386
- if (store === void 0) return { kind: "secretRotate", result: { error: HTTP_UNAVAILABLE } };
621
+ const store = ports.secretPorts?.secrets;
622
+ if (store === void 0) return { kind: "secretRotate", result: { error: SECRET_PORTS_UNAVAILABLE } };
387
623
  const rotate = store.rotate;
388
624
  if (rotate === void 0) return { kind: "secretRotate", result: { error: "this host keeps no rotatable credentials" } };
389
625
  return { kind: "secretRotate", result: await settle(async () => {
@@ -392,7 +628,7 @@ async function secretRotate(ports, request) {
392
628
  }) };
393
629
  }
394
630
  function random(ports, request) {
395
- const source = ports.http?.random ?? systemRandom;
631
+ const source = ports.secretPorts?.random ?? systemRandom;
396
632
  try {
397
633
  return { kind: "random", result: { ok: base64Standard(source(request.bytes)) } };
398
634
  } catch (error) {
@@ -400,8 +636,8 @@ function random(ports, request) {
400
636
  }
401
637
  }
402
638
  async function credentialStatus(ports, request) {
403
- const store = ports.http?.secrets;
404
- if (store === void 0) return { kind: "credentialStatus", result: { error: HTTP_UNAVAILABLE } };
639
+ const store = ports.secretPorts?.secrets;
640
+ if (store === void 0) return { kind: "credentialStatus", result: { error: SECRET_PORTS_UNAVAILABLE } };
405
641
  return { kind: "credentialStatus", result: await settle(async () => {
406
642
  const connected = credentialStatusConnected(await store.get(request.name, request.principal), request.principal);
407
643
  const label = connected ? await store.label?.(request.name, request.principal) : void 0;
@@ -409,23 +645,32 @@ async function credentialStatus(ports, request) {
409
645
  }) };
410
646
  }
411
647
  async function credentialForget(ports, request) {
412
- const store = ports.http?.secrets;
413
- if (store === void 0) return { kind: "credentialForget", result: { error: HTTP_UNAVAILABLE } };
648
+ const store = ports.secretPorts?.secrets;
649
+ if (store === void 0) return { kind: "credentialForget", result: { error: SECRET_PORTS_UNAVAILABLE } };
414
650
  return { kind: "credentialForget", result: await settle(async () => {
415
651
  await store.forget(request.name, request.principal);
416
652
  return null;
417
653
  }) };
418
654
  }
655
+ async function credentialConnect(ports, request) {
656
+ const connect = ports.secretPorts?.connect;
657
+ if (connect === void 0) return { kind: "credentialConnect", result: { error: { kind: "unavailable", message: CREDENTIAL_CONNECT_UNAVAILABLE } } };
658
+ try {
659
+ return { kind: "credentialConnect", result: await connect(request.grant) };
660
+ } catch (error) {
661
+ return { kind: "credentialConnect", result: { error: { kind: "unavailable", message: failureMessage(error) } } };
662
+ }
663
+ }
664
+ async function credentialEnvTails(ports, request) {
665
+ const env = ports.secretPorts?.env;
666
+ if (env === void 0) return { kind: "credentialEnvTails", result: { ok: { kind: "unsupported" } } };
667
+ return { kind: "credentialEnvTails", result: await settle(async () => ({ kind: "held", tails: env(request.names) })) };
668
+ }
419
669
  async function credentialAdmin(ports, work) {
420
- const port = ports.http?.credentials;
421
- if (port === void 0) return { error: HTTP_UNAVAILABLE };
670
+ const port = ports.secretPorts?.credentials;
671
+ if (port === void 0) return { error: SECRET_PORTS_UNAVAILABLE };
422
672
  return settle(() => work(port));
423
673
  }
424
- async function oauth(ports, request) {
425
- const port = ports.http?.oauth;
426
- if (port === void 0) return { kind: "oauth", result: { error: "this host keeps no OAuth state" } };
427
- return { kind: "oauth", result: await settle(async () => checkOAuthReply(await port.answer(request.ask, request.principal))) };
428
- }
429
674
  function rowData(value) {
430
675
  if (!isJsonObject(value)) throw new Error("persist: the row is not an object");
431
676
  return value;
@@ -528,18 +773,13 @@ async function answerRequest(ports, request, scope) {
528
773
  return { kind: "cancelled", result: { ok: null } };
529
774
  case "substrate":
530
775
  return substrate(ports, request, scope);
531
- case "http":
532
- case "httpStream":
533
- return http(ports, request, scope);
534
- case "httpBeacon":
535
- return httpBeacon(ports, request, scope);
536
776
  case "pageFacts":
537
777
  return pageFacts(ports, request);
538
778
  case "prompt":
539
779
  case "embed":
540
- return onDeviceModel(ports, request, scope);
780
+ return onDeviceModel(ports, request);
541
781
  case "tab":
542
- return tab(ports, request, scope);
782
+ return tab(ports, request);
543
783
  case "secret":
544
784
  return secret(ports, request);
545
785
  case "secretSet":
@@ -550,16 +790,26 @@ async function answerRequest(ports, request, scope) {
550
790
  return random(ports, request);
551
791
  case "os":
552
792
  return osAnswer(ports, request, scope);
793
+ case "gpu":
794
+ return heldGpuAnswer(ports, request, scope);
553
795
  case "clock":
554
796
  return { kind: "clock", result: { ok: (ports.now ?? Date.now)() } };
797
+ case "sealed":
798
+ return { kind: "sealed", result: { error: `${request.op}: a sealed operator is answered by the kernel, never by a host` } };
555
799
  case "deliver":
556
800
  return { kind: "deliver", result: { error: { kind: "down", id: request.envelope.id } } };
801
+ case "guest":
802
+ return { kind: "substrate", result: { error: { message: "program/dispatch: this host starts no guest kernels", errors: [{ kind: "unsupported", message: "program/dispatch: this host starts no guest kernels" }] } } };
557
803
  case "credentialStatus":
558
804
  return credentialStatus(ports, request);
559
805
  case "credentialForget":
560
806
  return credentialForget(ports, request);
807
+ case "credentialConnect":
808
+ return credentialConnect(ports, request);
561
809
  case "credentialStoreList":
562
810
  return { kind: request.kind, result: await credentialAdmin(ports, (port) => port.list()) };
811
+ case "credentialEnvTails":
812
+ return credentialEnvTails(ports, request);
563
813
  case "credentialStoreRead":
564
814
  return { kind: request.kind, result: await credentialAdmin(ports, (port) => port.read(request.name)) };
565
815
  case "credentialStoreWrite":
@@ -575,9 +825,7 @@ async function answerRequest(ports, request, scope) {
575
825
  return { kind: request.kind, result: await credentialAdmin(ports, (port) => port.mode()) };
576
826
  case "credentialModeWrite":
577
827
  return { kind: request.kind, result: await credentialAdmin(ports, (port) => port.setMode(request.mode)) };
578
- case "oauth":
579
- return oauth(ports, request);
580
828
  }
581
829
  }
582
830
 
583
- export { answerRequest, declareCapabilities, writeRows };
831
+ export { HostAskError, answerRequest, completeTls, consentFromRedirect, declareCapabilities, finishTls, hostAskReturn, kernelEventRequestParser, parseConsentRequest, parseSignInRequest, performHostAnswer, performHostAsk, writeRows };