arcane-os 0.5.7 → 0.5.9

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 (46) hide show
  1. package/CHANGELOG.md +25 -0
  2. package/README.md +39 -27
  3. package/browser-runtime/ai/browser-speech-artifacts.mjs +23 -1683
  4. package/browser-runtime/ai/browser-speech-providers.mjs +353 -143
  5. package/browser-runtime/ai/browser-wasm-llm-provider.mjs +32 -324
  6. package/browser-runtime/ai/speech-worker-client.mjs +51 -14
  7. package/browser-runtime/ai/speech-worker-runtime.mjs +45 -1072
  8. package/browser-runtime/dependencies/strong-type/package.json +22 -23
  9. package/browser-runtime/event-manager.mjs +27 -41
  10. package/package.json +2 -3
  11. package/runtime/arcane/components/chat.html +1 -1
  12. package/runtime/arcane/components/speech.html +8 -38
  13. package/runtime/arcane/components/voice-transcription.html +1 -1
  14. package/runtime/arcane/css/theme.css +1 -1
  15. package/runtime/arcane/entities/Chat.js +12 -7
  16. package/runtime/arcane/modules/AI.js +569 -402
  17. package/runtime/arcane/modules/AIPreferenceTuple.js +1 -1
  18. package/runtime/arcane/modules/AIProviderRuntime.js +129 -68
  19. package/runtime/arcane/modules/AIRuntimeState.js +2 -18
  20. package/runtime/arcane/modules/BrowserTestSuite.js +2 -5
  21. package/runtime/arcane/modules/CalculatorEngine.js +0 -4
  22. package/runtime/arcane/modules/ChatRecords.js +169 -1
  23. package/runtime/arcane/modules/CommunicationHub.js +0 -19
  24. package/runtime/arcane/modules/ConfiguredAIChatSession.js +28 -25
  25. package/runtime/arcane/modules/DBOPFSDocumentLibrary.js +4 -5
  26. package/runtime/arcane/modules/DocumentLexicalSearch.js +1 -1
  27. package/runtime/arcane/modules/Errors.js +6 -19
  28. package/runtime/arcane/modules/Mail.js +1 -2
  29. package/runtime/arcane/modules/MailTransport.mjs +1 -3
  30. package/runtime/arcane/modules/OllamaModelIdentifier.js +1 -1
  31. package/runtime/arcane/modules/PersistentAIChatSession.js +5 -5
  32. package/runtime/arcane/modules/ScreenCapture.js +2 -4
  33. package/runtime/arcane/modules/SpeechPlayback.js +0 -27
  34. package/runtime/arcane/modules/WaitForComponent.js +0 -1
  35. package/src/app-descriptor.mjs +1 -1
  36. package/src/doctor.mjs +1 -3
  37. package/src/event-manager.mjs +27 -41
  38. package/src/import-map.mjs +1 -1
  39. package/src/index.mjs +2 -9
  40. package/src/installed-sdk-runtime.mjs +1 -11
  41. package/src/mail-api.mjs +0 -1
  42. package/src/native-provider-loader.mjs +0 -9
  43. package/src/scaffold.mjs +9 -21
  44. package/src/toolchain.mjs +5 -28
  45. package/src/workspace-runtime.mjs +0 -4
  46. package/src/workspace.mjs +2 -23
@@ -6,7 +6,6 @@ const SPEECH_WORKER_ERROR_PROTOCOL = "arcane-ai-speech-worker-error/1";
6
6
 
7
7
  const ARTIFACT_GRAPH_MODULE_GRAPH =
8
8
  "browser-speech-authenticated-artifact-graph";
9
- const GRAPH_GUARD_NAME = "__arcaneBrowserSpeechArtifactGraphGuardsV1";
10
9
  const MODULE_ROUTER_NAME = "__arcaneBrowserSpeechModuleRouterV1";
11
10
  const NESTED_WORKER_PROTOCOL =
12
11
  "arcane-ai-browser-speech-artifact-module-worker/1";
@@ -18,10 +17,6 @@ const ONNX_NAMESPACES = completeValue({
18
17
  stt: "transformers-env-backends-onnx-wasm",
19
18
  tts: "kokoro-env-wasm-paths",
20
19
  });
21
- const ARTIFACT_GRAPH_TRANSFORM_KINDS = new Set([
22
- "function-return-this-to-global-this",
23
- "typed-array-constructor",
24
- ]);
25
20
  const PUBLIC_WORKER_OPERATIONS = completeValue([
26
21
  "load",
27
22
  "use",
@@ -40,14 +35,12 @@ const STATUS_OPERATION = completeValue(["status"]);
40
35
  const UNLOAD_OPERATION = completeValue(["unload"]);
41
36
  const DISPOSE_OPERATION = completeValue(["dispose"]);
42
37
  const UNLOAD_OR_DISPOSE_OPERATIONS = completeValue(["unload", "dispose"]);
43
- const LOAD_OR_USE_OPERATIONS = completeValue(["load", "use"]);
44
38
  const SDK_WORKER_ERRORS = new WeakSet();
45
39
  const WORKER_ERROR_MESSAGES = completeValue({
46
40
  ARCANE_AI_REQUEST_ABORTED: "The speech worker operation was cancelled.",
47
41
  ARCANE_AI_NOT_READY: "The speech worker is not loaded.",
48
42
  ARCANE_AI_INVALID_REQUEST: "The speech worker request was rejected.",
49
43
  ARCANE_AI_INVALID_PROVIDER_RESULT: "The speech engine result was rejected.",
50
- ARCANE_AI_UNDECLARED_ARTIFACT: "The speech engine requested an undeclared artifact.",
51
44
  ARCANE_AI_PROVIDER_UNAVAILABLE: "The selected speech engine is unavailable.",
52
45
  ARCANE_AI_PROVIDER_DISPOSED: "The speech worker is disposed.",
53
46
  ARCANE_AI_PROVIDER_REQUEST_FAILED: "The speech engine operation was rejected.",
@@ -55,16 +48,6 @@ const WORKER_ERROR_MESSAGES = completeValue({
55
48
  ARCANE_AI_WORKER_MESSAGE_ERROR: "The speech Worker message was rejected.",
56
49
  ARCANE_AI_ARTIFACT_GRAPH_CONFIGURATION_INVALID:
57
50
  "The authenticated artifact graph Worker configuration was rejected.",
58
- ARCANE_AI_ARTIFACT_GRAPH_FETCH_EDGE_UNDECLARED:
59
- "The runtime used an undeclared artifact graph fetch edge.",
60
- ARCANE_AI_ARTIFACT_GRAPH_IMPORT_EDGE_UNDECLARED:
61
- "The runtime used an undeclared artifact graph import edge.",
62
- ARCANE_AI_ARTIFACT_GRAPH_CACHE_EDGE_UNDECLARED:
63
- "The runtime used an undeclared artifact graph cache edge.",
64
- ARCANE_AI_ARTIFACT_GRAPH_WORKER_EDGE_UNDECLARED:
65
- "The runtime used an undeclared artifact graph module Worker edge.",
66
- ARCANE_AI_ARTIFACT_GRAPH_ISOLATION_UNAVAILABLE:
67
- "The Worker cannot install the authenticated artifact graph isolation boundary.",
68
51
  });
69
52
  const WORKER_ERROR_REASON_ADMISSIONS = new Map();
70
53
 
@@ -160,6 +143,7 @@ registerWorkerErrorReasons("ARCANE_AI_INVALID_REQUEST", BOTH_WORKER_ROLES, LOAD_
160
143
  "speech-runtime-entrypoint-not-materialized",
161
144
  "speech-worker-configuration-missing",
162
145
  "speech-worker-materialized-files-missing",
146
+ "speech-worker-execution-configuration-mismatch",
163
147
  "speech-worker-model-dtype-empty",
164
148
  "speech-worker-model-id-empty",
165
149
  "speech-worker-model-repository-empty",
@@ -188,19 +172,6 @@ registerWorkerErrorReasons("ARCANE_AI_INVALID_PROVIDER_RESULT", ["tts"], USE_OPE
188
172
  "tts-synthesis-pcm-sample-non-finite",
189
173
  "tts-synthesis-result-sample-rate-mismatch",
190
174
  ]);
191
- registerWorkerErrorReasons(
192
- "ARCANE_AI_UNDECLARED_ARTIFACT",
193
- BOTH_WORKER_ROLES,
194
- LOAD_OR_USE_OPERATIONS,
195
- [
196
- "artifact-graph-cache-write-rejected",
197
- "artifact-graph-runtime-request-url-malformed",
198
- "speech-worker-artifact-request-method-rejected",
199
- "speech-worker-artifact-request-undeclared",
200
- "speech-worker-cache-match-rejected",
201
- "speech-worker-cache-open-rejected",
202
- ],
203
- );
204
175
  registerWorkerErrorReasons("ARCANE_AI_PROVIDER_DISPOSED", ["stt"], LOAD_OPERATION, [
205
176
  "stt-load-rejected-after-dispose",
206
177
  ]);
@@ -214,19 +185,9 @@ registerWorkerErrorReasons("ARCANE_AI_NOT_READY", ["tts"], USE_OPERATION, [
214
185
  "tts-synthesis-rejected-before-load",
215
186
  ]);
216
187
  registerWorkerErrorReasons("ARCANE_AI_PROVIDER_UNAVAILABLE", BOTH_WORKER_ROLES, LOAD_OPERATION, [
217
- "artifact-graph-fetch-constructor-unavailable",
218
188
  "artifact-graph-onnx-wasm-pair-not-materialized",
219
189
  "speech-worker-fetch-unavailable",
220
190
  ]);
221
- registerWorkerErrorReasons(
222
- "ARCANE_AI_PROVIDER_UNAVAILABLE",
223
- BOTH_WORKER_ROLES,
224
- LOAD_OR_USE_OPERATIONS,
225
- [
226
- "artifact-graph-module-worker-constructor-unavailable",
227
- "artifact-graph-negative-response-constructor-unavailable",
228
- ],
229
- );
230
191
  registerWorkerErrorReasons("ARCANE_AI_PROVIDER_UNAVAILABLE", ["tts"], LOAD_OPERATION, [
231
192
  "kokoro-env-wasm-paths-assignment-rejected",
232
193
  "kokoro-env-wasm-paths-unavailable",
@@ -265,23 +226,9 @@ registerWorkerErrorReasons(
265
226
  [
266
227
  "artifact-graph-kokoro-voice-inventory-missing",
267
228
  "artifact-graph-module-worker-target-not-materialized",
268
- "artifact-graph-negative-request-routes-not-array",
269
229
  "artifact-graph-onnx-wasm-configuration-mismatch",
270
- "artifact-graph-runtime-request-route-ambiguous",
271
- "artifact-graph-transform-identity-ambiguous",
272
- "artifact-graph-transform-kind-not-admitted",
273
- "artifact-graph-transform-module-path-empty",
274
- "artifact-graph-transform-occurrence-not-positive-safe-integer",
275
- "artifact-graph-transformers-cache-edge-ambiguous",
276
- "artifact-graph-worker-configuration-incomplete",
277
230
  ],
278
231
  );
279
- registerWorkerErrorReasons(
280
- "ARCANE_AI_ARTIFACT_GRAPH_CONFIGURATION_INVALID",
281
- BOTH_WORKER_ROLES,
282
- LOAD_OR_USE_OPERATIONS,
283
- ["artifact-graph-typed-array-constructor-transform-undeclared"],
284
- );
285
232
  registerWorkerErrorReasons(
286
233
  "ARCANE_AI_ARTIFACT_GRAPH_CONFIGURATION_INVALID",
287
234
  ["tts"],
@@ -298,138 +245,6 @@ registerWorkerErrorReasons(
298
245
  "transformers-env-num-threads-not-positive-safe-integer",
299
246
  ],
300
247
  );
301
- for (const label of ["cache-open", "dynamic-import", "fetch", "module-worker"]) {
302
- registerWorkerErrorReasons(
303
- "ARCANE_AI_ARTIFACT_GRAPH_CONFIGURATION_INVALID",
304
- BOTH_WORKER_ROLES,
305
- LOAD_OPERATION,
306
- [
307
- `artifact-graph-${label}-edges-not-array`,
308
- `artifact-graph-${label}-edge-not-object`,
309
- `artifact-graph-${label}-edge-module-path-empty`,
310
- `artifact-graph-${label}-edge-occurrence-not-positive-safe-integer`,
311
- `artifact-graph-${label}-edge-policy-not-admitted`,
312
- `artifact-graph-${label}-edge-identity-ambiguous`,
313
- ],
314
- );
315
- }
316
- registerWorkerErrorReasons(
317
- "ARCANE_AI_ARTIFACT_GRAPH_IMPORT_EDGE_UNDECLARED",
318
- BOTH_WORKER_ROLES,
319
- LOAD_OR_USE_OPERATIONS,
320
- [
321
- "artifact-graph-dynamic-import-edge-undeclared",
322
- "artifact-graph-dynamic-import-edge-undeclared-inactive-runtime-branch-entered",
323
- "artifact-graph-dynamic-import-target-undeclared",
324
- ],
325
- );
326
- registerWorkerErrorReasons(
327
- "ARCANE_AI_ARTIFACT_GRAPH_FETCH_EDGE_UNDECLARED",
328
- BOTH_WORKER_ROLES,
329
- LOAD_OR_USE_OPERATIONS,
330
- [
331
- "artifact-graph-fetch-edge-undeclared",
332
- "artifact-graph-fetch-edge-undeclared-inactive-runtime-branch-entered",
333
- "artifact-graph-fetch-guard-bypassed",
334
- "artifact-graph-fetch-method-undeclared",
335
- "artifact-graph-fetch-target-undeclared",
336
- ],
337
- );
338
- registerWorkerErrorReasons(
339
- "ARCANE_AI_ARTIFACT_GRAPH_CACHE_EDGE_UNDECLARED",
340
- BOTH_WORKER_ROLES,
341
- LOAD_OR_USE_OPERATIONS,
342
- [
343
- "artifact-graph-cache-match-guard-bypassed",
344
- "artifact-graph-cache-name-mismatch",
345
- "artifact-graph-cache-open-edge-undeclared",
346
- "artifact-graph-cache-open-edge-undeclared-inactive-runtime-branch-entered",
347
- "artifact-graph-cache-open-guard-bypassed",
348
- "artifact-graph-cache-read-target-undeclared",
349
- ],
350
- );
351
- registerWorkerErrorReasons(
352
- "ARCANE_AI_ARTIFACT_GRAPH_WORKER_EDGE_UNDECLARED",
353
- BOTH_WORKER_ROLES,
354
- LOAD_OR_USE_OPERATIONS,
355
- [
356
- "artifact-graph-module-worker-edge-undeclared",
357
- "artifact-graph-module-worker-edge-undeclared-inactive-runtime-branch-entered",
358
- "artifact-graph-module-worker-target-undeclared",
359
- "artifact-graph-module-worker-type-mismatch",
360
- ],
361
- );
362
- registerWorkerErrorReasons(
363
- "ARCANE_AI_ARTIFACT_GRAPH_ISOLATION_UNAVAILABLE",
364
- BOTH_WORKER_ROLES,
365
- LOAD_OPERATION,
366
- [
367
- "artifact-graph-cache-isolation-unavailable",
368
- "artifact-graph-dynamic-code-constructor-isolation-unavailable",
369
- "artifact-graph-fetch-isolation-unavailable",
370
- "artifact-graph-guard-global-collision",
371
- "artifact-graph-guard-global-definition-rejected",
372
- "artifact-graph-indexeddb-isolation-unavailable",
373
- "artifact-graph-opfs-isolation-unavailable",
374
- "artifact-graph-private-message-port-missing",
375
- "artifact-graph-setinterval-isolation-unavailable",
376
- "artifact-graph-settimeout-isolation-unavailable",
377
- "artifact-graph-typed-array-validation-unavailable",
378
- "speech-worker-cache-isolation-unavailable",
379
- "speech-worker-fetch-isolation-unavailable",
380
- ],
381
- );
382
- registerWorkerErrorReasons(
383
- "ARCANE_AI_ARTIFACT_GRAPH_ISOLATION_UNAVAILABLE",
384
- BOTH_WORKER_ROLES,
385
- LOAD_OR_USE_OPERATIONS,
386
- [
387
- "artifact-graph-dynamic-code-constructor-rejected",
388
- "artifact-graph-guard-capability-mismatch",
389
- "artifact-graph-setinterval-string-callback-rejected",
390
- "artifact-graph-settimeout-string-callback-rejected",
391
- "artifact-graph-typed-array-constructor-intrinsic-mismatch",
392
- "artifact-graph-typed-array-constructor-receiver-not-typed-array",
393
- ],
394
- );
395
- for (const name of [
396
- "broadcastchannel",
397
- "eventsource",
398
- "function",
399
- "rtcpeerconnection",
400
- "shadowrealm",
401
- "sharedworker",
402
- "websocket",
403
- "websocketstream",
404
- "webtransport",
405
- "worker",
406
- "xmlhttprequest",
407
- "eval",
408
- "importscripts",
409
- ]) {
410
- registerWorkerErrorReasons(
411
- "ARCANE_AI_ARTIFACT_GRAPH_ISOLATION_UNAVAILABLE",
412
- BOTH_WORKER_ROLES,
413
- LOAD_OR_USE_OPERATIONS,
414
- [`artifact-graph-${name}-capability-undeclared`],
415
- );
416
- registerWorkerErrorReasons(
417
- "ARCANE_AI_ARTIFACT_GRAPH_ISOLATION_UNAVAILABLE",
418
- BOTH_WORKER_ROLES,
419
- LOAD_OPERATION,
420
- [`artifact-graph-${name}-isolation-unavailable`],
421
- );
422
- }
423
- registerWorkerErrorReasons(
424
- "ARCANE_AI_WORKER_MESSAGE_ERROR",
425
- BOTH_WORKER_ROLES,
426
- LOAD_OR_USE_OPERATIONS,
427
- [
428
- "artifact-graph-module-worker-error-envelope-rejected",
429
- "artifact-graph-module-worker-initialization-message-rejected",
430
- ],
431
- );
432
-
433
248
  function operationFailureReason(role, op) {
434
249
  if (op === "load") return `${role}-worker-model-load-rejected`;
435
250
  if (op === "use") {
@@ -890,6 +705,49 @@ function validateConfiguration(configuration, role) {
890
705
  requiredText(configuration.model?.repository, "Speech model repository", "speech-worker-model-repository-empty");
891
706
  requiredText(configuration.model?.revision, "Speech model revision", "speech-worker-model-revision-empty");
892
707
  requiredText(configuration.runtime?.entry, "Speech runtime entry", "speech-worker-runtime-entry-empty");
708
+ const execution = configuration.execution;
709
+ if (execution !== undefined) {
710
+ if (!execution || typeof execution !== "object" || Array.isArray(execution)) {
711
+ throw workerError(
712
+ "ARCANE_AI_INVALID_REQUEST",
713
+ "Speech worker execution must be a plain data record.",
714
+ undefined,
715
+ "speech-worker-execution-configuration-mismatch",
716
+ );
717
+ }
718
+ const prototype = Object.getPrototypeOf(execution);
719
+ if (prototype !== Object.prototype && prototype !== null) {
720
+ throw workerError(
721
+ "ARCANE_AI_INVALID_REQUEST",
722
+ "Speech worker execution must be a plain data record.",
723
+ undefined,
724
+ "speech-worker-execution-configuration-mismatch",
725
+ );
726
+ }
727
+ const descriptors = Object.getOwnPropertyDescriptors(execution);
728
+ let descriptorMismatch = false;
729
+ for (const key of Reflect.ownKeys(descriptors)) {
730
+ if (key !== "device" || !Object.hasOwn(descriptors[key], "value")) {
731
+ descriptorMismatch = true;
732
+ break;
733
+ }
734
+ }
735
+ if (
736
+ descriptorMismatch
737
+ || !Object.hasOwn(descriptors, "device")
738
+ || (role === "stt" && descriptors.device.value !== "wasm")
739
+ || (role === "tts"
740
+ && descriptors.device.value !== "wasm"
741
+ && descriptors.device.value !== "webgpu")
742
+ ) {
743
+ throw workerError(
744
+ "ARCANE_AI_INVALID_REQUEST",
745
+ "Speech worker execution device does not match the selected role.",
746
+ undefined,
747
+ "speech-worker-execution-configuration-mismatch",
748
+ );
749
+ }
750
+ }
893
751
  if (!Array.isArray(configuration.runtime?.files) || !Array.isArray(configuration.model?.files)) {
894
752
  throw workerError(
895
753
  "ARCANE_AI_INVALID_REQUEST",
@@ -981,496 +839,6 @@ function validateConfiguration(configuration, role) {
981
839
  return configuration;
982
840
  }
983
841
 
984
- function absoluteRequestUrl(value, scope) {
985
- const input = typeof value === "string" || value instanceof URL
986
- ? String(value)
987
- : value?.url;
988
- try {
989
- return new URL(input, scope.location?.href).href;
990
- } catch {
991
- throw workerError(
992
- "ARCANE_AI_UNDECLARED_ARTIFACT",
993
- "The speech engine requested a malformed artifact URL.",
994
- undefined,
995
- "artifact-graph-runtime-request-url-malformed",
996
- );
997
- }
998
- }
999
-
1000
- // Dormant hardening retained for future review only. The closed route reader,
1001
- // cache admission, and legacy fetch isolation below are not used by ordinary
1002
- // execution and must not be enabled without explicit user review.
1003
- function createArtifactRoutes(scope, configuration) {
1004
- const positive = new Map();
1005
- const negative = new Set();
1006
- const files = [
1007
- ...configuration.runtime.files,
1008
- ...configuration.model.files,
1009
- ];
1010
-
1011
- function addPositive(route, file) {
1012
- const absolute = absoluteRequestUrl(route, scope);
1013
- const existing = positive.get(absolute);
1014
- if (existing && existing.path !== file.path) {
1015
- throw workerError(
1016
- "ARCANE_AI_ARTIFACT_GRAPH_CONFIGURATION_INVALID",
1017
- "An artifact graph runtime request route names more than one file.",
1018
- undefined,
1019
- "artifact-graph-runtime-request-route-ambiguous",
1020
- );
1021
- }
1022
- positive.set(absolute, file);
1023
- }
1024
-
1025
- for (const file of files) {
1026
- addPositive(file.sourceUrl, file);
1027
- addPositive(file.moduleUrl, file);
1028
- for (const route of file.runtimeRequestUrls ?? []) addPositive(route, file);
1029
- }
1030
- for (const route of configuration.runtime.negativeRuntimeRequestUrls ?? []) {
1031
- const absolute = absoluteRequestUrl(route, scope);
1032
- if (positive.has(absolute) || negative.has(absolute)) {
1033
- throw workerError(
1034
- "ARCANE_AI_ARTIFACT_GRAPH_CONFIGURATION_INVALID",
1035
- "Artifact graph positive and negative runtime request routes overlap.",
1036
- undefined,
1037
- "artifact-graph-runtime-request-route-ambiguous",
1038
- );
1039
- }
1040
- negative.add(absolute);
1041
- }
1042
- return completeValue({ files, positive, negative });
1043
- }
1044
-
1045
- function requestMethod(input, init, scope) {
1046
- const RequestConstructor = scope.Request ?? globalThis.Request;
1047
- const inherited = typeof RequestConstructor === "function" && input instanceof RequestConstructor
1048
- ? input.method
1049
- : "GET";
1050
- return String(init?.method ?? inherited ?? "GET").toUpperCase();
1051
- }
1052
-
1053
- function installScopeValue(scope, name, value, reason) {
1054
- const descriptor = Object.getOwnPropertyDescriptor(scope, name);
1055
- if (descriptor?.configurable === false && descriptor.writable !== true) {
1056
- throw workerError(
1057
- "ARCANE_AI_ARTIFACT_GRAPH_ISOLATION_UNAVAILABLE",
1058
- `The speech Worker cannot isolate globalThis.${name}.`,
1059
- undefined,
1060
- reason,
1061
- );
1062
- }
1063
- try {
1064
- if (descriptor?.configurable === false) {
1065
- scope[name] = value;
1066
- } else {
1067
- Object.defineProperty(scope, name, {
1068
- configurable: true,
1069
- enumerable: descriptor?.enumerable ?? true,
1070
- writable: false,
1071
- value,
1072
- });
1073
- }
1074
- } catch (error) {
1075
- throw workerError(
1076
- "ARCANE_AI_ARTIFACT_GRAPH_ISOLATION_UNAVAILABLE",
1077
- `The speech Worker could not isolate globalThis.${name}.`,
1078
- error,
1079
- reason,
1080
- );
1081
- }
1082
- return function restoreScopeValue() {
1083
- if (descriptor) Object.defineProperty(scope, name, descriptor);
1084
- else delete scope[name];
1085
- };
1086
- }
1087
-
1088
- function restoreScopeValues(restores) {
1089
- for (const restore of restores.splice(0).reverse()) {
1090
- try {
1091
- restore();
1092
- } catch {
1093
- // Terminating the owning Worker remains the final isolation boundary.
1094
- }
1095
- }
1096
- }
1097
-
1098
- function installObjectValue(object, name, value, label, reason) {
1099
- const descriptor = Object.getOwnPropertyDescriptor(object, name);
1100
- if (descriptor?.configurable === false && descriptor.writable !== true) {
1101
- throw workerError(
1102
- "ARCANE_AI_ARTIFACT_GRAPH_ISOLATION_UNAVAILABLE",
1103
- `The speech Worker cannot isolate ${label}.`,
1104
- undefined,
1105
- reason,
1106
- );
1107
- }
1108
- try {
1109
- Object.defineProperty(object, name, {
1110
- configurable: true,
1111
- enumerable: descriptor?.enumerable ?? true,
1112
- writable: false,
1113
- value,
1114
- });
1115
- } catch (error) {
1116
- throw workerError(
1117
- "ARCANE_AI_ARTIFACT_GRAPH_ISOLATION_UNAVAILABLE",
1118
- `The speech Worker could not isolate ${label}.`,
1119
- error,
1120
- reason,
1121
- );
1122
- }
1123
- return function restoreObjectValue() {
1124
- if (descriptor) Object.defineProperty(object, name, descriptor);
1125
- else delete object[name];
1126
- };
1127
- }
1128
-
1129
- function createRouteReader(scope, configuration, originalFetch) {
1130
- const routes = createArtifactRoutes(scope, configuration);
1131
- const ResponseConstructor = scope.Response ?? globalThis.Response;
1132
-
1133
- async function responseFor(resolution, signal) {
1134
- if (resolution.kind === "negative") {
1135
- if (typeof ResponseConstructor !== "function") {
1136
- throw workerError(
1137
- "ARCANE_AI_PROVIDER_UNAVAILABLE",
1138
- "Browser Response is unavailable in the speech Worker.",
1139
- undefined,
1140
- "artifact-graph-negative-response-constructor-unavailable",
1141
- );
1142
- }
1143
- return new ResponseConstructor(null, {
1144
- status: 404,
1145
- statusText: "Not Found",
1146
- headers: { "cache-control": "no-store" },
1147
- });
1148
- }
1149
- return originalFetch(resolution.file.moduleUrl, {
1150
- method: "GET",
1151
- credentials: "omit",
1152
- redirect: "error",
1153
- signal,
1154
- });
1155
- }
1156
-
1157
- function resolve(input) {
1158
- const absolute = absoluteRequestUrl(input, scope);
1159
- const file = routes.positive.get(absolute);
1160
- if (file) return completeValue({ kind: "file", absolute, file });
1161
- if (routes.negative.has(absolute)) {
1162
- return completeValue({ kind: "negative", absolute, file: null });
1163
- }
1164
- return null;
1165
- }
1166
-
1167
- function cacheForPaths(targetPaths) {
1168
- const admittedPaths = new Set(targetPaths);
1169
- return completeValue({
1170
- async match(input) {
1171
- const resolution = resolve(input);
1172
- if (
1173
- !resolution
1174
- || resolution.kind !== "file"
1175
- || !admittedPaths.has(resolution.file.path)
1176
- ) {
1177
- throw workerError(
1178
- "ARCANE_AI_ARTIFACT_GRAPH_CACHE_EDGE_UNDECLARED",
1179
- "The runtime cache read target is outside its admitted artifact graph edge.",
1180
- undefined,
1181
- "artifact-graph-cache-read-target-undeclared",
1182
- );
1183
- }
1184
- return responseFor(resolution);
1185
- },
1186
- async put() {
1187
- throw workerError(
1188
- "ARCANE_AI_UNDECLARED_ARTIFACT",
1189
- "Speech runtime cache writes are disabled; DBOPFS is the sole durable artifact store.",
1190
- undefined,
1191
- "artifact-graph-cache-write-rejected",
1192
- );
1193
- },
1194
- async add() {
1195
- throw workerError(
1196
- "ARCANE_AI_UNDECLARED_ARTIFACT",
1197
- "Speech runtime cache writes are disabled; DBOPFS is the sole durable artifact store.",
1198
- undefined,
1199
- "artifact-graph-cache-write-rejected",
1200
- );
1201
- },
1202
- async addAll() {
1203
- throw workerError(
1204
- "ARCANE_AI_UNDECLARED_ARTIFACT",
1205
- "Speech runtime cache writes are disabled; DBOPFS is the sole durable artifact store.",
1206
- undefined,
1207
- "artifact-graph-cache-write-rejected",
1208
- );
1209
- },
1210
- async delete() {
1211
- return false;
1212
- },
1213
- async keys() {
1214
- return completeValue([]);
1215
- },
1216
- });
1217
- }
1218
-
1219
- const cache = cacheForPaths(routes.files.map((file) => file.path));
1220
- return completeValue({ cache, cacheForPaths, resolve, responseFor, routes });
1221
- }
1222
-
1223
- function installLegacyAuthorizedFetch(scope, configuration) {
1224
- const original = scope.fetch?.bind(scope);
1225
- if (typeof original !== "function") {
1226
- throw workerError(
1227
- "ARCANE_AI_PROVIDER_UNAVAILABLE",
1228
- "Browser fetch is unavailable in the speech Worker.",
1229
- undefined,
1230
- "speech-worker-fetch-unavailable",
1231
- );
1232
- }
1233
- const reader = createRouteReader(scope, configuration, original);
1234
- const authorized = async function fetchAuthorizedSpeechArtifact(input, init) {
1235
- if (requestMethod(input, init, scope) !== "GET") {
1236
- throw workerError(
1237
- "ARCANE_AI_UNDECLARED_ARTIFACT",
1238
- "Legacy speech artifacts admit only GET requests.",
1239
- undefined,
1240
- "speech-worker-artifact-request-method-rejected",
1241
- );
1242
- }
1243
- const resolution = reader.resolve(input);
1244
- if (!resolution) {
1245
- throw workerError(
1246
- "ARCANE_AI_UNDECLARED_ARTIFACT",
1247
- "The speech engine requested an artifact outside its admitted file map.",
1248
- undefined,
1249
- "speech-worker-artifact-request-undeclared",
1250
- );
1251
- }
1252
- return reader.responseFor(resolution, init?.signal);
1253
- };
1254
- const restore = installScopeValue(
1255
- scope,
1256
- "fetch",
1257
- authorized,
1258
- "speech-worker-fetch-isolation-unavailable",
1259
- );
1260
- return completeValue({ cache: null, cleanup: restore });
1261
- }
1262
-
1263
- function installDeniedCacheIsolation(scope) {
1264
- const denied = completeValue({
1265
- async open() {
1266
- throw workerError(
1267
- "ARCANE_AI_UNDECLARED_ARTIFACT",
1268
- "Speech runtime cache access is disabled; DBOPFS admission is the sole artifact source.",
1269
- undefined,
1270
- "speech-worker-cache-open-rejected",
1271
- );
1272
- },
1273
- async match() {
1274
- throw workerError(
1275
- "ARCANE_AI_UNDECLARED_ARTIFACT",
1276
- "Speech runtime cache access is disabled; DBOPFS admission is the sole artifact source.",
1277
- undefined,
1278
- "speech-worker-cache-match-rejected",
1279
- );
1280
- },
1281
- async has() {
1282
- return false;
1283
- },
1284
- async keys() {
1285
- return completeValue([]);
1286
- },
1287
- async delete() {
1288
- return false;
1289
- },
1290
- });
1291
- return installScopeValue(
1292
- scope,
1293
- "caches",
1294
- denied,
1295
- "speech-worker-cache-isolation-unavailable",
1296
- );
1297
- }
1298
-
1299
- function edgeKey(modulePath, occurrence) {
1300
- return `${modulePath}\u0000${String(occurrence)}`;
1301
- }
1302
-
1303
- function edgeMap(edges, label) {
1304
- if (!Array.isArray(edges)) {
1305
- throw workerError(
1306
- "ARCANE_AI_ARTIFACT_GRAPH_CONFIGURATION_INVALID",
1307
- `Artifact graph ${label} edges must be an array.`,
1308
- undefined,
1309
- `artifact-graph-${label}-edges-not-array`,
1310
- );
1311
- }
1312
- const map = new Map();
1313
- for (const edge of edges) {
1314
- if (!edge || typeof edge !== "object" || Array.isArray(edge)) {
1315
- throw workerError(
1316
- "ARCANE_AI_ARTIFACT_GRAPH_CONFIGURATION_INVALID",
1317
- `Artifact graph ${label} edge must be an object.`,
1318
- undefined,
1319
- `artifact-graph-${label}-edge-not-object`,
1320
- );
1321
- }
1322
- if (typeof edge.modulePath !== "string" || !edge.modulePath) {
1323
- throw workerError(
1324
- "ARCANE_AI_ARTIFACT_GRAPH_CONFIGURATION_INVALID",
1325
- `Artifact graph ${label} edge modulePath must be nonempty.`,
1326
- undefined,
1327
- `artifact-graph-${label}-edge-module-path-empty`,
1328
- );
1329
- }
1330
- if (!Number.isSafeInteger(edge.occurrence) || edge.occurrence < 1) {
1331
- throw workerError(
1332
- "ARCANE_AI_ARTIFACT_GRAPH_CONFIGURATION_INVALID",
1333
- `Artifact graph ${label} edge occurrence must be a positive safe integer.`,
1334
- undefined,
1335
- `artifact-graph-${label}-edge-occurrence-not-positive-safe-integer`,
1336
- );
1337
- }
1338
- if (edge.edgePolicy !== "artifact-targets-admitted"
1339
- && edge.edgePolicy !== "inactive-runtime-branch-rejected") {
1340
- throw workerError(
1341
- "ARCANE_AI_ARTIFACT_GRAPH_CONFIGURATION_INVALID",
1342
- `Artifact graph ${label} edge policy is not admitted.`,
1343
- undefined,
1344
- `artifact-graph-${label}-edge-policy-not-admitted`,
1345
- );
1346
- }
1347
- const key = edgeKey(edge.modulePath, edge.occurrence);
1348
- if (map.has(key)) {
1349
- throw workerError(
1350
- "ARCANE_AI_ARTIFACT_GRAPH_CONFIGURATION_INVALID",
1351
- `Artifact graph ${label} edge identity is ambiguous.`,
1352
- undefined,
1353
- `artifact-graph-${label}-edge-identity-ambiguous`,
1354
- );
1355
- }
1356
- map.set(key, edge);
1357
- }
1358
- return map;
1359
- }
1360
-
1361
- function transformSet(transforms, kind) {
1362
- const result = new Set();
1363
- for (const transform of transforms) {
1364
- if (!ARTIFACT_GRAPH_TRANSFORM_KINDS.has(transform?.kind)) {
1365
- throw workerError(
1366
- "ARCANE_AI_ARTIFACT_GRAPH_CONFIGURATION_INVALID",
1367
- "Artifact graph Worker configuration contains a transform kind that is not admitted.",
1368
- undefined,
1369
- "artifact-graph-transform-kind-not-admitted",
1370
- );
1371
- }
1372
- if (transform?.kind !== kind) continue;
1373
- if (typeof transform.modulePath !== "string" || !transform.modulePath) {
1374
- throw workerError(
1375
- "ARCANE_AI_ARTIFACT_GRAPH_CONFIGURATION_INVALID",
1376
- `Artifact graph ${kind} transform modulePath must be nonempty.`,
1377
- undefined,
1378
- "artifact-graph-transform-module-path-empty",
1379
- );
1380
- }
1381
- if (!Number.isSafeInteger(transform.occurrence) || transform.occurrence < 1) {
1382
- throw workerError(
1383
- "ARCANE_AI_ARTIFACT_GRAPH_CONFIGURATION_INVALID",
1384
- `Artifact graph ${kind} transform occurrence must be a positive safe integer.`,
1385
- undefined,
1386
- "artifact-graph-transform-occurrence-not-positive-safe-integer",
1387
- );
1388
- }
1389
- const key = edgeKey(transform.modulePath, transform.occurrence);
1390
- if (result.has(key)) {
1391
- throw workerError(
1392
- "ARCANE_AI_ARTIFACT_GRAPH_CONFIGURATION_INVALID",
1393
- `Artifact graph ${kind} transform identity is ambiguous.`,
1394
- undefined,
1395
- "artifact-graph-transform-identity-ambiguous",
1396
- );
1397
- }
1398
- result.add(key);
1399
- }
1400
- return result;
1401
- }
1402
-
1403
- function typedArrayIntrinsics(scope) {
1404
- const constructors = new Map();
1405
- for (const name of [
1406
- "BigInt64Array",
1407
- "BigUint64Array",
1408
- "Float32Array",
1409
- "Float64Array",
1410
- "Int8Array",
1411
- "Int16Array",
1412
- "Int32Array",
1413
- "Uint8Array",
1414
- "Uint8ClampedArray",
1415
- "Uint16Array",
1416
- "Uint32Array",
1417
- ]) {
1418
- const Constructor = scope[name] ?? globalThis[name];
1419
- if (typeof Constructor === "function" && Constructor.prototype) {
1420
- constructors.set(Constructor.prototype, Constructor);
1421
- }
1422
- }
1423
- const ArrayBufferConstructor = scope.ArrayBuffer ?? globalThis.ArrayBuffer;
1424
- const DataViewConstructor = scope.DataView ?? globalThis.DataView;
1425
- if (typeof ArrayBufferConstructor?.isView !== "function") {
1426
- throw workerError(
1427
- "ARCANE_AI_ARTIFACT_GRAPH_ISOLATION_UNAVAILABLE",
1428
- "Authenticated artifact graph typed-array validation is unavailable.",
1429
- undefined,
1430
- "artifact-graph-typed-array-validation-unavailable",
1431
- );
1432
- }
1433
- return completeValue({
1434
- constructors,
1435
- dataViewPrototype: DataViewConstructor?.prototype ?? null,
1436
- getPrototypeOf: Object.getPrototypeOf,
1437
- hasOwn: Object.hasOwn,
1438
- isView: ArrayBufferConstructor.isView.bind(ArrayBufferConstructor),
1439
- });
1440
- }
1441
-
1442
- function runtimeFileMap(configuration) {
1443
- return new Map(configuration.runtime.files.map((file) => [file.path, file]));
1444
- }
1445
-
1446
- function targetRecords(edge) {
1447
- if (Array.isArray(edge.targets)) return edge.targets;
1448
- if (Array.isArray(edge.targetPaths)) {
1449
- return edge.targetPaths.map((targetPath) => ({ targetPath }));
1450
- }
1451
- return [];
1452
- }
1453
-
1454
- function targetForRequest(edge, requested, files, sourceFile) {
1455
- const value = String(requested);
1456
- for (const target of targetRecords(edge)) {
1457
- const file = files.get(target?.targetPath);
1458
- if (!file) continue;
1459
- if (target.match === "exact-runtime-specifier") {
1460
- if (value === target.exactSpecifier) return file;
1461
- continue;
1462
- }
1463
- if (target.match === "self-module-url") {
1464
- if (file.path === sourceFile?.path && value === sourceFile.moduleUrl) return file;
1465
- continue;
1466
- }
1467
- if (target.match === "materialized-module-url" && value === file.moduleUrl) {
1468
- return file;
1469
- }
1470
- }
1471
- return null;
1472
- }
1473
-
1474
842
  function nestedWorkerUrl(role) {
1475
843
  const url = new URL(
1476
844
  role === "stt"
@@ -1500,401 +868,6 @@ function nestedWorkerFailureEvent(scope, error) {
1500
868
  return event;
1501
869
  }
1502
870
 
1503
- // Dormant hardening retained for future review only. Ordinary speech execution
1504
- // never installs this guard, its declared-edge admission, or its isolation
1505
- // controls. Do not enable it for secure mode without explicit user review.
1506
- function createArtifactGraphGuard(scope, configuration, role, reader, originalWorker) {
1507
- const files = runtimeFileMap(configuration);
1508
- const edges = configuration.runtime.edges;
1509
- const imports = edgeMap(edges.dynamicImports ?? [], "dynamic-import");
1510
- const fetches = edgeMap(edges.fetches ?? [], "fetch");
1511
- const workers = edgeMap(edges.moduleWorkers ?? [], "module-worker");
1512
- const cacheOpens = edgeMap(edges.cacheOpens ?? [], "cache-open");
1513
- const typedArrayConstructors = transformSet(
1514
- configuration.runtime.transforms,
1515
- "typed-array-constructor",
1516
- );
1517
- transformSet(configuration.runtime.transforms, "function-return-this-to-global-this");
1518
- const typedArrays = typedArrayIntrinsics(scope);
1519
- const guardCapability = configuration.runtime.guardCapability;
1520
- const nestedWorkers = new Set();
1521
-
1522
- function assertGuardCapability(candidate) {
1523
- if (candidate === guardCapability) return;
1524
- throw workerError(
1525
- "ARCANE_AI_ARTIFACT_GRAPH_ISOLATION_UNAVAILABLE",
1526
- "Authenticated artifact graph runtime guard capability did not match.",
1527
- undefined,
1528
- "artifact-graph-guard-capability-mismatch",
1529
- );
1530
- }
1531
-
1532
- function declaredEdge(map, modulePath, occurrence, code, reason) {
1533
- const edge = map.get(edgeKey(modulePath, occurrence));
1534
- if (edge?.edgePolicy === "artifact-targets-admitted") return edge;
1535
- if (edge?.edgePolicy === "inactive-runtime-branch-rejected") {
1536
- throw workerError(
1537
- code,
1538
- "The runtime entered an artifact graph branch declared inactive.",
1539
- undefined,
1540
- `${reason}-inactive-runtime-branch-entered`,
1541
- );
1542
- }
1543
- throw workerError(
1544
- code,
1545
- "The runtime used an undeclared authenticated artifact graph edge.",
1546
- undefined,
1547
- reason,
1548
- );
1549
- }
1550
-
1551
- function fetchEdgeAllows(edge, resolution) {
1552
- if (resolution.kind === "negative") {
1553
- return (edge.negativeRuntimeRequestUrls ?? [])
1554
- .map((route) => absoluteRequestUrl(route, scope))
1555
- .includes(resolution.absolute);
1556
- }
1557
- const paths = new Set([
1558
- ...(edge.targetPaths ?? []),
1559
- ...targetRecords(edge).map((target) => target?.targetPath),
1560
- ]);
1561
- if (!paths.has(resolution.file.path)) return false;
1562
- if (resolution.absolute === absoluteRequestUrl(resolution.file.moduleUrl, scope)) {
1563
- return edge.allowMaterializedUrls === true;
1564
- }
1565
- return true;
1566
- }
1567
-
1568
- const guard = completeValue({
1569
- protocol: "arcane-ai-browser-speech-artifact-graph-runtime/1",
1570
-
1571
- async dynamicImport(capability, modulePath, occurrence, specifier) {
1572
- assertGuardCapability(capability);
1573
- const edge = declaredEdge(
1574
- imports,
1575
- modulePath,
1576
- occurrence,
1577
- "ARCANE_AI_ARTIFACT_GRAPH_IMPORT_EDGE_UNDECLARED",
1578
- "artifact-graph-dynamic-import-edge-undeclared",
1579
- );
1580
- const sourceFile = files.get(modulePath);
1581
- const target = targetForRequest(edge, specifier, files, sourceFile);
1582
- if (!target) {
1583
- throw workerError(
1584
- "ARCANE_AI_ARTIFACT_GRAPH_IMPORT_EDGE_UNDECLARED",
1585
- "The runtime dynamic import target is outside its admitted artifact graph edge.",
1586
- undefined,
1587
- "artifact-graph-dynamic-import-target-undeclared",
1588
- );
1589
- }
1590
- return import(target.moduleUrl);
1591
- },
1592
-
1593
- async fetch(capability, modulePath, occurrence, input, init) {
1594
- assertGuardCapability(capability);
1595
- const edge = declaredEdge(
1596
- fetches,
1597
- modulePath,
1598
- occurrence,
1599
- "ARCANE_AI_ARTIFACT_GRAPH_FETCH_EDGE_UNDECLARED",
1600
- "artifact-graph-fetch-edge-undeclared",
1601
- );
1602
- const method = requestMethod(input, init, scope);
1603
- if (!(edge.methods ?? ["GET"]).includes(method)) {
1604
- throw workerError(
1605
- "ARCANE_AI_ARTIFACT_GRAPH_FETCH_EDGE_UNDECLARED",
1606
- "The runtime fetch method is outside its admitted artifact graph edge.",
1607
- undefined,
1608
- "artifact-graph-fetch-method-undeclared",
1609
- );
1610
- }
1611
- const resolution = reader.resolve(input);
1612
- if (!resolution || !fetchEdgeAllows(edge, resolution)) {
1613
- throw workerError(
1614
- "ARCANE_AI_ARTIFACT_GRAPH_FETCH_EDGE_UNDECLARED",
1615
- "The runtime fetch target is outside its admitted artifact graph edge.",
1616
- undefined,
1617
- "artifact-graph-fetch-target-undeclared",
1618
- );
1619
- }
1620
- return reader.responseFor(resolution, init?.signal);
1621
- },
1622
-
1623
- async openCache(capability, modulePath, occurrence, cacheName) {
1624
- assertGuardCapability(capability);
1625
- const edge = declaredEdge(
1626
- cacheOpens,
1627
- modulePath,
1628
- occurrence,
1629
- "ARCANE_AI_ARTIFACT_GRAPH_CACHE_EDGE_UNDECLARED",
1630
- "artifact-graph-cache-open-edge-undeclared",
1631
- );
1632
- if (cacheName !== edge.cacheName) {
1633
- throw workerError(
1634
- "ARCANE_AI_ARTIFACT_GRAPH_CACHE_EDGE_UNDECLARED",
1635
- "The runtime cache name is outside its admitted artifact graph edge.",
1636
- undefined,
1637
- "artifact-graph-cache-name-mismatch",
1638
- );
1639
- }
1640
- return reader.cacheForPaths(edge.targetPaths);
1641
- },
1642
-
1643
- createWorker(capability, modulePath, occurrence, specifier, options = {}) {
1644
- assertGuardCapability(capability);
1645
- const edge = declaredEdge(
1646
- workers,
1647
- modulePath,
1648
- occurrence,
1649
- "ARCANE_AI_ARTIFACT_GRAPH_WORKER_EDGE_UNDECLARED",
1650
- "artifact-graph-module-worker-edge-undeclared",
1651
- );
1652
- const sourceFile = files.get(modulePath);
1653
- const target = targetForRequest(edge, specifier, files, sourceFile);
1654
- if (!target) {
1655
- throw workerError(
1656
- "ARCANE_AI_ARTIFACT_GRAPH_WORKER_EDGE_UNDECLARED",
1657
- "The runtime module Worker target is outside its admitted artifact graph edge.",
1658
- undefined,
1659
- "artifact-graph-module-worker-target-undeclared",
1660
- );
1661
- }
1662
- if (options?.type !== "module") {
1663
- throw workerError(
1664
- "ARCANE_AI_ARTIFACT_GRAPH_WORKER_EDGE_UNDECLARED",
1665
- "Authenticated artifact graph child Workers must be module Workers.",
1666
- undefined,
1667
- "artifact-graph-module-worker-type-mismatch",
1668
- );
1669
- }
1670
- if (typeof originalWorker !== "function") {
1671
- throw workerError(
1672
- "ARCANE_AI_PROVIDER_UNAVAILABLE",
1673
- "Nested browser module Workers are unavailable.",
1674
- undefined,
1675
- "artifact-graph-module-worker-constructor-unavailable",
1676
- );
1677
- }
1678
- const worker = new originalWorker(nestedWorkerUrl(role), {
1679
- type: "module",
1680
- name: typeof options.name === "string" ? options.name : "arcane-speech-artifact-module",
1681
- });
1682
- nestedWorkers.add(worker);
1683
- const onBootstrapMessage = (event) => {
1684
- if (event.data?.protocol !== NESTED_WORKER_PROTOCOL
1685
- || event.data?.event !== "artifact-module-worker-bootstrap-rejected") return;
1686
- event.stopImmediatePropagation?.();
1687
- const admitted = normalizeSpeechWorkerErrorEnvelope(event.data.error, role, "load");
1688
- const failure = admitted
1689
- ? workerError(admitted.code, admitted.message, admitted.cause, admitted.reason)
1690
- : workerError(
1691
- "ARCANE_AI_WORKER_MESSAGE_ERROR",
1692
- "The authenticated artifact module Worker error envelope was rejected.",
1693
- undefined,
1694
- "artifact-graph-module-worker-error-envelope-rejected",
1695
- );
1696
- worker.dispatchEvent?.(nestedWorkerFailureEvent(scope, failure));
1697
- };
1698
- worker.addEventListener?.("message", onBootstrapMessage);
1699
- try {
1700
- worker.postMessage({
1701
- protocol: NESTED_WORKER_PROTOCOL,
1702
- op: "initialize-authenticated-artifact-module-worker",
1703
- role,
1704
- targetPath: target.path,
1705
- configuration,
1706
- });
1707
- } catch (error) {
1708
- nestedWorkers.delete(worker);
1709
- worker.terminate();
1710
- throw workerError(
1711
- "ARCANE_AI_WORKER_MESSAGE_ERROR",
1712
- "The authenticated artifact module Worker initialization message was rejected.",
1713
- error,
1714
- "artifact-graph-module-worker-initialization-message-rejected",
1715
- );
1716
- }
1717
- return worker;
1718
- },
1719
-
1720
- typedArrayConstructor(capability, modulePath, occurrence, receiver) {
1721
- assertGuardCapability(capability);
1722
- if (!typedArrayConstructors.has(edgeKey(modulePath, occurrence))) {
1723
- throw workerError(
1724
- "ARCANE_AI_ARTIFACT_GRAPH_CONFIGURATION_INVALID",
1725
- "The runtime used an undeclared typed-array constructor transform.",
1726
- undefined,
1727
- "artifact-graph-typed-array-constructor-transform-undeclared",
1728
- );
1729
- }
1730
- if (
1731
- !typedArrays.isView(receiver)
1732
- || typedArrays.getPrototypeOf(receiver) === typedArrays.dataViewPrototype
1733
- || typedArrays.hasOwn(receiver, "constructor")
1734
- ) {
1735
- throw workerError(
1736
- "ARCANE_AI_ARTIFACT_GRAPH_ISOLATION_UNAVAILABLE",
1737
- "The typed-array constructor transform received an unauthenticated receiver.",
1738
- undefined,
1739
- "artifact-graph-typed-array-constructor-receiver-not-typed-array",
1740
- );
1741
- }
1742
- const Constructor = typedArrays.constructors.get(
1743
- typedArrays.getPrototypeOf(receiver),
1744
- );
1745
- if (typeof Constructor !== "function") {
1746
- throw workerError(
1747
- "ARCANE_AI_ARTIFACT_GRAPH_ISOLATION_UNAVAILABLE",
1748
- "The typed-array constructor transform receiver does not use an intrinsic prototype.",
1749
- undefined,
1750
- "artifact-graph-typed-array-constructor-intrinsic-mismatch",
1751
- );
1752
- }
1753
- return Constructor;
1754
- },
1755
- });
1756
-
1757
- return completeValue({
1758
- guard,
1759
- transformersCache: (() => {
1760
- const edgesForTransformers = [...cacheOpens.values()].filter((edge) =>
1761
- edge.edgePolicy === "artifact-targets-admitted"
1762
- && edge.cacheName === "transformers-cache");
1763
- if (edgesForTransformers.length === 0) return null;
1764
- if (edgesForTransformers.length !== 1) {
1765
- throw workerError(
1766
- "ARCANE_AI_ARTIFACT_GRAPH_CONFIGURATION_INVALID",
1767
- "The Transformers custom cache edge is ambiguous.",
1768
- undefined,
1769
- "artifact-graph-transformers-cache-edge-ambiguous",
1770
- );
1771
- }
1772
- return reader.cacheForPaths(edgesForTransformers[0].targetPaths);
1773
- })(),
1774
- cleanup() {
1775
- for (const worker of nestedWorkers) {
1776
- try {
1777
- worker.terminate();
1778
- } catch {
1779
- // The owning speech Worker is already being torn down.
1780
- }
1781
- }
1782
- nestedWorkers.clear();
1783
- },
1784
- });
1785
- }
1786
-
1787
- function installDynamicCodeConstructorIsolation() {
1788
- const rejectingConstructor = function rejectArtifactGraphDynamicCodeConstructor() {
1789
- throw workerError(
1790
- "ARCANE_AI_ARTIFACT_GRAPH_ISOLATION_UNAVAILABLE",
1791
- "Authenticated artifact graph runtime code cannot construct executable strings.",
1792
- undefined,
1793
- "artifact-graph-dynamic-code-constructor-rejected",
1794
- );
1795
- };
1796
- const prototypes = new Set([
1797
- Object.getPrototypeOf(function artifactGraphFunctionProbe() {}),
1798
- Object.getPrototypeOf(async function artifactGraphAsyncFunctionProbe() {}),
1799
- Object.getPrototypeOf(function* artifactGraphGeneratorFunctionProbe() {}),
1800
- Object.getPrototypeOf(async function* artifactGraphAsyncGeneratorFunctionProbe() {}),
1801
- ]);
1802
- const restores = [];
1803
- try {
1804
- for (const prototype of prototypes) {
1805
- const descriptor = Object.getOwnPropertyDescriptor(prototype, "constructor");
1806
- if (!descriptor || (descriptor.configurable === false && descriptor.writable !== true)) {
1807
- throw workerError(
1808
- "ARCANE_AI_ARTIFACT_GRAPH_ISOLATION_UNAVAILABLE",
1809
- "The Worker cannot isolate a dynamic-code constructor prototype.",
1810
- undefined,
1811
- "artifact-graph-dynamic-code-constructor-isolation-unavailable",
1812
- );
1813
- }
1814
- Object.defineProperty(prototype, "constructor", {
1815
- ...descriptor,
1816
- value: rejectingConstructor,
1817
- });
1818
- restores.push(() => Object.defineProperty(prototype, "constructor", descriptor));
1819
- }
1820
- } catch (error) {
1821
- restoreScopeValues(restores);
1822
- throw error;
1823
- }
1824
- return () => restoreScopeValues(restores);
1825
- }
1826
-
1827
- function installStringTimerIsolation(scope, name) {
1828
- const original = scope[name];
1829
- if (typeof original !== "function") return () => undefined;
1830
- const invoke = original.bind(scope);
1831
- return installScopeValue(
1832
- scope,
1833
- name,
1834
- function authenticatedArtifactGraphTimer(callback, ...arguments_) {
1835
- if (typeof callback !== "function") {
1836
- throw workerError(
1837
- "ARCANE_AI_ARTIFACT_GRAPH_ISOLATION_UNAVAILABLE",
1838
- `Authenticated artifact graph ${name} requires a function callback.`,
1839
- undefined,
1840
- `artifact-graph-${name.toLowerCase()}-string-callback-rejected`,
1841
- );
1842
- }
1843
- return invoke(callback, ...arguments_);
1844
- },
1845
- `artifact-graph-${name.toLowerCase()}-isolation-unavailable`,
1846
- );
1847
- }
1848
-
1849
- function installArtifactGraphEnvironment(scope, configuration, role) {
1850
- const originalFetch = scope.fetch?.bind(scope);
1851
- const originalWorker = scope.Worker;
1852
- if (typeof originalFetch !== "function") {
1853
- throw workerError(
1854
- "ARCANE_AI_PROVIDER_UNAVAILABLE",
1855
- "Browser fetch is unavailable in the speech Worker.",
1856
- undefined,
1857
- "artifact-graph-fetch-constructor-unavailable",
1858
- );
1859
- }
1860
- if (GRAPH_GUARD_NAME in scope) {
1861
- throw workerError(
1862
- "ARCANE_AI_ARTIFACT_GRAPH_ISOLATION_UNAVAILABLE",
1863
- "The authenticated artifact graph guard global already exists.",
1864
- undefined,
1865
- "artifact-graph-guard-global-collision",
1866
- );
1867
- }
1868
- const reader = createRouteReader(scope, configuration, originalFetch);
1869
- const graphGuard = createArtifactGraphGuard(
1870
- scope,
1871
- configuration,
1872
- role,
1873
- reader,
1874
- originalWorker,
1875
- );
1876
- const restores = [];
1877
- try {
1878
- restores.push(installScopeValue(
1879
- scope,
1880
- GRAPH_GUARD_NAME,
1881
- graphGuard.guard,
1882
- "artifact-graph-guard-global-definition-rejected",
1883
- ));
1884
- } catch (error) {
1885
- restoreScopeValues(restores);
1886
- graphGuard.cleanup();
1887
- throw error;
1888
- }
1889
- return completeValue({
1890
- cache: graphGuard.transformersCache,
1891
- cleanup() {
1892
- graphGuard.cleanup();
1893
- restoreScopeValues(restores);
1894
- },
1895
- });
1896
- }
1897
-
1898
871
  function ordinaryRequestUrl(value, scope, base = scope.location?.href) {
1899
872
  const input = typeof value === "string" || value instanceof URL
1900
873
  ? String(value)
@@ -2431,7 +1404,7 @@ async function createKokoroEngine(namespace, configuration, signal, report) {
2431
1404
  const synthesizer = await namespace.KokoroTTS.from_pretrained(
2432
1405
  configuration.model.repository,
2433
1406
  {
2434
- device: "wasm",
1407
+ device: configuration.execution?.device ?? "wasm",
2435
1408
  dtype: configuration.model.dtype ?? "q8",
2436
1409
  revision: configuration.model.revision,
2437
1410
  progress_callback: report,