arcane-os 0.5.17 → 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 +24 -0
- 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 +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 +5 -1
- package/docs/reference/ai/browser-speech.md +198 -5
- 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 +117 -138
- 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/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
|
|
|
@@ -38,7 +41,7 @@ function throwIfAborted(signal){
|
|
|
38
41
|
}
|
|
39
42
|
|
|
40
43
|
async function emit(onEvent,event){
|
|
41
|
-
if(
|
|
44
|
+
if(!is.function(onEvent))return null;
|
|
42
45
|
try{
|
|
43
46
|
await onEvent(event);
|
|
44
47
|
return null;
|
|
@@ -56,7 +59,7 @@ function compareText(left,right){
|
|
|
56
59
|
}
|
|
57
60
|
|
|
58
61
|
function safeRelativePath(value,label='path'){
|
|
59
|
-
if(
|
|
62
|
+
if(!is.string(value)||!value||value.includes('\\')||value.includes('\0')
|
|
60
63
|
||path.posix.isAbsolute(value)||path.posix.normalize(value)!==value
|
|
61
64
|
||value==='.'||value.startsWith('../')||value.includes('/../')){
|
|
62
65
|
fail(`Import-map ${label} is unsafe: ${String(value)}.`);
|
|
@@ -66,7 +69,7 @@ function safeRelativePath(value,label='path'){
|
|
|
66
69
|
|
|
67
70
|
function normalizedDocumentPaths(entry,documents){
|
|
68
71
|
if(documents===undefined)return [entry];
|
|
69
|
-
if(!
|
|
72
|
+
if(!is.array(documents)||documents.length===0){
|
|
70
73
|
fail('Import-map documents must be a non-empty array of application-relative paths.');
|
|
71
74
|
}
|
|
72
75
|
const normalized=[];
|
|
@@ -266,7 +269,7 @@ function classHeader(tokens){
|
|
|
266
269
|
|
|
267
270
|
function functionHeader(tokens,closingParenthesis,enclosingBraceKind){
|
|
268
271
|
const openIndex=closingParenthesis?.openTokenIndex;
|
|
269
|
-
if(!
|
|
272
|
+
if(!is.integer(openIndex))return null;
|
|
270
273
|
for(let index=openIndex-1;index>=0;index-=1){
|
|
271
274
|
const token=tokens[index];
|
|
272
275
|
if(new Set([';', '{', '}']).has(token.value))break;
|
|
@@ -297,7 +300,7 @@ function arrowFunctionContext(tokens){
|
|
|
297
300
|
if(arrow?.value!=='=>')return null;
|
|
298
301
|
const parameter=tokens.at(-2);
|
|
299
302
|
let async=false;
|
|
300
|
-
if(parameter?.value===')'&&
|
|
303
|
+
if(parameter?.value===')'&&is.integer(parameter.openTokenIndex)){
|
|
301
304
|
const beforeOpen=tokens[parameter.openTokenIndex-1];
|
|
302
305
|
async=beforeOpen?.type==='identifier'&&beforeOpen.value==='async';
|
|
303
306
|
}else{
|
|
@@ -375,7 +378,7 @@ function contextualForOf(tokens,parentheses){
|
|
|
375
378
|
|
|
376
379
|
function functionParameterDeclaration(tokens,parentheses){
|
|
377
380
|
const context=parentheses.at(-1);
|
|
378
|
-
if(!
|
|
381
|
+
if(!is.integer(context?.openTokenIndex))return false;
|
|
379
382
|
for(let index=context.openTokenIndex-1;index>=0;index-=1){
|
|
380
383
|
const token=tokens[index];
|
|
381
384
|
if(new Set([';','{','}']).has(token.value))return false;
|
|
@@ -716,7 +719,7 @@ function importRecord(kind,token){
|
|
|
716
719
|
}
|
|
717
720
|
|
|
718
721
|
export function scanModuleImports(source,{importer='<module>'}={}){
|
|
719
|
-
if(
|
|
722
|
+
if(!is.string(source))throw new TypeError('scanModuleImports source must be a string.');
|
|
720
723
|
return moduleImportsFromTokens(tokenize(source),importer);
|
|
721
724
|
}
|
|
722
725
|
|
|
@@ -794,12 +797,12 @@ function moduleImportsFromTokens(tokens,importer){
|
|
|
794
797
|
}
|
|
795
798
|
|
|
796
799
|
export function versionAssetUrl(value,version=SDK_VERSION){
|
|
797
|
-
if(
|
|
800
|
+
if(!is.string(value))return value;
|
|
798
801
|
return applyReferenceEdits(value,assetUrlVersionEdits(value,version));
|
|
799
802
|
}
|
|
800
803
|
|
|
801
804
|
function assetUrlVersionEdits(value,version){
|
|
802
|
-
if(
|
|
805
|
+
if(!is.string(value)||!value||!version||value.startsWith('#')
|
|
803
806
|
||value.startsWith('//')||/^[A-Za-z][A-Za-z0-9+.-]*:/u.test(value)
|
|
804
807
|
||/^\s/u.test(value))return [];
|
|
805
808
|
const fragmentStart=value.indexOf('#');
|
|
@@ -949,7 +952,7 @@ function literalResourceFetch(argumentsList){
|
|
|
949
952
|
}
|
|
950
953
|
|
|
951
954
|
function reportAssetReference(onReference,url,kind,baseKind){
|
|
952
|
-
if(
|
|
955
|
+
if(is.function(onReference))onReference({url,kind,baseHref:null,...(baseKind?{baseKind}:{})});
|
|
953
956
|
}
|
|
954
957
|
|
|
955
958
|
function javascriptReferenceEdits(source,version,onReference){
|
|
@@ -1158,7 +1161,7 @@ function importMapReferenceEdits(source,version,onReference){
|
|
|
1158
1161
|
}
|
|
1159
1162
|
|
|
1160
1163
|
export function rewriteAssetReferences(source,{filePath,version=SDK_VERSION,onReference}={}){
|
|
1161
|
-
if(
|
|
1164
|
+
if(!is.string(source))throw new TypeError('Asset reference source must be a string.');
|
|
1162
1165
|
const extension=path.extname(String(filePath??'')).toLowerCase();
|
|
1163
1166
|
if(extension==='.js'||extension==='.mjs'){
|
|
1164
1167
|
return applyReferenceEdits(source,javascriptReferenceEdits(source,version,onReference));
|
|
@@ -1193,7 +1196,7 @@ function importMapUrlVersionEdits(value,version){
|
|
|
1193
1196
|
}
|
|
1194
1197
|
|
|
1195
1198
|
function validateInventory(files){
|
|
1196
|
-
if(!
|
|
1199
|
+
if(!is.array(files))throw new TypeError('buildImportMap files must be an array.');
|
|
1197
1200
|
const exact=new Set();
|
|
1198
1201
|
for(const value of [...files].sort(compareText)){
|
|
1199
1202
|
const relative=safeRelativePath(value,'runtime inventory path');
|
|
@@ -1249,6 +1252,11 @@ export async function buildImportMap({files,signal,version=SDK_VERSION}={}){
|
|
|
1249
1252
|
);
|
|
1250
1253
|
}
|
|
1251
1254
|
if(inventory.has('dependencies/strong-type/index.js')){
|
|
1255
|
+
registerSpecifier(
|
|
1256
|
+
namedRegistry,
|
|
1257
|
+
'strong-type',
|
|
1258
|
+
'./arcane/dependencies/strong-type/index.js'
|
|
1259
|
+
);
|
|
1252
1260
|
registerSpecifier(
|
|
1253
1261
|
namedRegistry,
|
|
1254
1262
|
'./node_modules/strong-type/index.js',
|
|
@@ -1344,7 +1352,7 @@ export async function readWorkspaceAssetVersion(workspaceRoot){
|
|
|
1344
1352
|
}
|
|
1345
1353
|
const document=JSON.parse(source);
|
|
1346
1354
|
const version=document?.sdk?.version;
|
|
1347
|
-
return
|
|
1355
|
+
return is.string(version)&&version?version:SDK_VERSION;
|
|
1348
1356
|
}
|
|
1349
1357
|
|
|
1350
1358
|
function asciiLower(value){
|
|
@@ -1432,7 +1440,7 @@ function decodeStructuralAttribute(value,label){
|
|
|
1432
1440
|
return {amp:'&',apos:"'",gt:'>',lt:'<',quot:'"'}[asciiLower(named)];
|
|
1433
1441
|
}
|
|
1434
1442
|
const point=Number.parseInt(decimal??hex,decimal?10:16);
|
|
1435
|
-
if(!
|
|
1443
|
+
if(!is.safeInteger(point)||point<=0||point>0x10ffff
|
|
1436
1444
|
||(point>=0xd800&&point<=0xdfff)){
|
|
1437
1445
|
fail(`Application HTML ${label} contains an invalid character reference.`);
|
|
1438
1446
|
}
|
|
@@ -1716,7 +1724,7 @@ function htmlAttributeView(value){
|
|
|
1716
1724
|
const point=entity[1]||entity[2]
|
|
1717
1725
|
?Number.parseInt(entity[1]??entity[2],entity[1]?10:16)
|
|
1718
1726
|
:null;
|
|
1719
|
-
if(point!==null&&(!
|
|
1727
|
+
if(point!==null&&(!is.safeInteger(point)||point<=0||point>0x10ffff))return null;
|
|
1720
1728
|
const character=point===null
|
|
1721
1729
|
?{amp:'&',apos:"'",gt:'>',lt:'<',quot:'"'}[asciiLower(entity[3])]
|
|
1722
1730
|
:String.fromCodePoint(point);
|
|
@@ -1788,7 +1796,7 @@ function htmlReferenceEdits(source,version,onReference){
|
|
|
1788
1796
|
const baseHref=base?structuralAttribute(parseTagAttributes(base.open),'href','base'):null;
|
|
1789
1797
|
if(baseHref&&(/^[A-Za-z][A-Za-z0-9+.-]*:/u.test(baseHref)||baseHref.startsWith('//')))version=null;
|
|
1790
1798
|
function reportHtmlReference(reference){
|
|
1791
|
-
if(
|
|
1799
|
+
if(is.function(onReference))onReference({...reference,baseHref});
|
|
1792
1800
|
}
|
|
1793
1801
|
function addNestedEdits(offset,nested){
|
|
1794
1802
|
for(const edit of nested)edits.push({...edit,start:offset+edit.start,end:offset+edit.end});
|
|
@@ -2115,7 +2123,7 @@ async function writeGeneratedFiles({root,files,signal,onEvent}){
|
|
|
2115
2123
|
}
|
|
2116
2124
|
|
|
2117
2125
|
function resolvedAppRoot(workspaceRoot,appId,appRoot){
|
|
2118
|
-
if(
|
|
2126
|
+
if(!is.string(appId)||appId.trim()===''){
|
|
2119
2127
|
throw new TypeError('Import-map app id must be a nonempty string.');
|
|
2120
2128
|
}
|
|
2121
2129
|
const resolved=path.resolve(appRoot??path.join(workspaceRoot,'apps',appId));
|
|
@@ -2129,13 +2137,13 @@ export async function createApplicationTestImportMapContext({
|
|
|
2129
2137
|
imports={},
|
|
2130
2138
|
signal
|
|
2131
2139
|
}={}){
|
|
2132
|
-
if(
|
|
2140
|
+
if(!is.string(applicationRoot)||applicationRoot.trim()===''){
|
|
2133
2141
|
throw new TypeError('applicationRoot must be a nonempty string.');
|
|
2134
2142
|
}
|
|
2135
2143
|
if(!['source','dist','test'].includes(boundary)){
|
|
2136
2144
|
throw new TypeError('boundary must be source, dist, or test.');
|
|
2137
2145
|
}
|
|
2138
|
-
if(imports===null
|
|
2146
|
+
if(imports===null||!is.object(imports)||is.array(imports)){
|
|
2139
2147
|
throw new TypeError('imports must be a plain object.');
|
|
2140
2148
|
}
|
|
2141
2149
|
throwIfAborted(signal);
|
|
@@ -2159,7 +2167,7 @@ export async function createApplicationTestImportMapContext({
|
|
|
2159
2167
|
const selectedImports={};
|
|
2160
2168
|
for(const [specifier,target] of Object.entries(imports)){
|
|
2161
2169
|
throwIfAborted(signal);
|
|
2162
|
-
if(
|
|
2170
|
+
if(!is.string(specifier)||specifier===''||!is.string(target)
|
|
2163
2171
|
||!target.startsWith('./')){
|
|
2164
2172
|
fail(`Application test import-map entry is invalid: ${String(specifier)}.`);
|
|
2165
2173
|
}
|
|
@@ -2192,10 +2200,10 @@ export async function readApplicationTestImportMapContext({
|
|
|
2192
2200
|
applicationRoot,
|
|
2193
2201
|
signal
|
|
2194
2202
|
}={}){
|
|
2195
|
-
if(
|
|
2203
|
+
if(!is.string(workspaceRoot)||workspaceRoot.trim()===''){
|
|
2196
2204
|
throw new TypeError('workspaceRoot must be a nonempty string.');
|
|
2197
2205
|
}
|
|
2198
|
-
if(
|
|
2206
|
+
if(!is.string(applicationRoot)||applicationRoot.trim()===''){
|
|
2199
2207
|
throw new TypeError('applicationRoot must be a nonempty string.');
|
|
2200
2208
|
}
|
|
2201
2209
|
throwIfAborted(signal);
|
|
@@ -2223,9 +2231,9 @@ export async function readApplicationTestImportMapContext({
|
|
|
2223
2231
|
catch(error){
|
|
2224
2232
|
fail(`Application test import-map artifact is not valid JSON: ${error.message}`);
|
|
2225
2233
|
}
|
|
2226
|
-
if(document===null
|
|
2227
|
-
||document.imports===null
|
|
2228
|
-
||
|
|
2234
|
+
if(document===null||!is.object(document)||is.array(document)
|
|
2235
|
+
||document.imports===null||!is.object(document.imports)
|
|
2236
|
+
||is.array(document.imports)){
|
|
2229
2237
|
fail('Application test import-map artifact must contain an imports object.');
|
|
2230
2238
|
}
|
|
2231
2239
|
return createApplicationTestImportMapContext({
|
|
@@ -2245,7 +2253,7 @@ async function generateImportMapUnlocked({
|
|
|
2245
2253
|
signal,
|
|
2246
2254
|
onEvent
|
|
2247
2255
|
}={}){
|
|
2248
|
-
if(
|
|
2256
|
+
if(!is.string(workspaceRoot)||workspaceRoot.trim()===''){
|
|
2249
2257
|
throw new TypeError('generateImportMap workspaceRoot must be a nonempty string.');
|
|
2250
2258
|
}
|
|
2251
2259
|
throwIfAborted(signal);
|
|
@@ -2348,7 +2356,7 @@ async function generateImportMapUnlocked({
|
|
|
2348
2356
|
|
|
2349
2357
|
export async function generateImportMap(options={}){
|
|
2350
2358
|
const {workspaceRoot}=options??{};
|
|
2351
|
-
if(
|
|
2359
|
+
if(!is.string(workspaceRoot)||workspaceRoot.trim()===''){
|
|
2352
2360
|
throw new TypeError('generateImportMap workspaceRoot must be a nonempty string.');
|
|
2353
2361
|
}
|
|
2354
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);
|