arcane-os 0.1.2 → 0.2.1
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 +35 -0
- package/NOTICE +5 -3
- package/README.md +73 -24
- package/browser-runtime/ARCANE_SDK_BROWSER_RELEASE.json +67 -18
- package/browser-runtime/ai/ARCANE_AI_BROWSER_WASM_COMPONENTS.json +16 -5
- package/browser-runtime/ai/browser-kokoro-worker.mjs +3 -0
- package/browser-runtime/ai/browser-speech-artifacts.mjs +1108 -0
- package/browser-runtime/ai/browser-speech-providers.mjs +780 -0
- package/browser-runtime/ai/browser-speech.mjs +9 -0
- package/browser-runtime/ai/browser-wasm-llm-provider.mjs +1537 -167
- package/browser-runtime/ai/browser-wasm.mjs +46 -1
- package/browser-runtime/ai/browser-whisper-worker.mjs +3 -0
- package/browser-runtime/ai/browser-wllama-runtime.mjs +677 -132
- package/browser-runtime/ai/model-controller.mjs +138 -12
- package/browser-runtime/ai/speech-worker-client.mjs +207 -0
- package/browser-runtime/ai/speech-worker-runtime.mjs +516 -0
- package/browser-runtime/ai/wllama/index.mjs +389 -0
- package/docs/architecture.md +132 -22
- package/docs/reference/README.md +1 -1
- package/docs/reference/ai/browser-wasm.md +101 -42
- package/docs/reference/availability-and-normalization.md +19 -5
- package/docs/reference/behavioral-testing.md +18 -5
- package/docs/reference/cli.md +2 -2
- package/docs/reference/inventory/package-api.json +14 -14
- package/docs/reference/protocols.md +4 -4
- package/docs/reference/sdk-api.md +68 -38
- package/docs/work-amplification.md +8 -4
- package/package.json +7 -3
- package/runtime/ARCANE_RUNTIME_RELEASE.json +50 -20
- package/runtime/arcane/components/chat.html +551 -62
- package/runtime/arcane/components/speech.html +1113 -265
- package/runtime/arcane/entities/Chat.js +246 -43
- package/runtime/arcane/modules/AI.js +1394 -162
- package/runtime/arcane/modules/AIProviderRuntime.js +2289 -0
- package/runtime/arcane/modules/AIRuntimeState.js +872 -0
- package/runtime/arcane/modules/ConfiguredAIChatSession.js +382 -31
- package/runtime/arcane/modules/DBOPFSDocumentLibrary.js +1106 -0
- package/runtime/arcane/modules/DocumentLexicalSearch.js +292 -0
- package/runtime/arcane/modules/PersistentAIChatSession.js +268 -0
- package/runtime/arcane/modules/StaticDocumentCatalog.js +25 -206
- package/schemas/arcane-lock.schema.json +10 -6
- package/src/cli/main.mjs +14 -2
- package/src/constants.mjs +1 -1
- package/src/dev-server.mjs +273 -26
- package/src/doctor.mjs +1 -3
- package/src/import-map.mjs +193 -84
- package/src/packager/core.mjs +313 -41
- package/src/runtime.mjs +14 -4
- package/src/scaffold.mjs +45 -17
- package/src/sdk-browser-runtime.mjs +28 -75
- package/src/templates/workspace-template.mjs +27 -8
- package/src/toolchain.mjs +13 -2
- package/src/workspace-runtime.mjs +1 -1
- package/src/workspace.mjs +178 -25
package/src/import-map.mjs
CHANGED
|
@@ -14,15 +14,26 @@ export const MANAGED_IMPORT_MAP_ATTRIBUTE='data-arcane-import-map';
|
|
|
14
14
|
const JAVASCRIPT_EXTENSION=/\.(?:js|mjs)$/u;
|
|
15
15
|
const NODE_ONLY_MODULE='modules/CaseEvidenceIndexer.js';
|
|
16
16
|
const RUNTIME_STRONG_TYPE_IMPORT='../../node_modules/strong-type/index.js';
|
|
17
|
+
const PERSISTENT_CHAT_IMPORT='#arcane/persistent-ai-chat-session';
|
|
18
|
+
const PERSISTENT_CHAT_MODULE='modules/PersistentAIChatSession.js';
|
|
17
19
|
const SDK_BROWSER_ENTRY='sdk/event-manager.mjs';
|
|
18
20
|
const SDK_BROWSER_AI_ENTRY='sdk/ai/browser-wasm.mjs';
|
|
21
|
+
const SDK_BROWSER_SPEECH_ENTRY='sdk/ai/browser-speech.mjs';
|
|
22
|
+
const SDK_BROWSER_SPEECH_WORKER_RUNTIME='sdk/ai/speech-worker-runtime.mjs';
|
|
19
23
|
const SDK_BROWSER_FILES=Object.freeze([
|
|
20
24
|
'sdk/ai/ARCANE_AI_BROWSER_WASM_COMPONENTS.json',
|
|
25
|
+
'sdk/ai/browser-kokoro-worker.mjs',
|
|
26
|
+
'sdk/ai/browser-speech-artifacts.mjs',
|
|
27
|
+
'sdk/ai/browser-speech-providers.mjs',
|
|
28
|
+
SDK_BROWSER_SPEECH_ENTRY,
|
|
21
29
|
'sdk/ai/browser-wasm-llm-provider.mjs',
|
|
22
30
|
SDK_BROWSER_AI_ENTRY,
|
|
31
|
+
'sdk/ai/browser-whisper-worker.mjs',
|
|
23
32
|
'sdk/ai/browser-wllama-runtime.mjs',
|
|
24
33
|
'sdk/ai/internal/sha256.mjs',
|
|
25
34
|
'sdk/ai/model-controller.mjs',
|
|
35
|
+
'sdk/ai/speech-worker-client.mjs',
|
|
36
|
+
SDK_BROWSER_SPEECH_WORKER_RUNTIME,
|
|
26
37
|
'sdk/ai/wllama/LICENCE',
|
|
27
38
|
'sdk/ai/wllama/index.mjs',
|
|
28
39
|
'sdk/ai/wllama/llama.cpp-LICENSE',
|
|
@@ -75,6 +86,35 @@ function safeRelativePath(value,label='path'){
|
|
|
75
86
|
return value;
|
|
76
87
|
}
|
|
77
88
|
|
|
89
|
+
function normalizedDocumentPaths(entry,documents){
|
|
90
|
+
if(documents===undefined)return Object.freeze([entry]);
|
|
91
|
+
if(!Array.isArray(documents)||documents.length===0){
|
|
92
|
+
fail('Import-map documents must be a non-empty array of application-relative paths.');
|
|
93
|
+
}
|
|
94
|
+
const normalized=[];
|
|
95
|
+
const identities=new Map();
|
|
96
|
+
for(const [index,value] of documents.entries()){
|
|
97
|
+
const relative=safeRelativePath(value,`documents[${String(index)}]`);
|
|
98
|
+
const key=collisionKey(relative);
|
|
99
|
+
const prior=identities.get(key);
|
|
100
|
+
if(prior!==undefined){
|
|
101
|
+
fail(
|
|
102
|
+
`Import-map documents contain a duplicate or portable path collision: `
|
|
103
|
+
+`${prior} and ${relative}.`
|
|
104
|
+
);
|
|
105
|
+
}
|
|
106
|
+
identities.set(key,relative);
|
|
107
|
+
normalized.push(relative);
|
|
108
|
+
}
|
|
109
|
+
if(!normalized.includes(entry)){
|
|
110
|
+
fail(`Import-map documents must include the configured application entry: ${entry}.`);
|
|
111
|
+
}
|
|
112
|
+
return Object.freeze([
|
|
113
|
+
entry,
|
|
114
|
+
...normalized.filter(relative=>relative!==entry).sort(compareUtf8)
|
|
115
|
+
]);
|
|
116
|
+
}
|
|
117
|
+
|
|
78
118
|
function decodedEscape(source,index){
|
|
79
119
|
const character=source[index];
|
|
80
120
|
if(/[1-9]/u.test(character)||(character==='0'&&/[0-9]/u.test(source[index+1]??''))){
|
|
@@ -719,6 +759,14 @@ function nonliteralDynamic(importer,offset){
|
|
|
719
759
|
);
|
|
720
760
|
}
|
|
721
761
|
|
|
762
|
+
function isAuthorizedSpeechRuntimeImport(tokens,index,close,importer){
|
|
763
|
+
if(importer!==SDK_BROWSER_SPEECH_WORKER_RUNTIME||close!==index+5)return false;
|
|
764
|
+
const [entry,dot,moduleUrl]=tokens.slice(index+2,close);
|
|
765
|
+
return entry?.type==='identifier'&&entry.value==='entry'
|
|
766
|
+
&&dot?.value==='.'
|
|
767
|
+
&&moduleUrl?.type==='identifier'&&moduleUrl.value==='moduleUrl';
|
|
768
|
+
}
|
|
769
|
+
|
|
722
770
|
export function scanModuleImports(source,{importer='<module>'}={}){
|
|
723
771
|
if(typeof source!=='string')throw new TypeError('scanModuleImports source must be a string.');
|
|
724
772
|
const tokens=tokenize(source);
|
|
@@ -745,6 +793,11 @@ export function scanModuleImports(source,{importer='<module>'}={}){
|
|
|
745
793
|
||commas.length>2
|
|
746
794
|
||(commas.length===2
|
|
747
795
|
&&(commas[1]!==close-1||commas[1]===commas[0]+1))){
|
|
796
|
+
if(isAuthorizedSpeechRuntimeImport(tokens,index,close,importer)){
|
|
797
|
+
hasModuleSyntax=true;
|
|
798
|
+
index=close;
|
|
799
|
+
continue;
|
|
800
|
+
}
|
|
748
801
|
nonliteralDynamic(importer,current.start);
|
|
749
802
|
}
|
|
750
803
|
hasModuleSyntax=true;
|
|
@@ -811,6 +864,20 @@ function unresolved(importer,specifier,normalizedTarget,reason='is not in the sh
|
|
|
811
864
|
}
|
|
812
865
|
|
|
813
866
|
function resolveImport(importer,specifier,files){
|
|
867
|
+
if(specifier===PERSISTENT_CHAT_IMPORT){
|
|
868
|
+
if(!files.has(PERSISTENT_CHAT_MODULE)){
|
|
869
|
+
unresolved(importer,specifier,PERSISTENT_CHAT_MODULE);
|
|
870
|
+
}
|
|
871
|
+
return {target:PERSISTENT_CHAT_MODULE,persistentChat:true};
|
|
872
|
+
}
|
|
873
|
+
if(specifier.startsWith(PERSISTENT_CHAT_IMPORT)){
|
|
874
|
+
unresolved(
|
|
875
|
+
importer,
|
|
876
|
+
specifier,
|
|
877
|
+
PERSISTENT_CHAT_MODULE,
|
|
878
|
+
'does not match the exact browser import-map key'
|
|
879
|
+
);
|
|
880
|
+
}
|
|
814
881
|
const reachableSpecifier=stripQueryAndHash(specifier);
|
|
815
882
|
if(!reachableSpecifier)unresolved(importer,specifier,'<empty>');
|
|
816
883
|
if(reachableSpecifier.includes('%')){
|
|
@@ -966,9 +1033,13 @@ export async function buildImportMap({files,readFile,signal}={}){
|
|
|
966
1033
|
}
|
|
967
1034
|
const hasSdkBrowserGraph=inventory.has(SDK_BROWSER_ENTRY);
|
|
968
1035
|
const hasSdkAiGraph=inventory.has(SDK_BROWSER_AI_ENTRY);
|
|
1036
|
+
const hasSdkSpeechGraph=inventory.has(SDK_BROWSER_SPEECH_ENTRY);
|
|
969
1037
|
if(hasSdkAiGraph&&!hasSdkBrowserGraph){
|
|
970
1038
|
unresolved(SDK_BROWSER_AI_ENTRY,'<authenticated SDK browser closure>',SDK_BROWSER_ENTRY);
|
|
971
1039
|
}
|
|
1040
|
+
if(hasSdkSpeechGraph&&!hasSdkAiGraph){
|
|
1041
|
+
unresolved(SDK_BROWSER_SPEECH_ENTRY,'<authenticated SDK browser closure>',SDK_BROWSER_AI_ENTRY);
|
|
1042
|
+
}
|
|
972
1043
|
if(hasSdkBrowserGraph){
|
|
973
1044
|
for(const required of SDK_BROWSER_FILES){
|
|
974
1045
|
if(!inventory.has(required)){
|
|
@@ -1016,11 +1087,20 @@ export async function buildImportMap({files,readFile,signal}={}){
|
|
|
1016
1087
|
'arcane-os/ai/browser-wasm',
|
|
1017
1088
|
'./arcane/sdk/ai/browser-wasm.mjs'
|
|
1018
1089
|
);
|
|
1090
|
+
registerSpecifier(
|
|
1091
|
+
namedRegistry,
|
|
1092
|
+
'arcane-os/ai/browser-speech',
|
|
1093
|
+
'./arcane/sdk/ai/browser-speech.mjs'
|
|
1094
|
+
);
|
|
1019
1095
|
}
|
|
1020
1096
|
}
|
|
1021
1097
|
|
|
1022
1098
|
const sdkRoots=hasSdkBrowserGraph
|
|
1023
|
-
?[
|
|
1099
|
+
?[
|
|
1100
|
+
SDK_BROWSER_ENTRY,
|
|
1101
|
+
...(hasSdkAiGraph?[SDK_BROWSER_AI_ENTRY]:[]),
|
|
1102
|
+
...(hasSdkSpeechGraph?[SDK_BROWSER_SPEECH_ENTRY]:[]),
|
|
1103
|
+
]:[];
|
|
1024
1104
|
const queue=[...roots,...sdkRoots];
|
|
1025
1105
|
const reached=new Set();
|
|
1026
1106
|
const entities=new Set();
|
|
@@ -1036,6 +1116,13 @@ export async function buildImportMap({files,readFile,signal}={}){
|
|
|
1036
1116
|
const resolution=resolveImport(importer,imported.specifier,inventory);
|
|
1037
1117
|
if(resolution.runtimeStrongType)usesRuntimeStrongType=true;
|
|
1038
1118
|
if(resolution.eventPubSub)usesEventPubSub=true;
|
|
1119
|
+
if(resolution.persistentChat){
|
|
1120
|
+
registerSpecifier(
|
|
1121
|
+
namedRegistry,
|
|
1122
|
+
PERSISTENT_CHAT_IMPORT,
|
|
1123
|
+
'./arcane/modules/PersistentAIChatSession.js'
|
|
1124
|
+
);
|
|
1125
|
+
}
|
|
1039
1126
|
if(resolution.target.startsWith('entities/'))entities.add(resolution.target);
|
|
1040
1127
|
if(!reached.has(resolution.target))queue.push(resolution.target);
|
|
1041
1128
|
}
|
|
@@ -1702,14 +1789,20 @@ export function inspectImportMapHtml(html){
|
|
|
1702
1789
|
});
|
|
1703
1790
|
}
|
|
1704
1791
|
|
|
1705
|
-
function
|
|
1792
|
+
function documentBaseHref(relative){
|
|
1793
|
+
const directory=path.posix.dirname(relative);
|
|
1794
|
+
const depth=directory==='.'?0:directory.split('/').length;
|
|
1795
|
+
return '../'.repeat(depth+2);
|
|
1796
|
+
}
|
|
1797
|
+
|
|
1798
|
+
function renderManagedHtml(html,json,baseHref='../../'){
|
|
1706
1799
|
const structure=scanHtmlStructure(html);
|
|
1707
1800
|
const activeBases=structure.bases.map(base=>({
|
|
1708
1801
|
...base,
|
|
1709
1802
|
href:structuralAttribute(parseTagAttributes(base.open),'href','base')
|
|
1710
1803
|
}));
|
|
1711
|
-
if(activeBases.length!==1||activeBases[0].href!==
|
|
1712
|
-
fail(
|
|
1804
|
+
if(activeBases.length!==1||activeBases[0].href!==baseHref){
|
|
1805
|
+
fail(`Application HTML must contain exactly one active <base href="${baseHref}"> element.`);
|
|
1713
1806
|
}
|
|
1714
1807
|
const complete=[];
|
|
1715
1808
|
for(const script of structure.scripts){
|
|
@@ -1738,8 +1831,8 @@ function renderManagedHtml(html,json){
|
|
|
1738
1831
|
...base,
|
|
1739
1832
|
href:structuralAttribute(parseTagAttributes(base.open),'href','base')
|
|
1740
1833
|
}));
|
|
1741
|
-
if(cleanedBases.length!==1||cleanedBases[0].href!==
|
|
1742
|
-
fail(
|
|
1834
|
+
if(cleanedBases.length!==1||cleanedBases[0].href!==baseHref){
|
|
1835
|
+
fail(`Application HTML must retain exactly one active <base href="${baseHref}"> element.`);
|
|
1743
1836
|
}
|
|
1744
1837
|
const firstBlocking=firstBlockingLoadPosition(withoutManaged);
|
|
1745
1838
|
if(firstBlocking>=0&&cleanedBases[0].start>firstBlocking){
|
|
@@ -2097,73 +2190,53 @@ async function installStagedFile(state,staged,label){
|
|
|
2097
2190
|
};
|
|
2098
2191
|
}
|
|
2099
2192
|
|
|
2100
|
-
async function
|
|
2101
|
-
|
|
2102
|
-
entryState,
|
|
2103
|
-
artifactBytes,
|
|
2104
|
-
entryBytes,
|
|
2193
|
+
async function commitGeneratedFiles({
|
|
2194
|
+
files,
|
|
2105
2195
|
signal,
|
|
2106
2196
|
onEvent
|
|
2107
2197
|
}){
|
|
2108
|
-
const
|
|
2109
|
-
|
|
2110
|
-
artifactBytes,
|
|
2111
|
-
artifactState.directoryState
|
|
2112
|
-
);
|
|
2113
|
-
let entryStage;
|
|
2114
|
-
let artifactInstall;
|
|
2115
|
-
let entryInstall;
|
|
2198
|
+
const staged=[];
|
|
2199
|
+
const installed=[];
|
|
2116
2200
|
let failure;
|
|
2117
2201
|
try{
|
|
2118
|
-
|
|
2119
|
-
|
|
2120
|
-
|
|
2121
|
-
|
|
2122
|
-
|
|
2202
|
+
for(const file of files){
|
|
2203
|
+
throwIfAborted(signal);
|
|
2204
|
+
staged.push(await stageSibling(
|
|
2205
|
+
file.state.filePath,
|
|
2206
|
+
file.bytes,
|
|
2207
|
+
file.state.directoryState
|
|
2208
|
+
));
|
|
2209
|
+
}
|
|
2123
2210
|
await emit(onEvent,{type:'import-map.commit.staged'});
|
|
2124
2211
|
throwIfAborted(signal);
|
|
2125
|
-
|
|
2126
|
-
|
|
2127
|
-
|
|
2128
|
-
|
|
2129
|
-
);
|
|
2130
|
-
entryInstall=await installStagedFile(entryState,entryStage,'Import-map application entry');
|
|
2131
|
-
await artifactInstall.verify();
|
|
2132
|
-
await entryInstall.verify();
|
|
2212
|
+
for(const [index,file] of files.entries()){
|
|
2213
|
+
installed.push(await installStagedFile(file.state,staged[index],file.label));
|
|
2214
|
+
throwIfAborted(signal);
|
|
2215
|
+
}
|
|
2216
|
+
for(const transaction of installed)await transaction.verify();
|
|
2133
2217
|
await emit(onEvent,{
|
|
2134
2218
|
type:'import-map.commit.progress',
|
|
2135
|
-
paths:Object.freeze(
|
|
2219
|
+
paths:Object.freeze(files.map(file=>file.state.filePath))
|
|
2136
2220
|
});
|
|
2137
2221
|
throwIfAborted(signal);
|
|
2138
|
-
await
|
|
2139
|
-
await entryInstall.verify();
|
|
2222
|
+
for(const transaction of installed)await transaction.verify();
|
|
2140
2223
|
}catch(error){
|
|
2141
|
-
|
|
2142
|
-
|
|
2143
|
-
await artifactInstall.rollback().catch(rollback=>{error.rollbackError??=rollback;});
|
|
2224
|
+
for(const transaction of [...installed].reverse()){
|
|
2225
|
+
await transaction.rollback().catch(rollback=>{error.rollbackError??=rollback;});
|
|
2144
2226
|
}
|
|
2145
2227
|
failure=error;
|
|
2146
2228
|
}
|
|
2147
2229
|
const cleanupErrors=[];
|
|
2148
|
-
|
|
2230
|
+
for(const [index,stage] of staged.entries()){
|
|
2231
|
+
if(index<installed.length)continue;
|
|
2149
2232
|
try{
|
|
2150
2233
|
const removed=await removeOwnedPath(
|
|
2151
|
-
|
|
2152
|
-
|
|
2153
|
-
|
|
2154
|
-
);
|
|
2155
|
-
if(!removed)fail(`Import-map artifact stage could not be safely cleaned: ${artifactStage.path}.`);
|
|
2156
|
-
}catch(error){cleanupErrors.push(error);}
|
|
2157
|
-
}
|
|
2158
|
-
if(entryStage&&!entryInstall){
|
|
2159
|
-
try{
|
|
2160
|
-
const removed=await removeOwnedPath(
|
|
2161
|
-
entryStage.path,
|
|
2162
|
-
entryStage.identity,
|
|
2163
|
-
entryStage.directoryState
|
|
2234
|
+
stage.path,
|
|
2235
|
+
stage.identity,
|
|
2236
|
+
stage.directoryState
|
|
2164
2237
|
);
|
|
2165
2238
|
if(!removed){
|
|
2166
|
-
fail(
|
|
2239
|
+
fail(`${files[index].label} stage could not be safely cleaned: ${stage.path}.`);
|
|
2167
2240
|
}
|
|
2168
2241
|
}catch(error){cleanupErrors.push(error);}
|
|
2169
2242
|
}
|
|
@@ -2180,12 +2253,11 @@ async function commitGeneratedPair({
|
|
|
2180
2253
|
}
|
|
2181
2254
|
|
|
2182
2255
|
const cleanupWarnings=[];
|
|
2183
|
-
for(const
|
|
2184
|
-
try{await
|
|
2256
|
+
for(const transaction of [...installed].reverse()){
|
|
2257
|
+
try{await transaction.commit();}
|
|
2185
2258
|
catch(error){cleanupWarnings.push(error);}
|
|
2186
2259
|
}
|
|
2187
|
-
await
|
|
2188
|
-
await entryInstall.verify();
|
|
2260
|
+
for(const transaction of installed)await transaction.verify();
|
|
2189
2261
|
if(cleanupWarnings.length>0){
|
|
2190
2262
|
return Object.freeze(cleanupWarnings.map(error=>String(error?.message??error)));
|
|
2191
2263
|
}
|
|
@@ -2206,6 +2278,7 @@ async function generateImportMapUnlocked({
|
|
|
2206
2278
|
appId,
|
|
2207
2279
|
appRoot,
|
|
2208
2280
|
entry='index.html',
|
|
2281
|
+
documents,
|
|
2209
2282
|
workspaceRuntimeReceipt,
|
|
2210
2283
|
signal,
|
|
2211
2284
|
onEvent
|
|
@@ -2217,21 +2290,45 @@ async function generateImportMapUnlocked({
|
|
|
2217
2290
|
const resolvedWorkspace=path.resolve(workspaceRoot);
|
|
2218
2291
|
const resolvedApp=resolvedAppRoot(resolvedWorkspace,appId,appRoot);
|
|
2219
2292
|
const safeEntry=safeRelativePath(entry,'application entry');
|
|
2220
|
-
const
|
|
2221
|
-
|
|
2293
|
+
const safeDocuments=normalizedDocumentPaths(safeEntry,documents);
|
|
2294
|
+
const documentPaths=Object.freeze(safeDocuments.map(relative=>{
|
|
2295
|
+
const documentPath=path.resolve(resolvedApp,...relative.split('/'));
|
|
2296
|
+
if(!pathInside(resolvedApp,documentPath)){
|
|
2297
|
+
fail(`Import-map application document escapes its app root: ${relative}.`);
|
|
2298
|
+
}
|
|
2299
|
+
return documentPath;
|
|
2300
|
+
}));
|
|
2301
|
+
const entryPath=documentPaths[0];
|
|
2222
2302
|
const artifactPath=path.join(resolvedApp,...IMPORT_MAP_RELATIVE_PATH.split('/'));
|
|
2223
|
-
await emit(onEvent,{
|
|
2303
|
+
await emit(onEvent,{
|
|
2304
|
+
type:'import-map.started',
|
|
2305
|
+
appId,
|
|
2306
|
+
artifactPath,
|
|
2307
|
+
entryPath,
|
|
2308
|
+
documentPaths,
|
|
2309
|
+
documentCount:documentPaths.length
|
|
2310
|
+
});
|
|
2224
2311
|
|
|
2225
|
-
const
|
|
2226
|
-
|
|
2227
|
-
|
|
2228
|
-
|
|
2229
|
-
|
|
2230
|
-
|
|
2231
|
-
|
|
2232
|
-
|
|
2233
|
-
|
|
2234
|
-
|
|
2312
|
+
const documentStates=[];
|
|
2313
|
+
for(const [index,documentPath] of documentPaths.entries()){
|
|
2314
|
+
throwIfAborted(signal);
|
|
2315
|
+
const label=index===0
|
|
2316
|
+
?'Import-map application entry'
|
|
2317
|
+
:`Import-map application document ${safeDocuments[index]}`;
|
|
2318
|
+
const directoryState=await captureDirectoryState(
|
|
2319
|
+
resolvedWorkspace,
|
|
2320
|
+
path.dirname(documentPath)
|
|
2321
|
+
);
|
|
2322
|
+
const state=await readRealFileState(documentPath,label);
|
|
2323
|
+
throwIfAborted(signal);
|
|
2324
|
+
state.directoryState=directoryState;
|
|
2325
|
+
const html=state.bytes.toString('utf8');
|
|
2326
|
+
// Reject malformed application structure before traversing the substantially larger
|
|
2327
|
+
// runtime graph. The real generated map is rendered and revalidated before commit.
|
|
2328
|
+
const baseHref=documentBaseHref(safeDocuments[index]);
|
|
2329
|
+
renderManagedHtml(html,'{"imports":{}}\n',baseHref);
|
|
2330
|
+
documentStates.push({state,html,label,baseHref});
|
|
2331
|
+
}
|
|
2235
2332
|
let runtime;
|
|
2236
2333
|
if(workspaceRuntimeReceipt){
|
|
2237
2334
|
await authenticateWorkspaceRuntimeReceipt(workspaceRuntimeReceipt,{
|
|
@@ -2261,7 +2358,10 @@ async function generateImportMapUnlocked({
|
|
|
2261
2358
|
const built=await buildImportMap({files:runtime.files,readFile:runtime.readFile,signal});
|
|
2262
2359
|
const document={imports:built.imports};
|
|
2263
2360
|
const json=`${JSON.stringify(document,null,2).replaceAll('<','\\u003c')}\n`;
|
|
2264
|
-
const
|
|
2361
|
+
const renderedDocuments=documentStates.map(item=>Object.freeze({
|
|
2362
|
+
...item,
|
|
2363
|
+
bytes:Buffer.from(renderManagedHtml(item.html,json,item.baseHref),'utf8')
|
|
2364
|
+
}));
|
|
2265
2365
|
|
|
2266
2366
|
throwIfAborted(signal);
|
|
2267
2367
|
const artifactDirectoryState=await captureDirectoryState(
|
|
@@ -2275,11 +2375,16 @@ async function generateImportMapUnlocked({
|
|
|
2275
2375
|
{optional:true}
|
|
2276
2376
|
);
|
|
2277
2377
|
artifactState.directoryState=artifactDirectoryState;
|
|
2278
|
-
const
|
|
2279
|
-
|
|
2280
|
-
|
|
2281
|
-
|
|
2282
|
-
|
|
2378
|
+
const artifactBytes=Buffer.from(json,'utf8');
|
|
2379
|
+
const cleanupWarnings=await commitGeneratedFiles({
|
|
2380
|
+
files:[
|
|
2381
|
+
{state:artifactState,bytes:artifactBytes,label:'Import-map artifact'},
|
|
2382
|
+
...renderedDocuments.map(item=>({
|
|
2383
|
+
state:item.state,
|
|
2384
|
+
bytes:item.bytes,
|
|
2385
|
+
label:item.label
|
|
2386
|
+
}))
|
|
2387
|
+
],
|
|
2283
2388
|
signal,
|
|
2284
2389
|
onEvent
|
|
2285
2390
|
});
|
|
@@ -2287,21 +2392,23 @@ async function generateImportMapUnlocked({
|
|
|
2287
2392
|
Object.freeze({
|
|
2288
2393
|
role:'artifact',
|
|
2289
2394
|
path:path.relative(resolvedWorkspace,artifactPath).split(path.sep).join('/'),
|
|
2290
|
-
bytes:
|
|
2291
|
-
sha256:sha256(
|
|
2395
|
+
bytes:artifactBytes.length,
|
|
2396
|
+
sha256:sha256(artifactBytes)
|
|
2292
2397
|
}),
|
|
2293
|
-
Object.freeze({
|
|
2294
|
-
role:'entry',
|
|
2295
|
-
path:path.relative(resolvedWorkspace,
|
|
2296
|
-
bytes:
|
|
2297
|
-
sha256:sha256(
|
|
2298
|
-
})
|
|
2398
|
+
...renderedDocuments.map((item,index)=>Object.freeze({
|
|
2399
|
+
role:index===0?'entry':'document',
|
|
2400
|
+
path:path.relative(resolvedWorkspace,item.state.filePath).split(path.sep).join('/'),
|
|
2401
|
+
bytes:item.bytes.length,
|
|
2402
|
+
sha256:sha256(item.bytes)
|
|
2403
|
+
}))
|
|
2299
2404
|
]);
|
|
2300
2405
|
const receipt=Object.freeze({
|
|
2301
2406
|
appId,
|
|
2302
2407
|
artifactPath,
|
|
2303
2408
|
artifactRelativePath:path.relative(resolvedWorkspace,artifactPath).split(path.sep).join('/'),
|
|
2304
2409
|
entryPath,
|
|
2410
|
+
documentPaths,
|
|
2411
|
+
documentCount:documentPaths.length,
|
|
2305
2412
|
imports:built.imports,
|
|
2306
2413
|
entryCount:built.entryCount,
|
|
2307
2414
|
excludedModules:built.excludedModules,
|
|
@@ -2315,6 +2422,8 @@ async function generateImportMapUnlocked({
|
|
|
2315
2422
|
appId,
|
|
2316
2423
|
artifactPath,
|
|
2317
2424
|
entryPath,
|
|
2425
|
+
documentPaths,
|
|
2426
|
+
documentCount:receipt.documentCount,
|
|
2318
2427
|
entryCount:receipt.entryCount,
|
|
2319
2428
|
cleanupWarnings:receipt.cleanupWarnings,
|
|
2320
2429
|
committed:true
|