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.
- package/CHANGELOG.md +44 -0
- package/README.md +42 -19
- 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 +53 -46
- package/browser-runtime/ai/browser-wasm-llm-provider.mjs +127 -124
- package/browser-runtime/ai/browser-wasm.mjs +6 -3
- package/browser-runtime/ai/browser-wllama-runtime.mjs +26 -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 +35 -0
- package/docs/architecture.md +1 -1
- package/docs/reference/README.md +8 -8
- package/docs/reference/ai/browser-speech.md +230 -16
- package/docs/reference/ai/twin-cloud.md +1 -1
- package/docs/reference/availability-and-normalization.md +42 -1
- package/docs/reference/cli.md +1 -1
- package/docs/reference/core/arcane-ai-contracts.md +1 -1
- package/docs/reference/inventory/package-api.json +60 -4
- package/docs/reference/inventory/runtime-components.json +2 -2
- package/docs/reference/inventory/runtime-modules.json +29 -31
- package/docs/reference/protocols.md +17 -13
- package/docs/reference/runtime-components.md +6 -5
- package/docs/reference/runtime-modules.md +212 -70
- package/docs/reference/sdk-api.md +197 -11
- 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 +4 -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 +118 -141
- 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 +503 -187
- package/runtime/arcane/modules/AIPreferenceRuntime.js +5 -2
- package/runtime/arcane/modules/AIPreferenceTuple.js +9 -6
- package/runtime/arcane/modules/AIProviderRuntime.js +117 -92
- 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/MarkdownSpeech.js +1 -50
- 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 +61 -28
- 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 +36 -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
|
@@ -1,45 +1,69 @@
|
|
|
1
|
-
{
|
|
2
|
-
"name": "strong-type",
|
|
3
|
-
"version": "
|
|
4
|
-
"type": "module",
|
|
5
|
-
"description": "
|
|
6
|
-
"main": "index.js",
|
|
7
|
-
"
|
|
8
|
-
"
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
"node": "
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
"
|
|
16
|
-
"
|
|
17
|
-
"
|
|
18
|
-
"
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
"
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
"
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
"
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
"
|
|
40
|
-
"
|
|
41
|
-
"
|
|
42
|
-
"
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
1
|
+
{
|
|
2
|
+
"name": "strong-type",
|
|
3
|
+
"version": "2.0.1",
|
|
4
|
+
"type": "module",
|
|
5
|
+
"description": "Dependency-free native ESM type enforcement for JavaScript values, objects, classes, browsers, and Node.",
|
|
6
|
+
"main": "index.js",
|
|
7
|
+
"exports": {
|
|
8
|
+
".": "./index.js",
|
|
9
|
+
"./index.js": "./index.js",
|
|
10
|
+
"./node": "./node.js",
|
|
11
|
+
"./node.js": "./node.js",
|
|
12
|
+
"./package.json": "./package.json"
|
|
13
|
+
},
|
|
14
|
+
"files": [
|
|
15
|
+
"index.js",
|
|
16
|
+
"node.js",
|
|
17
|
+
"benchmark/core.js",
|
|
18
|
+
"assets/strong-type-header.png",
|
|
19
|
+
"README.md",
|
|
20
|
+
"licence"
|
|
21
|
+
],
|
|
22
|
+
"sideEffects": false,
|
|
23
|
+
"directories": {
|
|
24
|
+
"example": "example"
|
|
25
|
+
},
|
|
26
|
+
"engines": {
|
|
27
|
+
"node": ">=12.21.0"
|
|
28
|
+
},
|
|
29
|
+
"scripts": {
|
|
30
|
+
"benchmark": "node benchmark/core.js",
|
|
31
|
+
"benchmark:baseline": "node benchmark/core.js --baseline",
|
|
32
|
+
"benchmark:historical": "node benchmark/core.js --historical",
|
|
33
|
+
"test": "node scripts/test.js",
|
|
34
|
+
"test:unit": "node scripts/test.js unit",
|
|
35
|
+
"test:functional": "node scripts/test.js functional",
|
|
36
|
+
"test:integration": "node scripts/test.js integration",
|
|
37
|
+
"test:regression": "node scripts/test.js regression",
|
|
38
|
+
"test:legacy": "node scripts/test.js legacy",
|
|
39
|
+
"coverage": "vanilla-test coverage node",
|
|
40
|
+
"start": "node scripts/serve.js",
|
|
41
|
+
"nodeExample": "node ./example/node/typecheck.js",
|
|
42
|
+
"check": "npm test"
|
|
43
|
+
},
|
|
44
|
+
"repository": {
|
|
45
|
+
"type": "git",
|
|
46
|
+
"url": "git+https://github.com/RIAEvangelist/strong-type.git"
|
|
47
|
+
},
|
|
48
|
+
"keywords": [
|
|
49
|
+
"strong",
|
|
50
|
+
"type",
|
|
51
|
+
"validation",
|
|
52
|
+
"validate",
|
|
53
|
+
"check",
|
|
54
|
+
"checking",
|
|
55
|
+
"esm",
|
|
56
|
+
"isomorphic",
|
|
57
|
+
"browser",
|
|
58
|
+
"node"
|
|
59
|
+
],
|
|
60
|
+
"author": "Roshi _ _",
|
|
61
|
+
"license": "MIT",
|
|
62
|
+
"bugs": {
|
|
63
|
+
"url": "https://github.com/RIAEvangelist/strong-type/issues"
|
|
64
|
+
},
|
|
65
|
+
"homepage": "https://riaevangelist.github.io/strong-type/",
|
|
66
|
+
"devDependencies": {
|
|
67
|
+
"vanilla-test": "2.1.0"
|
|
68
|
+
}
|
|
69
|
+
}
|
package/src/app-descriptor.mjs
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import Is from 'strong-type';
|
|
1
2
|
import {isDeepStrictEqual} from 'node:util';
|
|
2
3
|
import {readFile} from 'node:fs/promises';
|
|
3
4
|
import path from 'node:path';
|
|
@@ -12,6 +13,8 @@ import {
|
|
|
12
13
|
validateAppConfig as validateAppPackageConfig
|
|
13
14
|
} from './packager/core.mjs';
|
|
14
15
|
|
|
16
|
+
const is = new Is(false);
|
|
17
|
+
|
|
15
18
|
export const APP_DESCRIPTOR_NAME='arcane-app.json';
|
|
16
19
|
export const APP_DESCRIPTOR_SCHEMA_VERSION=2;
|
|
17
20
|
|
|
@@ -35,7 +38,7 @@ function fail(message){
|
|
|
35
38
|
}
|
|
36
39
|
|
|
37
40
|
function isObject(value){
|
|
38
|
-
return value!==null&&
|
|
41
|
+
return value!==null&&is.object(value)&&!is.array(value);
|
|
39
42
|
}
|
|
40
43
|
|
|
41
44
|
function assertOnlyKeys(value,allowed,label){
|
|
@@ -46,7 +49,7 @@ function assertOnlyKeys(value,allowed,label){
|
|
|
46
49
|
}
|
|
47
50
|
|
|
48
51
|
function safeText(value,label){
|
|
49
|
-
if(
|
|
52
|
+
if(!is.string(value)||value!==value.trim()||!value
|
|
50
53
|
||/[<>\u0000-\u001f\u007f]/u.test(value)){
|
|
51
54
|
fail(`${label} must be nonempty, trimmed presentation text.`);
|
|
52
55
|
}
|
|
@@ -54,11 +57,11 @@ function safeText(value,label){
|
|
|
54
57
|
}
|
|
55
58
|
|
|
56
59
|
function uniqueSortedStrings(value,label,{pattern,required=false}={}){
|
|
57
|
-
if(!
|
|
60
|
+
if(!is.array(value)||(required&&value.length===0)){
|
|
58
61
|
fail(`${label} must be ${required?'a nonempty':'an'} array.`);
|
|
59
62
|
}
|
|
60
63
|
const normalized=value.map((entry,index)=>{
|
|
61
|
-
if(
|
|
64
|
+
if(!is.string(entry)||entry!==entry.trim()||!entry
|
|
62
65
|
||(pattern&&!pattern.test(entry))){
|
|
63
66
|
fail(`${label}[${index}] is invalid.`);
|
|
64
67
|
}
|
|
@@ -68,7 +71,7 @@ function uniqueSortedStrings(value,label,{pattern,required=false}={}){
|
|
|
68
71
|
}
|
|
69
72
|
|
|
70
73
|
function relativePaths(value,label,{required=false}={}){
|
|
71
|
-
if(!
|
|
74
|
+
if(!is.array(value)||(required&&value.length===0)){
|
|
72
75
|
fail(`${label} must be ${required?'a nonempty':'an'} array.`);
|
|
73
76
|
}
|
|
74
77
|
const normalized=value.map((entry,index)=>normalizeRelativePath(entry,`${label}[${index}]`));
|
|
@@ -76,9 +79,9 @@ function relativePaths(value,label,{required=false}={}){
|
|
|
76
79
|
}
|
|
77
80
|
|
|
78
81
|
function validateOrigins(value,label){
|
|
79
|
-
if(!
|
|
82
|
+
if(!is.array(value))fail(`${label} must be an array of origins.`);
|
|
80
83
|
const origins=value.map((origin,index)=>{
|
|
81
|
-
if(
|
|
84
|
+
if(!is.string(origin)||!origin.trim())fail(`${label}[${index}] is invalid.`);
|
|
82
85
|
return origin;
|
|
83
86
|
});
|
|
84
87
|
return completeValue(origins);
|
|
@@ -87,14 +90,14 @@ function validateOrigins(value,label){
|
|
|
87
90
|
function validateLocalAIModelPolicy(value,label){
|
|
88
91
|
if(value===undefined)return undefined;
|
|
89
92
|
assertOnlyKeys(value,new Set(['verified_only','models']),label);
|
|
90
|
-
if(
|
|
93
|
+
if(!is.boolean(value.verified_only)||!is.array(value.models)){
|
|
91
94
|
fail(`${label} is invalid.`);
|
|
92
95
|
}
|
|
93
96
|
const models=value.models.map((model,index)=>{
|
|
94
97
|
const itemLabel=`${label}.models[${index}]`;
|
|
95
98
|
assertOnlyKeys(model,new Set(['name','definition']),itemLabel);
|
|
96
|
-
if(
|
|
97
|
-
|
|
99
|
+
if(!is.string(model.name)||!model.name
|
|
100
|
+
||!is.string(model.definition)||!model.definition.endsWith('Modelfile')){
|
|
98
101
|
fail(`${itemLabel} is invalid.`);
|
|
99
102
|
}
|
|
100
103
|
return completeValue({name:model.name,definition:normalizeRelativePath(model.definition,`${itemLabel}.definition`)});
|
|
@@ -144,7 +147,7 @@ function validatePackage(value,appId){
|
|
|
144
147
|
|
|
145
148
|
function validatePublisher(value){
|
|
146
149
|
assertOnlyKeys(value,new Set(['id','name']),'descriptor.publisher');
|
|
147
|
-
if(
|
|
150
|
+
if(!is.string(value.id)||!PUBLISHER_PATTERN.test(value.id)){
|
|
148
151
|
fail('descriptor.publisher.id must be a lowercase publisher identifier.');
|
|
149
152
|
}
|
|
150
153
|
return completeValue({id:value.id,name:safeText(value.name,'descriptor.publisher.name')});
|
|
@@ -191,7 +194,7 @@ function validateDocumentCatalog(value){
|
|
|
191
194
|
assertOnlyKeys(value,new Set([
|
|
192
195
|
'policy','release','destination','originals','manifest','expectedCount'
|
|
193
196
|
]),label);
|
|
194
|
-
if(value.policy!=='public-only'||!
|
|
197
|
+
if(value.policy!=='public-only'||!is.integer(value.expectedCount)
|
|
195
198
|
||value.expectedCount<1){
|
|
196
199
|
fail(`${label} has unsupported policy or expectedCount.`);
|
|
197
200
|
}
|
|
@@ -219,7 +222,7 @@ function validateNative(value,appId){
|
|
|
219
222
|
assertOnlyKeys(value,new Set(['type','icon','order','bundledApps','documentCatalog']),'descriptor.native');
|
|
220
223
|
if(!NATIVE_TYPES.has(value.type))fail('descriptor.native.type is unsupported.');
|
|
221
224
|
const icon=value.icon===null?null:normalizeRelativePath(value.icon,'descriptor.native.icon');
|
|
222
|
-
if(!
|
|
225
|
+
if(!is.integer(value.order)||value.order<0){
|
|
223
226
|
fail('descriptor.native.order must be a nonnegative integer.');
|
|
224
227
|
}
|
|
225
228
|
const bundledApps=uniqueSortedStrings(value.bundledApps,'descriptor.native.bundledApps',{
|
|
@@ -392,7 +395,7 @@ function synthesizedDescriptor(packageManifest,nativeDescriptor){
|
|
|
392
395
|
native:{
|
|
393
396
|
type:native.type??'app',
|
|
394
397
|
icon:native.icon??null,
|
|
395
|
-
order:
|
|
398
|
+
order:is.integer(native.order)?native.order:100,
|
|
396
399
|
bundledApps:[...(native.bundledApps??[])],
|
|
397
400
|
...(native.documentCatalog?{documentCatalog:native.documentCatalog}:{})
|
|
398
401
|
},
|
|
@@ -1,14 +1,17 @@
|
|
|
1
|
+
import Is from 'strong-type';
|
|
1
2
|
import {lstat,readdir,realpath} from 'node:fs/promises';
|
|
2
3
|
import path from 'node:path';
|
|
3
4
|
import {fileURLToPath} from 'node:url';
|
|
4
5
|
import {ArcaneError,ERROR_CODES,throwIfAborted} from './errors.mjs';
|
|
5
6
|
import {runProcess} from './process.mjs';
|
|
6
7
|
|
|
8
|
+
const is = new Is(false);
|
|
9
|
+
|
|
7
10
|
const TEST_RUNNER_PATH=fileURLToPath(new URL('../bin/arcane-test.mjs',import.meta.url));
|
|
8
11
|
const MANAGED_IMPORT_MAP_ENV='ARCANE_TEST_IMPORT_MAP_CONTEXT';
|
|
9
12
|
|
|
10
13
|
function normalizedTestOutput(value){
|
|
11
|
-
return
|
|
14
|
+
return is.string(value)?value:'';
|
|
12
15
|
}
|
|
13
16
|
|
|
14
17
|
function captureFailedTest(testFile,result,workspaceRoot){
|
package/src/cli/main.mjs
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import Is from 'strong-type';
|
|
1
2
|
import path from 'node:path';
|
|
2
3
|
import {createReporter} from '../events.mjs';
|
|
3
4
|
import {executeOperation} from '../toolchain.mjs';
|
|
@@ -6,6 +7,8 @@ import {CLI_NAME,SDK_NAME,SDK_VERSION,OUTPUT_MODES} from '../constants.mjs';
|
|
|
6
7
|
import {loadArcaneNativeProvider} from '../native-provider-loader.mjs';
|
|
7
8
|
import {APP_BUNDLE_EXTENSION} from '../release-bundle.mjs';
|
|
8
9
|
|
|
10
|
+
const is = new Is(false);
|
|
11
|
+
|
|
9
12
|
const VALUE_OPTIONS=new Set([
|
|
10
13
|
'path',
|
|
11
14
|
'display-name',
|
|
@@ -169,7 +172,7 @@ function readPort(value,defaultValue){
|
|
|
169
172
|
usage(`Invalid port: ${value}.`);
|
|
170
173
|
}
|
|
171
174
|
const port=Number(value);
|
|
172
|
-
if(!
|
|
175
|
+
if(!is.safeInteger(port)||port<0||port>65535){
|
|
173
176
|
usage(`Invalid port: ${value}.`);
|
|
174
177
|
}
|
|
175
178
|
return port;
|
|
@@ -181,7 +184,7 @@ function readRequestTimeout(value){
|
|
|
181
184
|
usage(`Invalid request timeout: ${value}.`);
|
|
182
185
|
}
|
|
183
186
|
const timeout=Number(value);
|
|
184
|
-
if(!
|
|
187
|
+
if(!is.safeInteger(timeout)||timeout<1||timeout>MAX_NODE_TIMER_DELAY_MS){
|
|
185
188
|
usage(
|
|
186
189
|
`Mail request timeout must be an integer from 1 through ${MAX_NODE_TIMER_DELAY_MS} `
|
|
187
190
|
+'milliseconds, the Node timer range.'
|
|
@@ -253,7 +256,7 @@ function readPipedMailSecret(input,signal){
|
|
|
253
256
|
}
|
|
254
257
|
|
|
255
258
|
function readMaskedMailSecret(input,output,signal,label,stdinOption){
|
|
256
|
-
if(!input?.isTTY
|
|
259
|
+
if(!input?.isTTY||!is.function(input.setRawMode)||!is.function(output?.write)){
|
|
257
260
|
usage(`Interactive mail credential entry requires a terminal; use ${stdinOption} for piped input.`);
|
|
258
261
|
}
|
|
259
262
|
return new Promise((resolve,reject)=>{
|
|
@@ -353,7 +356,7 @@ function readPipedMailReport(input,signal){
|
|
|
353
356
|
}catch{
|
|
354
357
|
usage('Mail report input must be one valid JSON object.');
|
|
355
358
|
}
|
|
356
|
-
if(!report
|
|
359
|
+
if(!report||!is.object(report)||is.array(report)){
|
|
357
360
|
usage('Mail report input must be one valid JSON object.');
|
|
358
361
|
}
|
|
359
362
|
finish(resolve,report);
|
|
@@ -839,7 +842,7 @@ function serverSummary(result){
|
|
|
839
842
|
|
|
840
843
|
async function waitForServer(result,signal,reporter){
|
|
841
844
|
reporter.emit('server.ready',serverSummary(result),`Development server ready at ${result.url}`);
|
|
842
|
-
if(result.lifecycle&&
|
|
845
|
+
if(result.lifecycle&&is.function(result.lifecycle.then)){
|
|
843
846
|
const abort=()=>{
|
|
844
847
|
void Promise.resolve().then(()=>result.close?.()).catch(()=>{});
|
|
845
848
|
};
|
package/src/constants.mjs
CHANGED
|
@@ -1,8 +1,11 @@
|
|
|
1
|
+
import Is from 'strong-type';
|
|
1
2
|
import path from 'node:path';
|
|
2
3
|
import {fileURLToPath} from 'node:url';
|
|
3
4
|
import packageDocument from '../package.json' with {type:'json'};
|
|
4
5
|
|
|
5
|
-
|
|
6
|
+
const is = new Is(false);
|
|
7
|
+
|
|
8
|
+
if(packageDocument.name!=='arcane-os'||!is.string(packageDocument.version)
|
|
6
9
|
||!/^[0-9]+\.[0-9]+\.[0-9]+(?:-[0-9A-Za-z.-]+)?$/u.test(packageDocument.version)){
|
|
7
10
|
throw new Error('The Arcane SDK package identity is invalid.');
|
|
8
11
|
}
|
package/src/dev-server.mjs
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import Is from 'strong-type';
|
|
1
2
|
import {constants as FS_CONSTANTS} from 'node:fs';
|
|
2
3
|
import {lstat,open,readFile,realpath} from 'node:fs/promises';
|
|
3
4
|
import http from 'node:http';
|
|
@@ -9,6 +10,8 @@ import {
|
|
|
9
10
|
readWorkspaceAssetVersion,rewriteAssetReferences
|
|
10
11
|
} from './import-map.mjs';
|
|
11
12
|
|
|
13
|
+
const is = new Is(false);
|
|
14
|
+
|
|
12
15
|
const MIME_TYPES=new Map([
|
|
13
16
|
['.css','text/css; charset=utf-8'],
|
|
14
17
|
['.gif','image/gif'],
|
|
@@ -165,12 +168,12 @@ function sdkBrowserSourcePathAllowed(relative){
|
|
|
165
168
|
}
|
|
166
169
|
|
|
167
170
|
async function emitRuntimeSourceEvent(onEvent,event){
|
|
168
|
-
if(
|
|
171
|
+
if(is.function(onEvent))await onEvent(event);
|
|
169
172
|
}
|
|
170
173
|
|
|
171
174
|
async function verifySdkRuntimeSourceRoot(sourceRoot,workspaceRoot,appId,{signal,onEvent}={}){
|
|
172
175
|
throwIfAborted(signal);
|
|
173
|
-
if(
|
|
176
|
+
if(!is.string(sourceRoot)||!sourceRoot.trim()){
|
|
174
177
|
fail('sdkRuntimeSourceRoot must name an Arcane SDK directory.',
|
|
175
178
|
'ARCANE_DEV_RUNTIME_SOURCE_INVALID');
|
|
176
179
|
}
|
|
@@ -449,7 +452,7 @@ async function sourceRoutes(workspaceRoot,appId,{
|
|
|
449
452
|
}
|
|
450
453
|
|
|
451
454
|
async function packagedRoutes(releaseRoot){
|
|
452
|
-
if(
|
|
455
|
+
if(!is.string(releaseRoot)||!releaseRoot.trim())fail('releaseRoot is required in packaged mode.','ARCANE_USAGE');
|
|
453
456
|
const requested=path.resolve(releaseRoot);
|
|
454
457
|
const canonical=await canonicalRealDirectory(requested,'Packaged release root');
|
|
455
458
|
return {
|
|
@@ -504,7 +507,7 @@ async function startOwnedDevServer({
|
|
|
504
507
|
if(host!=='127.0.0.1'&&host!=='::1'){
|
|
505
508
|
fail('Development server host must be a numeric loopback address (127.0.0.1 or ::1).','ARCANE_POLICY_DENIED');
|
|
506
509
|
}
|
|
507
|
-
if(!
|
|
510
|
+
if(!is.integer(port)||port<0||port>65535)fail('port must be an integer from 0 through 65535.','ARCANE_USAGE');
|
|
508
511
|
const requestedRuntimeMode=mode==='source'&&sdkRuntimeSourceRoot!==undefined
|
|
509
512
|
?'sdk-source'
|
|
510
513
|
:null;
|
|
@@ -624,7 +627,7 @@ async function startOwnedDevServer({
|
|
|
624
627
|
});
|
|
625
628
|
await listen(server,{host,port,signal});
|
|
626
629
|
const address=server.address();
|
|
627
|
-
if(!address||
|
|
630
|
+
if(!address||is.string(address)){
|
|
628
631
|
server.close();
|
|
629
632
|
fail('Development server did not expose a TCP address.');
|
|
630
633
|
}
|
package/src/doctor.mjs
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import Is from 'strong-type';
|
|
1
2
|
import path from 'node:path';
|
|
2
3
|
import {access,lstat,readdir,realpath} from 'node:fs/promises';
|
|
3
4
|
import {loadRuntimeRelease} from './runtime.mjs';
|
|
@@ -7,6 +8,8 @@ import {runProcess} from './process.mjs';
|
|
|
7
8
|
import {ARCANE_PROTOCOL,SDK_VERSION} from './constants.mjs';
|
|
8
9
|
import {ERROR_CODES,ArcaneError,throwIfAborted} from './errors.mjs';
|
|
9
10
|
|
|
11
|
+
const is = new Is(false);
|
|
12
|
+
|
|
10
13
|
const WINDOWS_SERVICE_NAME='ArcaneOllama';
|
|
11
14
|
const WINDOWS_SERVICE_HOST='C:\\Program Files\\Ollama\\ArcaneOllamaService.exe';
|
|
12
15
|
|
|
@@ -47,8 +50,8 @@ function parseProbe(text){
|
|
|
47
50
|
}catch{
|
|
48
51
|
return null;
|
|
49
52
|
}
|
|
50
|
-
if(!value
|
|
51
|
-
||Object.getPrototypeOf(value)!==Object.prototype
|
|
53
|
+
if(!value||!is.object(value)||is.array(value)
|
|
54
|
+
||Object.getPrototypeOf(value)!==Object.prototype||!is.boolean(value.ready)){
|
|
52
55
|
return null;
|
|
53
56
|
}
|
|
54
57
|
return {...value};
|
|
@@ -1,3 +1,7 @@
|
|
|
1
|
+
import Is from 'strong-type';
|
|
2
|
+
|
|
3
|
+
const is = new Is(false);
|
|
4
|
+
|
|
1
5
|
export const DOM_INTERACTION_EVENT='arcane.dom.interaction';
|
|
2
6
|
export const DOM_MUTATION_EVENT='arcane.dom.mutation';
|
|
3
7
|
export const DOM_OBSERVATION_STARTED_EVENT='arcane.dom.observation.started';
|
|
@@ -25,13 +29,13 @@ function capturedString(value){
|
|
|
25
29
|
}
|
|
26
30
|
|
|
27
31
|
function cssEscape(value){
|
|
28
|
-
if(
|
|
32
|
+
if(is.function(globalThis.CSS?.escape))return globalThis.CSS.escape(value);
|
|
29
33
|
return String(value).replaceAll(/[^a-zA-Z0-9_-]/gu,character=>`\\${character.codePointAt(0).toString(16)} `);
|
|
30
34
|
}
|
|
31
35
|
|
|
32
36
|
function readAttribute(target,name){
|
|
33
37
|
try{
|
|
34
|
-
return
|
|
38
|
+
return is.function(target?.getAttribute)?target.getAttribute(name):null;
|
|
35
39
|
}catch{
|
|
36
40
|
return null;
|
|
37
41
|
}
|
|
@@ -67,7 +71,7 @@ function selectorSegment(target){
|
|
|
67
71
|
}
|
|
68
72
|
|
|
69
73
|
export function domSelector(target,root){
|
|
70
|
-
if(!target
|
|
74
|
+
if(!target||!is.object(target))return null;
|
|
71
75
|
if(target.nodeType===9)return ':document';
|
|
72
76
|
if(target.nodeType===11)return ':shadow-root';
|
|
73
77
|
if(target.nodeType===3)return domSelector(target.parentElement??target.parentNode,root);
|
|
@@ -111,7 +115,7 @@ export function domSelector(target,root){
|
|
|
111
115
|
}
|
|
112
116
|
|
|
113
117
|
export function describeDOMTarget(target,root){
|
|
114
|
-
if(!target
|
|
118
|
+
if(!target||!is.object(target))return null;
|
|
115
119
|
if(target.nodeType===9){
|
|
116
120
|
return {kind:'document',selector:':document'};
|
|
117
121
|
}
|
|
@@ -145,7 +149,7 @@ export function describeDOMTarget(target,root){
|
|
|
145
149
|
}
|
|
146
150
|
|
|
147
151
|
function targetValue(target){
|
|
148
|
-
if(!target
|
|
152
|
+
if(!target||!is.object(target))return undefined;
|
|
149
153
|
const type=String(target.type??'').toLowerCase();
|
|
150
154
|
if(type==='checkbox'||type==='radio')return Boolean(target.checked);
|
|
151
155
|
if(type==='file'){
|
|
@@ -156,24 +160,24 @@ function targetValue(target){
|
|
|
156
160
|
}
|
|
157
161
|
|
|
158
162
|
function safeEventDetail(value){
|
|
159
|
-
if(
|
|
160
|
-
if(value===null||
|
|
163
|
+
if(is.string(value))return capturedString(value);
|
|
164
|
+
if(value===null||is.number(value)||is.boolean(value))return value;
|
|
161
165
|
return value;
|
|
162
166
|
}
|
|
163
167
|
|
|
164
168
|
function interactionRecord(event,root){
|
|
165
|
-
const path=
|
|
166
|
-
const target=path.find(item=>item&&
|
|
169
|
+
const path=is.function(event?.composedPath)?event.composedPath():[event?.target];
|
|
170
|
+
const target=path.find(item=>item&&is.object(item))??event?.target??null;
|
|
167
171
|
const eventType=String(event?.type??'');
|
|
168
172
|
const details={};
|
|
169
173
|
const fields=new Set([
|
|
170
174
|
...EVENT_FIELDS,
|
|
171
|
-
...Reflect.ownKeys(event??{}).filter(field=>
|
|
175
|
+
...Reflect.ownKeys(event??{}).filter(field=>is.string(field))
|
|
172
176
|
]);
|
|
173
177
|
for(const field of fields){
|
|
174
178
|
let value;
|
|
175
179
|
try{value=event?.[field];}catch{continue;}
|
|
176
|
-
if(value!==undefined
|
|
180
|
+
if(value!==undefined&&!is.function(value)){
|
|
177
181
|
details[field]=safeEventDetail(value);
|
|
178
182
|
}
|
|
179
183
|
}
|
|
@@ -254,7 +258,7 @@ function collectOpenShadowRoots(root){
|
|
|
254
258
|
const roots=[];
|
|
255
259
|
const candidates=[];
|
|
256
260
|
try{
|
|
257
|
-
if(
|
|
261
|
+
if(is.function(root?.querySelectorAll))candidates.push(...root.querySelectorAll('*'));
|
|
258
262
|
}catch{}
|
|
259
263
|
for(const candidate of candidates){
|
|
260
264
|
if(candidate?.shadowRoot)roots.push(candidate.shadowRoot,...collectOpenShadowRoots(candidate.shadowRoot));
|
|
@@ -270,18 +274,18 @@ export function createDOMInstrumentation({
|
|
|
270
274
|
captureMutations=true,
|
|
271
275
|
observeOpenShadowRoots=true
|
|
272
276
|
}={}){
|
|
273
|
-
if(!eventManager
|
|
277
|
+
if(!eventManager||!is.function(eventManager.emit)){
|
|
274
278
|
throw new TypeError('DOM instrumentation requires an event manager.');
|
|
275
279
|
}
|
|
276
|
-
if(!root
|
|
280
|
+
if(!root||!is.function(root.addEventListener)||!is.function(root.removeEventListener)){
|
|
277
281
|
throw new TypeError('DOM instrumentation requires an EventTarget-compatible root.');
|
|
278
282
|
}
|
|
279
|
-
if(!
|
|
283
|
+
if(!is.array(eventTypes)||eventTypes.some(type=>!is.string(type)||!type)){
|
|
280
284
|
throw new TypeError('DOM event types must be non-empty strings.');
|
|
281
285
|
}
|
|
282
286
|
eventTypes=[...new Set(eventTypes)];
|
|
283
287
|
for(const [name,value] of Object.entries({captureMutations,observeOpenShadowRoots})){
|
|
284
|
-
if(
|
|
288
|
+
if(!is.boolean(value))throw new TypeError(`${name} must be boolean.`);
|
|
285
289
|
}
|
|
286
290
|
const observedRoots=new Set();
|
|
287
291
|
const listenerRegistrations=new Map();
|
|
@@ -351,7 +355,7 @@ export function createDOMInstrumentation({
|
|
|
351
355
|
|
|
352
356
|
const publish=(type,payload,metadata)=>{
|
|
353
357
|
const before=Number(eventManager.eventCount??0);
|
|
354
|
-
if(
|
|
358
|
+
if(is.function(eventManager.instrument)){
|
|
355
359
|
eventManager.instrument(type,payload,{source:'dom',...metadata});
|
|
356
360
|
}else{
|
|
357
361
|
eventManager.emit(type,payload);
|
|
@@ -365,7 +369,7 @@ export function createDOMInstrumentation({
|
|
|
365
369
|
const interaction=(event,observedRoot)=>{
|
|
366
370
|
let path=[];
|
|
367
371
|
try{
|
|
368
|
-
if(
|
|
372
|
+
if(is.function(event?.composedPath))path=event.composedPath();
|
|
369
373
|
}catch{}
|
|
370
374
|
const outermostObservedRoot=path.reduce(
|
|
371
375
|
(selected,item)=>observedRoots.has(item)?item:selected,
|
|
@@ -446,7 +450,7 @@ export function createDOMInstrumentation({
|
|
|
446
450
|
if(active)return api;
|
|
447
451
|
try{
|
|
448
452
|
if(captureMutations){
|
|
449
|
-
if(
|
|
453
|
+
if(!is.function(MutationObserverImpl)){
|
|
450
454
|
throw new TypeError('MutationObserver is required when DOM mutation capture is enabled.');
|
|
451
455
|
}
|
|
452
456
|
observer=new MutationObserverImpl(mutations);
|
|
@@ -473,7 +477,7 @@ export function createDOMInstrumentation({
|
|
|
473
477
|
}
|
|
474
478
|
|
|
475
479
|
function stop({emitLifecycle=true}={}){
|
|
476
|
-
if(
|
|
480
|
+
if(!is.boolean(emitLifecycle))throw new TypeError('emitLifecycle must be boolean.');
|
|
477
481
|
if(!active)return api;
|
|
478
482
|
const shouldEmitLifecycle=emitLifecycle&&lifecycleStarted;
|
|
479
483
|
if(!emitLifecycle)lifecycleStarted=false;
|
package/src/errors.mjs
CHANGED
|
@@ -1,3 +1,7 @@
|
|
|
1
|
+
import Is from 'strong-type';
|
|
2
|
+
|
|
3
|
+
const is = new Is(false);
|
|
4
|
+
|
|
1
5
|
export const ERROR_CODES={
|
|
2
6
|
usage:'ARCANE_USAGE',
|
|
3
7
|
workspaceInvalid:'ARCANE_WORKSPACE_INVALID',
|
|
@@ -17,7 +21,7 @@ export class ArcaneError extends Error{
|
|
|
17
21
|
this.name='ArcaneError';
|
|
18
22
|
this.code=code||ERROR_CODES.operationFailed;
|
|
19
23
|
this.details=details;
|
|
20
|
-
this.exitCode=
|
|
24
|
+
this.exitCode=is.integer(exitCode)?exitCode:1;
|
|
21
25
|
}
|
|
22
26
|
}
|
|
23
27
|
|
|
@@ -49,7 +53,7 @@ export function normalizeError(error,fallbackCode=ERROR_CODES.operationFailed){
|
|
|
49
53
|
);
|
|
50
54
|
}
|
|
51
55
|
|
|
52
|
-
const reportedCode=
|
|
56
|
+
const reportedCode=is.string(error?.code)&&/^ARCANE_[A-Z0-9_]+$/u.test(error.code)
|
|
53
57
|
?error.code
|
|
54
58
|
:fallbackCode;
|
|
55
59
|
|
|
@@ -59,7 +63,7 @@ export function normalizeError(error,fallbackCode=ERROR_CODES.operationFailed){
|
|
|
59
63
|
{
|
|
60
64
|
cause:error,
|
|
61
65
|
details:error?.details,
|
|
62
|
-
exitCode:
|
|
66
|
+
exitCode:is.integer(error?.exitCode)?error.exitCode:undefined
|
|
63
67
|
}
|
|
64
68
|
);
|
|
65
69
|
}
|