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
@@ -10,6 +10,9 @@
10
10
  <html-import id="configModal" class="modal" href="./arcane/components/modal.html?v=13"></html-import>
11
11
 
12
12
  <script type="module">
13
+ const {default:Is}=await import('strong-type');
14
+ const is=new Is(false);
15
+
13
16
  const {arcaneLogging}=await import('arcane-os/logging');
14
17
 
15
18
  const host=this;
@@ -150,7 +153,7 @@
150
153
  return {
151
154
  ...definition.chartOptions,
152
155
  labels:{...definition.chartOptions.labels},
153
- chartOptions:typeof definition.chartOptions.chartOptions==='object'
156
+ chartOptions:is.object(definition.chartOptions.chartOptions)
154
157
  &&definition.chartOptions.chartOptions!==null
155
158
  ?{...definition.chartOptions.chartOptions}
156
159
  :definition.chartOptions.chartOptions
@@ -158,7 +161,7 @@
158
161
  }
159
162
 
160
163
  function isVisible(definition={}){
161
- return typeof visibility[definition.key]==='boolean'
164
+ return is.boolean(visibility[definition.key])
162
165
  ?visibility[definition.key]
163
166
  :definition.defaultVisible;
164
167
  }
@@ -337,7 +340,7 @@
337
340
  chartOptions:{
338
341
  ...definition.chartOptions,
339
342
  labels:{...definition.chartOptions.labels},
340
- chartOptions:typeof definition.chartOptions.chartOptions==='object'
343
+ chartOptions:is.object(definition.chartOptions.chartOptions)
341
344
  &&definition.chartOptions.chartOptions!==null
342
345
  ?{...definition.chartOptions.chartOptions}
343
346
  :definition.chartOptions.chartOptions
@@ -14,6 +14,9 @@
14
14
  <html-import id="dataModal" class="modal" href="./arcane/components/modal.html?v=13"></html-import>
15
15
 
16
16
  <script type="module">
17
+ const {default:Is}=await import('strong-type');
18
+ const is=new Is(false);
19
+
17
20
  const {arcaneLogging}=await import('arcane-os/logging');
18
21
 
19
22
  const host=this;
@@ -29,7 +32,7 @@
29
32
  let operationGeneration=0;
30
33
  let destroyed=false;
31
34
 
32
- host.beforeOpen=typeof host.beforeOpen==='function'
35
+ host.beforeOpen=is.function(host.beforeOpen)
33
36
  ?host.beforeOpen
34
37
  :async function beforeOpen(){};
35
38
  host.open=openData;
@@ -30,6 +30,9 @@
30
30
  </div>
31
31
 
32
32
  <script type="module">
33
+ const {default:Is}=await import('strong-type');
34
+ const is=new Is(false);
35
+
33
36
  const {arcaneLogging}=await import('arcane-os/logging');
34
37
 
35
38
  const host=this;
@@ -98,7 +101,7 @@
98
101
  if(destroyed){
99
102
  return false;
100
103
  }
101
- if(!input||typeof input!=='object'||Array.isArray(input)){
104
+ if(!input||!is.object(input)||is.array(input)){
102
105
  throw new TypeError('Directory picker configuration must be an object.');
103
106
  }
104
107
  const replacesSelection=Object.prototype.hasOwnProperty.call(input,'picker')
@@ -109,7 +112,7 @@
109
112
  :disabled;
110
113
  const nextPicker=input.picker===undefined?picker:input.picker;
111
114
  if(input.picker!==undefined){
112
- if(!nextPicker||typeof nextPicker.select!=='function'){
115
+ if(!nextPicker||!is.function(nextPicker.select)){
113
116
  throw new TypeError('picker must expose a select(options) function.');
114
117
  }
115
118
  }
@@ -47,6 +47,9 @@
47
47
  </section>
48
48
 
49
49
  <script type="module">
50
+ const {default:Is}=await import('strong-type');
51
+ const is=new Is(false);
52
+
50
53
  const host=this;
51
54
  const shadow=host.shadowRoot;
52
55
  const tabs=[...shadow.querySelectorAll('[role="tab"]')];
@@ -117,7 +120,7 @@
117
120
  const url=new URL(sourceUrl(value));
118
121
  if(page===null||page===undefined||page==='') return url.href;
119
122
  const resolvedPage=Number(page);
120
- if(!Number.isSafeInteger(resolvedPage)||resolvedPage<1) throw new TypeError('PDF page must be a positive integer.');
123
+ if(!is.safeInteger(resolvedPage)||resolvedPage<1) throw new TypeError('PDF page must be a positive integer.');
121
124
  url.searchParams.set('arcane-pdf-page',String(resolvedPage));
122
125
  url.hash=`page=${resolvedPage}`;
123
126
  return url.href;
@@ -202,7 +205,7 @@
202
205
  }));
203
206
  reviewStatus.value=String(config.review?.status||'not-reviewed');
204
207
  if(!reviewStatus.value&&reviewStatus.options.length) reviewStatus.selectedIndex=0;
205
- const classificationOptions=Array.isArray(config.classificationOptions)?config.classificationOptions:[];
208
+ const classificationOptions=is.array(config.classificationOptions)?config.classificationOptions:[];
206
209
  classificationField.hidden=!classificationOptions.length;
207
210
  classificationLabel.textContent=String(config.classificationLabel||'Classification');
208
211
  reviewClassification.replaceChildren(...classificationOptions.map(option=>{
@@ -211,7 +214,7 @@
211
214
  reviewClassification.value=String(config.review?.classification||'unassigned');
212
215
  if(!reviewClassification.value&&reviewClassification.options.length) reviewClassification.selectedIndex=0;
213
216
  reviewFields.replaceChildren();
214
- for(const definition of Array.isArray(config.reviewFields)?config.reviewFields:[]){
217
+ for(const definition of is.array(config.reviewFields)?config.reviewFields:[]){
215
218
  const key=String(definition.key||'').replace(/[^a-z0-9._-]/gi,'-');
216
219
  if(!key) continue;
217
220
  const label=document.createElement('label'); const caption=document.createElement('span'); caption.textContent=String(definition.label||key);
@@ -44,6 +44,9 @@
44
44
  </section>
45
45
 
46
46
  <script type="module">
47
+ const {default:Is}=await import('strong-type');
48
+ const is=new Is(false);
49
+
47
50
  const host=this;
48
51
  const root=host.shadowRoot;
49
52
  const {createArcaneEventSource,projectArcaneDOMEvent}=await import('arcane-os/event-manager');
@@ -220,7 +223,7 @@
220
223
  return progress;
221
224
  }
222
225
  const numeric=Number(value);
223
- progress=value===null||value===undefined||!Number.isFinite(numeric)
226
+ progress=value===null||value===undefined||!is.finite(numeric)
224
227
  ?null
225
228
  :Math.min(100,Math.max(0,numeric));
226
229
  feedback.hidden=progress===null&&!statusElement.innerText;
@@ -272,7 +275,7 @@
272
275
 
273
276
  function numberOr(value,fallback){
274
277
  const numeric=Number(value);
275
- return Number.isFinite(numeric)&&numeric>=0?numeric:fallback;
278
+ return is.finite(numeric)&&numeric>=0?numeric:fallback;
276
279
  }
277
280
 
278
281
  function destroy(){
@@ -54,6 +54,9 @@
54
54
  </section>
55
55
 
56
56
  <script type="module">
57
+ const {default:Is}=await import('strong-type');
58
+ const is=new Is(false);
59
+
57
60
  const host=this;
58
61
  const root=host.shadowRoot;
59
62
  const {createArcaneEventSource,projectArcaneDOMEvent}=await import('arcane-os/event-manager');
@@ -152,8 +155,8 @@
152
155
  }
153
156
 
154
157
  function renderMetadata(input=[]){
155
- const entries=Array.isArray(input)
156
- ?input.map(entry=>Array.isArray(entry)?entry:[entry.label,entry.value])
158
+ const entries=is.array(input)
159
+ ?input.map(entry=>is.array(entry)?entry:[entry.label,entry.value])
157
160
  :Object.entries(input||{});
158
161
  const fragment=document.createDocumentFragment();
159
162
  for(const [label,value] of entries){
@@ -177,7 +180,7 @@
177
180
  return false;
178
181
  }
179
182
  preview.replaceChildren();
180
- if(typeof Node!=='undefined'&&value instanceof Node){
183
+ if(!is.undefined(globalThis.Node)&&value instanceof Node){
181
184
  preview.append(value);
182
185
  }else if(`${value??''}`){
183
186
  const text=document.createElement('pre');
@@ -230,7 +233,7 @@
230
233
  if(destroyed){
231
234
  return false;
232
235
  }
233
- const next=typeof value==='object'?value:{label:value,status:value};
236
+ const next=is.object(value)?value:{label:value,status:value};
234
237
  status.innerText=`${next.label||''}`;
235
238
  status.dataset.status=`${next.status||''}`;
236
239
  status.hidden=!status.innerText;
@@ -278,7 +281,7 @@
278
281
 
279
282
  function formatSize(value){
280
283
  const bytes=Number(value);
281
- if(!Number.isFinite(bytes)||bytes<0){
284
+ if(!is.finite(bytes)||bytes<0){
282
285
  return '';
283
286
  }
284
287
  if(bytes<1024){
@@ -299,7 +302,7 @@
299
302
  return '';
300
303
  }
301
304
  const date=new Date(value);
302
- return Number.isNaN(date.getTime())?'':date.toLocaleString();
305
+ return is.NaN(date.getTime())?'':date.toLocaleString();
303
306
  }
304
307
 
305
308
  function clear(){
@@ -343,6 +343,9 @@
343
343
  <html-import id="deleteModal" class="modal" href="./arcane/components/modal.html?v=13"></html-import>
344
344
 
345
345
  <script type="module">
346
+ const {default:Is}=await import('strong-type');
347
+ const is=new Is(false);
348
+
346
349
  const {arcaneLogging}=await import('arcane-os/logging');
347
350
 
348
351
  import('../modules/DBOPFS.js');
@@ -431,12 +434,12 @@
431
434
  }
432
435
 
433
436
  function isVisibleEntry(entry={}){
434
- const normalized=typeof entry==='string'
437
+ const normalized=is.string(entry)
435
438
  ?{name:entry,path:entry,kind:'file'}
436
439
  :entry;
437
440
  const activeFilter=filter||provider?.filter;
438
441
 
439
- if(typeof activeFilter==='function'){
442
+ if(is.function(activeFilter)){
440
443
  return activeFilter(normalized)!==false;
441
444
  }
442
445
 
@@ -542,7 +545,7 @@
542
545
  if(destroyed){
543
546
  return null;
544
547
  }
545
- if(nextProvider!==null&&typeof nextProvider?.list!=='function'){
548
+ if(nextProvider!==null&&!is.function(nextProvider?.list)){
546
549
  throw new TypeError('File manager providers must expose list(path).');
547
550
  }
548
551
 
@@ -564,7 +567,7 @@
564
567
  if(destroyed){
565
568
  return null;
566
569
  }
567
- if(nextFilter!==null&&typeof nextFilter!=='function'){
570
+ if(nextFilter!==null&&!is.function(nextFilter)){
568
571
  throw new TypeError('File manager filters must be functions or null.');
569
572
  }
570
573
 
@@ -593,7 +596,7 @@
593
596
  }
594
597
 
595
598
  function normalizeProviderEntry(candidate={},parentPath=''){
596
- if(!candidate||typeof candidate!=='object'){
599
+ if(!candidate||!is.object(candidate)){
597
600
  return null;
598
601
  }
599
602
 
@@ -620,7 +623,7 @@
620
623
  name:name,
621
624
  path:path,
622
625
  kind:kind,
623
- size:Number.isFinite(Number(candidate.size))?Number(candidate.size):0,
626
+ size:is.finite(Number(candidate.size))?Number(candidate.size):0,
624
627
  mimeType:String(candidate.mimeType||''),
625
628
  lastModified:candidate.lastModified||'',
626
629
  status:String(candidate.status||''),
@@ -629,7 +632,7 @@
629
632
  }
630
633
 
631
634
  function normalizeProviderEntries(entries=[],parentPath=''){
632
- if(!Array.isArray(entries)){
635
+ if(!is.array(entries)){
633
636
  throw new TypeError('File manager provider list(path) must return an array.');
634
637
  }
635
638
 
@@ -833,7 +836,7 @@
833
836
  name.innerText=entry.name;
834
837
  count.className='tree-file-count';
835
838
 
836
- if(Number.isFinite(Number(entry.fileCount))){
839
+ if(is.finite(Number(entry.fileCount))){
837
840
  setFileCountLabel(count,Number(entry.fileCount),false);
838
841
  item.dataset.fileCount=String(Number(entry.fileCount));
839
842
  }
@@ -900,7 +903,7 @@
900
903
  const exact=Number(current._fileManagerEntry?.fileCount);
901
904
  const countElement=current.querySelector(':scope>.tree-item-row>.tree-file-count');
902
905
 
903
- if(Number.isFinite(exact)){
906
+ if(is.finite(exact)){
904
907
  current.dataset.fileCount=String(exact);
905
908
  setFileCountLabel(countElement,exact,false);
906
909
  }else if(current.dataset.loaded==='true'){
@@ -1188,7 +1191,7 @@
1188
1191
  return true;
1189
1192
  }
1190
1193
 
1191
- if(typeof activeTreeProvider().open==='function'){
1194
+ if(is.function(activeTreeProvider().open)){
1192
1195
  try{
1193
1196
  await activeTreeProvider().open(entry);
1194
1197
  if(destroyed||generation!==treeOpenGeneration){
@@ -1508,7 +1511,7 @@
1508
1511
 
1509
1512
  if(
1510
1513
  ['json','jsonl','ndjson'].includes(fileRef.ext)
1511
- &&typeof host.previewTransform==='function'
1514
+ &&is.function(host.previewTransform)
1512
1515
  ){
1513
1516
  preview=await host.previewTransform(
1514
1517
  preview,
@@ -1530,7 +1533,7 @@
1530
1533
  break;
1531
1534
  case 'jsonl':
1532
1535
  case 'ndjson':{
1533
- const records=Array.isArray(preview)?preview:[];
1536
+ const records=is.array(preview)?preview:[];
1534
1537
 
1535
1538
  for(let i=0;i<records.length;i++){
1536
1539
  rendered.append(
@@ -1729,7 +1732,7 @@
1729
1732
  return;
1730
1733
  }
1731
1734
 
1732
- if(closeFile&&typeof fileModal.close==='function'){
1735
+ if(closeFile&&is.function(fileModal.close)){
1733
1736
  await fileModal.close(undefined,true);
1734
1737
  if(destroyed||generation!==deleteGeneration){
1735
1738
  return;
@@ -95,6 +95,9 @@
95
95
  </section>
96
96
 
97
97
  <script type="module">
98
+ const {default:Is}=await import('strong-type');
99
+ const is=new Is(false);
100
+
98
101
  const host=this;
99
102
  const root=host.shadowRoot;
100
103
  const {createArcaneEventSource,projectArcaneDOMEvent}=await import('arcane-os/event-manager');
@@ -286,13 +289,13 @@
286
289
  }
287
290
 
288
291
  function positiveSafeInteger(value){
289
- return Number.isSafeInteger(value)&&value>0
292
+ return is.safeInteger(value)&&value>0
290
293
  ?value
291
294
  :null;
292
295
  }
293
296
 
294
297
  function normalizeResult(value={}){
295
- if(typeof value==='boolean'){
298
+ if(is.boolean(value)){
296
299
  return {
297
300
  required:true,
298
301
  ready:value,
@@ -211,6 +211,9 @@
211
211
  </section>
212
212
 
213
213
  <script type="module">
214
+ const {default:Is}=await import('strong-type');
215
+ const is=new Is(false);
216
+
214
217
  const {arcaneLogging}=await import('arcane-os/logging');
215
218
 
216
219
  const host=this;
@@ -380,19 +383,19 @@
380
383
  }
381
384
 
382
385
  function normalizeOptions(input={},previous=defaultOptions){
383
- if(!input||typeof input!=='object'||Array.isArray(input)){
386
+ if(!input||!is.object(input)||is.array(input)){
384
387
  throw new TypeError('Markdown document options must be an object.');
385
388
  }
386
389
 
387
390
  const labelInput=input.labels===undefined?{}:input.labels;
388
- if(!labelInput||typeof labelInput!=='object'||Array.isArray(labelInput)){
391
+ if(!labelInput||!is.object(labelInput)||is.array(labelInput)){
389
392
  throw new TypeError('Markdown document labels must be an object.');
390
393
  }
391
394
 
392
395
  const labels={...previous.labels};
393
396
  for(const name of ['content','empty','error','loading','tableOfContents']){
394
397
  if(labelInput[name]!==undefined){
395
- if(typeof labelInput[name]!=='string'||!labelInput[name].trim()){
398
+ if(!is.string(labelInput[name])||!labelInput[name].trim()){
396
399
  throw new TypeError(`Markdown document labels.${name} must be a nonempty string.`);
397
400
  }
398
401
  labels[name]=labelInput[name].trim();
@@ -412,14 +415,14 @@
412
415
  const onNavigate=input.onNavigate===undefined
413
416
  ?previous.onNavigate
414
417
  :input.onNavigate;
415
- if(onNavigate!==null&&typeof onNavigate!=='function'){
418
+ if(onNavigate!==null&&!is.function(onNavigate)){
416
419
  throw new TypeError('Markdown document onNavigate must be a function or null.');
417
420
  }
418
421
 
419
422
  const showTableOfContents=input.showTableOfContents===undefined
420
423
  ?previous.showTableOfContents
421
424
  :input.showTableOfContents;
422
- if(typeof showTableOfContents!=='boolean'){
425
+ if(!is.boolean(showTableOfContents)){
423
426
  throw new TypeError('Markdown document showTableOfContents must be boolean.');
424
427
  }
425
428
 
@@ -481,7 +484,7 @@
481
484
  }
482
485
 
483
486
  function sourceURLFrom(input={},fallback=options.sourceURL){
484
- if(!input||typeof input!=='object'||Array.isArray(input)){
487
+ if(!input||!is.object(input)||is.array(input)){
485
488
  throw new TypeError('Markdown document render options must be an object.');
486
489
  }
487
490
  const candidate=input.sourceURL??input.sourceUrl??fallback;
@@ -547,7 +550,7 @@
547
550
  transition('loading',{},operationId);
548
551
 
549
552
  try{
550
- const pending=typeof source==='function'
553
+ const pending=is.function(source)
551
554
  ?source({sourceURL,signal:controller.signal,operationId})
552
555
  :source;
553
556
  const result=await pending;
@@ -557,8 +560,8 @@
557
560
 
558
561
  if(
559
562
  result
560
- &&typeof result==='object'
561
- &&!Array.isArray(result)
563
+ &&is.object(result)
564
+ &&!is.array(result)
562
565
  ){
563
566
  sourceURL=sourceURLFrom(
564
567
  result,
@@ -598,7 +601,7 @@
598
601
  }
599
602
 
600
603
  function renderMarkdown(markdown='',sourceURL=options.sourceURL,operationId=null){
601
- if(typeof markdown!=='string'){
604
+ if(!is.string(markdown)){
602
605
  throw new TypeError('Markdown document content must be a string.');
603
606
  }
604
607
 
@@ -783,7 +786,7 @@
783
786
  };
784
787
  const publicDetail={
785
788
  characters:Number(detail.characters||currentMarkdown.length||0),
786
- headingCount:Array.isArray(detail.headings)?detail.headings.length:tableOfContents.length,
789
+ headingCount:is.array(detail.headings)?detail.headings.length:tableOfContents.length,
787
790
  state
788
791
  };
789
792
  if(detail.code){
@@ -74,6 +74,9 @@
74
74
  </section>
75
75
 
76
76
  <script type="module">
77
+ const {default:Is}=await import('strong-type');
78
+ const is=new Is(false);
79
+
77
80
  const {arcaneLogging}=await import('arcane-os/logging');
78
81
 
79
82
  const host=this;
@@ -300,7 +303,7 @@
300
303
  }
301
304
 
302
305
  const save=options.onSave||(
303
- typeof host.save==='function'?host.save.bind(host):null
306
+ is.function(host.save)?host.save.bind(host):null
304
307
  );
305
308
  if(!save){
306
309
  status.innerText=options.labels.unavailable;
@@ -156,6 +156,9 @@
156
156
  </dialog>
157
157
 
158
158
  <script type="module">
159
+ const {default:Is}=await import('strong-type');
160
+ const is=new Is(false);
161
+
159
162
  const {arcaneLogging}=await import('arcane-os/logging');
160
163
 
161
164
  const host=this;
@@ -339,7 +342,7 @@
339
342
  }
340
343
 
341
344
  const tasks=jobs.filter(function isRunnableTask(job){
342
- return job&&typeof job.name==='string'&&typeof job.task==='function';
345
+ return job&&is.string(job.name)&&is.function(job.task);
343
346
  });
344
347
  if(!tasks.length){
345
348
  return [];
@@ -41,6 +41,9 @@
41
41
  </section>
42
42
 
43
43
  <script type="module">
44
+ const {default:Is}=await import('strong-type');
45
+ const is=new Is(false);
46
+
44
47
  const host=this;
45
48
  const root=host.shadowRoot;
46
49
  const {createArcaneEventSource,projectArcaneDOMEvent}=await import('arcane-os/event-manager');
@@ -131,7 +134,7 @@
131
134
 
132
135
  function setBody(value=''){
133
136
  bodyContent.replaceChildren();
134
- if(typeof Node!=='undefined'&&value instanceof Node){
137
+ if(!is.undefined(globalThis.Node)&&value instanceof Node){
135
138
  bodyContent.append(value);
136
139
  }else if(`${value??''}`){
137
140
  const text=document.createElement('pre');
@@ -145,14 +148,14 @@
145
148
  }
146
149
 
147
150
  function setCoverage(value=''){
148
- const next=typeof value==='object'?value:{label:value};
151
+ const next=is.object(value)?value:{label:value};
149
152
  coverage.innerText=`${next.label??next.text??''}`;
150
153
  coverage.hidden=!coverage.innerText;
151
154
  return coverage.innerText;
152
155
  }
153
156
 
154
157
  function setStatus(value=''){
155
- const next=typeof value==='object'?value:{label:value,status:value};
158
+ const next=is.object(value)?value:{label:value,status:value};
156
159
  status.innerText=`${next.label||''}`;
157
160
  status.dataset.status=`${next.status||''}`;
158
161
  status.hidden=!status.innerText;
@@ -29,6 +29,9 @@
29
29
  </form>
30
30
 
31
31
  <script type="module">
32
+ const {default:Is}=await import('strong-type');
33
+ const is=new Is(false);
34
+
32
35
  const host=this;
33
36
  const root=host.shadowRoot;
34
37
  const form=root.querySelector('form');
@@ -68,7 +71,7 @@
68
71
  reset.addEventListener('click',()=>emit('preferences-reset'));
69
72
 
70
73
  function configure(options={}){
71
- schema=Array.from(options.schema||[]).map(item=>typeof item.toJSON==='function'?item.toJSON():{...item});
74
+ schema=Array.from(options.schema||[]).map(item=>is.function(item.toJSON)?item.toJSON():{...item});
72
75
  title.innerText=String(options.title||'Preferences');
73
76
  description.innerText=String(options.description||'');
74
77
  description.hidden=!description.innerText;
@@ -25,6 +25,9 @@
25
25
  <p class="empty" data-empty>No dated events match this view.</p>
26
26
 
27
27
  <script type="module">
28
+ const {default:Is}=await import('strong-type');
29
+ const is=new Is(false);
30
+
28
31
  const host=this;
29
32
  const list=host.shadowRoot.querySelector('[data-list]');
30
33
  const empty=host.shadowRoot.querySelector('[data-empty]');
@@ -49,7 +52,7 @@
49
52
  });
50
53
 
51
54
  function normalizeItem(item,index){
52
- const source=item&&typeof item==='object'?item:{};
55
+ const source=item&&is.object(item)?item:{};
53
56
  const date=String(source.date||source.isoDate||'');
54
57
  if(!source.id||!date) return null;
55
58
  return {
@@ -63,7 +66,7 @@
63
66
  sourceLabel:String(source.sourceLabel||''),
64
67
  status:String(source.status||''),
65
68
  factualPosture:String(source.factualPosture||''),
66
- sourceCount:Number.isFinite(Number(source.sourceCount))&&Number(source.sourceCount)>=0
69
+ sourceCount:is.finite(Number(source.sourceCount))&&Number(source.sourceCount)>=0
67
70
  ?Number(source.sourceCount)
68
71
  :0,
69
72
  order:index
@@ -71,8 +74,8 @@
71
74
  }
72
75
 
73
76
  function setItems(value=[],input={}){
74
- options={...options,...(input&&typeof input==='object'?input:{})};
75
- items=(Array.isArray(value)?value:[]).map(normalizeItem).filter(Boolean)
77
+ options={...options,...(input&&is.object(input)?input:{})};
78
+ items=(is.array(value)?value:[]).map(normalizeItem).filter(Boolean)
76
79
  .sort((left,right)=>left.date.localeCompare(right.date)||left.order-right.order);
77
80
  render();
78
81
  return items.map(item=>({...item}));
@@ -80,7 +83,7 @@
80
83
 
81
84
  function displayDate(value=''){
82
85
  const parsed=new Date(`${value.slice(0,10)}T00:00:00Z`);
83
- return Number.isFinite(parsed.getTime())
86
+ return is.finite(parsed.getTime())
84
87
  ?new Intl.DateTimeFormat(undefined,{year:'numeric',month:'short',day:'numeric',timeZone:'UTC'}).format(parsed)
85
88
  :value;
86
89
  }
@@ -29,6 +29,9 @@
29
29
  </section>
30
30
 
31
31
  <script type="module">
32
+ const {default:Is}=await import('strong-type');
33
+ const is=new Is(false);
34
+
32
35
  const host=this;
33
36
  const board=host.shadowRoot.querySelector('[data-board]');
34
37
  const selectedTitle=host.shadowRoot.querySelector('[data-selected-title]');
@@ -64,22 +67,22 @@
64
67
  });
65
68
 
66
69
  function normalizeNode(value,index){
67
- const item=value&&typeof value==='object'?value:{};
70
+ const item=value&&is.object(value)?value:{};
68
71
  if(!item.id) return null;
69
- return {...item,id:String(item.id),label:String(item.label||item.title||item.id),summary:String(item.summary||''),lane:String(item.lane||item.kind||'Other'),order:Number.isFinite(Number(item.order))?Number(item.order):index};
72
+ return {...item,id:String(item.id),label:String(item.label||item.title||item.id),summary:String(item.summary||''),lane:String(item.lane||item.kind||'Other'),order:is.finite(Number(item.order))?Number(item.order):index};
70
73
  }
71
74
  function normalizeEdge(value,index,known){
72
- const item=value&&typeof value==='object'?value:{};
75
+ const item=value&&is.object(value)?value:{};
73
76
  const from=String(item.from||''); const to=String(item.to||'');
74
77
  if(!from||!to||!known.has(from)||!known.has(to)) return null;
75
78
  return {...item,id:String(item.id||`edge-${index+1}`),from,to,label:String(item.label||'related to'),summary:String(item.summary||'')};
76
79
  }
77
80
 
78
81
  function setGraph(graph={},options={}){
79
- nodes=(Array.isArray(graph.nodes)?graph.nodes:[]).map(normalizeNode).filter(Boolean);
82
+ nodes=(is.array(graph.nodes)?graph.nodes:[]).map(normalizeNode).filter(Boolean);
80
83
  const known=new Set(nodes.map(item=>item.id));
81
- edges=(Array.isArray(graph.edges)?graph.edges:[]).map((item,index)=>normalizeEdge(item,index,known)).filter(Boolean);
82
- const supplied=Array.isArray(options.lanes)?options.lanes:Array.isArray(graph.lanes)?graph.lanes:[];
84
+ edges=(is.array(graph.edges)?graph.edges:[]).map((item,index)=>normalizeEdge(item,index,known)).filter(Boolean);
85
+ const supplied=is.array(options.lanes)?options.lanes:is.array(graph.lanes)?graph.lanes:[];
83
86
  lanes=[...new Set([...supplied.map(String),...nodes.map(item=>item.lane)])];
84
87
  board.style.setProperty('--lane-count',String(Math.max(1,Math.min(6,lanes.length))));
85
88
  if(selectedId&&!known.has(selectedId)) selectedId='';