arcane-os 0.5.16 → 0.5.18

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 (190) hide show
  1. package/CHANGELOG.md +44 -0
  2. package/README.md +42 -19
  3. package/bin/arcane-test.mjs +16 -13
  4. package/browser-runtime/ai/browser-speech-artifacts.mjs +41 -38
  5. package/browser-runtime/ai/browser-speech-providers.mjs +53 -46
  6. package/browser-runtime/ai/browser-wasm-llm-provider.mjs +127 -124
  7. package/browser-runtime/ai/browser-wasm.mjs +6 -3
  8. package/browser-runtime/ai/browser-wllama-runtime.mjs +26 -23
  9. package/browser-runtime/ai/model-controller.mjs +94 -91
  10. package/browser-runtime/ai/speech-worker-client.mjs +12 -9
  11. package/browser-runtime/ai/speech-worker-runtime.mjs +56 -53
  12. package/browser-runtime/dependencies/strong-type/index.js +207 -82
  13. package/browser-runtime/dependencies/strong-type/package.json +15 -6
  14. package/browser-runtime/dom-event-instrumentation.mjs +24 -20
  15. package/browser-runtime/event-manager.mjs +111 -108
  16. package/browser-runtime/speech-text.mjs +35 -0
  17. package/docs/architecture.md +1 -1
  18. package/docs/reference/README.md +8 -8
  19. package/docs/reference/ai/browser-speech.md +230 -16
  20. package/docs/reference/ai/twin-cloud.md +1 -1
  21. package/docs/reference/availability-and-normalization.md +42 -1
  22. package/docs/reference/cli.md +1 -1
  23. package/docs/reference/core/arcane-ai-contracts.md +1 -1
  24. package/docs/reference/inventory/package-api.json +60 -4
  25. package/docs/reference/inventory/runtime-components.json +2 -2
  26. package/docs/reference/inventory/runtime-modules.json +29 -31
  27. package/docs/reference/protocols.md +17 -13
  28. package/docs/reference/runtime-components.md +6 -5
  29. package/docs/reference/runtime-modules.md +212 -70
  30. package/docs/reference/sdk-api.md +197 -11
  31. package/examples/wasm-ai-demo/index.html +1 -0
  32. package/node_modules/event-pubsub/node_modules/strong-type/README.md +408 -0
  33. package/node_modules/event-pubsub/node_modules/strong-type/assets/strong-type-header.png +0 -0
  34. package/node_modules/event-pubsub/node_modules/strong-type/index.js +1151 -0
  35. package/node_modules/event-pubsub/node_modules/strong-type/licence +21 -0
  36. package/node_modules/event-pubsub/node_modules/strong-type/node.js +125 -0
  37. package/node_modules/event-pubsub/node_modules/strong-type/package.json +61 -0
  38. package/node_modules/strong-type/README.md +42 -24
  39. package/node_modules/strong-type/benchmark/core.js +324 -0
  40. package/node_modules/strong-type/index.js +207 -82
  41. package/node_modules/strong-type/package.json +14 -6
  42. package/package.json +4 -3
  43. package/runtime/arcane/components/app-bar.html +5 -2
  44. package/runtime/arcane/components/assistant-panel.html +5 -2
  45. package/runtime/arcane/components/chart.html +15 -12
  46. package/runtime/arcane/components/chat.html +118 -141
  47. package/runtime/arcane/components/dashboard-config.html +6 -3
  48. package/runtime/arcane/components/data-view.html +4 -1
  49. package/runtime/arcane/components/directory-picker.html +5 -2
  50. package/runtime/arcane/components/document-inspector.html +6 -3
  51. package/runtime/arcane/components/file-drop.html +5 -2
  52. package/runtime/arcane/components/file-inspector.html +9 -6
  53. package/runtime/arcane/components/file-manager.html +16 -13
  54. package/runtime/arcane/components/local-ai-status.html +5 -2
  55. package/runtime/arcane/components/markdown-document.html +14 -11
  56. package/runtime/arcane/components/markdown-editor.html +4 -1
  57. package/runtime/arcane/components/modal.html +4 -1
  58. package/runtime/arcane/components/output-panel.html +6 -3
  59. package/runtime/arcane/components/preferences-form.html +4 -1
  60. package/runtime/arcane/components/record-timeline.html +8 -5
  61. package/runtime/arcane/components/relationship-board.html +9 -6
  62. package/runtime/arcane/components/source-code-viewer.html +12 -9
  63. package/runtime/arcane/components/source-explanation.html +8 -5
  64. package/runtime/arcane/components/speech.html +24 -21
  65. package/runtime/arcane/components/summary-strip.html +4 -1
  66. package/runtime/arcane/components/task-progress.html +6 -3
  67. package/runtime/arcane/components/terminal-workspace.html +4 -1
  68. package/runtime/arcane/components/voice-transcription.html +11 -8
  69. package/runtime/arcane/components/web-navigator.html +5 -2
  70. package/runtime/arcane/entities/ApiModelRecord.js +5 -2
  71. package/runtime/arcane/entities/Calculation.js +5 -2
  72. package/runtime/arcane/entities/Chat.js +33 -33
  73. package/runtime/arcane/entities/CommunicationMessage.js +4 -1
  74. package/runtime/arcane/entities/CommunicationThread.js +4 -1
  75. package/runtime/arcane/entities/File.js +1 -1
  76. package/runtime/arcane/entities/Image.js +8 -5
  77. package/runtime/arcane/entities/IntentEnvelope.js +20 -17
  78. package/runtime/arcane/entities/Preference.js +9 -6
  79. package/runtime/arcane/entities/Theme.js +5 -2
  80. package/runtime/arcane/entities/User.js +11 -11
  81. package/runtime/arcane/entities/Weather.js +5 -2
  82. package/runtime/arcane/modules/AI.js +503 -187
  83. package/runtime/arcane/modules/AIPreferenceRuntime.js +5 -2
  84. package/runtime/arcane/modules/AIPreferenceTuple.js +9 -6
  85. package/runtime/arcane/modules/AIProviderRuntime.js +117 -92
  86. package/runtime/arcane/modules/AIResponseURLPolicy.js +148 -62
  87. package/runtime/arcane/modules/AIRuntimeState.js +29 -26
  88. package/runtime/arcane/modules/AnsiText.js +4 -1
  89. package/runtime/arcane/modules/ApiModelDatabase.js +22 -19
  90. package/runtime/arcane/modules/AppDataScope.js +8 -5
  91. package/runtime/arcane/modules/ArcaneCommunicationBridge.js +4 -1
  92. package/runtime/arcane/modules/ArcaneNavigationPolicy.js +8 -5
  93. package/runtime/arcane/modules/ArcaneNetworkPolicy.js +18 -15
  94. package/runtime/arcane/modules/AsyncBoundary.js +13 -10
  95. package/runtime/arcane/modules/BrowserTestSuite.js +19 -16
  96. package/runtime/arcane/modules/CalculatorEngine.js +5 -2
  97. package/runtime/arcane/modules/ChatRecords.js +18 -15
  98. package/runtime/arcane/modules/CommunicationAppController.js +9 -6
  99. package/runtime/arcane/modules/CommunicationHub.js +9 -6
  100. package/runtime/arcane/modules/CommunicationPreferences.js +4 -1
  101. package/runtime/arcane/modules/CommunicationProviderRegistry.js +4 -1
  102. package/runtime/arcane/modules/ComponentContracts.js +56 -53
  103. package/runtime/arcane/modules/ConfiguredAIChatSession.js +30 -27
  104. package/runtime/arcane/modules/ConversationActionItems.js +15 -12
  105. package/runtime/arcane/modules/ConversationClosingReport.js +11 -8
  106. package/runtime/arcane/modules/ConversationTimebox.js +28 -25
  107. package/runtime/arcane/modules/CoreLocalModelCatalog.js +17 -14
  108. package/runtime/arcane/modules/DBLS.js +7 -4
  109. package/runtime/arcane/modules/DBOPFS.js +7 -7
  110. package/runtime/arcane/modules/DBOPFSDocumentLibrary.js +34 -31
  111. package/runtime/arcane/modules/DevelopmentWorkspace.js +4 -1
  112. package/runtime/arcane/modules/DirectoryPicker.js +8 -5
  113. package/runtime/arcane/modules/DocumentLexicalSearch.js +11 -8
  114. package/runtime/arcane/modules/DocumentNavigation.js +7 -4
  115. package/runtime/arcane/modules/Errors.js +28 -25
  116. package/runtime/arcane/modules/HTMLImport.js +7 -4
  117. package/runtime/arcane/modules/IsolatedModelQuestionRunner.js +15 -12
  118. package/runtime/arcane/modules/LocalAIReadiness.js +21 -18
  119. package/runtime/arcane/modules/LocalAIReadinessController.js +6 -3
  120. package/runtime/arcane/modules/MD.js +1 -1
  121. package/runtime/arcane/modules/Mail.js +46 -43
  122. package/runtime/arcane/modules/MailOutbox.mjs +48 -45
  123. package/runtime/arcane/modules/MailTransport.mjs +29 -26
  124. package/runtime/arcane/modules/MarkdownSpeech.js +1 -50
  125. package/runtime/arcane/modules/MemoryRecords.js +7 -4
  126. package/runtime/arcane/modules/MessageAdvisory.js +6 -3
  127. package/runtime/arcane/modules/ModelDefinition.js +7 -4
  128. package/runtime/arcane/modules/Ollama.js +6 -3
  129. package/runtime/arcane/modules/OllamaModelIdentifier.js +4 -1
  130. package/runtime/arcane/modules/OpenMeteoWeatherProvider.js +18 -15
  131. package/runtime/arcane/modules/PersistentAIChatSession.js +33 -30
  132. package/runtime/arcane/modules/PreferenceStore.js +20 -17
  133. package/runtime/arcane/modules/PreparedSpeech.js +485 -0
  134. package/runtime/arcane/modules/Questionnaire.js +6 -3
  135. package/runtime/arcane/modules/RecordLinkIndex.js +4 -1
  136. package/runtime/arcane/modules/RecordPassageIndex.js +9 -6
  137. package/runtime/arcane/modules/RecordReviewStore.js +12 -9
  138. package/runtime/arcane/modules/RiskSignalAnalyzer.js +4 -1
  139. package/runtime/arcane/modules/ScopedOPFSCache.js +6 -3
  140. package/runtime/arcane/modules/ScreenCapture.js +20 -17
  141. package/runtime/arcane/modules/SpeechPlayback.js +61 -28
  142. package/runtime/arcane/modules/StaticDocumentCatalog.js +33 -30
  143. package/runtime/arcane/modules/SystemAppearance.js +5 -2
  144. package/runtime/arcane/modules/SystemToolRegistry.js +6 -3
  145. package/runtime/arcane/modules/TerminalClient.js +14 -11
  146. package/runtime/arcane/modules/TerminalCommandRegistry.js +4 -1
  147. package/runtime/arcane/modules/ThemeBootstrap.js +9 -6
  148. package/runtime/arcane/modules/ThemeManager.js +5 -2
  149. package/runtime/arcane/modules/TimeGuard.js +1 -1
  150. package/runtime/arcane/modules/ToolCallRouter.js +11 -8
  151. package/runtime/arcane/modules/WaitForComponent.js +19 -16
  152. package/runtime/arcane/modules/YouTubeMedia.js +4 -1
  153. package/runtime/strong-type/index.js +1276 -352
  154. package/runtime/strong-type/package.json +69 -45
  155. package/src/app-descriptor.mjs +17 -14
  156. package/src/application-tests.mjs +4 -1
  157. package/src/cli/main.mjs +8 -5
  158. package/src/constants.mjs +4 -1
  159. package/src/dev-server.mjs +8 -5
  160. package/src/doctor.mjs +5 -2
  161. package/src/dom-event-instrumentation.mjs +24 -20
  162. package/src/errors.mjs +7 -3
  163. package/src/event-manager.mjs +111 -108
  164. package/src/event-queue.mjs +8 -5
  165. package/src/events.mjs +12 -9
  166. package/src/import-map.mjs +36 -27
  167. package/src/installed-sdk-runtime.mjs +4 -1
  168. package/src/integrated-provider-loader.mjs +9 -6
  169. package/src/mail-credentials.mjs +16 -13
  170. package/src/mail-server.mjs +53 -50
  171. package/src/mail.mjs +18 -15
  172. package/src/native-plan.mjs +12 -9
  173. package/src/native-provider-loader.mjs +7 -4
  174. package/src/packager/core.mjs +18 -15
  175. package/src/process.mjs +6 -3
  176. package/src/release-bundle.mjs +14 -11
  177. package/src/runtime.mjs +4 -1
  178. package/src/scaffold.mjs +9 -6
  179. package/src/sdk-browser-runtime.mjs +4 -1
  180. package/src/source-server.mjs +17 -14
  181. package/src/targets/index.mjs +5 -2
  182. package/src/templates/workspace-template.mjs +13 -6
  183. package/src/testing-loader.mjs +7 -4
  184. package/src/testing.mjs +10 -7
  185. package/src/toolchain.mjs +13 -10
  186. package/src/update-check.mjs +9 -6
  187. package/src/workspace-operation-lock.mjs +14 -11
  188. package/src/workspace-runtime.mjs +4 -1
  189. package/src/workspace.mjs +17 -14
  190. package/runtime/arcane/modules/AIResponseLength.js +0 -32
@@ -1,3 +1,7 @@
1
+ import Is from "../dependencies/strong-type/index.js";
2
+
3
+ const is = new Is(false);
4
+
1
5
  export const SPEECH_WORKER_PROTOCOL = "arcane-ai-speech-worker/1";
2
6
 
3
7
  const completeValue = (value) => value;
@@ -266,14 +270,14 @@ function workerError(code, message, cause, reason) {
266
270
  ? "AbortError"
267
271
  : "ArcaneSpeechWorkerError";
268
272
  error.code = code;
269
- if (typeof reason === "string" && reason) error.reason = reason;
273
+ if (is.string(reason) && reason) error.reason = reason;
270
274
  SDK_WORKER_ERRORS.add(error);
271
275
  return error;
272
276
  }
273
277
 
274
278
  function isSdkWorkerError(value) {
275
279
  try {
276
- return value instanceof Error && SDK_WORKER_ERRORS.has(value);
280
+ return is.error(value) && SDK_WORKER_ERRORS.has(value);
277
281
  } catch {
278
282
  return false;
279
283
  }
@@ -307,20 +311,20 @@ export function collectSpeechTransferables(value) {
307
311
  const buffers = new Set();
308
312
  const seen = new WeakSet();
309
313
  function visit(candidate) {
310
- if (candidate instanceof ArrayBuffer) {
314
+ if (is.instanceCheck(candidate, ArrayBuffer)) {
311
315
  if (!buffers.has(candidate)) {
312
316
  buffers.add(candidate);
313
317
  transfers.push(candidate);
314
318
  }
315
319
  return;
316
320
  }
317
- if (ArrayBuffer.isView(candidate)) {
321
+ if (is.arrayBufferView(candidate)) {
318
322
  visit(candidate.buffer);
319
323
  return;
320
324
  }
321
- if (!candidate || typeof candidate !== "object" || seen.has(candidate)) return;
325
+ if (!candidate || !is.object(candidate) || seen.has(candidate)) return;
322
326
  seen.add(candidate);
323
- for (const child of Array.isArray(candidate)
327
+ for (const child of is.array(candidate)
324
328
  ? candidate
325
329
  : Object.values(candidate)) visit(child);
326
330
  }
@@ -352,7 +356,7 @@ function serializedError(error, role, op) {
352
356
  && admission?.code === reportedCode;
353
357
  const code = admittedCode ? reportedCode : "ARCANE_AI_PROVIDER_REQUEST_FAILED";
354
358
  const reason = admittedCode ? reportedReason : operationFailureReason(role, op);
355
- const message = typeof reportedMessage === "string" && reportedMessage.length > 0
359
+ const message = is.string(reportedMessage) && reportedMessage.length > 0
356
360
  ? reportedMessage
357
361
  : WORKER_ERROR_MESSAGES[code];
358
362
  const envelope = completeValue({
@@ -373,7 +377,7 @@ function fallbackSerializedError(error, role, op) {
373
377
  return completeValue({
374
378
  protocol: SPEECH_WORKER_ERROR_PROTOCOL,
375
379
  code: "ARCANE_AI_PROVIDER_REQUEST_FAILED",
376
- message: typeof message === "string" && message.length > 0
380
+ message: is.string(message) && message.length > 0
377
381
  ? message
378
382
  : WORKER_ERROR_MESSAGES.ARCANE_AI_PROVIDER_REQUEST_FAILED,
379
383
  reason: operationFailureReason(role, op),
@@ -424,9 +428,8 @@ function diagnosticType(value) {
424
428
 
425
429
  function serializedDiagnosticValue(value, seen = new WeakMap()) {
426
430
  if (value === null || value === undefined) return value;
427
- const type = typeof value;
428
- if (type !== "object" && type !== "function") {
429
- return type === "symbol"
431
+ if (is.primitive(value)) {
432
+ return is.symbol(value)
430
433
  ? diagnosticText(value, "[symbol could not be represented]")
431
434
  : value;
432
435
  }
@@ -473,7 +476,7 @@ function serializedDiagnosticValue(value, seen = new WeakMap()) {
473
476
  );
474
477
  }
475
478
  }
476
- if (typeof key === "symbol") {
479
+ if (is.symbol(key)) {
477
480
  const symbolProperty = Object.create(null);
478
481
  defineDiagnosticProperty(
479
482
  symbolProperty,
@@ -516,7 +519,7 @@ function serializedDiagnosticValue(value, seen = new WeakMap()) {
516
519
  defineDiagnosticProperty(metadata, "symbolProperties", symbolProperties);
517
520
  }
518
521
  try {
519
- if (type === "function") {
522
+ if (is.function(value)) {
520
523
  defineDiagnosticProperty(
521
524
  metadata,
522
525
  "source",
@@ -547,7 +550,7 @@ function serializedDiagnosticValue(value, seen = new WeakMap()) {
547
550
  } else {
548
551
  let view = false;
549
552
  try {
550
- view = ArrayBuffer.isView(value);
553
+ view = is.arrayBufferView(value);
551
554
  } catch {}
552
555
  if (view) defineDiagnosticProperty(metadata, "value", value);
553
556
  }
@@ -572,11 +575,11 @@ function workerErrorReasonAdmission(reason, role, op) {
572
575
  }
573
576
 
574
577
  export function normalizeSpeechWorkerErrorEnvelope(value, role, op) {
575
- if (!value || typeof value !== "object" || Array.isArray(value)) return null;
578
+ if (!value || !is.object(value) || is.array(value)) return null;
576
579
  let descriptors;
577
580
  try {
578
581
  const keys = Reflect.ownKeys(value);
579
- if (keys.some((key) => typeof key !== "string")
582
+ if (keys.some((key) => !is.string(key))
580
583
  || ![
581
584
  "code,message,protocol,reason",
582
585
  "cause,code,message,protocol,reason",
@@ -594,7 +597,7 @@ export function normalizeSpeechWorkerErrorEnvelope(value, role, op) {
594
597
  const reason = descriptors.reason.value;
595
598
  if (protocol !== SPEECH_WORKER_ERROR_PROTOCOL) return null;
596
599
  if (!Object.hasOwn(WORKER_ERROR_MESSAGES, code)) return null;
597
- if (typeof message !== "string" || message.length < 1) return null;
600
+ if (!is.string(message) || message.length < 1) return null;
598
601
  const admission = workerErrorReasonAdmission(reason, role, op);
599
602
  if (admission?.code !== code) return null;
600
603
  if (descriptors.cause && !Object.hasOwn(descriptors.cause, "value")) return null;
@@ -611,7 +614,7 @@ function requiredText(
611
614
  label,
612
615
  reason,
613
616
  ) {
614
- if (typeof value !== "string" || !value.trim()) {
617
+ if (!is.string(value) || !value.trim()) {
615
618
  throw workerError(
616
619
  "ARCANE_AI_INVALID_REQUEST",
617
620
  `${label} is required.`,
@@ -627,7 +630,7 @@ function requiredContent(
627
630
  label,
628
631
  reason,
629
632
  ) {
630
- if (typeof value !== "string" || !value.trim()) {
633
+ if (!is.string(value) || !value.trim()) {
631
634
  throw workerError(
632
635
  "ARCANE_AI_INVALID_REQUEST",
633
636
  `${label} is required.`,
@@ -640,7 +643,7 @@ function requiredContent(
640
643
 
641
644
  function requiredSampleRate(value, label, fallback) {
642
645
  const candidate = value ?? fallback;
643
- if (!Number.isSafeInteger(candidate) || candidate < 1) {
646
+ if (!is.safeInteger(candidate) || candidate < 1) {
644
647
  throw workerError(
645
648
  "ARCANE_AI_INVALID_REQUEST",
646
649
  `${label} must be a positive safe integer.`,
@@ -656,7 +659,7 @@ function graphConfiguration(configuration) {
656
659
  }
657
660
 
658
661
  function validateMaterializedFile(file, label) {
659
- if (!file || typeof file !== "object" || Array.isArray(file)) {
662
+ if (!file || !is.object(file) || is.array(file)) {
660
663
  throw workerError(
661
664
  "ARCANE_AI_INVALID_REQUEST",
662
665
  `${label} must be an object.`,
@@ -668,7 +671,7 @@ function validateMaterializedFile(file, label) {
668
671
  requiredText(file.sourceUrl, `${label} sourceUrl`, "artifact-graph-materialized-source-url-empty");
669
672
  requiredText(file.moduleUrl, `${label} moduleUrl`, "artifact-graph-materialized-module-url-empty");
670
673
  requiredText(file.mediaType, `${label} mediaType`, "artifact-graph-materialized-media-type-empty");
671
- if (file.runtimeRequestUrls !== undefined && !Array.isArray(file.runtimeRequestUrls)) {
674
+ if (file.runtimeRequestUrls !== undefined && !is.array(file.runtimeRequestUrls)) {
672
675
  throw workerError(
673
676
  "ARCANE_AI_INVALID_REQUEST",
674
677
  `${label} runtimeRequestUrls must be an array.`,
@@ -680,7 +683,7 @@ function validateMaterializedFile(file, label) {
680
683
  }
681
684
 
682
685
  function validateConfiguration(configuration, role) {
683
- if (!configuration || typeof configuration !== "object" || Array.isArray(configuration)) {
686
+ if (!configuration || !is.object(configuration) || is.array(configuration)) {
684
687
  throw workerError(
685
688
  "ARCANE_AI_INVALID_REQUEST",
686
689
  "Speech worker configuration is required.",
@@ -707,7 +710,7 @@ function validateConfiguration(configuration, role) {
707
710
  requiredText(configuration.runtime?.entry, "Speech runtime entry", "speech-worker-runtime-entry-empty");
708
711
  const execution = configuration.execution;
709
712
  if (execution !== undefined) {
710
- if (!execution || typeof execution !== "object" || Array.isArray(execution)) {
713
+ if (!execution || !is.object(execution) || is.array(execution)) {
711
714
  throw workerError(
712
715
  "ARCANE_AI_INVALID_REQUEST",
713
716
  "Speech worker execution must be a plain data record.",
@@ -748,7 +751,7 @@ function validateConfiguration(configuration, role) {
748
751
  );
749
752
  }
750
753
  }
751
- if (!Array.isArray(configuration.runtime?.files) || !Array.isArray(configuration.model?.files)) {
754
+ if (!is.array(configuration.runtime?.files) || !is.array(configuration.model?.files)) {
752
755
  throw workerError(
753
756
  "ARCANE_AI_INVALID_REQUEST",
754
757
  "Speech runtime and model files are required.",
@@ -811,7 +814,7 @@ function validateConfiguration(configuration, role) {
811
814
  }
812
815
  if (
813
816
  wasm.numThreads !== undefined
814
- && (!Number.isSafeInteger(wasm.numThreads) || wasm.numThreads < 1)
817
+ && (!is.safeInteger(wasm.numThreads) || wasm.numThreads < 1)
815
818
  ) {
816
819
  throw workerError(
817
820
  "ARCANE_AI_ARTIFACT_GRAPH_CONFIGURATION_INVALID",
@@ -826,7 +829,7 @@ function validateConfiguration(configuration, role) {
826
829
  } else {
827
830
  requiredSampleRate(configuration.model.outputSampleRate, "Kokoro outputSampleRate");
828
831
  requiredText(configuration.model.defaultVoice, "Kokoro defaultVoice", "tts-default-voice-empty");
829
- if (!Array.isArray(configuration.model.voices) || configuration.model.voices.length < 1) {
832
+ if (!is.array(configuration.model.voices) || configuration.model.voices.length < 1) {
830
833
  throw workerError(
831
834
  "ARCANE_AI_ARTIFACT_GRAPH_CONFIGURATION_INVALID",
832
835
  "Kokoro graph configuration requires the caller-owned voice inventory.",
@@ -852,7 +855,7 @@ function nestedWorkerUrl(role) {
852
855
 
853
856
  function nestedWorkerFailureEvent(scope, error) {
854
857
  const ErrorEventConstructor = scope.ErrorEvent ?? globalThis.ErrorEvent;
855
- if (typeof ErrorEventConstructor === "function") {
858
+ if (is.function(ErrorEventConstructor)) {
856
859
  return new ErrorEventConstructor("error", {
857
860
  error,
858
861
  message: error.message,
@@ -869,10 +872,10 @@ function nestedWorkerFailureEvent(scope, error) {
869
872
  }
870
873
 
871
874
  function ordinaryRequestUrl(value, scope, base = scope.location?.href) {
872
- const input = typeof value === "string" || value instanceof URL
875
+ const input = is.string(value) || is.instanceCheck(value, URL)
873
876
  ? String(value)
874
877
  : value?.url;
875
- if (typeof input !== "string" || input.length < 1) return null;
878
+ if (!is.string(input) || input.length < 1) return null;
876
879
  try {
877
880
  return new URL(input, base).href;
878
881
  } catch {
@@ -881,7 +884,7 @@ function ordinaryRequestUrl(value, scope, base = scope.location?.href) {
881
884
  }
882
885
 
883
886
  function isBareModuleSpecifier(value) {
884
- return typeof value === "string"
887
+ return is.string(value)
885
888
  && !value.startsWith("./")
886
889
  && !value.startsWith("../")
887
890
  && !value.startsWith("/")
@@ -932,7 +935,7 @@ function createOrdinaryRouteReader(
932
935
  }
933
936
 
934
937
  function nativeInput(input, modulePath) {
935
- if (typeof input !== "string" && !(input instanceof URL)) return input;
938
+ if (!is.string(input) && !is.instanceCheck(input, URL)) return input;
936
939
  return ordinaryRequestUrl(input, scope, sourceBase(modulePath)) ?? input;
937
940
  }
938
941
 
@@ -943,15 +946,15 @@ function createOrdinaryRouteReader(
943
946
  }
944
947
 
945
948
  function responseFor(resolution, input, init) {
946
- const mappedInput = typeof RequestConstructor === "function"
947
- && input instanceof RequestConstructor
949
+ const mappedInput = is.function(RequestConstructor)
950
+ && is.instanceCheck(input, RequestConstructor)
948
951
  ? new RequestConstructor(resolution.file.moduleUrl, input)
949
952
  : resolution.file.moduleUrl;
950
953
  return originalFetch(mappedInput, init);
951
954
  }
952
955
 
953
956
  async function nativeCache(name) {
954
- if (!originalCaches || typeof originalCaches.open !== "function") return null;
957
+ if (!originalCaches || !is.function(originalCaches.open)) return null;
955
958
  if (!nativeCaches.has(name)) {
956
959
  nativeCaches.set(name, Promise.resolve(originalCaches.open.call(originalCaches, name)));
957
960
  }
@@ -1031,7 +1034,7 @@ function createOrdinaryArtifactModuleRouter(
1031
1034
  },
1032
1035
 
1033
1036
  createWorker(modulePath, specifier, options = {}) {
1034
- if (typeof originalWorker !== "function") {
1037
+ if (!is.function(originalWorker)) {
1035
1038
  throw workerError(
1036
1039
  "ARCANE_AI_PROVIDER_UNAVAILABLE",
1037
1040
  "Nested browser Workers are unavailable.",
@@ -1043,7 +1046,7 @@ function createOrdinaryArtifactModuleRouter(
1043
1046
  if (!resolution) {
1044
1047
  return new originalWorker(reader.nativeInput(specifier, modulePath), options);
1045
1048
  }
1046
- const workerOptions = options && typeof options === "object"
1049
+ const workerOptions = options && is.object(options)
1047
1050
  ? { ...options, type: "module" }
1048
1051
  : { type: "module" };
1049
1052
  const worker = new originalWorker(nestedWorkerUrl(role), workerOptions);
@@ -1105,7 +1108,7 @@ function installOrdinaryArtifactModuleRouter(scope, configuration, role) {
1105
1108
  const originalFetch = scope.fetch?.bind(scope);
1106
1109
  const originalWorker = scope.Worker;
1107
1110
  const originalCaches = scope.caches;
1108
- if (typeof originalFetch !== "function") {
1111
+ if (!is.function(originalFetch)) {
1109
1112
  throw workerError(
1110
1113
  "ARCANE_AI_PROVIDER_UNAVAILABLE",
1111
1114
  "Browser fetch is unavailable in the speech Worker.",
@@ -1338,20 +1341,20 @@ function configureRuntimeNamespace(namespace, configuration, role, cache) {
1338
1341
 
1339
1342
  async function disposeEngine(engine) {
1340
1343
  if (!engine) return;
1341
- if (typeof engine.dispose === "function") {
1344
+ if (is.function(engine.dispose)) {
1342
1345
  await engine.dispose();
1343
1346
  return;
1344
1347
  }
1345
1348
  const disposed = new Set();
1346
1349
  for (const part of [engine.model, engine.tokenizer, engine.processor]) {
1347
- if (!part || disposed.has(part) || typeof part.dispose !== "function") continue;
1350
+ if (!part || disposed.has(part) || !is.function(part.dispose)) continue;
1348
1351
  disposed.add(part);
1349
1352
  await part.dispose();
1350
1353
  }
1351
1354
  }
1352
1355
 
1353
1356
  async function createWhisperEngine(namespace, configuration, signal, report) {
1354
- if (typeof namespace?.pipeline !== "function") {
1357
+ if (!is.function(namespace?.pipeline)) {
1355
1358
  throw workerError(
1356
1359
  "ARCANE_AI_PROVIDER_UNAVAILABLE",
1357
1360
  "The Whisper runtime does not export pipeline().",
@@ -1392,7 +1395,7 @@ async function createWhisperEngine(namespace, configuration, signal, report) {
1392
1395
  }
1393
1396
 
1394
1397
  async function createKokoroEngine(namespace, configuration, signal, report) {
1395
- if (typeof namespace?.KokoroTTS?.from_pretrained !== "function") {
1398
+ if (!is.function(namespace?.KokoroTTS?.from_pretrained)) {
1396
1399
  throw workerError(
1397
1400
  "ARCANE_AI_PROVIDER_UNAVAILABLE",
1398
1401
  "The Kokoro runtime does not export KokoroTTS.",
@@ -1429,7 +1432,7 @@ async function createKokoroEngine(namespace, configuration, signal, report) {
1429
1432
  signal: requestSignal,
1430
1433
  });
1431
1434
  throwIfAborted(requestSignal, "tts-synthesis-cancelled");
1432
- const audio = output?.audio instanceof Float32Array
1435
+ const audio = is.instanceCheck(output?.audio, Float32Array)
1433
1436
  ? output.audio
1434
1437
  : new Float32Array(output?.audio ?? []);
1435
1438
  return completeValue({
@@ -1444,7 +1447,7 @@ async function createKokoroEngine(namespace, configuration, signal, report) {
1444
1447
 
1445
1448
  function callerVoiceIds(configuration) {
1446
1449
  return new Set((configuration.model.voices ?? []).map((voice) =>
1447
- typeof voice === "string" ? voice : voice?.id));
1450
+ is.string(voice) ? voice : voice?.id));
1448
1451
  }
1449
1452
 
1450
1453
  function validateInput(role, payload, configuration) {
@@ -1454,7 +1457,7 @@ function validateInput(role, payload, configuration) {
1454
1457
  "Whisper inputSampleRate",
1455
1458
  16_000,
1456
1459
  );
1457
- if (!(payload?.audio instanceof Float32Array)) {
1460
+ if (!is.instanceCheck(payload?.audio, Float32Array)) {
1458
1461
  throw workerError(
1459
1462
  "ARCANE_AI_INVALID_REQUEST",
1460
1463
  "Whisper requires Float32Array audio.",
@@ -1488,7 +1491,7 @@ function validateInput(role, payload, configuration) {
1488
1491
  );
1489
1492
  }
1490
1493
  const speed = payload?.speed ?? 1;
1491
- if (!Number.isFinite(speed) || speed <= 0) {
1494
+ if (!is.finite(speed) || speed <= 0) {
1492
1495
  throw workerError(
1493
1496
  "ARCANE_AI_INVALID_REQUEST",
1494
1497
  "Kokoro speed must be greater than 0.",
@@ -1501,7 +1504,7 @@ function validateInput(role, payload, configuration) {
1501
1504
 
1502
1505
  function validateResult(role, result, configuration) {
1503
1506
  if (role === "stt") {
1504
- if (!result || typeof result.text !== "string") {
1507
+ if (!result || !is.string(result.text)) {
1505
1508
  throw workerError(
1506
1509
  "ARCANE_AI_INVALID_PROVIDER_RESULT",
1507
1510
  "Whisper did not return text.",
@@ -1516,7 +1519,7 @@ function validateResult(role, result, configuration) {
1516
1519
  "Kokoro outputSampleRate",
1517
1520
  24_000,
1518
1521
  );
1519
- if (!(result?.audio instanceof Float32Array)) {
1522
+ if (!is.instanceCheck(result?.audio, Float32Array)) {
1520
1523
  throw workerError(
1521
1524
  "ARCANE_AI_INVALID_PROVIDER_RESULT",
1522
1525
  "Kokoro must return Float32 PCM.",
@@ -1533,7 +1536,7 @@ function validateResult(role, result, configuration) {
1533
1536
  );
1534
1537
  }
1535
1538
  for (const sample of result.audio) {
1536
- if (!Number.isFinite(sample)) {
1539
+ if (!is.finite(sample)) {
1537
1540
  throw workerError(
1538
1541
  "ARCANE_AI_INVALID_PROVIDER_RESULT",
1539
1542
  "Kokoro returned non-finite PCM.",
@@ -1553,7 +1556,7 @@ export function createSpeechWorkerRuntime({ role, scope = globalThis, send } = {
1553
1556
  if (role !== "stt" && role !== "tts") {
1554
1557
  throw new TypeError('Speech worker role must be "stt" or "tts".');
1555
1558
  }
1556
- if (typeof send !== "function") {
1559
+ if (!is.function(send)) {
1557
1560
  throw new TypeError("Speech worker send() is required.");
1558
1561
  }
1559
1562
  let configuration = null;
@@ -1659,7 +1662,7 @@ export function createSpeechWorkerRuntime({ role, scope = globalThis, send } = {
1659
1662
  }
1660
1663
  const input = validateInput(role, request.payload, configuration);
1661
1664
  const method = role === "stt" ? engine.transcribe : engine.synthesize;
1662
- if (typeof method !== "function") {
1665
+ if (!is.function(method)) {
1663
1666
  throw workerError(
1664
1667
  "ARCANE_AI_PROVIDER_UNAVAILABLE",
1665
1668
  "The speech engine operation is unavailable.",
@@ -1769,7 +1772,7 @@ export function createSpeechWorkerRuntime({ role, scope = globalThis, send } = {
1769
1772
 
1770
1773
  function handleMessage(request) {
1771
1774
  if (request?.protocol !== SPEECH_WORKER_PROTOCOL
1772
- || !Number.isSafeInteger(request.id)
1775
+ || !is.safeInteger(request.id)
1773
1776
  || request.id < 1) {
1774
1777
  return Promise.reject(workerError(
1775
1778
  "ARCANE_AI_INVALID_REQUEST",
@@ -1836,7 +1839,7 @@ export function installBrowserSpeechWorker(role, scope = globalThis) {
1836
1839
  }
1837
1840
 
1838
1841
  function replayWorkerMessage(scope, event) {
1839
- if (typeof scope.dispatchEvent === "function") {
1842
+ if (is.function(scope.dispatchEvent)) {
1840
1843
  scope.dispatchEvent(event);
1841
1844
  return;
1842
1845
  }