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
package/src/event-queue.mjs
CHANGED
|
@@ -1,6 +1,9 @@
|
|
|
1
|
+
import Is from 'strong-type';
|
|
1
2
|
import {AsyncLocalStorage} from 'node:async_hooks';
|
|
2
3
|
import {arcaneEvents} from './event-manager.mjs';
|
|
3
4
|
|
|
5
|
+
const is = new Is(false);
|
|
6
|
+
|
|
4
7
|
const deliveryStorage=new AsyncLocalStorage();
|
|
5
8
|
|
|
6
9
|
function deliveryOccurrence(event){
|
|
@@ -17,13 +20,13 @@ function deliveryOccurrence(event){
|
|
|
17
20
|
}
|
|
18
21
|
|
|
19
22
|
function mirror(manager,event,eventMetadata,occurrence){
|
|
20
|
-
if(!manager||!event
|
|
23
|
+
if(!manager||!event||!is.object(event)||occurrence.managers.has(manager)){
|
|
21
24
|
return;
|
|
22
25
|
}
|
|
23
26
|
occurrence.managers.add(manager);
|
|
24
27
|
try{
|
|
25
28
|
const result=manager.forward(event,eventMetadata);
|
|
26
|
-
if(result&&
|
|
29
|
+
if(result&&is.function(result.then)){
|
|
27
30
|
void Promise.resolve(result).catch(()=>{});
|
|
28
31
|
}
|
|
29
32
|
}catch{
|
|
@@ -44,9 +47,9 @@ export function createEventQueue(onEvent,{
|
|
|
44
47
|
eventManager=arcaneEvents,
|
|
45
48
|
eventMetadata={source:'sdk',category:'operation'}
|
|
46
49
|
}={}){
|
|
47
|
-
const callback=
|
|
50
|
+
const callback=is.function(onEvent)?onEvent:null;
|
|
48
51
|
const manager=eventManager===null?null:eventManager;
|
|
49
|
-
if(manager
|
|
52
|
+
if(manager&&!is.function(manager.forward)){
|
|
50
53
|
throw new TypeError('The central event manager must provide forward(event, metadata).');
|
|
51
54
|
}
|
|
52
55
|
let firstError=null;
|
|
@@ -65,7 +68,7 @@ export function createEventQueue(onEvent,{
|
|
|
65
68
|
resolveFailure(firstError);
|
|
66
69
|
try{
|
|
67
70
|
const result=onFailure?.(firstError);
|
|
68
|
-
if(result&&
|
|
71
|
+
if(result&&is.function(result.then)){
|
|
69
72
|
void Promise.resolve(result).catch(()=>{});
|
|
70
73
|
}
|
|
71
74
|
}catch{
|
package/src/events.mjs
CHANGED
|
@@ -1,22 +1,25 @@
|
|
|
1
|
+
import Is from 'strong-type';
|
|
1
2
|
import {randomUUID} from 'node:crypto';
|
|
2
3
|
import {CLI_EVENT_PROTOCOL,OUTPUT_MODES} from './constants.mjs';
|
|
3
4
|
import {ArcaneError,ERROR_CODES,errorRecord} from './errors.mjs';
|
|
4
5
|
|
|
6
|
+
const is = new Is(false);
|
|
7
|
+
|
|
5
8
|
function write(stream,value){
|
|
6
9
|
stream.write(`${value}\n`);
|
|
7
10
|
}
|
|
8
11
|
|
|
9
12
|
function jsonSafe(value,seen=new WeakSet()){
|
|
10
|
-
if(value===undefined||value===null||
|
|
11
|
-
||
|
|
13
|
+
if(value===undefined||value===null||is.string(value)
|
|
14
|
+
||is.number(value)||is.boolean(value)){
|
|
12
15
|
return value;
|
|
13
16
|
}
|
|
14
17
|
|
|
15
|
-
if(
|
|
18
|
+
if(is.bigint(value)){
|
|
16
19
|
return value.toString();
|
|
17
20
|
}
|
|
18
21
|
|
|
19
|
-
if(
|
|
22
|
+
if(is.function(value)||is.symbol(value)){
|
|
20
23
|
return undefined;
|
|
21
24
|
}
|
|
22
25
|
|
|
@@ -24,7 +27,7 @@ function jsonSafe(value,seen=new WeakSet()){
|
|
|
24
27
|
return errorRecord(value);
|
|
25
28
|
}
|
|
26
29
|
|
|
27
|
-
if(
|
|
30
|
+
if(is.array(value)){
|
|
28
31
|
if(seen.has(value)){
|
|
29
32
|
return undefined;
|
|
30
33
|
}
|
|
@@ -35,7 +38,7 @@ function jsonSafe(value,seen=new WeakSet()){
|
|
|
35
38
|
return result;
|
|
36
39
|
}
|
|
37
40
|
|
|
38
|
-
if(
|
|
41
|
+
if(is.object(value)){
|
|
39
42
|
if(seen.has(value)){
|
|
40
43
|
return undefined;
|
|
41
44
|
}
|
|
@@ -152,7 +155,7 @@ export function createReporter({
|
|
|
152
155
|
}));
|
|
153
156
|
}else{
|
|
154
157
|
if(result!==undefined){
|
|
155
|
-
if(
|
|
158
|
+
if(is.string(result)){
|
|
156
159
|
write(stdout,result);
|
|
157
160
|
}else{
|
|
158
161
|
write(stdout,JSON.stringify(jsonSafe(result),null,2));
|
|
@@ -195,10 +198,10 @@ export function createReporter({
|
|
|
195
198
|
}
|
|
196
199
|
|
|
197
200
|
function forward(value,data){
|
|
198
|
-
if(
|
|
201
|
+
if(is.string(value)){
|
|
199
202
|
return emit(value,data);
|
|
200
203
|
}
|
|
201
|
-
if(value&&
|
|
204
|
+
if(value&&is.object(value)){
|
|
202
205
|
const {type='operation.progress',message,...rest}=value;
|
|
203
206
|
return emit(type,rest.data??rest,message);
|
|
204
207
|
}
|
package/src/import-map.mjs
CHANGED
|
@@ -1,8 +1,11 @@
|
|
|
1
|
+
import Is from 'strong-type';
|
|
1
2
|
import {lstat,mkdir,readFile as readFileFromDisk,readdir,realpath,writeFile} from 'node:fs/promises';
|
|
2
3
|
import path from 'node:path';
|
|
3
4
|
import {pathToFileURL} from 'node:url';
|
|
4
5
|
import {SDK_VERSION} from './constants.mjs';
|
|
5
6
|
|
|
7
|
+
const is = new Is(false);
|
|
8
|
+
|
|
6
9
|
export const IMPORT_MAP_RELATIVE_PATH='modules/arcane.importmap.json';
|
|
7
10
|
export const MANAGED_IMPORT_MAP_ATTRIBUTE='data-arcane-import-map';
|
|
8
11
|
|
|
@@ -20,6 +23,7 @@ const STATIC_RUNTIME_PACKAGE_IMPORTS=new Map([
|
|
|
20
23
|
const SDK_BROWSER_SELF_IMPORTS=new Map([
|
|
21
24
|
['arcane-os/event-manager',SDK_BROWSER_ENTRY],
|
|
22
25
|
['arcane-os/logging','sdk/logging.mjs'],
|
|
26
|
+
['arcane-os/speech-text','sdk/speech-text.mjs'],
|
|
23
27
|
['arcane-os/ai/browser-wasm',SDK_BROWSER_AI_ENTRY],
|
|
24
28
|
['arcane-os/ai/browser-speech',SDK_BROWSER_SPEECH_ENTRY]
|
|
25
29
|
]);
|
|
@@ -37,7 +41,7 @@ function throwIfAborted(signal){
|
|
|
37
41
|
}
|
|
38
42
|
|
|
39
43
|
async function emit(onEvent,event){
|
|
40
|
-
if(
|
|
44
|
+
if(!is.function(onEvent))return null;
|
|
41
45
|
try{
|
|
42
46
|
await onEvent(event);
|
|
43
47
|
return null;
|
|
@@ -55,7 +59,7 @@ function compareText(left,right){
|
|
|
55
59
|
}
|
|
56
60
|
|
|
57
61
|
function safeRelativePath(value,label='path'){
|
|
58
|
-
if(
|
|
62
|
+
if(!is.string(value)||!value||value.includes('\\')||value.includes('\0')
|
|
59
63
|
||path.posix.isAbsolute(value)||path.posix.normalize(value)!==value
|
|
60
64
|
||value==='.'||value.startsWith('../')||value.includes('/../')){
|
|
61
65
|
fail(`Import-map ${label} is unsafe: ${String(value)}.`);
|
|
@@ -65,7 +69,7 @@ function safeRelativePath(value,label='path'){
|
|
|
65
69
|
|
|
66
70
|
function normalizedDocumentPaths(entry,documents){
|
|
67
71
|
if(documents===undefined)return [entry];
|
|
68
|
-
if(!
|
|
72
|
+
if(!is.array(documents)||documents.length===0){
|
|
69
73
|
fail('Import-map documents must be a non-empty array of application-relative paths.');
|
|
70
74
|
}
|
|
71
75
|
const normalized=[];
|
|
@@ -265,7 +269,7 @@ function classHeader(tokens){
|
|
|
265
269
|
|
|
266
270
|
function functionHeader(tokens,closingParenthesis,enclosingBraceKind){
|
|
267
271
|
const openIndex=closingParenthesis?.openTokenIndex;
|
|
268
|
-
if(!
|
|
272
|
+
if(!is.integer(openIndex))return null;
|
|
269
273
|
for(let index=openIndex-1;index>=0;index-=1){
|
|
270
274
|
const token=tokens[index];
|
|
271
275
|
if(new Set([';', '{', '}']).has(token.value))break;
|
|
@@ -296,7 +300,7 @@ function arrowFunctionContext(tokens){
|
|
|
296
300
|
if(arrow?.value!=='=>')return null;
|
|
297
301
|
const parameter=tokens.at(-2);
|
|
298
302
|
let async=false;
|
|
299
|
-
if(parameter?.value===')'&&
|
|
303
|
+
if(parameter?.value===')'&&is.integer(parameter.openTokenIndex)){
|
|
300
304
|
const beforeOpen=tokens[parameter.openTokenIndex-1];
|
|
301
305
|
async=beforeOpen?.type==='identifier'&&beforeOpen.value==='async';
|
|
302
306
|
}else{
|
|
@@ -374,7 +378,7 @@ function contextualForOf(tokens,parentheses){
|
|
|
374
378
|
|
|
375
379
|
function functionParameterDeclaration(tokens,parentheses){
|
|
376
380
|
const context=parentheses.at(-1);
|
|
377
|
-
if(!
|
|
381
|
+
if(!is.integer(context?.openTokenIndex))return false;
|
|
378
382
|
for(let index=context.openTokenIndex-1;index>=0;index-=1){
|
|
379
383
|
const token=tokens[index];
|
|
380
384
|
if(new Set([';','{','}']).has(token.value))return false;
|
|
@@ -715,7 +719,7 @@ function importRecord(kind,token){
|
|
|
715
719
|
}
|
|
716
720
|
|
|
717
721
|
export function scanModuleImports(source,{importer='<module>'}={}){
|
|
718
|
-
if(
|
|
722
|
+
if(!is.string(source))throw new TypeError('scanModuleImports source must be a string.');
|
|
719
723
|
return moduleImportsFromTokens(tokenize(source),importer);
|
|
720
724
|
}
|
|
721
725
|
|
|
@@ -793,12 +797,12 @@ function moduleImportsFromTokens(tokens,importer){
|
|
|
793
797
|
}
|
|
794
798
|
|
|
795
799
|
export function versionAssetUrl(value,version=SDK_VERSION){
|
|
796
|
-
if(
|
|
800
|
+
if(!is.string(value))return value;
|
|
797
801
|
return applyReferenceEdits(value,assetUrlVersionEdits(value,version));
|
|
798
802
|
}
|
|
799
803
|
|
|
800
804
|
function assetUrlVersionEdits(value,version){
|
|
801
|
-
if(
|
|
805
|
+
if(!is.string(value)||!value||!version||value.startsWith('#')
|
|
802
806
|
||value.startsWith('//')||/^[A-Za-z][A-Za-z0-9+.-]*:/u.test(value)
|
|
803
807
|
||/^\s/u.test(value))return [];
|
|
804
808
|
const fragmentStart=value.indexOf('#');
|
|
@@ -948,7 +952,7 @@ function literalResourceFetch(argumentsList){
|
|
|
948
952
|
}
|
|
949
953
|
|
|
950
954
|
function reportAssetReference(onReference,url,kind,baseKind){
|
|
951
|
-
if(
|
|
955
|
+
if(is.function(onReference))onReference({url,kind,baseHref:null,...(baseKind?{baseKind}:{})});
|
|
952
956
|
}
|
|
953
957
|
|
|
954
958
|
function javascriptReferenceEdits(source,version,onReference){
|
|
@@ -1157,7 +1161,7 @@ function importMapReferenceEdits(source,version,onReference){
|
|
|
1157
1161
|
}
|
|
1158
1162
|
|
|
1159
1163
|
export function rewriteAssetReferences(source,{filePath,version=SDK_VERSION,onReference}={}){
|
|
1160
|
-
if(
|
|
1164
|
+
if(!is.string(source))throw new TypeError('Asset reference source must be a string.');
|
|
1161
1165
|
const extension=path.extname(String(filePath??'')).toLowerCase();
|
|
1162
1166
|
if(extension==='.js'||extension==='.mjs'){
|
|
1163
1167
|
return applyReferenceEdits(source,javascriptReferenceEdits(source,version,onReference));
|
|
@@ -1192,7 +1196,7 @@ function importMapUrlVersionEdits(value,version){
|
|
|
1192
1196
|
}
|
|
1193
1197
|
|
|
1194
1198
|
function validateInventory(files){
|
|
1195
|
-
if(!
|
|
1199
|
+
if(!is.array(files))throw new TypeError('buildImportMap files must be an array.');
|
|
1196
1200
|
const exact=new Set();
|
|
1197
1201
|
for(const value of [...files].sort(compareText)){
|
|
1198
1202
|
const relative=safeRelativePath(value,'runtime inventory path');
|
|
@@ -1248,6 +1252,11 @@ export async function buildImportMap({files,signal,version=SDK_VERSION}={}){
|
|
|
1248
1252
|
);
|
|
1249
1253
|
}
|
|
1250
1254
|
if(inventory.has('dependencies/strong-type/index.js')){
|
|
1255
|
+
registerSpecifier(
|
|
1256
|
+
namedRegistry,
|
|
1257
|
+
'strong-type',
|
|
1258
|
+
'./arcane/dependencies/strong-type/index.js'
|
|
1259
|
+
);
|
|
1251
1260
|
registerSpecifier(
|
|
1252
1261
|
namedRegistry,
|
|
1253
1262
|
'./node_modules/strong-type/index.js',
|
|
@@ -1343,7 +1352,7 @@ export async function readWorkspaceAssetVersion(workspaceRoot){
|
|
|
1343
1352
|
}
|
|
1344
1353
|
const document=JSON.parse(source);
|
|
1345
1354
|
const version=document?.sdk?.version;
|
|
1346
|
-
return
|
|
1355
|
+
return is.string(version)&&version?version:SDK_VERSION;
|
|
1347
1356
|
}
|
|
1348
1357
|
|
|
1349
1358
|
function asciiLower(value){
|
|
@@ -1431,7 +1440,7 @@ function decodeStructuralAttribute(value,label){
|
|
|
1431
1440
|
return {amp:'&',apos:"'",gt:'>',lt:'<',quot:'"'}[asciiLower(named)];
|
|
1432
1441
|
}
|
|
1433
1442
|
const point=Number.parseInt(decimal??hex,decimal?10:16);
|
|
1434
|
-
if(!
|
|
1443
|
+
if(!is.safeInteger(point)||point<=0||point>0x10ffff
|
|
1435
1444
|
||(point>=0xd800&&point<=0xdfff)){
|
|
1436
1445
|
fail(`Application HTML ${label} contains an invalid character reference.`);
|
|
1437
1446
|
}
|
|
@@ -1715,7 +1724,7 @@ function htmlAttributeView(value){
|
|
|
1715
1724
|
const point=entity[1]||entity[2]
|
|
1716
1725
|
?Number.parseInt(entity[1]??entity[2],entity[1]?10:16)
|
|
1717
1726
|
:null;
|
|
1718
|
-
if(point!==null&&(!
|
|
1727
|
+
if(point!==null&&(!is.safeInteger(point)||point<=0||point>0x10ffff))return null;
|
|
1719
1728
|
const character=point===null
|
|
1720
1729
|
?{amp:'&',apos:"'",gt:'>',lt:'<',quot:'"'}[asciiLower(entity[3])]
|
|
1721
1730
|
:String.fromCodePoint(point);
|
|
@@ -1787,7 +1796,7 @@ function htmlReferenceEdits(source,version,onReference){
|
|
|
1787
1796
|
const baseHref=base?structuralAttribute(parseTagAttributes(base.open),'href','base'):null;
|
|
1788
1797
|
if(baseHref&&(/^[A-Za-z][A-Za-z0-9+.-]*:/u.test(baseHref)||baseHref.startsWith('//')))version=null;
|
|
1789
1798
|
function reportHtmlReference(reference){
|
|
1790
|
-
if(
|
|
1799
|
+
if(is.function(onReference))onReference({...reference,baseHref});
|
|
1791
1800
|
}
|
|
1792
1801
|
function addNestedEdits(offset,nested){
|
|
1793
1802
|
for(const edit of nested)edits.push({...edit,start:offset+edit.start,end:offset+edit.end});
|
|
@@ -2114,7 +2123,7 @@ async function writeGeneratedFiles({root,files,signal,onEvent}){
|
|
|
2114
2123
|
}
|
|
2115
2124
|
|
|
2116
2125
|
function resolvedAppRoot(workspaceRoot,appId,appRoot){
|
|
2117
|
-
if(
|
|
2126
|
+
if(!is.string(appId)||appId.trim()===''){
|
|
2118
2127
|
throw new TypeError('Import-map app id must be a nonempty string.');
|
|
2119
2128
|
}
|
|
2120
2129
|
const resolved=path.resolve(appRoot??path.join(workspaceRoot,'apps',appId));
|
|
@@ -2128,13 +2137,13 @@ export async function createApplicationTestImportMapContext({
|
|
|
2128
2137
|
imports={},
|
|
2129
2138
|
signal
|
|
2130
2139
|
}={}){
|
|
2131
|
-
if(
|
|
2140
|
+
if(!is.string(applicationRoot)||applicationRoot.trim()===''){
|
|
2132
2141
|
throw new TypeError('applicationRoot must be a nonempty string.');
|
|
2133
2142
|
}
|
|
2134
2143
|
if(!['source','dist','test'].includes(boundary)){
|
|
2135
2144
|
throw new TypeError('boundary must be source, dist, or test.');
|
|
2136
2145
|
}
|
|
2137
|
-
if(imports===null
|
|
2146
|
+
if(imports===null||!is.object(imports)||is.array(imports)){
|
|
2138
2147
|
throw new TypeError('imports must be a plain object.');
|
|
2139
2148
|
}
|
|
2140
2149
|
throwIfAborted(signal);
|
|
@@ -2158,7 +2167,7 @@ export async function createApplicationTestImportMapContext({
|
|
|
2158
2167
|
const selectedImports={};
|
|
2159
2168
|
for(const [specifier,target] of Object.entries(imports)){
|
|
2160
2169
|
throwIfAborted(signal);
|
|
2161
|
-
if(
|
|
2170
|
+
if(!is.string(specifier)||specifier===''||!is.string(target)
|
|
2162
2171
|
||!target.startsWith('./')){
|
|
2163
2172
|
fail(`Application test import-map entry is invalid: ${String(specifier)}.`);
|
|
2164
2173
|
}
|
|
@@ -2191,10 +2200,10 @@ export async function readApplicationTestImportMapContext({
|
|
|
2191
2200
|
applicationRoot,
|
|
2192
2201
|
signal
|
|
2193
2202
|
}={}){
|
|
2194
|
-
if(
|
|
2203
|
+
if(!is.string(workspaceRoot)||workspaceRoot.trim()===''){
|
|
2195
2204
|
throw new TypeError('workspaceRoot must be a nonempty string.');
|
|
2196
2205
|
}
|
|
2197
|
-
if(
|
|
2206
|
+
if(!is.string(applicationRoot)||applicationRoot.trim()===''){
|
|
2198
2207
|
throw new TypeError('applicationRoot must be a nonempty string.');
|
|
2199
2208
|
}
|
|
2200
2209
|
throwIfAborted(signal);
|
|
@@ -2222,9 +2231,9 @@ export async function readApplicationTestImportMapContext({
|
|
|
2222
2231
|
catch(error){
|
|
2223
2232
|
fail(`Application test import-map artifact is not valid JSON: ${error.message}`);
|
|
2224
2233
|
}
|
|
2225
|
-
if(document===null
|
|
2226
|
-
||document.imports===null
|
|
2227
|
-
||
|
|
2234
|
+
if(document===null||!is.object(document)||is.array(document)
|
|
2235
|
+
||document.imports===null||!is.object(document.imports)
|
|
2236
|
+
||is.array(document.imports)){
|
|
2228
2237
|
fail('Application test import-map artifact must contain an imports object.');
|
|
2229
2238
|
}
|
|
2230
2239
|
return createApplicationTestImportMapContext({
|
|
@@ -2244,7 +2253,7 @@ async function generateImportMapUnlocked({
|
|
|
2244
2253
|
signal,
|
|
2245
2254
|
onEvent
|
|
2246
2255
|
}={}){
|
|
2247
|
-
if(
|
|
2256
|
+
if(!is.string(workspaceRoot)||workspaceRoot.trim()===''){
|
|
2248
2257
|
throw new TypeError('generateImportMap workspaceRoot must be a nonempty string.');
|
|
2249
2258
|
}
|
|
2250
2259
|
throwIfAborted(signal);
|
|
@@ -2347,7 +2356,7 @@ async function generateImportMapUnlocked({
|
|
|
2347
2356
|
|
|
2348
2357
|
export async function generateImportMap(options={}){
|
|
2349
2358
|
const {workspaceRoot}=options??{};
|
|
2350
|
-
if(
|
|
2359
|
+
if(!is.string(workspaceRoot)||workspaceRoot.trim()===''){
|
|
2351
2360
|
throw new TypeError('generateImportMap workspaceRoot must be a nonempty string.');
|
|
2352
2361
|
}
|
|
2353
2362
|
return generateImportMapUnlocked(options);
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import Is from 'strong-type';
|
|
1
2
|
import {lstat,readFile,realpath,stat,writeFile} from 'node:fs/promises';
|
|
2
3
|
import path from 'node:path';
|
|
3
4
|
import {materializeWorkspaceRuntimeContent} from './workspace-runtime.mjs';
|
|
@@ -8,6 +9,8 @@ import {
|
|
|
8
9
|
resolveSdkPackageDeclaration
|
|
9
10
|
} from './workspace.mjs';
|
|
10
11
|
|
|
12
|
+
const is = new Is(false);
|
|
13
|
+
|
|
11
14
|
function fail(message,code='ARCANE_INSTALLED_SDK_RUNTIME_INVALID'){
|
|
12
15
|
const error=new Error(message);
|
|
13
16
|
error.code=code;
|
|
@@ -22,7 +25,7 @@ function throwIfAborted(signal){
|
|
|
22
25
|
}
|
|
23
26
|
|
|
24
27
|
async function canonicalWorkspaceRoot(workspaceRoot){
|
|
25
|
-
if(
|
|
28
|
+
if(!is.string(workspaceRoot)||!workspaceRoot.trim()){
|
|
26
29
|
fail('workspaceRoot is required to materialize an installed SDK runtime.');
|
|
27
30
|
}
|
|
28
31
|
const requested=path.resolve(workspaceRoot);
|
|
@@ -1,9 +1,12 @@
|
|
|
1
|
+
import Is from 'strong-type';
|
|
1
2
|
import {stat} from 'node:fs/promises';
|
|
2
3
|
import path from 'node:path';
|
|
3
4
|
import {pathToFileURL} 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
|
export const INTEGRATED_TOOLCHAIN_PROTOCOL='arcane-integrated-toolchain/1';
|
|
8
11
|
export const ARCANE_INTEGRATED_PROVIDER_RELATIVE_PATH=[
|
|
9
12
|
'tools',
|
|
@@ -19,7 +22,7 @@ async function emit(onEvent,event){
|
|
|
19
22
|
}
|
|
20
23
|
|
|
21
24
|
async function selectedProvider(arcaneRoot){
|
|
22
|
-
if(
|
|
25
|
+
if(!is.string(arcaneRoot)||!arcaneRoot.trim()){
|
|
23
26
|
fail('An explicit Arcane OS root is required for shared development.',ERROR_CODES.usage);
|
|
24
27
|
}
|
|
25
28
|
const toolchainRoot=path.resolve(arcaneRoot);
|
|
@@ -53,10 +56,10 @@ async function selectedProvider(arcaneRoot){
|
|
|
53
56
|
async function importedProvider(providerPath){
|
|
54
57
|
const namespace=await import(pathToFileURL(providerPath).href);
|
|
55
58
|
const provider=namespace?.integratedDevelopmentProvider;
|
|
56
|
-
if(!provider
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
59
|
+
if(!provider||!is.object(provider)
|
|
60
|
+
||!is.function(provider.describe)
|
|
61
|
+
||!is.function(provider.prepare)
|
|
62
|
+
||!is.function(provider.execute)){
|
|
60
63
|
fail('The integrated provider must export integratedDevelopmentProvider.');
|
|
61
64
|
}
|
|
62
65
|
return provider;
|
|
@@ -69,7 +72,7 @@ export async function loadArcaneIntegratedProvider({
|
|
|
69
72
|
run=runProcess
|
|
70
73
|
}={}){
|
|
71
74
|
throwIfAborted(signal);
|
|
72
|
-
if(
|
|
75
|
+
if(!is.function(run)){
|
|
73
76
|
fail('The integrated provider process runner must be a function.',ERROR_CODES.usage);
|
|
74
77
|
}
|
|
75
78
|
await emit(onEvent,{
|
package/src/mail-credentials.mjs
CHANGED
|
@@ -1,8 +1,11 @@
|
|
|
1
|
+
import Is from 'strong-type';
|
|
1
2
|
import {spawn} from 'node:child_process';
|
|
2
3
|
import path from 'node:path';
|
|
3
4
|
import {TextDecoder} from 'node:util';
|
|
4
5
|
import {ArcaneError,ERROR_CODES} from './errors.mjs';
|
|
5
6
|
|
|
7
|
+
const is = new Is(false);
|
|
8
|
+
|
|
6
9
|
export const RESEND_CREDENTIAL_TARGET_PREFIX='ArcaneOSSDK/mail/resend/';
|
|
7
10
|
|
|
8
11
|
const CREDENTIAL_STORE='windows-credential-manager';
|
|
@@ -264,7 +267,7 @@ function assertNotAborted(signal){
|
|
|
264
267
|
}
|
|
265
268
|
|
|
266
269
|
export function validateMailCredentialProfile(profile){
|
|
267
|
-
if(
|
|
270
|
+
if(!is.string(profile)||profile.length>MAX_PROFILE_LENGTH
|
|
268
271
|
||!PROFILE_PATTERN.test(profile)){
|
|
269
272
|
throw usageError(
|
|
270
273
|
'A credential profile must be 1-64 lowercase letters, digits, dots, underscores, or hyphens, and must begin and end with a letter or digit.'
|
|
@@ -278,7 +281,7 @@ export function mailCredentialTarget(profile){
|
|
|
278
281
|
}
|
|
279
282
|
|
|
280
283
|
function validateSecret(secret){
|
|
281
|
-
if(
|
|
284
|
+
if(!is.string(secret)||!SECRET_PATTERN.test(secret)
|
|
282
285
|
||Buffer.byteLength(secret,'utf8')>MAX_CREDENTIAL_BYTES){
|
|
283
286
|
throw usageError(
|
|
284
287
|
'A Resend API key must be a nonempty printable ASCII string no larger than 2,560 bytes.'
|
|
@@ -292,7 +295,7 @@ function validatePlatform(platform){
|
|
|
292
295
|
}
|
|
293
296
|
|
|
294
297
|
function validateTimeout(timeoutMs){
|
|
295
|
-
if(!
|
|
298
|
+
if(!is.safeInteger(timeoutMs)||timeoutMs<1||timeoutMs>MAX_HELPER_TIMEOUT_MS){
|
|
296
299
|
throw usageError(
|
|
297
300
|
`Credential helper timeout must be an integer from 1 through ${String(MAX_HELPER_TIMEOUT_MS)} milliseconds.`
|
|
298
301
|
);
|
|
@@ -301,7 +304,7 @@ function validateTimeout(timeoutMs){
|
|
|
301
304
|
}
|
|
302
305
|
|
|
303
306
|
function powershellExecutable(systemRoot){
|
|
304
|
-
if(
|
|
307
|
+
if(!is.string(systemRoot)||systemRoot.length===0
|
|
305
308
|
||systemRoot.includes('\0')||!path.win32.isAbsolute(systemRoot)){
|
|
306
309
|
throw unavailableError();
|
|
307
310
|
}
|
|
@@ -327,7 +330,7 @@ function helperArguments(){
|
|
|
327
330
|
}
|
|
328
331
|
|
|
329
332
|
function helperEnvironment(systemRoot,temporaryDirectory){
|
|
330
|
-
if(
|
|
333
|
+
if(!is.string(temporaryDirectory)||temporaryDirectory.length===0
|
|
331
334
|
||temporaryDirectory.includes('\0')||!path.win32.isAbsolute(temporaryDirectory)){
|
|
332
335
|
throw unavailableError();
|
|
333
336
|
}
|
|
@@ -352,7 +355,7 @@ function parseResponse(buffer){
|
|
|
352
355
|
try{
|
|
353
356
|
responseText=buffer.toString('utf8');
|
|
354
357
|
const response=JSON.parse(responseText);
|
|
355
|
-
if(response===null
|
|
358
|
+
if(response===null||!is.object(response)||is.array(response)
|
|
356
359
|
||response.ok!==true){
|
|
357
360
|
throw operationError();
|
|
358
361
|
}
|
|
@@ -374,7 +377,7 @@ function runCredentialProcess({
|
|
|
374
377
|
signal,
|
|
375
378
|
timeoutMs
|
|
376
379
|
}){
|
|
377
|
-
if(
|
|
380
|
+
if(!is.function(spawnImpl))throw usageError('spawnImpl must be a function.');
|
|
378
381
|
let input=stdin;
|
|
379
382
|
return new Promise(function executeCredentialHelper(resolve,reject){
|
|
380
383
|
let child;
|
|
@@ -494,7 +497,7 @@ async function runWindowsCredentialHelper(request,{
|
|
|
494
497
|
}={}){
|
|
495
498
|
validatePlatform(platform);
|
|
496
499
|
assertNotAborted(signal);
|
|
497
|
-
if(
|
|
500
|
+
if(!is.function(runner))throw usageError('runner must be a function.');
|
|
498
501
|
const executable=powershellExecutable(systemRoot);
|
|
499
502
|
const args=helperArguments();
|
|
500
503
|
const boundedTimeout=validateTimeout(timeoutMs);
|
|
@@ -527,7 +530,7 @@ async function runWindowsCredentialHelper(request,{
|
|
|
527
530
|
invocation.stdin='';
|
|
528
531
|
requestText='';
|
|
529
532
|
}
|
|
530
|
-
if(
|
|
533
|
+
if(is.string(output))output=Buffer.from(output,'utf8');
|
|
531
534
|
if(!Buffer.isBuffer(output))throw operationError();
|
|
532
535
|
if(output.length>MAX_HELPER_OUTPUT_BYTES){
|
|
533
536
|
output.fill(0);
|
|
@@ -557,7 +560,7 @@ function credentialStatus(profile,exists){
|
|
|
557
560
|
}
|
|
558
561
|
|
|
559
562
|
function validateOptions(options){
|
|
560
|
-
if(options===null
|
|
563
|
+
if(options===null||!is.object(options)||is.array(options)){
|
|
561
564
|
throw usageError('Mail credential options must be an object.');
|
|
562
565
|
}
|
|
563
566
|
return options;
|
|
@@ -601,7 +604,7 @@ export async function setMailCredential(options={}){
|
|
|
601
604
|
}
|
|
602
605
|
|
|
603
606
|
function decodeSecret(value){
|
|
604
|
-
if(
|
|
607
|
+
if(!is.string(value)||value.length===0||value.length%4!==0
|
|
605
608
|
||!BASE64_PATTERN.test(value)){
|
|
606
609
|
throw operationError();
|
|
607
610
|
}
|
|
@@ -648,7 +651,7 @@ export async function getMailCredentialStatus(options={}){
|
|
|
648
651
|
{operation:'status',target},
|
|
649
652
|
helperOptions(options)
|
|
650
653
|
);
|
|
651
|
-
if(
|
|
654
|
+
if(!is.boolean(response.configured))throw operationError();
|
|
652
655
|
return credentialStatus(validatedProfile,response.configured);
|
|
653
656
|
}
|
|
654
657
|
|
|
@@ -660,7 +663,7 @@ export async function deleteMailCredential(options={}){
|
|
|
660
663
|
{operation:'delete',target},
|
|
661
664
|
helperOptions(options)
|
|
662
665
|
);
|
|
663
|
-
if(
|
|
666
|
+
if(!is.boolean(response.deleted)||response.configured!==false){
|
|
664
667
|
throw operationError();
|
|
665
668
|
}
|
|
666
669
|
return credentialStatus(validatedProfile,false);
|