arcane-os 0.5.17 → 0.5.19
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.
- package/CHANGELOG.md +34 -1
- package/README.md +9 -9
- package/bin/arcane-test.mjs +16 -13
- package/browser-runtime/ai/browser-speech-artifacts.mjs +41 -38
- package/browser-runtime/ai/browser-speech-providers.mjs +46 -43
- package/browser-runtime/ai/browser-wasm-llm-provider.mjs +158 -135
- package/browser-runtime/ai/browser-wasm.mjs +6 -3
- package/browser-runtime/ai/browser-wllama-runtime.mjs +104 -23
- package/browser-runtime/ai/model-controller.mjs +94 -91
- package/browser-runtime/ai/speech-worker-client.mjs +12 -9
- package/browser-runtime/ai/speech-worker-runtime.mjs +56 -53
- package/browser-runtime/dependencies/strong-type/index.js +207 -82
- package/browser-runtime/dependencies/strong-type/package.json +15 -6
- package/browser-runtime/dom-event-instrumentation.mjs +24 -20
- package/browser-runtime/event-manager.mjs +111 -108
- package/browser-runtime/speech-text.mjs +5 -1
- package/docs/architecture.md +1 -1
- package/docs/publishing.md +10 -4
- package/docs/reference/ai/browser-speech.md +198 -5
- package/docs/reference/ai/browser-wasm.md +29 -6
- package/docs/reference/availability-and-normalization.md +40 -0
- package/docs/reference/inventory/package-api.json +1 -1
- package/docs/reference/inventory/runtime-components.json +1 -1
- package/docs/reference/inventory/runtime-modules.json +20 -24
- package/docs/reference/protocols.md +1 -1
- package/docs/reference/runtime-modules.md +125 -35
- package/docs/reference/sdk-api.md +23 -7
- package/examples/wasm-ai-demo/index.html +1 -0
- package/node_modules/event-pubsub/node_modules/strong-type/README.md +408 -0
- package/node_modules/event-pubsub/node_modules/strong-type/assets/strong-type-header.png +0 -0
- package/node_modules/event-pubsub/node_modules/strong-type/index.js +1151 -0
- package/node_modules/event-pubsub/node_modules/strong-type/licence +21 -0
- package/node_modules/event-pubsub/node_modules/strong-type/node.js +125 -0
- package/node_modules/event-pubsub/node_modules/strong-type/package.json +61 -0
- package/node_modules/strong-type/README.md +42 -24
- package/node_modules/strong-type/benchmark/core.js +324 -0
- package/node_modules/strong-type/index.js +207 -82
- package/node_modules/strong-type/package.json +14 -6
- package/package.json +3 -3
- package/runtime/arcane/components/app-bar.html +5 -2
- package/runtime/arcane/components/assistant-panel.html +5 -2
- package/runtime/arcane/components/chart.html +15 -12
- package/runtime/arcane/components/chat.html +170 -148
- package/runtime/arcane/components/dashboard-config.html +6 -3
- package/runtime/arcane/components/data-view.html +4 -1
- package/runtime/arcane/components/directory-picker.html +5 -2
- package/runtime/arcane/components/document-inspector.html +6 -3
- package/runtime/arcane/components/file-drop.html +5 -2
- package/runtime/arcane/components/file-inspector.html +9 -6
- package/runtime/arcane/components/file-manager.html +16 -13
- package/runtime/arcane/components/local-ai-status.html +5 -2
- package/runtime/arcane/components/markdown-document.html +14 -11
- package/runtime/arcane/components/markdown-editor.html +4 -1
- package/runtime/arcane/components/modal.html +4 -1
- package/runtime/arcane/components/output-panel.html +6 -3
- package/runtime/arcane/components/preferences-form.html +4 -1
- package/runtime/arcane/components/record-timeline.html +8 -5
- package/runtime/arcane/components/relationship-board.html +9 -6
- package/runtime/arcane/components/source-code-viewer.html +12 -9
- package/runtime/arcane/components/source-explanation.html +8 -5
- package/runtime/arcane/components/speech.html +24 -21
- package/runtime/arcane/components/summary-strip.html +4 -1
- package/runtime/arcane/components/task-progress.html +6 -3
- package/runtime/arcane/components/terminal-workspace.html +4 -1
- package/runtime/arcane/components/voice-transcription.html +11 -8
- package/runtime/arcane/components/web-navigator.html +5 -2
- package/runtime/arcane/entities/ApiModelRecord.js +5 -2
- package/runtime/arcane/entities/Calculation.js +5 -2
- package/runtime/arcane/entities/Chat.js +33 -33
- package/runtime/arcane/entities/CommunicationMessage.js +4 -1
- package/runtime/arcane/entities/CommunicationThread.js +4 -1
- package/runtime/arcane/entities/File.js +1 -1
- package/runtime/arcane/entities/Image.js +8 -5
- package/runtime/arcane/entities/IntentEnvelope.js +20 -17
- package/runtime/arcane/entities/Preference.js +9 -6
- package/runtime/arcane/entities/Theme.js +5 -2
- package/runtime/arcane/entities/User.js +11 -11
- package/runtime/arcane/entities/Weather.js +5 -2
- package/runtime/arcane/modules/AI.js +491 -165
- package/runtime/arcane/modules/AIPreferenceRuntime.js +5 -2
- package/runtime/arcane/modules/AIPreferenceTuple.js +9 -6
- package/runtime/arcane/modules/AIProviderRuntime.js +88 -85
- package/runtime/arcane/modules/AIResponseURLPolicy.js +148 -62
- package/runtime/arcane/modules/AIRuntimeState.js +29 -26
- package/runtime/arcane/modules/AnsiText.js +4 -1
- package/runtime/arcane/modules/ApiModelDatabase.js +22 -19
- package/runtime/arcane/modules/AppDataScope.js +8 -5
- package/runtime/arcane/modules/ArcaneCommunicationBridge.js +4 -1
- package/runtime/arcane/modules/ArcaneNavigationPolicy.js +8 -5
- package/runtime/arcane/modules/ArcaneNetworkPolicy.js +18 -15
- package/runtime/arcane/modules/AsyncBoundary.js +13 -10
- package/runtime/arcane/modules/BrowserTestSuite.js +19 -16
- package/runtime/arcane/modules/CalculatorEngine.js +5 -2
- package/runtime/arcane/modules/ChatRecords.js +18 -15
- package/runtime/arcane/modules/CommunicationAppController.js +9 -6
- package/runtime/arcane/modules/CommunicationHub.js +9 -6
- package/runtime/arcane/modules/CommunicationPreferences.js +4 -1
- package/runtime/arcane/modules/CommunicationProviderRegistry.js +4 -1
- package/runtime/arcane/modules/ComponentContracts.js +56 -53
- package/runtime/arcane/modules/ConfiguredAIChatSession.js +30 -27
- package/runtime/arcane/modules/ConversationActionItems.js +15 -12
- package/runtime/arcane/modules/ConversationClosingReport.js +11 -8
- package/runtime/arcane/modules/ConversationTimebox.js +28 -25
- package/runtime/arcane/modules/CoreLocalModelCatalog.js +17 -14
- package/runtime/arcane/modules/DBLS.js +7 -4
- package/runtime/arcane/modules/DBOPFS.js +7 -7
- package/runtime/arcane/modules/DBOPFSDocumentLibrary.js +34 -31
- package/runtime/arcane/modules/DevelopmentWorkspace.js +4 -1
- package/runtime/arcane/modules/DirectoryPicker.js +8 -5
- package/runtime/arcane/modules/DocumentLexicalSearch.js +11 -8
- package/runtime/arcane/modules/DocumentNavigation.js +7 -4
- package/runtime/arcane/modules/Errors.js +28 -25
- package/runtime/arcane/modules/HTMLImport.js +7 -4
- package/runtime/arcane/modules/IsolatedModelQuestionRunner.js +15 -12
- package/runtime/arcane/modules/LocalAIReadiness.js +21 -18
- package/runtime/arcane/modules/LocalAIReadinessController.js +6 -3
- package/runtime/arcane/modules/MD.js +1 -1
- package/runtime/arcane/modules/Mail.js +46 -43
- package/runtime/arcane/modules/MailOutbox.mjs +48 -45
- package/runtime/arcane/modules/MailTransport.mjs +29 -26
- package/runtime/arcane/modules/MemoryRecords.js +7 -4
- package/runtime/arcane/modules/MessageAdvisory.js +6 -3
- package/runtime/arcane/modules/ModelDefinition.js +7 -4
- package/runtime/arcane/modules/Ollama.js +6 -3
- package/runtime/arcane/modules/OllamaModelIdentifier.js +4 -1
- package/runtime/arcane/modules/OpenMeteoWeatherProvider.js +18 -15
- package/runtime/arcane/modules/PersistentAIChatSession.js +33 -30
- package/runtime/arcane/modules/PreferenceStore.js +20 -17
- package/runtime/arcane/modules/PreparedSpeech.js +485 -0
- package/runtime/arcane/modules/Questionnaire.js +6 -3
- package/runtime/arcane/modules/RecordLinkIndex.js +4 -1
- package/runtime/arcane/modules/RecordPassageIndex.js +9 -6
- package/runtime/arcane/modules/RecordReviewStore.js +12 -9
- package/runtime/arcane/modules/RiskSignalAnalyzer.js +4 -1
- package/runtime/arcane/modules/ScopedOPFSCache.js +6 -3
- package/runtime/arcane/modules/ScreenCapture.js +20 -17
- package/runtime/arcane/modules/SpeechPlayback.js +29 -26
- package/runtime/arcane/modules/StaticDocumentCatalog.js +33 -30
- package/runtime/arcane/modules/SystemAppearance.js +5 -2
- package/runtime/arcane/modules/SystemToolRegistry.js +6 -3
- package/runtime/arcane/modules/TerminalClient.js +14 -11
- package/runtime/arcane/modules/TerminalCommandRegistry.js +4 -1
- package/runtime/arcane/modules/ThemeBootstrap.js +9 -6
- package/runtime/arcane/modules/ThemeManager.js +5 -2
- package/runtime/arcane/modules/TimeGuard.js +1 -1
- package/runtime/arcane/modules/ToolCallRouter.js +11 -8
- package/runtime/arcane/modules/WaitForComponent.js +19 -16
- package/runtime/arcane/modules/YouTubeMedia.js +4 -1
- package/runtime/strong-type/index.js +1276 -352
- package/runtime/strong-type/package.json +69 -45
- package/src/app-descriptor.mjs +17 -14
- package/src/application-tests.mjs +4 -1
- package/src/cli/main.mjs +8 -5
- package/src/constants.mjs +4 -1
- package/src/dev-server.mjs +8 -5
- package/src/doctor.mjs +5 -2
- package/src/dom-event-instrumentation.mjs +24 -20
- package/src/errors.mjs +7 -3
- package/src/event-manager.mjs +111 -108
- package/src/event-queue.mjs +8 -5
- package/src/events.mjs +12 -9
- package/src/import-map.mjs +35 -27
- package/src/installed-sdk-runtime.mjs +4 -1
- package/src/integrated-provider-loader.mjs +9 -6
- package/src/mail-credentials.mjs +16 -13
- package/src/mail-server.mjs +53 -50
- package/src/mail.mjs +18 -15
- package/src/native-plan.mjs +12 -9
- package/src/native-provider-loader.mjs +7 -4
- package/src/packager/core.mjs +18 -15
- package/src/process.mjs +6 -3
- package/src/release-bundle.mjs +14 -11
- package/src/runtime.mjs +4 -1
- package/src/scaffold.mjs +9 -6
- package/src/sdk-browser-runtime.mjs +4 -1
- package/src/source-server.mjs +17 -14
- package/src/targets/index.mjs +5 -2
- package/src/templates/workspace-template.mjs +13 -6
- package/src/testing-loader.mjs +7 -4
- package/src/testing.mjs +10 -7
- package/src/toolchain.mjs +13 -10
- package/src/update-check.mjs +9 -6
- package/src/workspace-operation-lock.mjs +14 -11
- package/src/workspace-runtime.mjs +4 -1
- package/src/workspace.mjs +17 -14
- package/runtime/arcane/modules/AIResponseLength.js +0 -32
package/CHANGELOG.md
CHANGED
|
@@ -1,6 +1,39 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
-
##
|
|
3
|
+
## 0.5.19
|
|
4
|
+
|
|
5
|
+
- Report observed Wllama initialization stages and runtime activity through
|
|
6
|
+
direct provider loading and the shared AI lifecycle. Keep initialization
|
|
7
|
+
indeterminate when the runtime supplies no meaningful completion total.
|
|
8
|
+
- Show the current initialization stage, stage duration, and time since runtime
|
|
9
|
+
activity in shared chat instead of a completed file count during activation.
|
|
10
|
+
Preserve download progress, cancellation, and complete runtime logging.
|
|
11
|
+
- Remove an adjacent duplicate cancellation check while retaining cancellation
|
|
12
|
+
handling before initialization and after loading.
|
|
13
|
+
|
|
14
|
+
## 0.5.18
|
|
15
|
+
|
|
16
|
+
- Use `strong-type` predicates throughout SDK-owned toolchain, runtime,
|
|
17
|
+
browser-provider, and component code while retaining existing defaults,
|
|
18
|
+
domain rules, public errors, and nominal constructor behavior. Align the
|
|
19
|
+
direct dependency and both shipped projections at `strong-type` 2.0.1,
|
|
20
|
+
replacing the portable runtime's 1.1.0 snapshot and avoiding Error allocation
|
|
21
|
+
for ordinary false predicates. Keep managed browser imports and Node reference
|
|
22
|
+
loading on the same declared dependency.
|
|
23
|
+
- Remove `AIResponseLength` exports; applications own response verbosity.
|
|
24
|
+
Parse URL-audit HTML with the native HTML parser.
|
|
25
|
+
|
|
26
|
+
- Add `AI.prepareTTS()` for detached punctuation-segmented synthesis, optional
|
|
27
|
+
DBOPFS audio storage, complete semantic-input reuse, shared pending work and
|
|
28
|
+
independent preparation cancellation. Persist MIME metadata with each audio
|
|
29
|
+
segment and retain successful segments after interruption or partial failure.
|
|
30
|
+
- Add `AI.playPreparedTTS()` to replay prepared or pending audio through the
|
|
31
|
+
existing audio-clock scheduler. Playback has its own completion, pause,
|
|
32
|
+
resume, stop, state and error surface; stopping playback keeps detached
|
|
33
|
+
preparation alive. Cached audio plays without loading a speech model.
|
|
34
|
+
- Keep Markdown cleanup at its shared owner, preserve the existing TTS APIs,
|
|
35
|
+
and share provider capacity across preparation requests. Applications own
|
|
36
|
+
content grouping, storage keys, preparation order and retention policy.
|
|
4
37
|
|
|
5
38
|
## 0.5.17
|
|
6
39
|
|
package/README.md
CHANGED
|
@@ -19,7 +19,7 @@ version-locked SDK runtime, while an integrated Arcane checkout uses its live
|
|
|
19
19
|
`arcane/` runtime. Both profiles preserve the same app URLs, theme, packaging,
|
|
20
20
|
event, cancellation, and browser run contracts.
|
|
21
21
|
|
|
22
|
-
This checkout defines the `0.5.
|
|
22
|
+
This checkout defines the `0.5.19` SDK contract. Applications pin one exact npm
|
|
23
23
|
version and lockfile; registry state is deliberately not baked into application
|
|
24
24
|
artifacts.
|
|
25
25
|
|
|
@@ -35,7 +35,7 @@ Create one browser application, install its pinned SDK, and start its source
|
|
|
35
35
|
server:
|
|
36
36
|
|
|
37
37
|
```bash
|
|
38
|
-
npx arcane-os@0.5.
|
|
38
|
+
npx arcane-os@0.5.19 new hello-speech --path ./hello-speech --target browser
|
|
39
39
|
cd hello-speech
|
|
40
40
|
npm install
|
|
41
41
|
npm run dev
|
|
@@ -332,7 +332,7 @@ Streaming calls also recognize a run split across chunks. Single marks and
|
|
|
332
332
|
ordinary repeated punctuation remain literal. No application option is needed;
|
|
333
333
|
an existing `textFormat` extra is ignored and cannot disable cleanup. Original
|
|
334
334
|
messages and caller payloads remain unchanged for display, storage, and model
|
|
335
|
-
input. The
|
|
335
|
+
input. The `arcane-os/speech-text` entrypoint exports the same
|
|
336
336
|
`MarkdownSpeech` streaming class and `stripSpeechFormatting()` one-pass helper
|
|
337
337
|
for code that needs the speech-only transformation directly.
|
|
338
338
|
|
|
@@ -357,7 +357,7 @@ uses the same controller for automatic memory extraction.
|
|
|
357
357
|
Create a new repository-shaped Arcane application with the exact stable SDK:
|
|
358
358
|
|
|
359
359
|
```bash
|
|
360
|
-
npx arcane-os@0.5.
|
|
360
|
+
npx arcane-os@0.5.19 new my-app --path ./my-app --target portable --git
|
|
361
361
|
cd my-app
|
|
362
362
|
npm install
|
|
363
363
|
npm run dev
|
|
@@ -367,7 +367,7 @@ To enroll an existing repository, install the exact SDK and initialize only
|
|
|
367
367
|
missing Arcane files:
|
|
368
368
|
|
|
369
369
|
```bash
|
|
370
|
-
npm install --save-dev --save-exact arcane-os@0.5.
|
|
370
|
+
npm install --save-dev --save-exact arcane-os@0.5.19
|
|
371
371
|
npm exec -- arcane init my-app --target portable
|
|
372
372
|
```
|
|
373
373
|
|
|
@@ -383,7 +383,7 @@ npm exec -- arcane-os targets
|
|
|
383
383
|
No global SDK install or standalone Arcane CLI is required. The application
|
|
384
384
|
repository's exact npm dependency and lockfile own the CLI and toolchain version.
|
|
385
385
|
|
|
386
|
-
Use `npx arcane-os@0.5.
|
|
386
|
+
Use `npx arcane-os@0.5.19` for the initial bootstrap because it names this npm
|
|
387
387
|
package explicitly; bare `npx arcane` outside an installed project could resolve
|
|
388
388
|
a different package. Both installed commands invoke the same headless toolchain.
|
|
389
389
|
Project-local npm scripts use the SDK pinned by that app's `package-lock.json`,
|
|
@@ -403,7 +403,7 @@ node ./bin/arcane.mjs new local-app --path ../local-app --target portable --git
|
|
|
403
403
|
|
|
404
404
|
# From the generated app repository
|
|
405
405
|
cd ../local-app
|
|
406
|
-
npm install --save-dev --save-exact ../arcane-os-sdk/arcane-os-0.5.
|
|
406
|
+
npm install --save-dev --save-exact ../arcane-os-sdk/arcane-os-0.5.19.tgz
|
|
407
407
|
npm ci
|
|
408
408
|
```
|
|
409
409
|
|
|
@@ -412,7 +412,7 @@ same location. The lockfile retains the selected package dependency while
|
|
|
412
412
|
Arcane uses the installed package name and version. Local directory `file:` dependencies are not
|
|
413
413
|
accepted because npm may install them as links; use a packed `.tgz`. A GitHub
|
|
414
414
|
runner also needs that tarball at the locked path. After publication, replace
|
|
415
|
-
the local declaration with the exact `arcane-os@0.5.
|
|
415
|
+
the local declaration with the exact `arcane-os@0.5.19` registry package and
|
|
416
416
|
commit the regenerated lock.
|
|
417
417
|
|
|
418
418
|
Generated repositories use `npm ci --ignore-scripts` in CI. Run dependency
|
|
@@ -551,7 +551,7 @@ package installation, or assertions.
|
|
|
551
551
|
|
|
552
552
|
## Current target support
|
|
553
553
|
|
|
554
|
-
Version `0.5.
|
|
554
|
+
Version `0.5.19` exposes one browser target and five explicitly paired
|
|
555
555
|
native development targets: a non-runnable portable directory, a
|
|
556
556
|
Windows x64 unsigned-local-test EXE bundle, Linux x64 and Linux ARM64
|
|
557
557
|
unsigned-local-test DEBs, and an Android development-signed APK. The
|
package/bin/arcane-test.mjs
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
+
import Is from 'strong-type';
|
|
2
3
|
import {spawn} from 'node:child_process';
|
|
3
4
|
import {lstat,readdir,realpath} from 'node:fs/promises';
|
|
4
5
|
import {register} from 'node:module';
|
|
@@ -6,6 +7,8 @@ import path from 'node:path';
|
|
|
6
7
|
import {fileURLToPath,pathToFileURL} from 'node:url';
|
|
7
8
|
import test,{DEFAULT_TEST_TIMEOUT_MS,runRegisteredTests} from '../src/testing.mjs';
|
|
8
9
|
|
|
10
|
+
const is = new Is(false);
|
|
11
|
+
|
|
9
12
|
const SINGLE_FILE_ARGUMENT='--arcane-single-test-file';
|
|
10
13
|
const RUNNER_PATH=fileURLToPath(import.meta.url);
|
|
11
14
|
const TEST_FILE_PATTERN=/\.test\.(?:mjs|cjs|js)$/u;
|
|
@@ -27,7 +30,7 @@ const COORDINATOR_MANAGED_IMPORT_MAP=!ISOLATED_MODE
|
|
|
27
30
|
&&MANAGED_IMPORT_MAP_SOURCE!==''
|
|
28
31
|
?MANAGED_IMPORT_MAP_SOURCE
|
|
29
32
|
:undefined;
|
|
30
|
-
const ISOLATED_SEND=ISOLATED_MODE&&
|
|
33
|
+
const ISOLATED_SEND=ISOLATED_MODE&&is.function(process.send)
|
|
31
34
|
?process.send.bind(process)
|
|
32
35
|
:null;
|
|
33
36
|
delete process.env[MANAGED_IMPORT_MAP_ENV];
|
|
@@ -55,12 +58,12 @@ async function readManagedImportMapContext(source,signal,testFile){
|
|
|
55
58
|
let context;
|
|
56
59
|
try{context=JSON.parse(source);}
|
|
57
60
|
catch(error){importMapFailure(`Managed import-map context is not valid JSON: ${error.message}`);}
|
|
58
|
-
if(context===null
|
|
61
|
+
if(context===null||!is.object(context)||is.array(context)
|
|
59
62
|
||context.protocol!==MANAGED_IMPORT_MAP_PROTOCOL
|
|
60
63
|
||!APPLICATION_MAP_BOUNDARIES.has(context.boundary)
|
|
61
|
-
|
|
62
|
-
||context.imports===null
|
|
63
|
-
||
|
|
64
|
+
||!is.string(context.baseURL)
|
|
65
|
+
||context.imports===null||!is.object(context.imports)
|
|
66
|
+
||is.array(context.imports)){
|
|
64
67
|
importMapFailure('Managed import-map context is malformed.');
|
|
65
68
|
}
|
|
66
69
|
let suppliedBase;
|
|
@@ -281,8 +284,8 @@ function parseTaskkillTargets(output,leaderPid){
|
|
|
281
284
|
const target=Number(matches[0][1]);
|
|
282
285
|
const parent=matches.length===2?Number(matches[1][1]):null;
|
|
283
286
|
if(
|
|
284
|
-
!
|
|
285
|
-
||(parent!==null&&(!
|
|
287
|
+
!is.safeInteger(target)||target<=0
|
|
288
|
+
||(parent!==null&&(!is.safeInteger(parent)||parent<=0))
|
|
286
289
|
||/\d/u.test(line.replaceAll(/\bPID\s+\d+\b/giu,'PID'))
|
|
287
290
|
)return null;
|
|
288
291
|
entries.push({target,parent});
|
|
@@ -592,21 +595,21 @@ function runIsolatedFile(file,signal){
|
|
|
592
595
|
const onMessage=message=>{
|
|
593
596
|
if(
|
|
594
597
|
message?.protocol!==IPC_PROTOCOL
|
|
595
|
-
|
|
598
|
+
||!is.string(message.type)
|
|
596
599
|
)return;
|
|
597
600
|
if(message.type==='phase'){
|
|
598
601
|
if(
|
|
599
602
|
completion!==null
|
|
600
603
|
||watchdogFailure!==null
|
|
601
|
-
|
|
604
|
+
||!is.string(message.id)
|
|
602
605
|
||message.id===''
|
|
603
606
|
)return;
|
|
604
607
|
if(message.status==='started'){
|
|
605
608
|
if(
|
|
606
|
-
|
|
607
|
-
|
|
609
|
+
!is.string(message.kind)
|
|
610
|
+
||!is.string(message.name)
|
|
608
611
|
||(message.timeoutMs!==null&&(
|
|
609
|
-
!
|
|
612
|
+
!is.safeInteger(message.timeoutMs)
|
|
610
613
|
||message.timeoutMs<1
|
|
611
614
|
||message.timeoutMs>3_600_000
|
|
612
615
|
))
|
|
@@ -796,7 +799,7 @@ async function main(){
|
|
|
796
799
|
||message?.type!=='abort'
|
|
797
800
|
)return;
|
|
798
801
|
const error=new Error(
|
|
799
|
-
|
|
802
|
+
is.string(message.reason)?message.reason:'The coordinator cancelled the test file.'
|
|
800
803
|
);
|
|
801
804
|
error.code='ARCANE_TEST_CANCELLED';
|
|
802
805
|
controller.abort(error);
|
|
@@ -1,7 +1,10 @@
|
|
|
1
|
+
import Is from "../dependencies/strong-type/index.js";
|
|
1
2
|
import {
|
|
2
3
|
normalizeModelSecurity,
|
|
3
4
|
} from "./model-controller.mjs";
|
|
4
5
|
|
|
6
|
+
const is = new Is(false);
|
|
7
|
+
|
|
5
8
|
const completeValue = (value) => value;
|
|
6
9
|
|
|
7
10
|
export const BROWSER_SPEECH_ARTIFACT_PROTOCOL =
|
|
@@ -20,10 +23,10 @@ const ARTIFACT_GRAPHS = new WeakSet();
|
|
|
20
23
|
const ARTIFACT_GRAPH_METADATA = new WeakMap();
|
|
21
24
|
const ARTIFACT_ERRORS = new WeakSet();
|
|
22
25
|
const STORES = new WeakSet();
|
|
23
|
-
const PLATFORM_CREATE_OBJECT_URL =
|
|
26
|
+
const PLATFORM_CREATE_OBJECT_URL = is.function(globalThis.URL?.createObjectURL)
|
|
24
27
|
? globalThis.URL.createObjectURL.bind(globalThis.URL)
|
|
25
28
|
: null;
|
|
26
|
-
const PLATFORM_REVOKE_OBJECT_URL =
|
|
29
|
+
const PLATFORM_REVOKE_OBJECT_URL = is.function(globalThis.URL?.revokeObjectURL)
|
|
27
30
|
? globalThis.URL.revokeObjectURL.bind(globalThis.URL)
|
|
28
31
|
: null;
|
|
29
32
|
const ARTIFACT_ERROR_REASONS = completeValue({
|
|
@@ -70,7 +73,7 @@ function speechError(code, message, cause, reason = ARTIFACT_ERROR_REASONS[code]
|
|
|
70
73
|
: new Error(message, { cause });
|
|
71
74
|
error.name = "ArcaneBrowserSpeechError";
|
|
72
75
|
error.code = code;
|
|
73
|
-
if (
|
|
76
|
+
if (is.string(reason) && reason) error.reason = reason;
|
|
74
77
|
ARTIFACT_ERRORS.add(error);
|
|
75
78
|
return error;
|
|
76
79
|
}
|
|
@@ -104,7 +107,7 @@ function throwIfAborted(signal) {
|
|
|
104
107
|
}
|
|
105
108
|
|
|
106
109
|
function requiredText(value, label) {
|
|
107
|
-
if (
|
|
110
|
+
if (!is.string(value) || !value.trim()) {
|
|
108
111
|
throw new TypeError(`${label} must be a nonempty string.`);
|
|
109
112
|
}
|
|
110
113
|
return value.trim();
|
|
@@ -115,7 +118,7 @@ function identifier(value, label) {
|
|
|
115
118
|
}
|
|
116
119
|
|
|
117
120
|
function artifactGraphText(value, label, reason = "artifact-graph-field-text-required") {
|
|
118
|
-
if (
|
|
121
|
+
if (!is.string(value) || !value.trim()) {
|
|
119
122
|
throw artifactGraphTypeError(reason, `${label} must be a nonempty string.`);
|
|
120
123
|
}
|
|
121
124
|
return value.trim();
|
|
@@ -176,7 +179,7 @@ function graphPositiveInteger(
|
|
|
176
179
|
label,
|
|
177
180
|
reason = "artifact-graph-positive-safe-integer-required",
|
|
178
181
|
) {
|
|
179
|
-
if (!
|
|
182
|
+
if (!is.safeInteger(value) || value < 1) {
|
|
180
183
|
throw artifactGraphTypeError(
|
|
181
184
|
reason,
|
|
182
185
|
`${label} must be a positive safe integer.`,
|
|
@@ -272,7 +275,7 @@ function lexicalCompare(left, right) {
|
|
|
272
275
|
}
|
|
273
276
|
|
|
274
277
|
function normalizeFile(value, kind, index) {
|
|
275
|
-
if (!value ||
|
|
278
|
+
if (!value || !is.object(value) || is.array(value)) {
|
|
276
279
|
throw new TypeError(`${kind} file ${String(index)} must be an object.`);
|
|
277
280
|
}
|
|
278
281
|
const path = requiredText(value.path ?? value.name, `${kind} file path`);
|
|
@@ -289,7 +292,7 @@ function normalizeFile(value, kind, index) {
|
|
|
289
292
|
index,
|
|
290
293
|
path,
|
|
291
294
|
url,
|
|
292
|
-
mediaType:
|
|
295
|
+
mediaType: is.string(value.mediaType) && value.mediaType.trim()
|
|
293
296
|
? value.mediaType.trim()
|
|
294
297
|
: kind === "runtime" && /\.(?:m?js)$/iu.test(path)
|
|
295
298
|
? "text/javascript"
|
|
@@ -300,7 +303,7 @@ function normalizeFile(value, kind, index) {
|
|
|
300
303
|
function uniqueFiles(files, label, kind, {
|
|
301
304
|
allowEmpty = false,
|
|
302
305
|
} = {}) {
|
|
303
|
-
if (!
|
|
306
|
+
if (!is.array(files) || (!allowEmpty && files.length < 1)) {
|
|
304
307
|
throw new TypeError(
|
|
305
308
|
allowEmpty
|
|
306
309
|
? `${label} files must be an array.`
|
|
@@ -330,7 +333,7 @@ function publicFile(file) {
|
|
|
330
333
|
}
|
|
331
334
|
|
|
332
335
|
function normalizeArtifactGraphFile(value, index) {
|
|
333
|
-
if (!value ||
|
|
336
|
+
if (!value || !is.object(value) || is.array(value)) {
|
|
334
337
|
throw artifactGraphTypeError(
|
|
335
338
|
"artifact-graph-file-descriptor-not-object",
|
|
336
339
|
`Artifact graph file ${String(index)} must be an object.`,
|
|
@@ -398,7 +401,7 @@ function normalizeArtifactGraphFile(value, index) {
|
|
|
398
401
|
);
|
|
399
402
|
}
|
|
400
403
|
const requestUrls = value.runtimeRequestUrls ?? [];
|
|
401
|
-
if (!
|
|
404
|
+
if (!is.array(requestUrls)) {
|
|
402
405
|
throw artifactGraphTypeError(
|
|
403
406
|
"artifact-graph-runtime-request-routes-not-array",
|
|
404
407
|
`Artifact graph file ${path} runtimeRequestUrls must be an array.`,
|
|
@@ -461,14 +464,14 @@ function normalizeGraphTargetPath(value, label, filesByPath, javascript = false)
|
|
|
461
464
|
}
|
|
462
465
|
|
|
463
466
|
function normalizeArtifactGraphVoices(value, defaultVoice, filesByPath) {
|
|
464
|
-
if (!
|
|
467
|
+
if (!is.array(value) || value.length < 1) {
|
|
465
468
|
throw artifactGraphTypeError(
|
|
466
469
|
"artifact-graph-voice-inventory-missing",
|
|
467
470
|
"A TTS artifact graph requires a nonempty voices array.",
|
|
468
471
|
);
|
|
469
472
|
}
|
|
470
473
|
const voices = value.map((voice, index) => {
|
|
471
|
-
if (!voice ||
|
|
474
|
+
if (!voice || !is.object(voice) || is.array(voice)) {
|
|
472
475
|
throw artifactGraphTypeError(
|
|
473
476
|
"artifact-graph-voice-descriptor-not-object",
|
|
474
477
|
`Artifact graph voice ${String(index)} must be an object.`,
|
|
@@ -567,19 +570,19 @@ export function createBrowserSpeechArtifactGraph({
|
|
|
567
570
|
"artifact-graph-provider-id-missing",
|
|
568
571
|
"artifact-graph-provider-id-length-exceeded",
|
|
569
572
|
);
|
|
570
|
-
if (!model ||
|
|
573
|
+
if (!model || !is.object(model) || is.array(model)) {
|
|
571
574
|
throw artifactGraphTypeError(
|
|
572
575
|
"artifact-graph-model-descriptor-missing",
|
|
573
576
|
"Browser speech artifact graph model descriptor is required.",
|
|
574
577
|
);
|
|
575
578
|
}
|
|
576
|
-
if (!runtime ||
|
|
579
|
+
if (!runtime || !is.object(runtime) || is.array(runtime)) {
|
|
577
580
|
throw artifactGraphTypeError(
|
|
578
581
|
"artifact-graph-runtime-descriptor-missing",
|
|
579
582
|
"Browser speech artifact graph runtime descriptor is required.",
|
|
580
583
|
);
|
|
581
584
|
}
|
|
582
|
-
if (!
|
|
585
|
+
if (!is.array(files) || files.length < 1) {
|
|
583
586
|
throw artifactGraphTypeError(
|
|
584
587
|
"artifact-graph-file-inventory-missing",
|
|
585
588
|
"Browser speech artifact graph requires a nonempty files array.",
|
|
@@ -677,7 +680,7 @@ export function createBrowserSpeechArtifactGraph({
|
|
|
677
680
|
);
|
|
678
681
|
}
|
|
679
682
|
const onnxWasm = runtime.onnxWasm;
|
|
680
|
-
if (!onnxWasm ||
|
|
683
|
+
if (!onnxWasm || !is.object(onnxWasm) || is.array(onnxWasm)) {
|
|
681
684
|
throw artifactGraphTypeError(
|
|
682
685
|
"artifact-graph-onnx-wasm-descriptor-missing",
|
|
683
686
|
"Browser speech artifact graph runtime onnxWasm descriptor is required.",
|
|
@@ -880,10 +883,10 @@ export function createBrowserSpeechAuthority({
|
|
|
880
883
|
if (role !== "stt" && role !== "tts") {
|
|
881
884
|
throw new TypeError('Browser speech role must be "stt" or "tts".');
|
|
882
885
|
}
|
|
883
|
-
if (!model ||
|
|
886
|
+
if (!model || !is.object(model) || is.array(model)) {
|
|
884
887
|
throw new TypeError("Browser speech model descriptor is required.");
|
|
885
888
|
}
|
|
886
|
-
if (!runtime ||
|
|
889
|
+
if (!runtime || !is.object(runtime) || is.array(runtime)) {
|
|
887
890
|
throw new TypeError("Browser speech runtime descriptor is required.");
|
|
888
891
|
}
|
|
889
892
|
const normalizedSecurity = normalizeModelSecurity(
|
|
@@ -1084,14 +1087,14 @@ function storageNames(authority, files) {
|
|
|
1084
1087
|
}
|
|
1085
1088
|
|
|
1086
1089
|
async function* byteChunks(body, signal) {
|
|
1087
|
-
if (body
|
|
1090
|
+
if (is.instanceCheck(body, Uint8Array) || is.instanceCheck(body, ArrayBuffer) || is.arrayBufferView(body)) {
|
|
1088
1091
|
throwIfAborted(signal);
|
|
1089
|
-
yield body
|
|
1092
|
+
yield is.instanceCheck(body, Uint8Array)
|
|
1090
1093
|
? body
|
|
1091
1094
|
: new Uint8Array(body.buffer ?? body, body.byteOffset ?? 0, body.byteLength);
|
|
1092
1095
|
return;
|
|
1093
1096
|
}
|
|
1094
|
-
if (body &&
|
|
1097
|
+
if (body && is.function(body.getReader)) {
|
|
1095
1098
|
const reader = body.getReader();
|
|
1096
1099
|
const abort = () => void reader.cancel(signal?.reason).catch(() => undefined);
|
|
1097
1100
|
signal?.addEventListener?.("abort", abort, { once: true });
|
|
@@ -1100,7 +1103,7 @@ async function* byteChunks(body, signal) {
|
|
|
1100
1103
|
throwIfAborted(signal);
|
|
1101
1104
|
const { done, value } = await reader.read();
|
|
1102
1105
|
if (done) return;
|
|
1103
|
-
yield value
|
|
1106
|
+
yield is.instanceCheck(value, Uint8Array) ? value : new Uint8Array(value);
|
|
1104
1107
|
}
|
|
1105
1108
|
} finally {
|
|
1106
1109
|
signal?.removeEventListener?.("abort", abort);
|
|
@@ -1347,7 +1350,7 @@ function ordinaryArtifactUrl(value, base) {
|
|
|
1347
1350
|
}
|
|
1348
1351
|
|
|
1349
1352
|
function isBareModuleSpecifier(value) {
|
|
1350
|
-
return
|
|
1353
|
+
return is.string(value)
|
|
1351
1354
|
&& !value.startsWith("./")
|
|
1352
1355
|
&& !value.startsWith("../")
|
|
1353
1356
|
&& !value.startsWith("/")
|
|
@@ -1696,7 +1699,7 @@ async function createOrdinaryArtifactObjectUrls(
|
|
|
1696
1699
|
) {
|
|
1697
1700
|
const create = objectUrlFactory?.create ?? PLATFORM_CREATE_OBJECT_URL;
|
|
1698
1701
|
const revoke = objectUrlFactory?.revoke ?? PLATFORM_REVOKE_OBJECT_URL;
|
|
1699
|
-
if (
|
|
1702
|
+
if (!is.function(create) || !is.function(revoke)) {
|
|
1700
1703
|
throw artifactGraphError(
|
|
1701
1704
|
"artifact-graph-object-url-platform-unavailable",
|
|
1702
1705
|
"Artifact materialization requires native Blob URL creation and revocation.",
|
|
@@ -1706,11 +1709,11 @@ async function createOrdinaryArtifactObjectUrls(
|
|
|
1706
1709
|
const materializedByPath = new Map();
|
|
1707
1710
|
const created = [];
|
|
1708
1711
|
async function materialize(descriptor, body) {
|
|
1709
|
-
const blob = body
|
|
1712
|
+
const blob = is.instanceCheck(body, Blob) && body.type === descriptor.mediaType
|
|
1710
1713
|
? body
|
|
1711
1714
|
: new Blob([body], { type: descriptor.mediaType });
|
|
1712
1715
|
const moduleUrl = create(blob);
|
|
1713
|
-
if (
|
|
1716
|
+
if (!is.string(moduleUrl)) {
|
|
1714
1717
|
throw artifactGraphError(
|
|
1715
1718
|
"artifact-graph-object-url-platform-unavailable",
|
|
1716
1719
|
`Artifact file ${descriptor.path} did not produce an object URL.`,
|
|
@@ -1777,7 +1780,7 @@ async function createOrdinaryArtifactObjectUrls(
|
|
|
1777
1780
|
function createObjectUrls(files, factory) {
|
|
1778
1781
|
const create = factory?.create ?? ((blob) => URL.createObjectURL(blob));
|
|
1779
1782
|
const revoke = factory?.revoke ?? ((url) => URL.revokeObjectURL(url));
|
|
1780
|
-
if (
|
|
1783
|
+
if (!is.function(create) || !is.function(revoke)) {
|
|
1781
1784
|
throw new TypeError("Browser speech objectUrlFactory requires create() and revoke().");
|
|
1782
1785
|
}
|
|
1783
1786
|
const created = [];
|
|
@@ -1830,14 +1833,14 @@ export function createDbopfsSpeechArtifactStore({
|
|
|
1830
1833
|
fetchImpl = null,
|
|
1831
1834
|
objectUrlFactory = null,
|
|
1832
1835
|
} = {}) {
|
|
1833
|
-
if (!dbopfs ||
|
|
1836
|
+
if (!dbopfs || !is.function(dbopfs.getTableHandle)) {
|
|
1834
1837
|
throw new TypeError("createDbopfsSpeechArtifactStore requires an existing DBOPFS instance.");
|
|
1835
1838
|
}
|
|
1836
|
-
if (dbopfs.readyPromise !== undefined &&
|
|
1839
|
+
if (dbopfs.readyPromise !== undefined && !is.function(dbopfs.readyPromise?.then)) {
|
|
1837
1840
|
throw new TypeError("The DBOPFS readyPromise must be thenable.");
|
|
1838
1841
|
}
|
|
1839
1842
|
const locks = dbopfs.lockManager ?? globalThis.navigator?.locks;
|
|
1840
|
-
if (!locks ||
|
|
1843
|
+
if (!locks || !is.function(locks.request)) {
|
|
1841
1844
|
throw new TypeError(
|
|
1842
1845
|
"createDbopfsSpeechArtifactStore requires the browser Web Locks API.",
|
|
1843
1846
|
);
|
|
@@ -1873,7 +1876,7 @@ export function createDbopfsSpeechArtifactStore({
|
|
|
1873
1876
|
if (dbopfs.readyPromise) await dbopfs.readyPromise;
|
|
1874
1877
|
tablePromise ||= Promise.resolve(dbopfs.getTableHandle(tableName));
|
|
1875
1878
|
const result = await tablePromise;
|
|
1876
|
-
if (!result ||
|
|
1879
|
+
if (!result || !is.function(result.getFileHandle) || !is.function(result.removeEntry)) {
|
|
1877
1880
|
throw speechError("ARCANE_AI_STORAGE_UNAVAILABLE", "DBOPFS did not provide a speech artifact table.");
|
|
1878
1881
|
}
|
|
1879
1882
|
return result;
|
|
@@ -1934,7 +1937,7 @@ export function createDbopfsSpeechArtifactStore({
|
|
|
1934
1937
|
const metadata = artifactMetadata(authority);
|
|
1935
1938
|
const names = storageNames(authority, metadata.files);
|
|
1936
1939
|
const priorSelection = await readJsonFile(names.selection);
|
|
1937
|
-
const priorCount =
|
|
1940
|
+
const priorCount = is.array(priorSelection?.files)
|
|
1938
1941
|
? priorSelection.files.length
|
|
1939
1942
|
: 0;
|
|
1940
1943
|
const fileNames = Array.from(
|
|
@@ -2000,7 +2003,7 @@ export function createDbopfsSpeechArtifactStore({
|
|
|
2000
2003
|
const metadata = artifactMetadata(authority);
|
|
2001
2004
|
const names = storageNames(authority, metadata.files);
|
|
2002
2005
|
const fetchFunction = fetchImpl ?? globalThis.fetch?.bind(globalThis);
|
|
2003
|
-
if (
|
|
2006
|
+
if (!is.function(fetchFunction)) {
|
|
2004
2007
|
throw speechError("ARCANE_AI_ARTIFACT_SOURCE_UNAVAILABLE", "Browser fetch is unavailable.");
|
|
2005
2008
|
}
|
|
2006
2009
|
await removeUnlocked(authority);
|
|
@@ -2039,16 +2042,16 @@ export function createDbopfsSpeechArtifactStore({
|
|
|
2039
2042
|
let responseOk;
|
|
2040
2043
|
let responseStatus;
|
|
2041
2044
|
try {
|
|
2042
|
-
if (!response ||
|
|
2045
|
+
if (!response || !is.object(response)) {
|
|
2043
2046
|
throw new TypeError("The artifact fetch result is not an object.");
|
|
2044
2047
|
}
|
|
2045
2048
|
responseBody = response.body;
|
|
2046
2049
|
responseOk = response.ok;
|
|
2047
2050
|
responseStatus = response.status;
|
|
2048
2051
|
if (
|
|
2049
|
-
|
|
2050
|
-
|| !
|
|
2051
|
-
|| (responseBody !== null &&
|
|
2052
|
+
!is.boolean(responseOk)
|
|
2053
|
+
|| !is.integer(responseStatus)
|
|
2054
|
+
|| (responseBody !== null && !is.function(responseBody?.getReader))
|
|
2052
2055
|
) {
|
|
2053
2056
|
throw new TypeError("The artifact fetch result is not a readable Fetch Response.");
|
|
2054
2057
|
}
|