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,6 @@
1
+ import Is from 'strong-type';
2
+ const is=new Is(false);
3
+
1
4
  import {createArcaneEventSource} from 'arcane-os/event-manager';
2
5
  import TerminalSession from '../entities/TerminalSession.js';
3
6
 
@@ -47,17 +50,17 @@ function terminalEventReason(type){
47
50
 
48
51
  function terminalPublicDetail(detail,type,reason){
49
52
  const id=detail?.session?.id??detail?.sessionId;
50
- const output=typeof detail?.data==='string'?detail.data:'';
53
+ const output=is.string(detail?.data)?detail.data:'';
51
54
  const code=type==='error'
52
- ?typeof detail?.code==='string'&&detail.code
55
+ ?is.string(detail?.code)&&detail.code
53
56
  ?detail.code
54
57
  :TERMINAL_CLIENT_ERROR_CODES.sessionHostError
55
58
  :null;
56
59
  return {
57
- ...(typeof id==='string'&&id?{id}:{}),
58
- ...(typeof detail?.stream==='string'?{stream:detail.stream}:{}),
59
- ...(typeof detail?.data==='string'?{data:output}:{}),
60
- ...(typeof detail?.session?.state==='string'?{status:detail.session.state}:{}),
60
+ ...(is.string(id)&&id?{id}:{}),
61
+ ...(is.string(detail?.stream)?{stream:detail.stream}:{}),
62
+ ...(is.string(detail?.data)?{data:output}:{}),
63
+ ...(is.string(detail?.session?.state)?{status:detail.session.state}:{}),
61
64
  ...(code?{code}:{}),
62
65
  reason
63
66
  };
@@ -93,8 +96,8 @@ export default class TerminalClient extends EventTarget{
93
96
  type,
94
97
  receiveTerminalHostEvent
95
98
  );
96
- if(typeof unsubscribe!=='function'
97
- &&typeof unsubscribe?.dispose!=='function'){
99
+ if(!is.function(unsubscribe)
100
+ &&!is.function(unsubscribe?.dispose)){
98
101
  throw terminalClientError(
99
102
  TERMINAL_CLIENT_ERROR_CODES.hostEventSubscriptionInvalid,
100
103
  TERMINAL_CLIENT_REASONS.hostEventSubscriptionInvalid,
@@ -144,7 +147,7 @@ export default class TerminalClient extends EventTarget{
144
147
 
145
148
  #assertCapability(method){
146
149
  this.#assertOpen();
147
- if(typeof this.api?.[method]!=='function'){
150
+ if(!is.function(this.api?.[method])){
148
151
  throw terminalClientError(
149
152
  TERMINAL_CLIENT_ERROR_CODES.capabilityUnavailable,
150
153
  TERMINAL_CLIENT_REASONS.capabilityUnavailable,
@@ -163,7 +166,7 @@ export default class TerminalClient extends EventTarget{
163
166
  let firstError=null;
164
167
  for(const subscription of this.unsubscribe){
165
168
  try{
166
- if(typeof subscription==='function')subscription();
169
+ if(is.function(subscription))subscription();
167
170
  else subscription.dispose();
168
171
  }catch(error){
169
172
  firstError??=error;
@@ -179,7 +182,7 @@ export default class TerminalClient extends EventTarget{
179
182
  const result=await this.api.start(options);
180
183
  if(this.#destroyed||generation!==this.#generation){
181
184
  let cleanupError=null;
182
- if(typeof result?.id==='string'&&typeof this.api?.close==='function'){
185
+ if(is.string(result?.id)&&is.function(this.api?.close)){
183
186
  try{
184
187
  await this.api.close(result.id);
185
188
  }catch(error){
@@ -1,3 +1,6 @@
1
+ import Is from 'strong-type';
2
+ const is=new Is(false);
3
+
1
4
  const COMMAND_PATTERN=/^(?:[a-z][a-z0-9:_-]{0,63}|\?)$/;
2
5
 
3
6
  export function splitCommandLine(input=''){
@@ -28,7 +31,7 @@ export default class TerminalCommandRegistry{
28
31
  register({name,aliases=[],description='',usage='',run}={}){
29
32
  const normalized=String(name||'').trim().toLowerCase();
30
33
  if(!COMMAND_PATTERN.test(normalized)) throw new TypeError('Terminal command names must use lowercase command syntax.');
31
- if(typeof run!=='function') throw new TypeError(`Terminal command ${normalized} requires a run function.`);
34
+ if(!is.function(run)) throw new TypeError(`Terminal command ${normalized} requires a run function.`);
32
35
  const record=Object.freeze({name:normalized,aliases:Object.freeze(aliases.map(alias=>String(alias).toLowerCase())),description:String(description),usage:String(usage||normalized),run});
33
36
  for(const key of [record.name,...record.aliases]){
34
37
  if(!COMMAND_PATTERN.test(key)||this.commands.has(key)) throw new TypeError(`Duplicate or invalid terminal command: ${key}`);
@@ -1,3 +1,6 @@
1
+ import Is from 'strong-type';
2
+ const is=new Is(false);
3
+
1
4
  import { arcaneLogging } from 'arcane-os/logging';
2
5
  import {loadAndApplyTheme} from './ThemeManager.js';
3
6
  import {createArcaneEventSource} from 'arcane-os/event-manager';
@@ -16,7 +19,7 @@ const themeBootstrapEvents=createArcaneEventSource(
16
19
 
17
20
  function installAppearanceListener(ready){
18
21
  const hostEvents=globalThis.Arcane?.events;
19
- if(typeof hostEvents?.on!=='function'||globalThis[listenerKey]){
22
+ if(!is.function(hostEvents?.on)||globalThis[listenerKey]){
20
23
  return;
21
24
  }
22
25
 
@@ -26,11 +29,11 @@ function installAppearanceListener(ready){
26
29
  function forwardAppearanceChange(detail={}){
27
30
  themeBootstrapOperationSequence+=1;
28
31
  const forwarded={
29
- scheme:typeof detail?.scheme==='string'?detail.scheme:null,
30
- effectiveScheme:typeof detail?.effectiveScheme==='string'
32
+ scheme:is.string(detail?.scheme)?detail.scheme:null,
33
+ effectiveScheme:is.string(detail?.effectiveScheme)
31
34
  ?detail.effectiveScheme
32
35
  :null,
33
- source:typeof detail?.source==='string'?detail.source:null,
36
+ source:is.string(detail?.source)?detail.source:null,
34
37
  reason:'host-appearance-changed'
35
38
  };
36
39
  themeBootstrapEvents.dispatch(
@@ -56,7 +59,7 @@ function installAppearanceListener(ready){
56
59
  return false;
57
60
  }
58
61
  active=false;
59
- if(typeof hostUnsubscribe==='function'){
62
+ if(is.function(hostUnsubscribe)){
60
63
  hostUnsubscribe();
61
64
  }
62
65
  if(globalThis[listenerKey]===dispose){
@@ -94,7 +97,7 @@ export function bootstrapArcaneTheme(options={}){
94
97
 
95
98
  export function disposeArcaneThemeBootstrap(){
96
99
  const dispose=globalThis[listenerKey];
97
- return typeof dispose==='function'?dispose():false;
100
+ return is.function(dispose)?dispose():false;
98
101
  }
99
102
 
100
103
  export const arcaneThemeReady=bootstrapArcaneTheme();
@@ -1,3 +1,6 @@
1
+ import Is from 'strong-type';
2
+ const is=new Is(false);
3
+
1
4
  import Theme,{arcaneDarkThemeTokens,arcaneLightThemeTokens} from '../entities/Theme.js';
2
5
  import PreferenceStore from './PreferenceStore.js';
3
6
  import {applyAppearancePreferences,createAppearancePreferenceStore} from './AppearancePreferences.js';
@@ -135,8 +138,8 @@ export default class ThemeManager{
135
138
  publicDetail:{mode:detail.mode,reason}
136
139
  }
137
140
  );
138
- if(typeof globalThis.CustomEvent==='function'
139
- &&typeof globalThis.dispatchEvent==='function'){
141
+ if(is.function(globalThis.CustomEvent)
142
+ &&is.function(globalThis.dispatchEvent)){
140
143
  projectArcaneDOMEvent(globalThis,occurrence);
141
144
  }
142
145
  return occurrence;
@@ -1,4 +1,4 @@
1
- import Is from '../../node_modules/strong-type/index.js';
1
+ import Is from 'strong-type';
2
2
  import './DBOPFS.js';
3
3
  import UserEntity from '../entities/User.js';
4
4
  import {
@@ -1,7 +1,10 @@
1
+ import Is from 'strong-type';
2
+ const is=new Is(false);
3
+
1
4
  import { arcaneLogging } from 'arcane-os/logging';
2
5
  function parseArguments(value,name=''){
3
6
  let parsed=value;
4
- if(typeof parsed==='string'){
7
+ if(is.string(parsed)){
5
8
  try{
6
9
  parsed=JSON.parse(parsed);
7
10
  }catch(error){
@@ -9,15 +12,15 @@ function parseArguments(value,name=''){
9
12
  throw new Error(`Tool ${name} returned invalid JSON arguments.`);
10
13
  }
11
14
  }
12
- const prototype=parsed&&typeof parsed==='object'
15
+ const prototype=parsed&&is.object(parsed)
13
16
  ?Object.getPrototypeOf(parsed)
14
17
  :undefined;
15
18
  if(
16
19
  !parsed
17
- ||typeof parsed!=='object'
18
- ||Array.isArray(parsed)
20
+ ||!is.object(parsed)
21
+ ||is.array(parsed)
19
22
  ||(prototype!==Object.prototype&&prototype!==null)
20
- ||typeof parsed.message!=='string'
23
+ ||!is.string(parsed.message)
21
24
  ||!parsed.message.trim()
22
25
  ){
23
26
  const error=new Error(
@@ -32,7 +35,7 @@ function parseArguments(value,name=''){
32
35
  function getResponseCalls(response={}){
33
36
  const calls=response?.choices?.[0]?.message?.tool_calls;
34
37
 
35
- if(!Array.isArray(calls)||!calls.length){
38
+ if(!is.array(calls)||!calls.length){
36
39
  throw new Error('AI response did not contain a tool call.');
37
40
  }
38
41
 
@@ -40,7 +43,7 @@ function getResponseCalls(response={}){
40
43
  }
41
44
 
42
45
  function dispatch(name='',argumentsValue='',handlers={}){
43
- if(typeof handlers[name]!=='function'){
46
+ if(!is.function(handlers[name])){
44
47
  throw new Error(`No handler is registered for tool ${name}.`);
45
48
  }
46
49
 
@@ -75,7 +78,7 @@ async function handleResponse(response={},handlers={}){
75
78
  }
76
79
 
77
80
  async function handleStreamedCalls(calls={},handlers={}){
78
- if(!calls||typeof calls!=='object'||Array.isArray(calls)){
81
+ if(!calls||!is.object(calls)||is.array(calls)){
79
82
  throw new Error('Streamed tool calls must be an object.');
80
83
  }
81
84
 
@@ -1,3 +1,6 @@
1
+ import Is from 'strong-type';
2
+ const is=new Is(false);
3
+
1
4
  const componentWaitErrorCodes={
2
5
  abortSignalInvalid:'ARCANE_COMPONENT_READINESS_ABORT_SIGNAL_INVALID',
3
6
  elementRequired:'ARCANE_COMPONENT_READINESS_ELEMENT_REQUIRED',
@@ -34,7 +37,7 @@ export const COMPONENT_WAIT_ERROR_CODES={...componentWaitErrorCodes};
34
37
  export const COMPONENT_WAIT_REASONS={...componentWaitReasons};
35
38
 
36
39
  function defineComponentWaitError(error,code,reason,cause){
37
- const priorCode=typeof error?.code==='string'&&error.code
40
+ const priorCode=is.string(error?.code)&&error.code
38
41
  ?error.code
39
42
  :null;
40
43
  try{
@@ -102,7 +105,7 @@ function componentWaitAbortError(reason){
102
105
  }
103
106
 
104
107
  function waitForComponent(element,options={}){
105
- if(!options||typeof options!=='object'||Array.isArray(options)){
108
+ if(!options||!is.object(options)||is.array(options)){
106
109
  return Promise.reject(
107
110
  componentWaitError(
108
111
  'Component readiness wait options must be an object.',
@@ -121,13 +124,13 @@ function waitForComponent(element,options={}){
121
124
  timeoutMs=0
122
125
  }=options;
123
126
 
124
- if(typeof errorEvent!=='string'
125
- ||!Array.isArray(methods)
127
+ if(!is.string(errorEvent)
128
+ ||!is.array(methods)
126
129
  ||methods.some(function invalidComponentMethod(method){
127
- return typeof method!=='string'||method.trim().length<1;
130
+ return !is.string(method)||method.trim().length<1;
128
131
  })
129
- ||typeof property!=='string'
130
- ||typeof event!=='string'){
132
+ ||!is.string(property)
133
+ ||!is.string(event)){
131
134
  return Promise.reject(
132
135
  componentWaitError(
133
136
  'Component readiness event, errorEvent, property, and methods options are invalid.',
@@ -137,7 +140,7 @@ function waitForComponent(element,options={}){
137
140
  )
138
141
  );
139
142
  }
140
- if(!Number.isFinite(timeoutMs)||timeoutMs<0){
143
+ if(!is.finite(timeoutMs)||timeoutMs<0){
141
144
  return Promise.reject(
142
145
  componentWaitError(
143
146
  'timeoutMs must be a non-negative finite number.',
@@ -149,10 +152,10 @@ function waitForComponent(element,options={}){
149
152
  }
150
153
  if(signal!==null
151
154
  &&(
152
- typeof signal!=='object'
153
- ||typeof signal.aborted!=='boolean'
154
- ||typeof signal.addEventListener!=='function'
155
- ||typeof signal.removeEventListener!=='function'
155
+ !is.object(signal)
156
+ ||!is.boolean(signal.aborted)
157
+ ||!is.function(signal.addEventListener)
158
+ ||!is.function(signal.removeEventListener)
156
159
  )){
157
160
  return Promise.reject(
158
161
  componentWaitError(
@@ -211,7 +214,7 @@ function waitForComponent(element,options={}){
211
214
  }
212
215
 
213
216
  return methods.every(function componentMethodAvailable(method){
214
- return typeof element[method]==='function';
217
+ return is.function(element[method]);
215
218
  });
216
219
  }
217
220
 
@@ -294,7 +297,7 @@ function waitForComponent(element,options={}){
294
297
  const error=new Error(
295
298
  detail?.message||'The component reported a loading error.'
296
299
  );
297
- const componentCode=typeof detail?.code==='string'
300
+ const componentCode=is.string(detail?.code)
298
301
  &&detail.code.trim()
299
302
  ?detail.code
300
303
  :null;
@@ -335,8 +338,8 @@ function waitForComponent(element,options={}){
335
338
  }
336
339
  if((event||errorEvent)
337
340
  &&(
338
- typeof element.addEventListener!=='function'
339
- ||typeof element.removeEventListener!=='function'
341
+ !is.function(element.addEventListener)
342
+ ||!is.function(element.removeEventListener)
340
343
  )){
341
344
  fail(
342
345
  componentWaitError(
@@ -1,3 +1,6 @@
1
+ import Is from 'strong-type';
2
+ const is=new Is(false);
3
+
1
4
  const RAW_ID=/^[A-Za-z0-9_-]+$/;
2
5
  export function parseYouTubeMedia(value){
3
6
  const raw=String(value||'').trim();if(!raw)throw new TypeError('Enter a YouTube video or playlist URL.');let url;
@@ -14,4 +17,4 @@ export function parseYouTubeMedia(value){
14
17
  if(playlist)return {type:'playlist',id:playlist};
15
18
  throw new TypeError('The address does not contain a supported video or playlist id.');
16
19
  }
17
- export function youtubeEmbedUrl(locator,{privacyEnhanced=false}={}){const item=typeof locator==='string'?parseYouTubeMedia(locator):locator;const origin=privacyEnhanced?'https://www.youtube-nocookie.com':'https://www.youtube.com';if(item.type==='playlist')return `${origin}/embed?listType=playlist&list=${encodeURIComponent(item.id)}`;const url=new URL(`${origin}/embed/${encodeURIComponent(item.id)}`);if(item.playlist)url.searchParams.set('list',item.playlist);url.searchParams.set('playsinline','1');return url.href;}
20
+ export function youtubeEmbedUrl(locator,{privacyEnhanced=false}={}){const item=is.string(locator)?parseYouTubeMedia(locator):locator;const origin=privacyEnhanced?'https://www.youtube-nocookie.com':'https://www.youtube.com';if(item.type==='playlist')return `${origin}/embed?listType=playlist&list=${encodeURIComponent(item.id)}`;const url=new URL(`${origin}/embed/${encodeURIComponent(item.id)}`);if(item.playlist)url.searchParams.set('list',item.playlist);url.searchParams.set('playsinline','1');return url.href;}