@almadar/shell-runtime 1.0.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.
@@ -20,6 +20,9 @@ function headersOf(value) {
20
20
  return headers;
21
21
  }
22
22
  var failed = (kind, op, message) => ({ error: { kind, message: `${op}: ${message}` } });
23
+ var isGpuOp = (op) => op.startsWith("gpu/");
24
+ var noGpu = (op) => failed("unsupported", op, "this host installed no gpu answerer");
25
+ var fetchOnly = (op) => failed("unsupported", op, "a browser host answers only os/fetch, and os/recv and os/close on the handle of a streamed one");
23
26
  function createFetchOsHost(performFetch) {
24
27
  const pending = /* @__PURE__ */ new Set();
25
28
  const bodies = /* @__PURE__ */ new Map();
@@ -57,9 +60,10 @@ function createFetchOsHost(performFetch) {
57
60
  }
58
61
  return {
59
62
  async answer(op, args) {
63
+ if (isGpuOp(op)) return noGpu(op);
60
64
  if (op === "os/recv") return receive(args);
61
65
  if (op === "os/close") return release(args);
62
- if (op !== "os/fetch") return { error: { kind: "unsupported", message: `${op}: a browser host answers only os/fetch, and os/recv and os/close on the handle of a streamed one` } };
66
+ if (op !== "os/fetch") return fetchOnly(op);
63
67
  const [method, url, request] = args;
64
68
  if (typeof method !== "string" || typeof url !== "string") return fail("invalid", "the method and the url must be text");
65
69
  if (request !== void 0 && !isRecord(request)) return fail("invalid", "the request must be { headers?, body?, timeoutMs?, stream? }");
@@ -495,7 +495,7 @@ async function withCredentialSegments(ports, op, args, principal) {
495
495
  }
496
496
  async function osAnswer(ports, request, scope) {
497
497
  const { os } = ports;
498
- if (os === void 0) return { kind: "os", result: { error: { kind: "denied", message: `${request.op}: no os host configured` } } };
498
+ if (os === void 0) return { kind: "os", result: { error: { kind: "unsupported", message: `${request.op}: no os host configured` } } };
499
499
  const { op, key, site, orbital: asking } = request;
500
500
  const completions = ports.osCompletions;
501
501
  const sink = ports.deferCallOutcome();
@@ -573,6 +573,37 @@ async function osAnswer(ports, request, scope) {
573
573
  }
574
574
  return { kind: "os", result: await os.answer(op, args, asking) };
575
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;
606
+ }
576
607
  async function secret(ports, request) {
577
608
  const store = ports.secretPorts?.secrets;
578
609
  if (store === void 0) return { kind: "secret", result: { error: SECRET_PORTS_UNAVAILABLE } };
@@ -759,6 +790,8 @@ async function answerRequest(ports, request, scope) {
759
790
  return random(ports, request);
760
791
  case "os":
761
792
  return osAnswer(ports, request, scope);
793
+ case "gpu":
794
+ return heldGpuAnswer(ports, request, scope);
762
795
  case "clock":
763
796
  return { kind: "clock", result: { ok: (ports.now ?? Date.now)() } };
764
797
  case "sealed":
@@ -1,6 +1,6 @@
1
1
  import { defaultCallService } from './chunk-4SEK5ER2.js';
2
2
  import { routeByEntity } from './chunk-O57GKTYU.js';
3
- import { KernelEngine, evaluateOnKernel } from './chunk-I3TKINSO.js';
3
+ import { KernelEngine, evaluateOnKernel } from './chunk-VKQA2DJX.js';
4
4
  import { InFlightCalls } from './chunk-MZKIL5IN.js';
5
5
  import { createInProcessTransport } from './chunk-UD2CXYSJ.js';
6
6
  import { orbitalInlineEntities, storesRowsInBrowser, inlineTraitRefs } from '@almadar/core';
@@ -33,7 +33,8 @@ function openLocalKernel(options) {
33
33
  ...options.secretPorts !== void 0 ? { secretPorts: options.secretPorts } : {},
34
34
  ...options.onDevice !== void 0 ? { onDevice: options.onDevice } : {},
35
35
  ...options.tabs !== void 0 ? { tabs: options.tabs } : {},
36
- ...options.os !== void 0 ? { os: options.os } : {}
36
+ ...options.os !== void 0 ? { os: options.os } : {},
37
+ ...options.gpu !== void 0 ? { gpu: options.gpu } : {}
37
38
  });
38
39
  for (const trait of engine.programSurface().traits) engine.mountClient(LOCAL_CLIENT, trait.orbital, [trait.name]);
39
40
  return engine;
@@ -1,6 +1,6 @@
1
1
  import { LaneHeldByParkedDispatch } from './chunk-NU6LVKGS.js';
2
- import { decodeDueTicks, decodeResolveProgress, decodeProgress, decodeNext } from './chunk-X6W44WHO.js';
3
- import { declareCapabilities, answerRequest } from './chunk-7WB6VWRK.js';
2
+ import { decodeAnswer, decodeHeldCompletion, decodeDueTicks, decodeResolveProgress, decodeProgress, decodeNext } from './chunk-XZGVOBY6.js';
3
+ import { declareCapabilities, answerRequest } from './chunk-JVSREWQO.js';
4
4
  import { installKernelEvaluator, LiveBroadcastItemSchema, MountSeedSchema, ExternalInputSchema, NameListSchema, PayloadJsonSchemaSchema, PayloadIssueSchema, InboundOnlySchema, OptionalNameSchema, EntityRowSchema, isEntityReferenceAny, InboundAnswerSchema, EventPayloadSchema, InboundFoundSchema } from '@almadar/core';
5
5
 
6
6
  var PROGRAM_SURFACE = {
@@ -46,7 +46,15 @@ var KernelEngine = class _KernelEngine {
46
46
  this.ports = {
47
47
  ...ports,
48
48
  substrateMessage: (site, key, value) => JSON.parse(kernel.osCompletionEvent(JSON.stringify({ ...site, emit: { success: site.emit.onMessage } }), key, JSON.stringify({ ok: value }))),
49
- substrateCompletion: (site, key, op, args, outcome) => JSON.parse(kernel.substrateCompletionEvent(JSON.stringify(site), key, op, JSON.stringify(args), JSON.stringify(outcome)))
49
+ substrateCompletion: (site, key, op, args, outcome) => JSON.parse(kernel.substrateCompletionEvent(JSON.stringify(site), key, op, JSON.stringify(args), JSON.stringify(outcome))),
50
+ ...ports.gpu !== void 0 ? {
51
+ heldGpu: {
52
+ answer: async (ticket, completed) => decodeAnswer(await this.handle.answerGpu(ticket, (json) => completed(decodeHeldCompletion(json)))),
53
+ drop: (heldPayload) => {
54
+ this.handle.dropHeldPayload(heldPayload);
55
+ }
56
+ }
57
+ } : {}
50
58
  };
51
59
  this.handle = providedHandle ?? forkedFrom?.fork() ?? this.openServer();
52
60
  this.declare();
@@ -78,8 +86,11 @@ var KernelEngine = class _KernelEngine {
78
86
  return new _KernelEngine(this.kernel, schemaJson, ports, entityTypes, void 0, this.handle.forkProgram(schemaJson), true);
79
87
  }
80
88
  /** A server over the host's ports. */
89
+ /** A server over the host's ports; the host's GPU answerer is installed in it, so it holds every `gpu/` ask. */
81
90
  openServer() {
82
- return new this.kernel.Server(this.schemaJson, this.lazyDir);
91
+ const server = new this.kernel.Server(this.schemaJson, this.lazyDir);
92
+ if (this.ports.gpu !== void 0) server.installGpu(this.ports.gpu);
93
+ return server;
83
94
  }
84
95
  declare() {
85
96
  const handle = this.handle;
@@ -1,10 +1,17 @@
1
- import { decodeServerProgressWire, decodeNextWire, decodeResolveProgressWire, decodeFiredTick } from '@almadar/core/kernel-wire';
1
+ import { decodeServerProgressWire, decodeIoAnswerWire, decodeHeldGpuCompletion, decodeNextWire, decodeResolveProgressWire, decodeFiredTick } from '@almadar/core/kernel-wire';
2
2
  export { decodeIoRequestWire } from '@almadar/core/kernel-wire';
3
3
 
4
4
  // src/kernel/decode.ts
5
5
  function decodeProgress(json) {
6
6
  return decodeServerProgressWire(JSON.parse(json));
7
7
  }
8
+ function decodeAnswer(json) {
9
+ return decodeIoAnswerWire(JSON.parse(json));
10
+ }
11
+ function decodeHeldCompletion(json) {
12
+ const value = JSON.parse(json);
13
+ return value === null ? null : decodeHeldGpuCompletion(value);
14
+ }
8
15
  function decodeNext(json) {
9
16
  const value = JSON.parse(json);
10
17
  return value === null ? null : decodeNextWire(value);
@@ -23,4 +30,4 @@ function decodeDueTicks(json) {
23
30
  return byOrbital;
24
31
  }
25
32
 
26
- export { decodeDueTicks, decodeNext, decodeProgress, decodeResolveProgress };
33
+ export { decodeAnswer, decodeDueTicks, decodeHeldCompletion, decodeNext, decodeProgress, decodeResolveProgress };
package/dist/index.d.ts CHANGED
@@ -17,16 +17,16 @@ export { InFlightCalls, KeyedCallLease, KeyedCallOutcome, untilAborted } from '.
17
17
  export { NO_ON_DEVICE_EMBEDDER, NO_ON_DEVICE_MODEL, OnDeviceModelFailure, embedOnDevice, promptOnDevice } from './effects/on-device-model.js';
18
18
  export { EventBus, createEventBus } from './events/EventBus.js';
19
19
  export { StampEmitIdentity, stampEmitSource } from './events/emit-stamp.js';
20
- export { decodeDueTicks, decodeNext, decodeProgress, decodeResolveProgress } from './kernel/decode.js';
20
+ export { decodeAnswer, decodeDueTicks, decodeHeldCompletion, decodeNext, decodeProgress, decodeResolveProgress } from './kernel/decode.js';
21
21
  export { KernelEngine, KernelEvaluation, ProgramlessContract, evaluateOnKernel, kernelRequest } from './kernel/engine.js';
22
22
  export { FrameApplied, FrameDispatch, FramePostPort, TickEffects, applyFrame, decodeFrame } from './kernel/frame-applier.js';
23
- export { DeferredCallOutcome, EventRequestParser, HostAskError, HostAskFailureKind, HostAskOutcome, HostAskReturn, HostAudioAsk, HostConsentAnswer, HostConsentRequest, HostSignInAnswer, HostSignInRequest, KernelAnswerScope, KernelCallService, KernelHostActions, KernelHostPorts, SubstrateStreamSource, answerRequest, completeTls, consentFromRedirect, declareCapabilities, finishTls, hostAskReturn, kernelEventRequestParser, parseConsentRequest, parseSignInRequest, performHostAnswer, performHostAsk, writeRows } from './kernel/host.js';
23
+ export { DeferredCallOutcome, EventRequestParser, HeldGpuCompletion, HeldGpuPort, HostAskError, HostAskFailureKind, HostAskOutcome, HostAskReturn, HostAudioAsk, HostConsentAnswer, HostConsentRequest, HostSignInAnswer, HostSignInRequest, KernelAnswerScope, KernelCallService, KernelHostActions, KernelHostPorts, SubstrateStreamSource, answerRequest, completeTls, consentFromRedirect, declareCapabilities, finishTls, hostAskReturn, kernelEventRequestParser, parseConsentRequest, parseSignInRequest, performHostAnswer, performHostAsk, writeRows } from './kernel/host.js';
24
24
  export { CredentialAdminPort, CredentialConnectPort, EnvTailsPort, RANDOM_BYTES_MAX, RandomSource, SecretPorts, SecretPortsOptions, SecretStore, SecretStoreHost, base64Standard, base64Url, createBrowserSecretPorts, createCredentialAdminPort, createCredentialConnectPort, createSecretPorts, createSecretStore, credentialForgetPayload, credentialStatusPayload, envTailsOf, randomBytesPayload, systemRandom, userCredentialKey } from './kernel/secret-ports.js';
25
25
  export { LaneHeldByParkedDispatch } from './kernel/lane.js';
26
26
  export { AnchoredPath, OsAnchorProblem, OsAnchors, OsCompletionEvent, OsCompletionMatchers, OsCompletionPort, OsDesktopKind, OsFsMode, OsGrantKernel, OsGrantMatchers, OsGrantPort, OsHostPort, OsNetKind, OsRequirement, OsStdioKind, OsSysKind, OsTlsKernel, OsTlsPort, OsTlsStep, anchoredGrants, expandAnchor, kernelOsCompletions, kernelOsGrants, kernelOsTls } from './kernel/os-port.js';
27
27
  export { createFetchOsHost } from './kernel/os-fetch-port.js';
28
28
  export { PROGRAM_EFFECTS, ProgramEffectName, ProgramEffectOutcome, ProgramValidationReport, StepRequest, isProgramEffect } from './kernel/program-effects.js';
29
- export { FiredByOrbital, KernelModule, KernelServerClass, KernelServerHandle } from './kernel/wire.js';
29
+ export { FiredByOrbital, KernelCanvas3D, KernelCanvas3DFactory, KernelGpuHost, KernelModule, KernelSceneCanvas, KernelSceneCanvasFactory, KernelServerClass, KernelServerHandle } from './kernel/wire.js';
30
30
  export { loadLazyPage } from './loader/lazy-page.js';
31
31
  export { FetchSchemaLoader } from './loader/fetch-loader.js';
32
32
  export { BaseLoaderOptions, ImportChainLike, LoadResult, LoadedOrbital, LoadedSchema, SchemaLoader } from './loader/schema-loader.js';
package/dist/index.js CHANGED
@@ -1,25 +1,25 @@
1
1
  import './chunk-ELBLT2HZ.js';
2
2
  export { NativeMemoryPersistenceAdapter, NativeMemoryWriteError } from './chunk-7SDV3QWR.js';
3
3
  export { bindDeclaredCollections } from './chunk-BAS26HBN.js';
4
- export { createLocalStoreTransport, localStorePersistence, openLocalKernel, resolveLocalRows } from './chunk-MU335ZA4.js';
4
+ export { createLocalStoreTransport, localStorePersistence, openLocalKernel, resolveLocalRows } from './chunk-OQVSN7DP.js';
5
5
  export { defaultCallService } from './chunk-4SEK5ER2.js';
6
6
  export { ServiceCallError, callRegisteredService, registerServiceProvider, registeredServices, unregisterServiceProvider } from './chunk-UBN5JJKZ.js';
7
7
  export { createResidenceTransport } from './chunk-V4EMDPCO.js';
8
8
  export { routeByEntity } from './chunk-O57GKTYU.js';
9
9
  export { eventRouteKey } from './chunk-BY5G4225.js';
10
10
  import './chunk-LYFIQPXX.js';
11
- export { createFetchOsHost } from './chunk-625EP7W2.js';
11
+ export { createFetchOsHost } from './chunk-2WCVOMZ2.js';
12
12
  export { anchoredGrants, expandAnchor, kernelOsCompletions, kernelOsGrants, kernelOsTls } from './chunk-BOVU4TCQ.js';
13
13
  import './chunk-EZZYLTWY.js';
14
14
  export { FetchSchemaLoader } from './chunk-57SBCUSM.js';
15
15
  export { loadLazyPage } from './chunk-XXWNMJI6.js';
16
16
  export { EventBus, createEventBus } from './chunk-SOQDEPME.js';
17
17
  export { stampEmitSource } from './chunk-64IH2SMY.js';
18
- export { KernelEngine, evaluateOnKernel, kernelRequest } from './chunk-I3TKINSO.js';
18
+ export { KernelEngine, evaluateOnKernel, kernelRequest } from './chunk-VKQA2DJX.js';
19
19
  export { LaneHeldByParkedDispatch } from './chunk-NU6LVKGS.js';
20
- export { decodeDueTicks, decodeNext, decodeProgress, decodeIoRequestWire as decodeRequest, decodeResolveProgress } from './chunk-X6W44WHO.js';
20
+ export { decodeAnswer, decodeDueTicks, decodeHeldCompletion, decodeNext, decodeProgress, decodeIoRequestWire as decodeRequest, decodeResolveProgress } from './chunk-XZGVOBY6.js';
21
21
  export { applyFrame, decodeFrame } from './chunk-NTFQ36UN.js';
22
- export { HostAskError, answerRequest, completeTls, consentFromRedirect, declareCapabilities, finishTls, hostAskReturn, kernelEventRequestParser, parseConsentRequest, parseSignInRequest, performHostAnswer, performHostAsk, writeRows } from './chunk-7WB6VWRK.js';
22
+ export { HostAskError, answerRequest, completeTls, consentFromRedirect, declareCapabilities, finishTls, hostAskReturn, kernelEventRequestParser, parseConsentRequest, parseSignInRequest, performHostAnswer, performHostAsk, writeRows } from './chunk-JVSREWQO.js';
23
23
  export { PROGRAM_EFFECTS, isProgramEffect } from './chunk-WGCWJOT2.js';
24
24
  export { RANDOM_BYTES_MAX, base64Standard, base64Url, createBrowserSecretPorts, createCredentialAdminPort, createCredentialConnectPort, createSecretPorts, createSecretStore, credentialForgetPayload, credentialStatusPayload, envTailsOf, randomBytesPayload, systemRandom, userCredentialKey } from './chunk-ZUSM4VW4.js';
25
25
  export { NO_ON_DEVICE_EMBEDDER, NO_ON_DEVICE_MODEL, OnDeviceModelFailure, embedOnDevice, promptOnDevice } from './chunk-FWA5K7Q2.js';
@@ -1,4 +1,4 @@
1
- import { NextWire, ServerProgressWire, ResolveProgressWire } from '@almadar/core/kernel-wire';
1
+ import { IoAnswerWire, HeldGpuCompletion, NextWire, ServerProgressWire, ResolveProgressWire } from '@almadar/core/kernel-wire';
2
2
  export { decodeIoRequestWire as decodeRequest } from '@almadar/core/kernel-wire';
3
3
  import { FiredByOrbital } from './wire.js';
4
4
  import '@almadar/core';
@@ -6,8 +6,10 @@ import '@almadar/core';
6
6
  /** Decoders for what the kernel hands back as JSON: the generated decoders of `@almadar/core/kernel-wire`, which throw naming the failing path. */
7
7
 
8
8
  declare function decodeProgress(json: string): ServerProgressWire;
9
+ declare function decodeAnswer(json: string): IoAnswerWire;
10
+ declare function decodeHeldCompletion(json: string): HeldGpuCompletion | null;
9
11
  declare function decodeNext(json: string): NextWire | null;
10
12
  declare function decodeResolveProgress(json: string): ResolveProgressWire;
11
13
  declare function decodeDueTicks(json: string): FiredByOrbital;
12
14
 
13
- export { decodeDueTicks, decodeNext, decodeProgress, decodeResolveProgress };
15
+ export { decodeAnswer, decodeDueTicks, decodeHeldCompletion, decodeNext, decodeProgress, decodeResolveProgress };
@@ -1 +1 @@
1
- export { decodeDueTicks, decodeNext, decodeProgress, decodeIoRequestWire as decodeRequest, decodeResolveProgress } from '../chunk-X6W44WHO.js';
1
+ export { decodeAnswer, decodeDueTicks, decodeHeldCompletion, decodeNext, decodeProgress, decodeIoRequestWire as decodeRequest, decodeResolveProgress } from '../chunk-XZGVOBY6.js';
@@ -55,6 +55,7 @@ declare class KernelEngine {
55
55
  fork(ports?: KernelHostPorts): KernelEngine;
56
56
  forkProgram(program: OrbitalSchema, ports?: KernelHostPorts): KernelEngine;
57
57
  /** A server over the host's ports. */
58
+ /** A server over the host's ports; the host's GPU answerer is installed in it, so it holds every `gpu/` ask. */
58
59
  private openServer;
59
60
  private declare;
60
61
  /** The contract answers for a host with no program registered yet: the kernel's, asked with no program. */
@@ -1,7 +1,7 @@
1
- export { KernelEngine, evaluateOnKernel, kernelRequest } from '../chunk-I3TKINSO.js';
1
+ export { KernelEngine, evaluateOnKernel, kernelRequest } from '../chunk-VKQA2DJX.js';
2
2
  import '../chunk-NU6LVKGS.js';
3
- import '../chunk-X6W44WHO.js';
4
- import '../chunk-7WB6VWRK.js';
3
+ import '../chunk-XZGVOBY6.js';
4
+ import '../chunk-JVSREWQO.js';
5
5
  import '../chunk-WGCWJOT2.js';
6
6
  import '../chunk-ZUSM4VW4.js';
7
7
  import '../chunk-FWA5K7Q2.js';
@@ -3,8 +3,8 @@ import { InFlightCalls } from '../effects/in-flight-calls.js';
3
3
  import { ServiceCallContext } from '../service/service-provider.js';
4
4
  import { ProgramEffectName, ProgramEffectOutcome } from './program-effects.js';
5
5
  import { SecretPorts } from './secret-ports.js';
6
- import { Settled, EventRequest, CallSiteWire, SubstrateFailureWire, IoRequestWire, IoAnswerWire, OsError } from '@almadar/core/kernel-wire';
7
- import { KernelModule } from './wire.js';
6
+ import { Settled, EventRequest, CallSiteWire, SubstrateFailureWire, IoAnswerWire, IoRequestWire, OsError } from '@almadar/core/kernel-wire';
7
+ import { KernelGpuHost, KernelModule } from './wire.js';
8
8
  import { OsHostPort, OsCompletionPort, OsTlsPort, OsCompletionEvent } from './os-port.js';
9
9
  import '../credentials/vault.js';
10
10
 
@@ -23,6 +23,8 @@ interface DeferredCallOutcome {
23
23
  traitName: string;
24
24
  event: string;
25
25
  payload: EventPayload | undefined;
26
+ /** The payload is held in the kernel under this ticket (a `gpu/` completion): the request names it instead of carrying it. */
27
+ heldPayload?: number;
26
28
  entityId: string | undefined;
27
29
  originClientId: string | undefined;
28
30
  locale: string | undefined;
@@ -147,6 +149,25 @@ interface KernelHostPorts {
147
149
  substrateCompletion?: (site: CallSiteWire, key: string, op: string, args: readonly JsonValue[], outcome: Settled<JsonValue, SubstrateFailureWire>) => OsCompletionEvent | null;
148
150
  /** The host clock in epoch milliseconds, answering the kernel's `clock` ask; absent, the system clock. */
149
151
  now?: () => number;
152
+ /** The browser's GPU answerer, installed into the kernel: every `gpu/` ask is then held and answered there. */
153
+ gpu?: KernelGpuHost;
154
+ /** The GPU answerer installed in the kernel (bound by the engine from `gpu`): it answers a held `gpu` ask by ticket, so its bytes never reach this host. */
155
+ heldGpu?: HeldGpuPort;
156
+ }
157
+ /** A deferred held `gpu/` ask's completion: the route event and the ticket its payload is held under in the kernel. */
158
+ interface HeldGpuCompletion {
159
+ orbital?: string;
160
+ traitName: string;
161
+ entityId?: string;
162
+ event: string;
163
+ heldPayload: number;
164
+ }
165
+ /** The kernel's own GPU answerer (orbital-wasm `Server.answerGpu`), bound to the kernel the host runs. */
166
+ interface HeldGpuPort {
167
+ /** `completed` runs once for a deferred ask: its completion, or `null` when the outcome takes no declared route. */
168
+ answer(ticket: number, completed: (completion: HeldGpuCompletion | null) => void): Promise<IoAnswerWire>;
169
+ /** Drop a held completion payload no request will start. */
170
+ drop(heldPayload: number): void;
150
171
  }
151
172
  /** What one dispatch brings to its answers. */
152
173
  interface KernelAnswerScope {
@@ -203,4 +224,4 @@ declare function declareCapabilities(persistence: PersistenceAdapter, declare: (
203
224
  declare function answerRequest(ports: KernelHostPorts, request: IoRequestWire, scope: KernelAnswerScope): Promise<IoAnswerWire>;
204
225
 
205
226
  export { HostAskError, answerRequest, completeTls, consentFromRedirect, declareCapabilities, finishTls, hostAskReturn, kernelEventRequestParser, parseConsentRequest, parseSignInRequest, performHostAnswer, performHostAsk, writeRows };
206
- export type { DeferredCallOutcome, EventRequestParser, HostAskFailureKind, HostAskOutcome, HostAskReturn, HostAudioAsk, HostConsentAnswer, HostConsentRequest, HostSignInAnswer, HostSignInRequest, KernelAnswerScope, KernelCallService, KernelHostActions, KernelHostPorts, SubstrateStreamSource };
227
+ export type { DeferredCallOutcome, EventRequestParser, HeldGpuCompletion, HeldGpuPort, HostAskFailureKind, HostAskOutcome, HostAskReturn, HostAudioAsk, HostConsentAnswer, HostConsentRequest, HostSignInAnswer, HostSignInRequest, KernelAnswerScope, KernelCallService, KernelHostActions, KernelHostPorts, SubstrateStreamSource };
@@ -1,4 +1,4 @@
1
- export { HostAskError, answerRequest, completeTls, consentFromRedirect, declareCapabilities, finishTls, hostAskReturn, kernelEventRequestParser, parseConsentRequest, parseSignInRequest, performHostAnswer, performHostAsk, writeRows } from '../chunk-7WB6VWRK.js';
1
+ export { HostAskError, answerRequest, completeTls, consentFromRedirect, declareCapabilities, finishTls, hostAskReturn, kernelEventRequestParser, parseConsentRequest, parseSignInRequest, performHostAnswer, performHostAsk, writeRows } from '../chunk-JVSREWQO.js';
2
2
  import '../chunk-WGCWJOT2.js';
3
3
  import '../chunk-ZUSM4VW4.js';
4
4
  import '../chunk-FWA5K7Q2.js';
@@ -1,3 +1,3 @@
1
- export { createFetchOsHost } from '../chunk-625EP7W2.js';
1
+ export { createFetchOsHost } from '../chunk-2WCVOMZ2.js';
2
2
  import '../chunk-ZUSM4VW4.js';
3
3
  import '../chunk-HLOUDLPI.js';
@@ -5,8 +5,71 @@ export { CallRoutesWire, CallSiteWire, CallerWire, IoAnswerWire, IoReplyWire, Io
5
5
  /** Fired ticks keyed by the orbital that declares them: the one a `runTick` request is addressed to. */
6
6
  type FiredByOrbital = FrameWire['fired'];
7
7
 
8
+ /** The wasm `GpuHost` (orbital-wasm): the browser's GPU answerer, installed into a kernel `Server` with `installGpu`. */
9
+ interface KernelGpuHost {
10
+ closeAll(): void;
11
+ }
12
+ /**
13
+ * The wasm `Canvas3D` (orbital-wasm): orbital-canvas drawing a `canvas mode:"3d"` render node into a page canvas, on
14
+ * the device the page's `GpuHost` shares. JSON crosses as text; `pointerUp` answers the click it made.
15
+ */
16
+ interface KernelCanvas3D {
17
+ /** `themeJson`: the page's resolved canvas theme, or `null`; orbital-canvas reads its scene axis, ground and tones. */
18
+ setScene(nodeJson: string, themeJson: string): void;
19
+ resize(cssWidth: number, cssHeight: number, pixelRatio: number): void;
20
+ setReducedMotion(reduced: boolean): void;
21
+ render(): void;
22
+ /** Advances the canvas clock to `nowMs` (`performance.now()`) with the page clock `epochMs` (`performance.timeOrigin + now`), eases a following camera and the orbit damping; true when the frame changed. */
23
+ frame(nowMs: number, epochMs: number): boolean;
24
+ /** False on the WebGL2 fallback, where GPU drawables are refused. */
25
+ webgpu(): boolean;
26
+ pointerDown(id: number, x: number, y: number, button: number, touch: boolean): void;
27
+ pointerMove(id: number, x: number, y: number): boolean;
28
+ pointerLeave(): void;
29
+ /** `{"unit":{"id","x","z"}}`, `{"tile":{"x","z"}}`, `{"select":{"id"}}`, `{"move":{"id","x","y"}}`, `{"shape":{"id","index"}}` (a learning canvas's click payload) or `null`. */
30
+ pointerUp(id: number, x: number, y: number, unitEvents: boolean, tileEvents: boolean): string;
31
+ wheel(deltaY: number): boolean;
32
+ /** The camera as the user moved it, as JSON, or `null` before a scene. */
33
+ camera(): string;
34
+ /** `[x, y, z]` as JSON; true when the camera moved. */
35
+ setCameraPosition(positionJson: string): boolean;
36
+ lookAt(targetJson: string): boolean;
37
+ resetCamera(): boolean;
38
+ free(): void;
39
+ }
40
+ /**
41
+ * The wasm `SceneCanvas` (orbital-wasm): orbital-canvas mapping and drawing a canvas-style render node (learning
42
+ * instruments, diagrams, a 2D game `canvas`) into a page canvas, with its own layout, clock and input.
43
+ */
44
+ interface KernelSceneCanvas {
45
+ setScene(nodeJson: string): void;
46
+ resize(cssWidth: number, cssHeight: number, pixelRatio: number): void;
47
+ setMotion(enabled: boolean): void;
48
+ /** Advances the scene clock to `nowMs`; true while the page should keep drawing. */
49
+ frame(nowMs: number): boolean;
50
+ render(): void;
51
+ /** `touch-down`, `touch-move`, `touch-up` or `touch-cancel`, in CSS pixels. */
52
+ input(kind: string, x: number, y: number, button: number): void;
53
+ /** Whether the scene took the zoom (a pannable scene); the page scrolls when it did not. */
54
+ zoom(factor: number, x: number, y: number): boolean;
55
+ doubleTap(x: number, y: number): void;
56
+ /** `[{ "event", "payload" }]` queued by input. */
57
+ takeEvents(): string;
58
+ webgpu(): boolean;
59
+ free(): void;
60
+ }
61
+ /** Makes a `SceneCanvas` on a page canvas (`(canvas) => SceneCanvas.create(canvas)` from `@almadar/kernel/client`). */
62
+ type KernelSceneCanvasFactory = (canvas: HTMLCanvasElement) => Promise<KernelSceneCanvas>;
63
+ /** Makes a `Canvas3D` on a page canvas (`(canvas) => Canvas3D.create(canvas)` from `@almadar/kernel/client`). */
64
+ type KernelCanvas3DFactory = (canvas: HTMLCanvasElement) => Promise<KernelCanvas3D>;
8
65
  /** The `Server` class of `@almadar/kernel` (wasm-bindgen), as the runtime uses it. */
9
66
  interface KernelServerHandle {
67
+ /** Install the GPU answerer: the server then holds every `gpu/` ask, and the host answers it by ticket. */
68
+ installGpu(gpu: KernelGpuHost): void;
69
+ /** Answer the held `gpu` ask `ticket`: the `IoAnswerWire` JSON to reply with. A deferred completion reaches `completed` as `HeldGpuCompletion` JSON, or `null`. */
70
+ answerGpu(ticket: number, completed: (completionJson: string) => void): Promise<string>;
71
+ /** Drop a held completion payload no request will start. */
72
+ dropHeldPayload(ticket: number): boolean;
10
73
  start(orbital: string, requestJson: string): string;
11
74
  resume(flight: number, repliesJson: string): string;
12
75
  /** The oldest request the kernel queued, started now the lane is free: a `NextWire` as JSON, or `null`. */
@@ -101,4 +164,4 @@ interface KernelModule extends KernelEvaluatorExports {
101
164
  installLanguage(bundleJson: string): void;
102
165
  }
103
166
 
104
- export type { FiredByOrbital, KernelModule, KernelServerClass, KernelServerHandle };
167
+ export type { FiredByOrbital, KernelCanvas3D, KernelCanvas3DFactory, KernelGpuHost, KernelModule, KernelSceneCanvas, KernelSceneCanvasFactory, KernelServerClass, KernelServerHandle };
@@ -38,6 +38,8 @@ interface LocalKernelOptions {
38
38
  tabs?: BrowserTabPort;
39
39
  /** The host's `os` port (`createFetchOsHost` in a browser); absent, every `os` ask is denied. */
40
40
  os?: OsHostPort;
41
+ /** The browser's GPU answerer (the kernel module's `GpuHost`), installed into the kernel; absent, every `gpu/` ask answers `unsupported`. */
42
+ gpu?: KernelHostPorts['gpu'];
41
43
  }
42
44
  /** A local store's rows as the kernel holds them: browser-stored entities in `store`, every other entity in `memory` (a native `MemoryStore` adapter). */
43
45
  declare function localStorePersistence(schema: OrbitalSchema, store: PersistenceAdapter, memory: PersistenceAdapter): PersistenceAdapter;
@@ -1,11 +1,11 @@
1
- export { createLocalStoreTransport, localStorePersistence, openLocalKernel, resolveLocalRows } from '../../chunk-MU335ZA4.js';
1
+ export { createLocalStoreTransport, localStorePersistence, openLocalKernel, resolveLocalRows } from '../../chunk-OQVSN7DP.js';
2
2
  import '../../chunk-4SEK5ER2.js';
3
3
  import '../../chunk-UBN5JJKZ.js';
4
4
  import '../../chunk-O57GKTYU.js';
5
- import '../../chunk-I3TKINSO.js';
5
+ import '../../chunk-VKQA2DJX.js';
6
6
  import '../../chunk-NU6LVKGS.js';
7
- import '../../chunk-X6W44WHO.js';
8
- import '../../chunk-7WB6VWRK.js';
7
+ import '../../chunk-XZGVOBY6.js';
8
+ import '../../chunk-JVSREWQO.js';
9
9
  import '../../chunk-WGCWJOT2.js';
10
10
  import '../../chunk-ZUSM4VW4.js';
11
11
  import '../../chunk-FWA5K7Q2.js';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@almadar/shell-runtime",
3
- "version": "1.0.0",
3
+ "version": "1.1.0",
4
4
  "orbRelease": {
5
5
  "severity": "normal"
6
6
  },
@@ -24,10 +24,10 @@
24
24
  ],
25
25
  "sideEffects": false,
26
26
  "dependencies": {
27
- "@almadar/core": "^11.1.0",
27
+ "@almadar/core": "^11.3.0",
28
28
  "@almadar/kernel": "^19.0.1",
29
- "@almadar/logger": "^2.1.0",
30
- "@almadar/std": "^17.0.0"
29
+ "@almadar/logger": "^2.3.0",
30
+ "@almadar/std": "^17.1.0"
31
31
  },
32
32
  "devDependencies": {
33
33
  "@types/node": "^20.0.0",