arcane-os 0.5.17 → 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 (183) hide show
  1. package/CHANGELOG.md +24 -0
  2. package/README.md +9 -9
  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 +46 -43
  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 +5 -1
  17. package/docs/reference/ai/browser-speech.md +198 -5
  18. package/docs/reference/availability-and-normalization.md +40 -0
  19. package/docs/reference/inventory/package-api.json +1 -1
  20. package/docs/reference/inventory/runtime-components.json +1 -1
  21. package/docs/reference/inventory/runtime-modules.json +20 -24
  22. package/docs/reference/protocols.md +1 -1
  23. package/docs/reference/runtime-modules.md +125 -35
  24. package/docs/reference/sdk-api.md +23 -7
  25. package/examples/wasm-ai-demo/index.html +1 -0
  26. package/node_modules/event-pubsub/node_modules/strong-type/README.md +408 -0
  27. package/node_modules/event-pubsub/node_modules/strong-type/assets/strong-type-header.png +0 -0
  28. package/node_modules/event-pubsub/node_modules/strong-type/index.js +1151 -0
  29. package/node_modules/event-pubsub/node_modules/strong-type/licence +21 -0
  30. package/node_modules/event-pubsub/node_modules/strong-type/node.js +125 -0
  31. package/node_modules/event-pubsub/node_modules/strong-type/package.json +61 -0
  32. package/node_modules/strong-type/README.md +42 -24
  33. package/node_modules/strong-type/benchmark/core.js +324 -0
  34. package/node_modules/strong-type/index.js +207 -82
  35. package/node_modules/strong-type/package.json +14 -6
  36. package/package.json +3 -3
  37. package/runtime/arcane/components/app-bar.html +5 -2
  38. package/runtime/arcane/components/assistant-panel.html +5 -2
  39. package/runtime/arcane/components/chart.html +15 -12
  40. package/runtime/arcane/components/chat.html +117 -138
  41. package/runtime/arcane/components/dashboard-config.html +6 -3
  42. package/runtime/arcane/components/data-view.html +4 -1
  43. package/runtime/arcane/components/directory-picker.html +5 -2
  44. package/runtime/arcane/components/document-inspector.html +6 -3
  45. package/runtime/arcane/components/file-drop.html +5 -2
  46. package/runtime/arcane/components/file-inspector.html +9 -6
  47. package/runtime/arcane/components/file-manager.html +16 -13
  48. package/runtime/arcane/components/local-ai-status.html +5 -2
  49. package/runtime/arcane/components/markdown-document.html +14 -11
  50. package/runtime/arcane/components/markdown-editor.html +4 -1
  51. package/runtime/arcane/components/modal.html +4 -1
  52. package/runtime/arcane/components/output-panel.html +6 -3
  53. package/runtime/arcane/components/preferences-form.html +4 -1
  54. package/runtime/arcane/components/record-timeline.html +8 -5
  55. package/runtime/arcane/components/relationship-board.html +9 -6
  56. package/runtime/arcane/components/source-code-viewer.html +12 -9
  57. package/runtime/arcane/components/source-explanation.html +8 -5
  58. package/runtime/arcane/components/speech.html +24 -21
  59. package/runtime/arcane/components/summary-strip.html +4 -1
  60. package/runtime/arcane/components/task-progress.html +6 -3
  61. package/runtime/arcane/components/terminal-workspace.html +4 -1
  62. package/runtime/arcane/components/voice-transcription.html +11 -8
  63. package/runtime/arcane/components/web-navigator.html +5 -2
  64. package/runtime/arcane/entities/ApiModelRecord.js +5 -2
  65. package/runtime/arcane/entities/Calculation.js +5 -2
  66. package/runtime/arcane/entities/Chat.js +33 -33
  67. package/runtime/arcane/entities/CommunicationMessage.js +4 -1
  68. package/runtime/arcane/entities/CommunicationThread.js +4 -1
  69. package/runtime/arcane/entities/File.js +1 -1
  70. package/runtime/arcane/entities/Image.js +8 -5
  71. package/runtime/arcane/entities/IntentEnvelope.js +20 -17
  72. package/runtime/arcane/entities/Preference.js +9 -6
  73. package/runtime/arcane/entities/Theme.js +5 -2
  74. package/runtime/arcane/entities/User.js +11 -11
  75. package/runtime/arcane/entities/Weather.js +5 -2
  76. package/runtime/arcane/modules/AI.js +491 -165
  77. package/runtime/arcane/modules/AIPreferenceRuntime.js +5 -2
  78. package/runtime/arcane/modules/AIPreferenceTuple.js +9 -6
  79. package/runtime/arcane/modules/AIProviderRuntime.js +88 -85
  80. package/runtime/arcane/modules/AIResponseURLPolicy.js +148 -62
  81. package/runtime/arcane/modules/AIRuntimeState.js +29 -26
  82. package/runtime/arcane/modules/AnsiText.js +4 -1
  83. package/runtime/arcane/modules/ApiModelDatabase.js +22 -19
  84. package/runtime/arcane/modules/AppDataScope.js +8 -5
  85. package/runtime/arcane/modules/ArcaneCommunicationBridge.js +4 -1
  86. package/runtime/arcane/modules/ArcaneNavigationPolicy.js +8 -5
  87. package/runtime/arcane/modules/ArcaneNetworkPolicy.js +18 -15
  88. package/runtime/arcane/modules/AsyncBoundary.js +13 -10
  89. package/runtime/arcane/modules/BrowserTestSuite.js +19 -16
  90. package/runtime/arcane/modules/CalculatorEngine.js +5 -2
  91. package/runtime/arcane/modules/ChatRecords.js +18 -15
  92. package/runtime/arcane/modules/CommunicationAppController.js +9 -6
  93. package/runtime/arcane/modules/CommunicationHub.js +9 -6
  94. package/runtime/arcane/modules/CommunicationPreferences.js +4 -1
  95. package/runtime/arcane/modules/CommunicationProviderRegistry.js +4 -1
  96. package/runtime/arcane/modules/ComponentContracts.js +56 -53
  97. package/runtime/arcane/modules/ConfiguredAIChatSession.js +30 -27
  98. package/runtime/arcane/modules/ConversationActionItems.js +15 -12
  99. package/runtime/arcane/modules/ConversationClosingReport.js +11 -8
  100. package/runtime/arcane/modules/ConversationTimebox.js +28 -25
  101. package/runtime/arcane/modules/CoreLocalModelCatalog.js +17 -14
  102. package/runtime/arcane/modules/DBLS.js +7 -4
  103. package/runtime/arcane/modules/DBOPFS.js +7 -7
  104. package/runtime/arcane/modules/DBOPFSDocumentLibrary.js +34 -31
  105. package/runtime/arcane/modules/DevelopmentWorkspace.js +4 -1
  106. package/runtime/arcane/modules/DirectoryPicker.js +8 -5
  107. package/runtime/arcane/modules/DocumentLexicalSearch.js +11 -8
  108. package/runtime/arcane/modules/DocumentNavigation.js +7 -4
  109. package/runtime/arcane/modules/Errors.js +28 -25
  110. package/runtime/arcane/modules/HTMLImport.js +7 -4
  111. package/runtime/arcane/modules/IsolatedModelQuestionRunner.js +15 -12
  112. package/runtime/arcane/modules/LocalAIReadiness.js +21 -18
  113. package/runtime/arcane/modules/LocalAIReadinessController.js +6 -3
  114. package/runtime/arcane/modules/MD.js +1 -1
  115. package/runtime/arcane/modules/Mail.js +46 -43
  116. package/runtime/arcane/modules/MailOutbox.mjs +48 -45
  117. package/runtime/arcane/modules/MailTransport.mjs +29 -26
  118. package/runtime/arcane/modules/MemoryRecords.js +7 -4
  119. package/runtime/arcane/modules/MessageAdvisory.js +6 -3
  120. package/runtime/arcane/modules/ModelDefinition.js +7 -4
  121. package/runtime/arcane/modules/Ollama.js +6 -3
  122. package/runtime/arcane/modules/OllamaModelIdentifier.js +4 -1
  123. package/runtime/arcane/modules/OpenMeteoWeatherProvider.js +18 -15
  124. package/runtime/arcane/modules/PersistentAIChatSession.js +33 -30
  125. package/runtime/arcane/modules/PreferenceStore.js +20 -17
  126. package/runtime/arcane/modules/PreparedSpeech.js +485 -0
  127. package/runtime/arcane/modules/Questionnaire.js +6 -3
  128. package/runtime/arcane/modules/RecordLinkIndex.js +4 -1
  129. package/runtime/arcane/modules/RecordPassageIndex.js +9 -6
  130. package/runtime/arcane/modules/RecordReviewStore.js +12 -9
  131. package/runtime/arcane/modules/RiskSignalAnalyzer.js +4 -1
  132. package/runtime/arcane/modules/ScopedOPFSCache.js +6 -3
  133. package/runtime/arcane/modules/ScreenCapture.js +20 -17
  134. package/runtime/arcane/modules/SpeechPlayback.js +29 -26
  135. package/runtime/arcane/modules/StaticDocumentCatalog.js +33 -30
  136. package/runtime/arcane/modules/SystemAppearance.js +5 -2
  137. package/runtime/arcane/modules/SystemToolRegistry.js +6 -3
  138. package/runtime/arcane/modules/TerminalClient.js +14 -11
  139. package/runtime/arcane/modules/TerminalCommandRegistry.js +4 -1
  140. package/runtime/arcane/modules/ThemeBootstrap.js +9 -6
  141. package/runtime/arcane/modules/ThemeManager.js +5 -2
  142. package/runtime/arcane/modules/TimeGuard.js +1 -1
  143. package/runtime/arcane/modules/ToolCallRouter.js +11 -8
  144. package/runtime/arcane/modules/WaitForComponent.js +19 -16
  145. package/runtime/arcane/modules/YouTubeMedia.js +4 -1
  146. package/runtime/strong-type/index.js +1276 -352
  147. package/runtime/strong-type/package.json +69 -45
  148. package/src/app-descriptor.mjs +17 -14
  149. package/src/application-tests.mjs +4 -1
  150. package/src/cli/main.mjs +8 -5
  151. package/src/constants.mjs +4 -1
  152. package/src/dev-server.mjs +8 -5
  153. package/src/doctor.mjs +5 -2
  154. package/src/dom-event-instrumentation.mjs +24 -20
  155. package/src/errors.mjs +7 -3
  156. package/src/event-manager.mjs +111 -108
  157. package/src/event-queue.mjs +8 -5
  158. package/src/events.mjs +12 -9
  159. package/src/import-map.mjs +35 -27
  160. package/src/installed-sdk-runtime.mjs +4 -1
  161. package/src/integrated-provider-loader.mjs +9 -6
  162. package/src/mail-credentials.mjs +16 -13
  163. package/src/mail-server.mjs +53 -50
  164. package/src/mail.mjs +18 -15
  165. package/src/native-plan.mjs +12 -9
  166. package/src/native-provider-loader.mjs +7 -4
  167. package/src/packager/core.mjs +18 -15
  168. package/src/process.mjs +6 -3
  169. package/src/release-bundle.mjs +14 -11
  170. package/src/runtime.mjs +4 -1
  171. package/src/scaffold.mjs +9 -6
  172. package/src/sdk-browser-runtime.mjs +4 -1
  173. package/src/source-server.mjs +17 -14
  174. package/src/targets/index.mjs +5 -2
  175. package/src/templates/workspace-template.mjs +13 -6
  176. package/src/testing-loader.mjs +7 -4
  177. package/src/testing.mjs +10 -7
  178. package/src/toolchain.mjs +13 -10
  179. package/src/update-check.mjs +9 -6
  180. package/src/workspace-operation-lock.mjs +14 -11
  181. package/src/workspace-runtime.mjs +4 -1
  182. package/src/workspace.mjs +17 -14
  183. package/runtime/arcane/modules/AIResponseLength.js +0 -32
@@ -1,3 +1,4 @@
1
+ import Is from "../dependencies/strong-type/index.js";
1
2
  import {
2
3
  createBrowserSpeechAuthority,
3
4
  isBrowserSpeechArtifactGraph,
@@ -7,6 +8,8 @@ import {
7
8
  } from "./browser-speech-artifacts.mjs";
8
9
  import { stripSpeechFormatting } from "../speech-text.mjs";
9
10
 
11
+ const is = new Is(false);
12
+
10
13
  const completeValue = (value) => value;
11
14
  import {
12
15
  createSpeechWorkerClient,
@@ -46,7 +49,7 @@ function providerError(code, message, cause, reason) {
46
49
  ? "AbortError"
47
50
  : "ArcaneBrowserSpeechProviderError";
48
51
  error.code = code;
49
- error.reason = typeof reason === "string" && reason
52
+ error.reason = is.string(reason) && reason
50
53
  ? reason
51
54
  : UNMAPPED_PROVIDER_REASON;
52
55
  PROVIDER_ERRORS.add(error);
@@ -54,7 +57,7 @@ function providerError(code, message, cause, reason) {
54
57
  }
55
58
 
56
59
  function isBrowserSpeechProviderError(value) {
57
- return typeof value === "object"
60
+ return is.object(value)
58
61
  && value !== null
59
62
  && PROVIDER_ERRORS.has(value);
60
63
  }
@@ -69,7 +72,7 @@ function trustedLoadFailure(error, role) {
69
72
  if (isTrustedSpeechError(error)) return error;
70
73
  return providerError(
71
74
  "ARCANE_AI_PROVIDER_LOAD_FAILED",
72
- typeof error?.message === "string" && error.message
75
+ is.string(error?.message) && error.message
73
76
  ? error.message
74
77
  : `The browser ${role} provider load was rejected.`,
75
78
  error,
@@ -81,7 +84,7 @@ function trustedRequestFailure(error, role) {
81
84
  if (isTrustedSpeechError(error)) return error;
82
85
  return providerError(
83
86
  "ARCANE_AI_PROVIDER_REQUEST_FAILED",
84
- typeof error?.message === "string" && error.message
87
+ is.string(error?.message) && error.message
85
88
  ? error.message
86
89
  : `The browser ${role} engine operation was rejected.`,
87
90
  error,
@@ -95,7 +98,7 @@ function trustedWorkerFailure(error, role) {
95
98
  if (isTrustedSpeechError(error)) return error;
96
99
  return providerError(
97
100
  "ARCANE_AI_WORKER_MESSAGE_REJECTED",
98
- typeof error?.message === "string" && error.message
101
+ is.string(error?.message) && error.message
99
102
  ? error.message
100
103
  : `The browser ${role} Worker returned an unreadable error envelope.`,
101
104
  error,
@@ -107,7 +110,7 @@ function trustedLifecycleFailure(error, role, operation) {
107
110
  if (isTrustedSpeechError(error)) return error;
108
111
  return providerError(
109
112
  "ARCANE_AI_INVALID_REQUEST",
110
- typeof error?.message === "string" && error.message
113
+ is.string(error?.message) && error.message
111
114
  ? error.message
112
115
  : `The browser ${role} ${operation} context could not be read.`,
113
116
  error,
@@ -116,8 +119,8 @@ function trustedLifecycleFailure(error, role, operation) {
116
119
  }
117
120
 
118
121
  function resolveReason(reason, fallback = UNMAPPED_PROVIDER_REASON) {
119
- const resolved = typeof reason === "function" ? reason() : reason;
120
- return typeof resolved === "string" && resolved ? resolved : fallback;
122
+ const resolved = is.function(reason) ? reason() : reason;
123
+ return is.string(resolved) && resolved ? resolved : fallback;
121
124
  }
122
125
 
123
126
  function abortError(signal, reason = UNMAPPED_PROVIDER_REASON) {
@@ -140,7 +143,7 @@ function workerFailureCode(error) {
140
143
  }
141
144
 
142
145
  function requiredIdentifier(value, label) {
143
- if (typeof value !== "string" || !value.trim()) {
146
+ if (!is.string(value) || !value.trim()) {
144
147
  throw new TypeError(`${label} must be a nonempty trimmed string.`);
145
148
  }
146
149
  return value.trim();
@@ -159,7 +162,7 @@ function normalizeSpeechExecution(role, execution) {
159
162
  maxConcurrentRequests: DEFAULT_TTS_MAX_CONCURRENT_REQUESTS,
160
163
  });
161
164
  }
162
- if (!execution || typeof execution !== "object" || Array.isArray(execution)) {
165
+ if (!execution || !is.object(execution) || is.array(execution)) {
163
166
  throw new TypeError("Browser Kokoro execution must be a plain data record.");
164
167
  }
165
168
  const prototype = Object.getPrototypeOf(execution);
@@ -185,7 +188,7 @@ function normalizeSpeechExecution(role, execution) {
185
188
  throw new TypeError('Browser Kokoro execution.device must be "auto", "webgpu", or "wasm".');
186
189
  }
187
190
  if (
188
- !Number.isSafeInteger(maxConcurrentRequests)
191
+ !is.safeInteger(maxConcurrentRequests)
189
192
  || maxConcurrentRequests < 1
190
193
  || maxConcurrentRequests > MAX_TTS_CONCURRENT_REQUESTS
191
194
  ) {
@@ -320,15 +323,15 @@ function linkedAbortFailure(linked, fallbackReason) {
320
323
  function isAbortSignal(value) {
321
324
  return value === null
322
325
  || value === undefined
323
- || (typeof value === "object"
324
- && typeof value.aborted === "boolean"
325
- && typeof value.addEventListener === "function"
326
- && typeof value.removeEventListener === "function");
326
+ || (is.object(value)
327
+ && is.boolean(value.aborted)
328
+ && is.function(value.addEventListener)
329
+ && is.function(value.removeEventListener));
327
330
  }
328
331
 
329
332
  function providerContext(context, role, operation) {
330
333
  if (context === undefined) return completeValue({ signal: null });
331
- if (!context || typeof context !== "object" || Array.isArray(context)) {
334
+ if (!context || !is.object(context) || is.array(context)) {
332
335
  throw providerError(
333
336
  "ARCANE_AI_INVALID_REQUEST",
334
337
  `Browser ${role} ${operation} context must be an object.`,
@@ -471,7 +474,7 @@ function genericPayloadDescriptors(
471
474
  }
472
475
  const descriptors = Object.getOwnPropertyDescriptors(payload);
473
476
  for (const key of Reflect.ownKeys(descriptors)) {
474
- if (typeof key === "symbol" || !allowedKeys.includes(key)) {
477
+ if (is.symbol(key) || !allowedKeys.includes(key)) {
475
478
  throw providerError(
476
479
  "ARCANE_AI_INVALID_REQUEST",
477
480
  `${label} contains an unknown field.`,
@@ -502,7 +505,7 @@ function genericPayloadDescriptors(
502
505
  }
503
506
 
504
507
  function audioMimeEssence(value, label, reasonPrefix) {
505
- if (typeof value !== "string") {
508
+ if (!is.string(value)) {
506
509
  throw providerError(
507
510
  "ARCANE_AI_INVALID_REQUEST",
508
511
  `${label} must be an audio MIME type.`,
@@ -586,7 +589,7 @@ function observeLoadOperation(record, { signal, progress }, role) {
586
589
  };
587
590
  const observer = completeValue({
588
591
  progress(value) {
589
- if (settled || typeof progress !== "function") return;
592
+ if (settled || !is.function(progress)) return;
590
593
  try {
591
594
  progress(value);
592
595
  } catch (error) {
@@ -642,7 +645,7 @@ async function decodeSharedTranscriptionPayload(
642
645
  operationSubject: "stt-transcription",
643
646
  });
644
647
  const audio = descriptors.audio.value;
645
- if (typeof Blob !== "function") {
648
+ if (!is.function(globalThis.Blob)) {
646
649
  throw providerError(
647
650
  "ARCANE_AI_INVALID_REQUEST",
648
651
  "Shared speech transcription requires the browser Blob constructor.",
@@ -650,7 +653,7 @@ async function decodeSharedTranscriptionPayload(
650
653
  "stt-transcription-blob-constructor-unavailable",
651
654
  );
652
655
  }
653
- if (!(audio instanceof Blob)) {
656
+ if (!is.instanceCheck(audio, Blob)) {
654
657
  throw providerError(
655
658
  "ARCANE_AI_INVALID_REQUEST",
656
659
  "Shared speech transcription audio must be a Blob or File.",
@@ -685,7 +688,7 @@ async function decodeSharedTranscriptionPayload(
685
688
  }
686
689
  const OfflineAudioContext = globalThis.OfflineAudioContext
687
690
  ?? globalThis.webkitOfflineAudioContext;
688
- if (typeof OfflineAudioContext !== "function") {
691
+ if (!is.function(OfflineAudioContext)) {
689
692
  throw providerError(
690
693
  "ARCANE_AI_AUDIO_DECODE_UNAVAILABLE",
691
694
  `Shared Blob transcription requires OfflineAudioContext decoding at ${sampleRate} Hz.`,
@@ -704,7 +707,7 @@ async function decodeSharedTranscriptionPayload(
704
707
  "stt-browser-offline-audio-context-construction-rejected",
705
708
  );
706
709
  }
707
- if (typeof decoder.decodeAudioData !== "function") {
710
+ if (!is.function(decoder.decodeAudioData)) {
708
711
  throw providerError(
709
712
  "ARCANE_AI_AUDIO_DECODE_UNAVAILABLE",
710
713
  "Shared Blob transcription requires browser audio decoding.",
@@ -735,7 +738,7 @@ async function decodeSharedTranscriptionPayload(
735
738
  "stt-browser-audio-decode-operation-rejected",
736
739
  );
737
740
  }
738
- if (!decoded || typeof decoded !== "object") {
741
+ if (!decoded || !is.object(decoded)) {
739
742
  throw providerError(
740
743
  "ARCANE_AI_AUDIO_DECODE_FAILED",
741
744
  "Decoded speech audio must be an AudioBuffer-like object.",
@@ -751,7 +754,7 @@ async function decodeSharedTranscriptionPayload(
751
754
  "stt-browser-decoded-audio-sample-rate-mismatch",
752
755
  );
753
756
  }
754
- if (!Number.isSafeInteger(decoded.length)) {
757
+ if (!is.safeInteger(decoded.length)) {
755
758
  throw providerError(
756
759
  "ARCANE_AI_AUDIO_DECODE_FAILED",
757
760
  "Decoded speech audio frame length must be a safe integer.",
@@ -767,7 +770,7 @@ async function decodeSharedTranscriptionPayload(
767
770
  "stt-browser-decoded-audio-empty",
768
771
  );
769
772
  }
770
- if (!Number.isSafeInteger(decoded.numberOfChannels)) {
773
+ if (!is.safeInteger(decoded.numberOfChannels)) {
771
774
  throw providerError(
772
775
  "ARCANE_AI_AUDIO_DECODE_FAILED",
773
776
  "Decoded speech audio channel count must be a safe integer.",
@@ -783,7 +786,7 @@ async function decodeSharedTranscriptionPayload(
783
786
  "stt-browser-decoded-audio-channel-count-zero",
784
787
  );
785
788
  }
786
- if (typeof decoded.getChannelData !== "function") {
789
+ if (!is.function(decoded.getChannelData)) {
787
790
  throw providerError(
788
791
  "ARCANE_AI_AUDIO_DECODE_FAILED",
789
792
  "Decoded speech audio must expose getChannelData().",
@@ -804,7 +807,7 @@ async function decodeSharedTranscriptionPayload(
804
807
  "stt-browser-decoded-audio-channel-read-rejected",
805
808
  );
806
809
  }
807
- if (!(channel instanceof Float32Array)) {
810
+ if (!is.instanceCheck(channel, Float32Array)) {
808
811
  throw providerError(
809
812
  "ARCANE_AI_AUDIO_DECODE_FAILED",
810
813
  "Decoded speech audio channels must be Float32Array values.",
@@ -827,7 +830,7 @@ async function decodeSharedTranscriptionPayload(
827
830
  let sample = 0;
828
831
  for (const channel of channels) sample += channel[index];
829
832
  sample /= channels.length;
830
- if (!Number.isFinite(sample)) {
833
+ if (!is.finite(sample)) {
831
834
  throw providerError(
832
835
  "ARCANE_AI_AUDIO_DECODE_FAILED",
833
836
  "Decoded speech audio contains a non-finite sample.",
@@ -854,7 +857,7 @@ function cloneNativeTranscriptionPayload(payload, authority) {
854
857
  );
855
858
  assertPayloadModel(payload, authority, { operationSubject: "stt-transcription" });
856
859
  const sampleRate = inputSampleRate(authority);
857
- if (!(descriptors.audio.value instanceof Float32Array)) {
860
+ if (!is.instanceCheck(descriptors.audio.value, Float32Array)) {
858
861
  throw providerError(
859
862
  "ARCANE_AI_INVALID_REQUEST",
860
863
  "Whisper requires Float32Array audio.",
@@ -879,7 +882,7 @@ function cloneNativeTranscriptionPayload(payload, authority) {
879
882
  );
880
883
  }
881
884
  for (const sample of descriptors.audio.value) {
882
- if (!Number.isFinite(sample)) {
885
+ if (!is.finite(sample)) {
883
886
  throw providerError(
884
887
  "ARCANE_AI_INVALID_REQUEST",
885
888
  "Whisper audio must contain only finite Float32 PCM samples.",
@@ -933,12 +936,12 @@ function normalizeSynthesisPayload(payload, authority, speechInputPrepared) {
933
936
  assertPayloadModel(payload, authority, { operationSubject: "tts-synthesis" });
934
937
  textValue = descriptors.text.value;
935
938
  }
936
- const suppliedText = typeof textValue === "string" ? textValue : "";
939
+ const suppliedText = is.string(textValue) ? textValue : "";
937
940
  const text = speechInputPrepared === true ? suppliedText : stripSpeechFormatting(suppliedText);
938
941
  const voiceValue = Object.hasOwn(descriptors, "voice")
939
942
  ? descriptors.voice.value
940
943
  : authority.defaultVoice;
941
- const voice = typeof voiceValue === "string" ? voiceValue : "";
944
+ const voice = is.string(voiceValue) ? voiceValue : "";
942
945
  const speed = Object.hasOwn(descriptors, "speed") ? descriptors.speed.value : 1;
943
946
  if (!text.trim()) {
944
947
  throw providerError(
@@ -956,7 +959,7 @@ function normalizeSynthesisPayload(payload, authority, speechInputPrepared) {
956
959
  "tts-synthesis-voice-empty",
957
960
  );
958
961
  }
959
- if (!Number.isFinite(speed) || speed <= 0) {
962
+ if (!is.finite(speed) || speed <= 0) {
960
963
  throw providerError(
961
964
  "ARCANE_AI_INVALID_REQUEST",
962
965
  "Kokoro speed must be greater than 0.",
@@ -987,7 +990,7 @@ async function normalizeRequestPayload(
987
990
  cancellationReason,
988
991
  speechInputPrepared,
989
992
  ) {
990
- if (!payload || typeof payload !== "object" || Array.isArray(payload)) {
993
+ if (!payload || !is.object(payload) || is.array(payload)) {
991
994
  throw providerError(
992
995
  "ARCANE_AI_INVALID_REQUEST",
993
996
  "Speech request payload must be an object.",
@@ -1001,8 +1004,8 @@ async function normalizeRequestPayload(
1001
1004
  const audio = Object.getOwnPropertyDescriptor(payload, "audio");
1002
1005
  if (Object.hasOwn(payload, "mimeType")
1003
1006
  || (Object.hasOwn(audio ?? {}, "value")
1004
- && typeof Blob === "function"
1005
- && audio.value instanceof Blob)) {
1007
+ && is.function(globalThis.Blob)
1008
+ && is.instanceCheck(audio.value, Blob))) {
1006
1009
  return decodeSharedTranscriptionPayload(
1007
1010
  payload,
1008
1011
  authority,
@@ -1017,7 +1020,7 @@ async function normalizeRequestPayload(
1017
1020
 
1018
1021
  function encodeSharedSynthesisResult(result, authority) {
1019
1022
  const sampleRate = outputSampleRate(authority);
1020
- if (!result || typeof result !== "object") {
1023
+ if (!result || !is.object(result)) {
1021
1024
  throw providerError(
1022
1025
  "ARCANE_AI_INVALID_PROVIDER_RESULT",
1023
1026
  "Browser Kokoro must return a synthesis result object.",
@@ -1025,7 +1028,7 @@ function encodeSharedSynthesisResult(result, authority) {
1025
1028
  "tts-synthesis-result-not-object",
1026
1029
  );
1027
1030
  }
1028
- if (!(result.audio instanceof Float32Array)) {
1031
+ if (!is.instanceCheck(result.audio, Float32Array)) {
1029
1032
  throw providerError(
1030
1033
  "ARCANE_AI_INVALID_PROVIDER_RESULT",
1031
1034
  "Browser Kokoro must return Float32 PCM audio.",
@@ -1080,7 +1083,7 @@ function encodeSharedSynthesisResult(result, authority) {
1080
1083
  view.setUint32(40, result.audio.length * 2, true);
1081
1084
  for (let index = 0; index < result.audio.length; index += 1) {
1082
1085
  const sample = result.audio[index];
1083
- if (!Number.isFinite(sample)) {
1086
+ if (!is.finite(sample)) {
1084
1087
  throw providerError(
1085
1088
  "ARCANE_AI_INVALID_PROVIDER_RESULT",
1086
1089
  "Browser Kokoro returned a non-finite PCM sample.",
@@ -1115,7 +1118,7 @@ function createBrowserSpeechProvider({
1115
1118
  if (localOnly !== true) {
1116
1119
  throw new TypeError("Browser speech providers are localOnly.");
1117
1120
  }
1118
- if (typeof offline !== "boolean") {
1121
+ if (!is.boolean(offline)) {
1119
1122
  throw new TypeError("Browser speech offline must be a boolean.");
1120
1123
  }
1121
1124
  if (!isDbopfsSpeechArtifactStore(store)) {
@@ -1446,7 +1449,7 @@ function createBrowserSpeechProvider({
1446
1449
  } catch (error) {
1447
1450
  return Promise.reject(trustedLoadFailure(error, role));
1448
1451
  }
1449
- if (loadProgress !== undefined && typeof loadProgress !== "function") {
1452
+ if (loadProgress !== undefined && !is.function(loadProgress)) {
1450
1453
  return Promise.reject(providerError(
1451
1454
  "ARCANE_AI_INVALID_REQUEST",
1452
1455
  "Browser speech load progress must be a function when supplied.",
@@ -1514,7 +1517,7 @@ function createBrowserSpeechProvider({
1514
1517
  prepared,
1515
1518
  released: false,
1516
1519
  };
1517
- record.warnings = Array.isArray(prepared.warnings)
1520
+ record.warnings = is.array(prepared.warnings)
1518
1521
  ? completeValue([...prepared.warnings])
1519
1522
  : NO_PROVIDER_WARNINGS;
1520
1523
  lastWarnings = record.warnings;