arcane-os 0.3.1 → 0.3.3
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 +27 -0
- package/README.md +86 -117
- package/bin/arcane-test.mjs +170 -46
- package/browser-runtime/ai/browser-speech-artifacts.mjs +855 -895
- package/browser-runtime/ai/browser-speech-providers.mjs +80 -204
- package/browser-runtime/ai/browser-wasm-llm-provider.mjs +627 -819
- package/browser-runtime/ai/browser-wasm.mjs +24 -35
- package/browser-runtime/ai/browser-wllama-runtime.mjs +64 -316
- package/browser-runtime/ai/model-controller.mjs +584 -181
- package/browser-runtime/ai/speech-worker-client.mjs +8 -148
- package/browser-runtime/ai/speech-worker-runtime.mjs +642 -374
- package/browser-runtime/dom-event-instrumentation.mjs +55 -147
- package/browser-runtime/event-manager.mjs +239 -624
- package/package.json +5 -6
- package/runtime/arcane/components/app-bar.html +3 -15
- package/runtime/arcane/components/assistant-panel.html +10 -10
- package/runtime/arcane/components/calculator.html +1 -1
- package/runtime/arcane/components/chat.html +1359 -135
- package/runtime/arcane/components/conversation-view.html +2 -2
- package/runtime/arcane/components/document-inspector.html +11 -17
- package/runtime/arcane/components/file-manager.html +13 -56
- package/runtime/arcane/components/markdown-document.html +82 -281
- package/runtime/arcane/components/markdown-editor.html +7 -10
- package/runtime/arcane/components/media-embed.html +6 -6
- package/runtime/arcane/components/screen-capture.html +4 -4
- package/runtime/arcane/components/source-explanation.html +2 -2
- package/runtime/arcane/components/speech.html +113 -69
- package/runtime/arcane/components/terminal-workspace.html +4 -4
- package/runtime/arcane/components/theme-editor.html +1 -1
- package/runtime/arcane/components/unified-inbox.html +2 -2
- package/runtime/arcane/components/voice-transcription.html +31 -21
- package/runtime/arcane/entities/Calculation.js +2 -3
- package/runtime/arcane/entities/Chat.js +228 -43
- package/runtime/arcane/entities/Preference.js +3 -5
- package/runtime/arcane/entities/Weather.js +5 -5
- package/runtime/arcane/modules/AI.js +1042 -427
- package/runtime/arcane/modules/AIProviderRuntime.js +618 -359
- package/runtime/arcane/modules/AIResponseLength.js +9 -19
- package/runtime/arcane/modules/AIRuntimeState.js +109 -72
- package/runtime/arcane/modules/ArcaneNavigationPolicy.js +45 -32
- package/runtime/arcane/modules/BrowserTestSuite.js +78 -122
- package/runtime/arcane/modules/CalculatorEngine.js +9 -9
- package/runtime/arcane/modules/CommunicationAppController.js +3 -7
- package/runtime/arcane/modules/ComponentContracts.js +30 -32
- package/runtime/arcane/modules/ConfiguredAIChatSession.js +281 -230
- package/runtime/arcane/modules/ConversationActionItems.js +26 -59
- package/runtime/arcane/modules/ConversationClosingReport.js +34 -61
- package/runtime/arcane/modules/ConversationTimebox.js +27 -15
- package/runtime/arcane/modules/DBOPFSDocumentLibrary.js +152 -344
- package/runtime/arcane/modules/DocumentLexicalSearch.js +25 -91
- package/runtime/arcane/modules/HTMLImport.js +54 -1
- package/runtime/arcane/modules/IsolatedModelQuestionRunner.js +40 -203
- package/runtime/arcane/modules/LocalAIReadiness.js +40 -60
- package/runtime/arcane/modules/LocalAIReadinessController.js +15 -13
- package/runtime/arcane/modules/MD.js +1 -45
- package/runtime/arcane/modules/Mail.js +51 -103
- package/runtime/arcane/modules/MailOutbox.mjs +95 -193
- package/runtime/arcane/modules/MailTransport.mjs +36 -57
- package/runtime/arcane/modules/ModelDefinition.js +22 -106
- package/runtime/arcane/modules/OpenMeteoWeatherProvider.js +39 -101
- package/runtime/arcane/modules/PersistentAIChatSession.js +281 -18
- package/runtime/arcane/modules/PreferenceStore.js +102 -30
- package/runtime/arcane/modules/RiskSignalAnalyzer.js +8 -9
- package/runtime/arcane/modules/ScopedOPFSCache.js +7 -42
- package/runtime/arcane/modules/ScreenCapture.js +175 -128
- package/runtime/arcane/modules/SpeechPlayback.js +46 -149
- package/runtime/arcane/modules/StaticDocumentCatalog.js +173 -407
- package/runtime/arcane/modules/ToolCallRouter.js +25 -12
- package/runtime/arcane/modules/YouTubeMedia.js +6 -5
- package/schemas/arcane-app-bundle.schema.json +13 -78
- package/schemas/arcane-app.schema.json +9 -25
- package/schemas/arcane-lock.schema.json +19 -149
- package/schemas/arcane-package.schema.json +2 -16
- package/schemas/native-build-plan.schema.json +119 -122
- package/src/app-descriptor.mjs +75 -132
- package/src/application-tests.mjs +200 -0
- package/src/cli/main.mjs +27 -46
- package/src/constants.mjs +3 -4
- package/src/dev-server.mjs +42 -327
- package/src/doctor.mjs +92 -154
- package/src/dom-event-instrumentation.mjs +55 -147
- package/src/errors.mjs +2 -3
- package/src/event-manager.mjs +239 -624
- package/src/event-queue.mjs +3 -3
- package/src/import-map.mjs +273 -1028
- package/src/index.mjs +14 -16
- package/src/installed-sdk-runtime.mjs +48 -66
- package/src/integrated-provider-loader.mjs +53 -382
- package/src/mail-api.mjs +0 -2
- package/src/mail-server.mjs +224 -580
- package/src/mail.mjs +4 -10
- package/src/native-plan.mjs +163 -598
- package/src/native-provider-loader.mjs +104 -1063
- package/src/packager/core.mjs +492 -3229
- package/src/process.mjs +5 -10
- package/src/release-bundle.mjs +292 -2405
- package/src/runtime.mjs +76 -396
- package/src/scaffold.mjs +48 -79
- package/src/sdk-browser-runtime.mjs +70 -626
- package/src/source-server.mjs +588 -0
- package/src/targets/index.mjs +78 -188
- package/src/templates/workspace-template.mjs +55 -135
- package/src/testing-loader.mjs +164 -0
- package/src/testing.mjs +1 -1
- package/src/toolchain.mjs +133 -544
- package/src/update-check.mjs +26 -64
- package/src/workspace-operation-lock.mjs +139 -430
- package/src/workspace-runtime.mjs +109 -1558
- package/src/workspace.mjs +40 -302
- package/browser-runtime/ARCANE_SDK_BROWSER_RELEASE.json +0 -218
- package/browser-runtime/ai/ARCANE_AI_BROWSER_SPEECH_COMPONENTS.json +0 -203
- package/browser-runtime/ai/ARCANE_AI_BROWSER_WASM_COMPONENTS.json +0 -80
- package/browser-runtime/ai/internal/sha256.mjs +0 -166
- package/docs/architecture.md +0 -344
- package/docs/compatibility.md +0 -36
- package/docs/event-manager.md +0 -294
- package/docs/platform-targets.md +0 -108
- package/docs/publishing.md +0 -201
- package/docs/reference/README.md +0 -185
- package/docs/reference/ai/browser-speech-package-authority.json +0 -835
- package/docs/reference/ai/browser-speech.md +0 -1295
- package/docs/reference/ai/browser-wasm.md +0 -530
- package/docs/reference/arcane-ollama.md +0 -288
- package/docs/reference/availability-and-normalization.md +0 -183
- package/docs/reference/behavioral-testing.md +0 -133
- package/docs/reference/cli.md +0 -779
- package/docs/reference/core/README.md +0 -62
- package/docs/reference/core/arcane-ai-contracts.md +0 -907
- package/docs/reference/core/arcane-api.md +0 -601
- package/docs/reference/core/arcane-entities.md +0 -65
- package/docs/reference/core/arcane-events.md +0 -134
- package/docs/reference/core/ollama-module.md +0 -181
- package/docs/reference/core/reference/arcane-api/ai-and-ollama.md +0 -1909
- package/docs/reference/core/reference/arcane-api/applications-terminal-capabilities.md +0 -1057
- package/docs/reference/core/reference/arcane-api/core-and-events.md +0 -320
- package/docs/reference/core/reference/arcane-api/filesystem-storage-preferences-appearance.md +0 -610
- package/docs/reference/core/reference/arcane-api/namespaces.md +0 -1157
- package/docs/reference/core/reference/arcane-api/platform-installation-users-system.md +0 -1423
- package/docs/reference/core/reference/arcane-api/session-provisioning-diagnostics-development.md +0 -315
- package/docs/reference/event-manager.md +0 -1511
- package/docs/reference/inventory/package-api.json +0 -3284
- package/docs/reference/inventory/runtime-components.json +0 -1011
- package/docs/reference/inventory/runtime-entities.json +0 -26
- package/docs/reference/inventory/runtime-modules.json +0 -1431
- package/docs/reference/mail.md +0 -316
- package/docs/reference/protocols.md +0 -719
- package/docs/reference/runtime-components.md +0 -1366
- package/docs/reference/runtime-entities.md +0 -303
- package/docs/reference/runtime-modules.md +0 -2965
- package/docs/reference/sdk-api.md +0 -6698
- package/docs/roadmap.md +0 -79
- package/docs/work-amplification.md +0 -129
- package/runtime/ARCANE_RUNTIME_RELEASE.json +0 -826
package/src/toolchain.mjs
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import path from 'node:path';
|
|
2
2
|
import {readdir,lstat,realpath} from 'node:fs/promises';
|
|
3
|
-
import {fileURLToPath} from 'node:url';
|
|
4
3
|
import {createWorkspace,initWorkspace} from './scaffold.mjs';
|
|
5
4
|
import {
|
|
6
5
|
discoverApps as discoverWorkspaceApps,
|
|
@@ -11,26 +10,16 @@ import {
|
|
|
11
10
|
} from './workspace.mjs';
|
|
12
11
|
import {loadArcaneIntegratedProvider} from './integrated-provider-loader.mjs';
|
|
13
12
|
import {startDevServer} from './dev-server.mjs';
|
|
14
|
-
import {authenticateRuntimeReceipt,verifyRuntime} from './runtime.mjs';
|
|
15
|
-
import {
|
|
16
|
-
authenticateSdkBrowserRuntimeReceipt,
|
|
17
|
-
verifySdkBrowserRuntime
|
|
18
|
-
} from './sdk-browser-runtime.mjs';
|
|
19
|
-
import {
|
|
20
|
-
authenticateWorkspaceRuntimeReceipt,
|
|
21
|
-
verifyWorkspaceRuntime
|
|
22
|
-
} from './workspace-runtime.mjs';
|
|
23
13
|
import {generateImportMap} from './import-map.mjs';
|
|
24
14
|
import {withWorkspaceOperationLock} from './workspace-operation-lock.mjs';
|
|
25
15
|
import {
|
|
26
|
-
|
|
16
|
+
inspectApp as inspectPackagedApp,
|
|
27
17
|
packageApp,
|
|
28
|
-
prepareSharedPayloadSnapshot,
|
|
29
18
|
verifyApp
|
|
30
19
|
} from './packager/core.mjs';
|
|
31
|
-
import {assertNativeToolchainCompatibility} from './native-plan.mjs';
|
|
32
20
|
import {runDoctor} from './doctor.mjs';
|
|
33
21
|
import {runProcess} from './process.mjs';
|
|
22
|
+
import {runApplicationTests} from './application-tests.mjs';
|
|
34
23
|
import {
|
|
35
24
|
buildTarget,
|
|
36
25
|
createNativeTargetAdapter,
|
|
@@ -50,132 +39,34 @@ import {
|
|
|
50
39
|
verifyAppReleaseBundle
|
|
51
40
|
} from './release-bundle.mjs';
|
|
52
41
|
|
|
53
|
-
const TEST_RUNNER_PATH=fileURLToPath(new URL('../bin/arcane-test.mjs',import.meta.url));
|
|
54
|
-
const MAX_TEST_FAILURE_STREAM_BYTES=32*1024;
|
|
55
|
-
const MAX_TEST_FAILURE_AGGREGATE_BYTES=256*1024;
|
|
56
|
-
const MAX_TEST_FAILURE_MESSAGE_BYTES=24*1024;
|
|
57
|
-
const TEST_OUTPUT_TRUNCATION_NOTICE='[... earlier test output omitted ...]\n';
|
|
58
|
-
|
|
59
|
-
function normalizedTestOutput(value){
|
|
60
|
-
return typeof value==='string'?value.trim():'';
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
function boundedTestOutputTail(value,maxBytes){
|
|
64
|
-
const source=normalizedTestOutput(value);
|
|
65
|
-
const sourceBytes=Buffer.byteLength(source,'utf8');
|
|
66
|
-
if(sourceBytes<=maxBytes){
|
|
67
|
-
return {text:source,bytes:sourceBytes,truncated:false};
|
|
68
|
-
}
|
|
69
|
-
const noticeBytes=Buffer.byteLength(TEST_OUTPUT_TRUNCATION_NOTICE,'utf8');
|
|
70
|
-
if(maxBytes<noticeBytes){
|
|
71
|
-
return {text:'',bytes:0,truncated:sourceBytes>0};
|
|
72
|
-
}
|
|
73
|
-
const buffer=Buffer.from(source,'utf8');
|
|
74
|
-
let start=buffer.length-(maxBytes-noticeBytes);
|
|
75
|
-
while(start<buffer.length&&(buffer[start]&0xc0)===0x80){
|
|
76
|
-
start+=1;
|
|
77
|
-
}
|
|
78
|
-
const text=`${TEST_OUTPUT_TRUNCATION_NOTICE}${buffer.subarray(start).toString('utf8')}`;
|
|
79
|
-
return {text,bytes:Buffer.byteLength(text,'utf8'),truncated:true};
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
function failedTestOutputBudgets(stderr,stdout,maxBytes){
|
|
83
|
-
const desiredStderr=Math.min(
|
|
84
|
-
MAX_TEST_FAILURE_STREAM_BYTES,
|
|
85
|
-
Buffer.byteLength(normalizedTestOutput(stderr),'utf8')
|
|
86
|
-
);
|
|
87
|
-
const desiredStdout=Math.min(
|
|
88
|
-
MAX_TEST_FAILURE_STREAM_BYTES,
|
|
89
|
-
Buffer.byteLength(normalizedTestOutput(stdout),'utf8')
|
|
90
|
-
);
|
|
91
|
-
if(desiredStderr+desiredStdout<=maxBytes){
|
|
92
|
-
return {stderr:desiredStderr,stdout:desiredStdout};
|
|
93
|
-
}
|
|
94
|
-
const shared=Math.floor(maxBytes/2);
|
|
95
|
-
let stderrBudget=Math.min(desiredStderr,shared);
|
|
96
|
-
let stdoutBudget=Math.min(desiredStdout,shared);
|
|
97
|
-
let remaining=maxBytes-stderrBudget-stdoutBudget;
|
|
98
|
-
const additionalStderr=Math.min(remaining,desiredStderr-stderrBudget);
|
|
99
|
-
stderrBudget+=additionalStderr;
|
|
100
|
-
remaining-=additionalStderr;
|
|
101
|
-
stdoutBudget+=Math.min(remaining,desiredStdout-stdoutBudget);
|
|
102
|
-
return {stderr:stderrBudget,stdout:stdoutBudget};
|
|
103
|
-
}
|
|
104
|
-
|
|
105
|
-
function captureFailedTest(testFile,result,workspaceRoot,maxBytes){
|
|
106
|
-
const budgets=failedTestOutputBudgets(result.stderr,result.stdout,maxBytes);
|
|
107
|
-
const stderr=boundedTestOutputTail(result.stderr,budgets.stderr);
|
|
108
|
-
const stdout=boundedTestOutputTail(result.stdout,budgets.stdout);
|
|
109
|
-
return {
|
|
110
|
-
failure:Object.freeze({
|
|
111
|
-
testFile:path.relative(workspaceRoot,testFile).replaceAll('\\','/'),
|
|
112
|
-
exitCode:result.code,
|
|
113
|
-
signal:result.signal,
|
|
114
|
-
stdout:stdout.text,
|
|
115
|
-
stderr:stderr.text,
|
|
116
|
-
stdoutTruncated:stdout.truncated,
|
|
117
|
-
stderrTruncated:stderr.truncated
|
|
118
|
-
}),
|
|
119
|
-
bytes:stdout.bytes+stderr.bytes
|
|
120
|
-
};
|
|
121
|
-
}
|
|
122
|
-
|
|
123
|
-
function failedTestMessage(failures){
|
|
124
|
-
const summary=`${String(failures.length)} isolated test file${failures.length===1?'':'s'} failed.`;
|
|
125
|
-
const actionable=failures.find(failure=>failure.stderr||failure.stdout);
|
|
126
|
-
if(!actionable){
|
|
127
|
-
return summary;
|
|
128
|
-
}
|
|
129
|
-
const heading=`\n\n${actionable.testFile}:\n`;
|
|
130
|
-
const available=Math.max(
|
|
131
|
-
0,
|
|
132
|
-
MAX_TEST_FAILURE_MESSAGE_BYTES-Buffer.byteLength(`${summary}${heading}`,'utf8')
|
|
133
|
-
);
|
|
134
|
-
const diagnostic=boundedTestOutputTail(
|
|
135
|
-
actionable.stderr||actionable.stdout,
|
|
136
|
-
available
|
|
137
|
-
).text;
|
|
138
|
-
return diagnostic?`${summary}${heading}${diagnostic}`:summary;
|
|
139
|
-
}
|
|
140
|
-
|
|
141
42
|
async function emit(onEvent,event){
|
|
142
43
|
await onEvent?.(event);
|
|
143
44
|
}
|
|
144
45
|
|
|
145
|
-
function nativeArtifactReceipt(result){
|
|
146
|
-
return result?.artifactReceipt??result?.built?.artifactReceipt??null;
|
|
147
|
-
}
|
|
148
|
-
|
|
149
46
|
function withEventDeliveryFailure(result,error){
|
|
150
|
-
const eventDelivery=
|
|
47
|
+
const eventDelivery={
|
|
151
48
|
status:'degraded',
|
|
152
49
|
errorCode:'ARCANE_EVENT_DELIVERY_FAILED',
|
|
153
50
|
message:String(error?.message??error)
|
|
154
|
-
}
|
|
155
|
-
if(result?.built?.
|
|
51
|
+
};
|
|
52
|
+
if(result?.built?.artifact){
|
|
156
53
|
return {...result,built:{...result.built,eventDelivery}};
|
|
157
54
|
}
|
|
158
55
|
return {...result,eventDelivery};
|
|
159
56
|
}
|
|
160
57
|
|
|
161
58
|
function isOuterCommitEvent(label,event){
|
|
162
|
-
if(label==='build')return event?.type==='native.build.
|
|
163
|
-
return label==='bundle'&&event?.type==='bundle.
|
|
59
|
+
if(label==='build')return event?.type==='native.build.completed';
|
|
60
|
+
return label==='bundle'&&event?.type==='bundle.completed'
|
|
164
61
|
&&event?.phase==='publish'&&event?.status==='completed';
|
|
165
62
|
}
|
|
166
63
|
|
|
167
|
-
function
|
|
168
|
-
return value?.kind==='arcane-app-release-verification'
|
|
169
|
-
&&typeof value?.contentSha256==='string';
|
|
170
|
-
}
|
|
171
|
-
|
|
172
|
-
function hasAuthenticatedOuterResult(label,result){
|
|
64
|
+
function hasCommittedOuterResult(label,result){
|
|
173
65
|
if(label==='import-map')return result?.committed===true;
|
|
174
|
-
if(label==='package')return
|
|
175
|
-
if(label==='bundle')return result?.
|
|
176
|
-
==='arcane-app-release-bundle-artifact';
|
|
66
|
+
if(label==='package')return typeof result?.outputRoot==='string';
|
|
67
|
+
if(label==='bundle')return typeof result?.bundlePath==='string';
|
|
177
68
|
if(label!=='build')return false;
|
|
178
|
-
return
|
|
69
|
+
return result?.artifact!=null||typeof result?.release?.outputRoot==='string';
|
|
179
70
|
}
|
|
180
71
|
|
|
181
72
|
async function ownedWork(label,work,{
|
|
@@ -247,7 +138,7 @@ async function ownedWork(label,work,{
|
|
|
247
138
|
onEvent:forwardEvent
|
|
248
139
|
},execute)
|
|
249
140
|
:await execute();
|
|
250
|
-
if(
|
|
141
|
+
if(hasCommittedOuterResult(label,result))committed=true;
|
|
251
142
|
stopProducers();
|
|
252
143
|
if(!committed||label==='run')throwIfAborted(controller.signal);
|
|
253
144
|
try{
|
|
@@ -276,33 +167,6 @@ async function ownedWork(label,work,{
|
|
|
276
167
|
}
|
|
277
168
|
}
|
|
278
169
|
|
|
279
|
-
async function collectTests(root,files,signal){
|
|
280
|
-
let entries;
|
|
281
|
-
try{
|
|
282
|
-
entries=await readdir(root,{withFileTypes:true});
|
|
283
|
-
}catch(error){
|
|
284
|
-
if(error?.code==='ENOENT'){
|
|
285
|
-
return;
|
|
286
|
-
}
|
|
287
|
-
throw error;
|
|
288
|
-
}
|
|
289
|
-
for(const entry of entries.sort((left,right)=>left.name.localeCompare(right.name,'en'))){
|
|
290
|
-
throwIfAborted(signal);
|
|
291
|
-
const absolute=path.join(root,entry.name);
|
|
292
|
-
if(entry.isSymbolicLink()){
|
|
293
|
-
continue;
|
|
294
|
-
}
|
|
295
|
-
if(entry.isDirectory()){
|
|
296
|
-
await collectTests(absolute,files,signal);
|
|
297
|
-
}else if(entry.isFile()&&/\.test\.(?:mjs|cjs|js)$/u.test(entry.name)){
|
|
298
|
-
const info=await lstat(absolute);
|
|
299
|
-
if(info.isFile()&&!info.isSymbolicLink()){
|
|
300
|
-
files.add(absolute);
|
|
301
|
-
}
|
|
302
|
-
}
|
|
303
|
-
}
|
|
304
|
-
}
|
|
305
|
-
|
|
306
170
|
async function selectedWorkspace(options){
|
|
307
171
|
const resolved=await resolveWorkspace({
|
|
308
172
|
workspaceRoot:options.workspaceRoot,
|
|
@@ -360,13 +224,12 @@ async function executeIntegratedSharedOperation(operation,options){
|
|
|
360
224
|
signal,
|
|
361
225
|
onEvent
|
|
362
226
|
});
|
|
363
|
-
return
|
|
227
|
+
return {
|
|
364
228
|
scope:'shared',
|
|
365
229
|
workspaceMode:'integrated',
|
|
366
230
|
workspaceRoot:profile.workspaceRoot,
|
|
367
|
-
providerGeneration:provider.providerGeneration,
|
|
368
231
|
result
|
|
369
|
-
}
|
|
232
|
+
};
|
|
370
233
|
},
|
|
371
234
|
options
|
|
372
235
|
);
|
|
@@ -386,7 +249,7 @@ async function preparedWorkspace(options){
|
|
|
386
249
|
||typeof workspace.sdkInstallation.browserRuntimeRoot!=='string')){
|
|
387
250
|
throw new ArcaneError(
|
|
388
251
|
ERROR_CODES.workspaceInvalid,
|
|
389
|
-
'Validated external workspace is missing its
|
|
252
|
+
'Validated external workspace is missing its SDK runtime directories.'
|
|
390
253
|
);
|
|
391
254
|
}
|
|
392
255
|
const runtimeRoot=external
|
|
@@ -395,39 +258,7 @@ async function preparedWorkspace(options){
|
|
|
395
258
|
const browserRuntimeRoot=external
|
|
396
259
|
?workspace.sdkInstallation.browserRuntimeRoot
|
|
397
260
|
:null;
|
|
398
|
-
const runtimeReceipt=external&&!options.deferRuntimeVerification
|
|
399
|
-
?await verifyRuntime({
|
|
400
|
-
runtimeRoot,
|
|
401
|
-
signal:options.signal,
|
|
402
|
-
onEvent:options.onEvent
|
|
403
|
-
})
|
|
404
|
-
:null;
|
|
405
|
-
const sdkBrowserRuntimeReceipt=external&&!options.deferRuntimeVerification
|
|
406
|
-
?await verifySdkBrowserRuntime({
|
|
407
|
-
browserRuntimeRoot,
|
|
408
|
-
signal:options.signal,
|
|
409
|
-
onEvent:options.onEvent
|
|
410
|
-
})
|
|
411
|
-
:null;
|
|
412
|
-
const workspaceRuntimeReceipt=external&&!options.deferRuntimeVerification
|
|
413
|
-
?await verifyWorkspaceRuntime({
|
|
414
|
-
workspaceRoot:workspace.workspaceRoot,
|
|
415
|
-
runtimeRoot,
|
|
416
|
-
runtimeReceipt,
|
|
417
|
-
browserRuntimeRoot,
|
|
418
|
-
sdkBrowserRuntimeReceipt,
|
|
419
|
-
signal:options.signal,
|
|
420
|
-
onEvent:options.onEvent
|
|
421
|
-
})
|
|
422
|
-
:null;
|
|
423
|
-
const runtimeVerificationState=external&&!options.deferRuntimeVerification
|
|
424
|
-
?Object.freeze({runtimeReceipt,sdkBrowserRuntimeReceipt,workspaceRuntimeReceipt})
|
|
425
|
-
:null;
|
|
426
261
|
return {
|
|
427
|
-
runtimeReceipt,
|
|
428
|
-
sdkBrowserRuntimeReceipt,
|
|
429
|
-
workspaceRuntimeReceipt,
|
|
430
|
-
runtimeVerificationState,
|
|
431
262
|
runtimeRoot,
|
|
432
263
|
browserRuntimeRoot,
|
|
433
264
|
workspaceMode:workspace.workspaceMode,
|
|
@@ -440,146 +271,14 @@ async function preparedWorkspace(options){
|
|
|
440
271
|
};
|
|
441
272
|
}
|
|
442
273
|
|
|
443
|
-
function forwardedRuntimeVerificationState(options,prepared){
|
|
444
|
-
return Object.hasOwn(options,'runtimeVerificationState')
|
|
445
|
-
?options.runtimeVerificationState
|
|
446
|
-
:prepared.runtimeVerificationState??undefined;
|
|
447
|
-
}
|
|
448
|
-
|
|
449
|
-
function compareRuntimeInventory(left,right){
|
|
450
|
-
return left.path.localeCompare(right.path,'en');
|
|
451
|
-
}
|
|
452
|
-
|
|
453
|
-
async function externalRuntimeSnapshotReceipt(prepared,sharedPayloadSnapshot,sharedPayloadIds,{signal,onEvent}={}){
|
|
454
|
-
throwIfAborted(signal);
|
|
455
|
-
await authenticateSharedPayloadSnapshot(sharedPayloadSnapshot,{
|
|
456
|
-
workspaceRoot:prepared.workspaceRoot,
|
|
457
|
-
sharedPayloadIds,
|
|
458
|
-
signal
|
|
459
|
-
});
|
|
460
|
-
const runtimeReceipt=await verifyRuntime({
|
|
461
|
-
runtimeRoot:prepared.runtimeRoot,
|
|
462
|
-
signal,
|
|
463
|
-
onEvent
|
|
464
|
-
});
|
|
465
|
-
const sdkBrowserRuntimeReceipt=await verifySdkBrowserRuntime({
|
|
466
|
-
browserRuntimeRoot:prepared.browserRuntimeRoot,
|
|
467
|
-
signal,
|
|
468
|
-
onEvent
|
|
469
|
-
});
|
|
470
|
-
const workspaceRuntimeReceipt=await verifyWorkspaceRuntime({
|
|
471
|
-
workspaceRoot:prepared.workspaceRoot,
|
|
472
|
-
runtimeRoot:prepared.runtimeRoot,
|
|
473
|
-
runtimeReceipt,
|
|
474
|
-
browserRuntimeRoot:prepared.browserRuntimeRoot,
|
|
475
|
-
sdkBrowserRuntimeReceipt,
|
|
476
|
-
signal,
|
|
477
|
-
onEvent
|
|
478
|
-
});
|
|
479
|
-
const retained=sharedPayloadSnapshot.files
|
|
480
|
-
.filter(file=>file.source.startsWith('arcane/'))
|
|
481
|
-
.map(file=>Object.freeze({
|
|
482
|
-
path:file.source.slice('arcane/'.length),
|
|
483
|
-
bytes:file.bytes,
|
|
484
|
-
sha256:file.sha256
|
|
485
|
-
}))
|
|
486
|
-
.sort(compareRuntimeInventory);
|
|
487
|
-
const upstreamFiles=runtimeReceipt.files.map(file=>Object.freeze({
|
|
488
|
-
path:file.path.startsWith('arcane/')
|
|
489
|
-
?file.path.slice('arcane/'.length)
|
|
490
|
-
:`dependencies/strong-type/${file.path.slice('strong-type/'.length)}`,
|
|
491
|
-
sourcePath:file.path,
|
|
492
|
-
bytes:file.bytes,
|
|
493
|
-
sha256:file.sha256
|
|
494
|
-
})).sort(compareRuntimeInventory);
|
|
495
|
-
const sdkFiles=sdkBrowserRuntimeReceipt.files.map(file=>Object.freeze({
|
|
496
|
-
path:`sdk/${file.path}`,
|
|
497
|
-
sourcePath:file.path,
|
|
498
|
-
bytes:file.bytes,
|
|
499
|
-
sha256:file.sha256
|
|
500
|
-
})).sort(compareRuntimeInventory);
|
|
501
|
-
const expected=[...upstreamFiles,...sdkFiles]
|
|
502
|
-
.map(file=>Object.freeze({path:file.path,bytes:file.bytes,sha256:file.sha256}))
|
|
503
|
-
.sort(compareRuntimeInventory);
|
|
504
|
-
if(JSON.stringify(retained)!==JSON.stringify(expected)){
|
|
505
|
-
throw new ArcaneError(
|
|
506
|
-
ERROR_CODES.integrityFailed,
|
|
507
|
-
'The retained shared payload does not match the composed Arcane and SDK browser runtime receipts.'
|
|
508
|
-
);
|
|
509
|
-
}
|
|
510
|
-
const receipt=Object.freeze({
|
|
511
|
-
schemaVersion:1,
|
|
512
|
-
kind:'arcane-sdk-runtime-shared-payload',
|
|
513
|
-
canonicalLocation:prepared.runtimeRoot,
|
|
514
|
-
source:Object.freeze({...runtimeReceipt.source}),
|
|
515
|
-
sources:Object.freeze({
|
|
516
|
-
arcane:Object.freeze({
|
|
517
|
-
manifestSha256:runtimeReceipt.manifestSha256,
|
|
518
|
-
contentSha256:runtimeReceipt.contentSha256,
|
|
519
|
-
source:runtimeReceipt.source
|
|
520
|
-
}),
|
|
521
|
-
sdkBrowser:Object.freeze({
|
|
522
|
-
manifestSha256:sdkBrowserRuntimeReceipt.manifestSha256,
|
|
523
|
-
contentSha256:sdkBrowserRuntimeReceipt.contentSha256,
|
|
524
|
-
source:sdkBrowserRuntimeReceipt.source
|
|
525
|
-
})
|
|
526
|
-
}),
|
|
527
|
-
files:Object.freeze(runtimeReceipt.files.map(file=>Object.freeze({...file}))),
|
|
528
|
-
fileCount:runtimeReceipt.fileCount,
|
|
529
|
-
totalBytes:runtimeReceipt.totalBytes,
|
|
530
|
-
contentSha256:runtimeReceipt.contentSha256,
|
|
531
|
-
browserFiles:Object.freeze(sdkBrowserRuntimeReceipt.files.map(
|
|
532
|
-
file=>Object.freeze({...file})
|
|
533
|
-
)),
|
|
534
|
-
browserFileCount:sdkBrowserRuntimeReceipt.fileCount,
|
|
535
|
-
browserTotalBytes:sdkBrowserRuntimeReceipt.totalBytes,
|
|
536
|
-
browserContentSha256:sdkBrowserRuntimeReceipt.contentSha256,
|
|
537
|
-
sharedFiles:Object.freeze(retained),
|
|
538
|
-
sharedFileCount:retained.length,
|
|
539
|
-
sharedTotalBytes:retained.reduce((total,file)=>total+file.bytes,0),
|
|
540
|
-
sharedPayloadContentSha256:sharedPayloadSnapshot.contentSha256
|
|
541
|
-
});
|
|
542
|
-
await emit(onEvent,{
|
|
543
|
-
type:'runtime.snapshot.verified',
|
|
544
|
-
contentSha256:receipt.contentSha256,
|
|
545
|
-
fileCount:receipt.fileCount,
|
|
546
|
-
totalBytes:receipt.totalBytes,
|
|
547
|
-
browserContentSha256:receipt.browserContentSha256,
|
|
548
|
-
browserFileCount:receipt.browserFileCount,
|
|
549
|
-
browserTotalBytes:receipt.browserTotalBytes
|
|
550
|
-
});
|
|
551
|
-
return Object.freeze({
|
|
552
|
-
receipt,
|
|
553
|
-
runtimeVerificationState:Object.freeze({
|
|
554
|
-
runtimeReceipt,
|
|
555
|
-
sdkBrowserRuntimeReceipt,
|
|
556
|
-
workspaceRuntimeReceipt
|
|
557
|
-
})
|
|
558
|
-
});
|
|
559
|
-
}
|
|
560
|
-
|
|
561
274
|
async function validatePreparedRuntime(prepared,{signal}={}){
|
|
562
|
-
if(prepared.workspaceMode==='external'){
|
|
563
|
-
await authenticateRuntimeReceipt(prepared.runtimeReceipt,{
|
|
564
|
-
runtimeRoot:prepared.runtimeRoot,
|
|
565
|
-
signal
|
|
566
|
-
});
|
|
567
|
-
await authenticateSdkBrowserRuntimeReceipt(prepared.sdkBrowserRuntimeReceipt,{
|
|
568
|
-
browserRuntimeRoot:prepared.browserRuntimeRoot,
|
|
569
|
-
signal
|
|
570
|
-
});
|
|
571
|
-
return authenticateWorkspaceRuntimeReceipt(prepared.workspaceRuntimeReceipt,{
|
|
572
|
-
workspaceRoot:prepared.workspaceRoot,
|
|
573
|
-
signal
|
|
574
|
-
});
|
|
575
|
-
}
|
|
576
275
|
const validation=await validateWorkspace({
|
|
577
276
|
workspaceRoot:prepared.workspaceRoot,
|
|
578
277
|
appId:prepared.appId,
|
|
579
278
|
signal
|
|
580
279
|
});
|
|
581
|
-
if(validation.workspaceMode!==
|
|
582
|
-
throw new ArcaneError(ERROR_CODES.workspaceInvalid,'The
|
|
280
|
+
if(validation.workspaceMode!==prepared.workspaceMode){
|
|
281
|
+
throw new ArcaneError(ERROR_CODES.workspaceInvalid,'The Arcane workspace profile changed during the operation.');
|
|
583
282
|
}
|
|
584
283
|
return validation;
|
|
585
284
|
}
|
|
@@ -587,21 +286,37 @@ async function validatePreparedRuntime(prepared,{signal}={}){
|
|
|
587
286
|
async function refreshPreparedImportMap(prepared,{signal,onEvent,workspaceOperationLease}={}){
|
|
588
287
|
if(prepared.workspaceMode==='integrated'
|
|
589
288
|
&&prepared.validation.config.browserRuntimeLayout==='integrated-legacy'){
|
|
590
|
-
const
|
|
289
|
+
const result={
|
|
591
290
|
appId:prepared.appId,
|
|
592
291
|
skipped:true,
|
|
593
292
|
compatibility:'integrated-legacy',
|
|
594
293
|
reason:'The canonical integrated Arcane OS root retains its physical two-route browser runtime.'
|
|
595
|
-
}
|
|
596
|
-
await emit(onEvent,{type:'import-map.compatibility.skipped',...
|
|
597
|
-
return
|
|
294
|
+
};
|
|
295
|
+
await emit(onEvent,{type:'import-map.compatibility.skipped',...result});
|
|
296
|
+
return result;
|
|
297
|
+
}
|
|
298
|
+
const manifest=prepared.validation.app.manifest;
|
|
299
|
+
const inspected=await inspectPackagedApp({
|
|
300
|
+
workspaceRoot:prepared.workspaceRoot,
|
|
301
|
+
appId:prepared.appId,
|
|
302
|
+
signal
|
|
303
|
+
});
|
|
304
|
+
if(inspected.entry!==manifest.entry
|
|
305
|
+
||JSON.stringify(inspected.include)!==JSON.stringify(manifest.include)
|
|
306
|
+
||JSON.stringify(inspected.exclude)!==JSON.stringify(manifest.exclude)){
|
|
307
|
+
throw new ArcaneError(
|
|
308
|
+
ERROR_CODES.workspaceInvalid,
|
|
309
|
+
'The selected application package descriptor changed before import-map refresh.'
|
|
310
|
+
);
|
|
598
311
|
}
|
|
599
312
|
return generateImportMap({
|
|
600
313
|
workspaceRoot:prepared.workspaceRoot,
|
|
601
314
|
appId:prepared.appId,
|
|
602
315
|
appRoot:prepared.appRoot,
|
|
603
|
-
entry:
|
|
604
|
-
|
|
316
|
+
entry:manifest.entry,
|
|
317
|
+
documents:inspected.browserDocuments.map(function selectBrowserDocumentPath(document){
|
|
318
|
+
return document.path;
|
|
319
|
+
}),
|
|
605
320
|
workspaceOperationLease,
|
|
606
321
|
signal,
|
|
607
322
|
onEvent
|
|
@@ -633,6 +348,33 @@ export async function initializeApplication(options={}){
|
|
|
633
348
|
return initWorkspace(options);
|
|
634
349
|
}
|
|
635
350
|
|
|
351
|
+
export async function upgradeApplication(options={}){
|
|
352
|
+
assertApplicationScope(options,'Workspace upgrade');
|
|
353
|
+
const selected=await resolveWorkspace({
|
|
354
|
+
workspaceRoot:options.workspaceRoot,
|
|
355
|
+
appId:options.appId
|
|
356
|
+
});
|
|
357
|
+
if(selected.config.workspaceMode!=='external'){
|
|
358
|
+
throw new ArcaneError(
|
|
359
|
+
ERROR_CODES.policyDenied,
|
|
360
|
+
'Workspace upgrade is available only to installed-SDK external workspaces.'
|
|
361
|
+
);
|
|
362
|
+
}
|
|
363
|
+
const result=await runProcess('npm',['upgrade'],{
|
|
364
|
+
cwd:selected.workspaceRoot,
|
|
365
|
+
signal:options.signal,
|
|
366
|
+
onEvent:options.onEvent
|
|
367
|
+
});
|
|
368
|
+
return {
|
|
369
|
+
schemaVersion:1,
|
|
370
|
+
kind:'arcane-application-upgrade',
|
|
371
|
+
workspaceRoot:selected.workspaceRoot,
|
|
372
|
+
workspaceMode:selected.config.workspaceMode,
|
|
373
|
+
appId:selected.appId,
|
|
374
|
+
...result
|
|
375
|
+
};
|
|
376
|
+
}
|
|
377
|
+
|
|
636
378
|
export async function doctorApplication(options={}){
|
|
637
379
|
const result=await runDoctor(options);
|
|
638
380
|
if(!result.ok){
|
|
@@ -645,6 +387,18 @@ export async function doctorApplication(options={}){
|
|
|
645
387
|
return result;
|
|
646
388
|
}
|
|
647
389
|
|
|
390
|
+
async function runPreparedApplicationTests(prepared,options={}){
|
|
391
|
+
throwIfAborted(options.signal);
|
|
392
|
+
return runApplicationTests({
|
|
393
|
+
workspaceRoot:prepared.workspaceRoot,
|
|
394
|
+
workspaceMode:prepared.workspaceMode,
|
|
395
|
+
appId:prepared.appId,
|
|
396
|
+
appRoot:prepared.appRoot,
|
|
397
|
+
signal:options.signal,
|
|
398
|
+
onEvent:options.onEvent
|
|
399
|
+
});
|
|
400
|
+
}
|
|
401
|
+
|
|
648
402
|
export async function testApplication(options={}){
|
|
649
403
|
throwIfAborted(options.signal);
|
|
650
404
|
if(operationScope(options)==='shared'){
|
|
@@ -656,96 +410,8 @@ export async function testApplication(options={}){
|
|
|
656
410
|
}
|
|
657
411
|
return executeIntegratedSharedOperation('focused-test',options);
|
|
658
412
|
}
|
|
659
|
-
const
|
|
660
|
-
|
|
661
|
-
workspaceRoot:options.workspaceRoot,
|
|
662
|
-
workspaceMode:options.workspaceMode
|
|
663
|
-
??(await inspectWorkspaceProfile(options.workspaceRoot)).workspaceMode,
|
|
664
|
-
appId:options.appId,
|
|
665
|
-
appRoot:options.appRoot
|
|
666
|
-
}
|
|
667
|
-
:await selectedWorkspace(options);
|
|
668
|
-
const files=new Set();
|
|
669
|
-
if(workspace.workspaceMode==='external'){
|
|
670
|
-
await collectTests(path.join(workspace.workspaceRoot,'test'),files,options.signal);
|
|
671
|
-
}
|
|
672
|
-
if(workspace.appRoot){
|
|
673
|
-
await collectTests(path.join(workspace.appRoot,'test'),files,options.signal);
|
|
674
|
-
}
|
|
675
|
-
const testFiles=[...files].sort();
|
|
676
|
-
if(testFiles.length===0){
|
|
677
|
-
await emit(options.onEvent,{
|
|
678
|
-
type:'test.skipped',
|
|
679
|
-
message:'No JavaScript test files were found.',
|
|
680
|
-
data:{workspaceRoot:workspace.workspaceRoot,appId:workspace.appId}
|
|
681
|
-
});
|
|
682
|
-
return {...workspace,passed:true,skipped:true,testFiles:[]};
|
|
683
|
-
}
|
|
684
|
-
const outputs=[];
|
|
685
|
-
const failures=[];
|
|
686
|
-
let failureOutputBytes=0;
|
|
687
|
-
const perFileFailureOutputBytes=Math.min(
|
|
688
|
-
MAX_TEST_FAILURE_STREAM_BYTES*2,
|
|
689
|
-
Math.floor(MAX_TEST_FAILURE_AGGREGATE_BYTES/testFiles.length)
|
|
690
|
-
);
|
|
691
|
-
for(const testFile of testFiles){
|
|
692
|
-
throwIfAborted(options.signal);
|
|
693
|
-
const result=await runProcess(
|
|
694
|
-
process.execPath,
|
|
695
|
-
[TEST_RUNNER_PATH,testFile],
|
|
696
|
-
{
|
|
697
|
-
cwd:workspace.workspaceRoot,
|
|
698
|
-
signal:options.signal,
|
|
699
|
-
onEvent:options.onEvent,
|
|
700
|
-
allowNonzero:true
|
|
701
|
-
}
|
|
702
|
-
);
|
|
703
|
-
if(result.code===0){
|
|
704
|
-
if(result.stdout.trim())outputs.push(result.stdout.trim());
|
|
705
|
-
}else if(result.code===1){
|
|
706
|
-
const captured=captureFailedTest(
|
|
707
|
-
testFile,
|
|
708
|
-
result,
|
|
709
|
-
workspace.workspaceRoot,
|
|
710
|
-
Math.min(
|
|
711
|
-
perFileFailureOutputBytes,
|
|
712
|
-
MAX_TEST_FAILURE_AGGREGATE_BYTES-failureOutputBytes
|
|
713
|
-
)
|
|
714
|
-
);
|
|
715
|
-
failures.push(captured.failure);
|
|
716
|
-
failureOutputBytes+=captured.bytes;
|
|
717
|
-
}else if(result.code!==0){
|
|
718
|
-
throw new ArcaneError(
|
|
719
|
-
ERROR_CODES.operationFailed,
|
|
720
|
-
`The isolated test runner exited with code ${String(result.code)} for ${path.basename(testFile)}.`,
|
|
721
|
-
{details:{testFile,result}}
|
|
722
|
-
);
|
|
723
|
-
}
|
|
724
|
-
}
|
|
725
|
-
if(failures.length>0){
|
|
726
|
-
throw new ArcaneError(
|
|
727
|
-
ERROR_CODES.operationFailed,
|
|
728
|
-
failedTestMessage(failures),
|
|
729
|
-
{
|
|
730
|
-
details:{
|
|
731
|
-
testFiles:failures.map(failure=>failure.testFile),
|
|
732
|
-
failures,
|
|
733
|
-
outputBytes:failureOutputBytes,
|
|
734
|
-
outputLimitBytes:MAX_TEST_FAILURE_AGGREGATE_BYTES,
|
|
735
|
-
outputTruncated:failures.some(
|
|
736
|
-
failure=>failure.stdoutTruncated||failure.stderrTruncated
|
|
737
|
-
)
|
|
738
|
-
}
|
|
739
|
-
}
|
|
740
|
-
);
|
|
741
|
-
}
|
|
742
|
-
return {
|
|
743
|
-
...workspace,
|
|
744
|
-
passed:true,
|
|
745
|
-
skipped:false,
|
|
746
|
-
testFiles:testFiles.map(file=>path.relative(workspace.workspaceRoot,file).replaceAll('\\','/')),
|
|
747
|
-
output:outputs.join('\n')
|
|
748
|
-
};
|
|
413
|
+
const prepared=await preparedWorkspace({...options,allowMissingManagedImportMap:true});
|
|
414
|
+
return runPreparedApplicationTests(prepared,options);
|
|
749
415
|
}
|
|
750
416
|
|
|
751
417
|
export async function checkApplication(options={}){
|
|
@@ -755,10 +421,15 @@ export async function checkApplication(options={}){
|
|
|
755
421
|
}
|
|
756
422
|
return executeIntegratedSharedOperation('development-check',options);
|
|
757
423
|
}
|
|
758
|
-
const prepared=await preparedWorkspace(options);
|
|
424
|
+
const prepared=await preparedWorkspace({...options,allowMissingManagedImportMap:true});
|
|
759
425
|
const tests=options.skipTests
|
|
760
|
-
?{
|
|
761
|
-
|
|
426
|
+
?{
|
|
427
|
+
passed:true,
|
|
428
|
+
skipped:true,
|
|
429
|
+
testFiles:[],
|
|
430
|
+
output:''
|
|
431
|
+
}
|
|
432
|
+
:await runPreparedApplicationTests(prepared,options);
|
|
762
433
|
await validatePreparedRuntime(prepared,{signal:options.signal});
|
|
763
434
|
return {
|
|
764
435
|
ok:true,
|
|
@@ -766,17 +437,10 @@ export async function checkApplication(options={}){
|
|
|
766
437
|
workspaceRoot:prepared.workspaceRoot,
|
|
767
438
|
appId:prepared.appId,
|
|
768
439
|
descriptorSource:prepared.descriptorSource,
|
|
769
|
-
runtime:
|
|
770
|
-
?
|
|
771
|
-
|
|
772
|
-
|
|
773
|
-
contentSha256:prepared.runtimeReceipt.contentSha256,
|
|
774
|
-
fileCount:prepared.runtimeReceipt.fileCount
|
|
775
|
-
}
|
|
776
|
-
:{
|
|
777
|
-
mode:'workspace',
|
|
778
|
-
sourceRoot:'arcane'
|
|
779
|
-
},
|
|
440
|
+
runtime:{
|
|
441
|
+
mode:prepared.workspaceMode==='external'?'sdk':'workspace',
|
|
442
|
+
sourceRoot:'arcane'
|
|
443
|
+
},
|
|
780
444
|
checks:prepared.validation.checks,
|
|
781
445
|
tests
|
|
782
446
|
};
|
|
@@ -798,7 +462,6 @@ export async function developApplication(options={}){
|
|
|
798
462
|
workspaceRoot:prepared.workspaceRoot,
|
|
799
463
|
appId:prepared.appId,
|
|
800
464
|
mode:'source',
|
|
801
|
-
workspaceRuntimeReceipt:prepared.workspaceRuntimeReceipt,
|
|
802
465
|
workspaceMode:prepared.workspaceMode,
|
|
803
466
|
...(options.sdkRuntimeSourceRoot===undefined?{}:{
|
|
804
467
|
sdkRuntimeSourceRoot:options.sdkRuntimeSourceRoot
|
|
@@ -819,23 +482,22 @@ export async function packageApplication(options={}){
|
|
|
819
482
|
});
|
|
820
483
|
const release=await ownedWork(
|
|
821
484
|
'package',
|
|
822
|
-
({signal,onEvent,workspaceOperationLease})=>
|
|
485
|
+
async({signal,onEvent,workspaceOperationLease})=>{
|
|
486
|
+
return packageApp({
|
|
823
487
|
workspaceRoot:prepared.workspaceRoot,
|
|
824
488
|
appId:prepared.appId,
|
|
825
489
|
dryRun:Boolean(options.dryRun),
|
|
826
490
|
signal,
|
|
827
491
|
onEvent,
|
|
828
|
-
workspaceOperationLease
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
}),
|
|
492
|
+
workspaceOperationLease
|
|
493
|
+
});
|
|
494
|
+
},
|
|
832
495
|
{...options,workspaceRoot:prepared.workspaceRoot}
|
|
833
496
|
);
|
|
834
497
|
return {
|
|
835
498
|
workspaceRoot:prepared.workspaceRoot,
|
|
836
499
|
workspaceMode:prepared.workspaceMode,
|
|
837
500
|
appId:prepared.appId,
|
|
838
|
-
runtimeContentSha256:prepared.runtimeReceipt?.contentSha256??null,
|
|
839
501
|
release
|
|
840
502
|
};
|
|
841
503
|
}
|
|
@@ -848,7 +510,6 @@ export async function verifyApplication(options={}){
|
|
|
848
510
|
({signal,onEvent})=>verifyApp({
|
|
849
511
|
workspaceRoot:prepared.workspaceRoot,
|
|
850
512
|
appId:prepared.appId,
|
|
851
|
-
runtimeVerificationState:forwardedRuntimeVerificationState(options,prepared),
|
|
852
513
|
signal,
|
|
853
514
|
onEvent
|
|
854
515
|
}),
|
|
@@ -859,7 +520,6 @@ export async function verifyApplication(options={}){
|
|
|
859
520
|
workspaceRoot:prepared.workspaceRoot,
|
|
860
521
|
workspaceMode:prepared.workspaceMode,
|
|
861
522
|
appId:prepared.appId,
|
|
862
|
-
runtimeContentSha256:prepared.runtimeReceipt?.contentSha256??null,
|
|
863
523
|
release
|
|
864
524
|
};
|
|
865
525
|
}
|
|
@@ -876,19 +536,18 @@ export async function bundleApplication(options={}){
|
|
|
876
536
|
const verified=await verifyApp({
|
|
877
537
|
workspaceRoot:prepared.workspaceRoot,
|
|
878
538
|
appId:prepared.appId,
|
|
879
|
-
runtimeVerificationState:forwardedRuntimeVerificationState(options,prepared),
|
|
880
539
|
signal,
|
|
881
540
|
onEvent
|
|
882
541
|
});
|
|
883
542
|
await validatePreparedRuntime(prepared,{signal});
|
|
884
|
-
const releaseRoot=verified.
|
|
543
|
+
const releaseRoot=verified.outputRoot;
|
|
885
544
|
const outputPath=options.artifactPath??path.join(
|
|
886
545
|
path.dirname(releaseRoot),
|
|
887
546
|
`${prepared.appId}-${verified.version}${APP_BUNDLE_EXTENSION}`
|
|
888
547
|
);
|
|
889
548
|
return createAppReleaseBundle({
|
|
890
|
-
receipt:verified.receipt,
|
|
891
549
|
releaseRoot,
|
|
550
|
+
appDescriptor:prepared.descriptor,
|
|
892
551
|
outputPath,
|
|
893
552
|
overwrite:options.overwrite,
|
|
894
553
|
signal,
|
|
@@ -901,7 +560,6 @@ export async function bundleApplication(options={}){
|
|
|
901
560
|
workspaceRoot:prepared.workspaceRoot,
|
|
902
561
|
workspaceMode:prepared.workspaceMode,
|
|
903
562
|
appId:prepared.appId,
|
|
904
|
-
runtimeContentSha256:prepared.runtimeReceipt?.contentSha256??null,
|
|
905
563
|
bundle
|
|
906
564
|
};
|
|
907
565
|
}
|
|
@@ -1059,19 +717,6 @@ export function assertIntegratedPortableToolchain(options={}){
|
|
|
1059
717
|
return assertIntegratedNativeToolchain({...options,target:'portable'});
|
|
1060
718
|
}
|
|
1061
719
|
|
|
1062
|
-
export function assertNativeApplicationToolchainCompatibility({prepared,toolchainReceipt}={}){
|
|
1063
|
-
return assertNativeToolchainCompatibility({
|
|
1064
|
-
appDescriptor:prepared?.descriptor,
|
|
1065
|
-
toolchainReceipt,
|
|
1066
|
-
minimumCoreVersion:prepared?.runtimeReceipt?.source?.bundleVersion
|
|
1067
|
-
??ARCANE_MACHINE_BUNDLE_VERSION
|
|
1068
|
-
});
|
|
1069
|
-
}
|
|
1070
|
-
|
|
1071
|
-
export function assertPortableToolchainCompatibility(options={}){
|
|
1072
|
-
return assertNativeApplicationToolchainCompatibility(options);
|
|
1073
|
-
}
|
|
1074
|
-
|
|
1075
720
|
export async function verifyNativeArtifact(options={}){
|
|
1076
721
|
const {target,adapter}=targetSelection(options);
|
|
1077
722
|
const targetDescription=await adapter.describe();
|
|
@@ -1106,7 +751,7 @@ async function nativeDependencyClosure(prepared,{target,signal,onEvent}={}){
|
|
|
1106
751
|
if(JSON.stringify(selected.descriptor)!==JSON.stringify(prepared.descriptor)){
|
|
1107
752
|
nativeDependencyError(
|
|
1108
753
|
`The selected app ${prepared.appId} descriptor changed during native build preflight.`,
|
|
1109
|
-
ERROR_CODES.
|
|
754
|
+
ERROR_CODES.workspaceInvalid
|
|
1110
755
|
);
|
|
1111
756
|
}
|
|
1112
757
|
if(!prepared.descriptor.targets.includes(target)){
|
|
@@ -1118,7 +763,6 @@ async function nativeDependencyClosure(prepared,{target,signal,onEvent}={}){
|
|
|
1118
763
|
|
|
1119
764
|
const visiting=new Set([prepared.appId]);
|
|
1120
765
|
const visited=new Set();
|
|
1121
|
-
const discovered=new Set();
|
|
1122
766
|
const dependencies=[];
|
|
1123
767
|
function visit(descriptor){
|
|
1124
768
|
for(const dependencyId of descriptor.native.bundledApps){
|
|
@@ -1138,10 +782,6 @@ async function nativeDependencyClosure(prepared,{target,signal,onEvent}={}){
|
|
|
1138
782
|
ERROR_CODES.targetUnavailable
|
|
1139
783
|
);
|
|
1140
784
|
}
|
|
1141
|
-
if(discovered.size>=64){
|
|
1142
|
-
nativeDependencyError('A native app dependency closure may contain at most 64 apps.');
|
|
1143
|
-
}
|
|
1144
|
-
discovered.add(dependencyId);
|
|
1145
785
|
visiting.add(dependencyId);
|
|
1146
786
|
visit(dependency.descriptor);
|
|
1147
787
|
visiting.delete(dependencyId);
|
|
@@ -1162,13 +802,13 @@ async function nativeDependencyClosure(prepared,{target,signal,onEvent}={}){
|
|
|
1162
802
|
signal,
|
|
1163
803
|
onEvent
|
|
1164
804
|
});
|
|
1165
|
-
validated.push(
|
|
805
|
+
validated.push({
|
|
1166
806
|
...dependency,
|
|
1167
807
|
descriptor:validation.app.descriptor,
|
|
1168
808
|
validation
|
|
1169
|
-
})
|
|
809
|
+
});
|
|
1170
810
|
}
|
|
1171
|
-
return
|
|
811
|
+
return validated;
|
|
1172
812
|
}
|
|
1173
813
|
|
|
1174
814
|
async function externalWorkspaceProtectedRoots(prepared,{signal}={}){
|
|
@@ -1222,45 +862,28 @@ function pathsOverlap(left,right){
|
|
|
1222
862
|
}
|
|
1223
863
|
|
|
1224
864
|
async function packageNativeRelease(prepared,app,{
|
|
1225
|
-
sharedPayloadSnapshot,
|
|
1226
865
|
workspaceOperationLease,
|
|
1227
866
|
signal,
|
|
1228
867
|
onEvent
|
|
1229
868
|
}={}){
|
|
1230
|
-
const sourceState={
|
|
1231
|
-
...prepared,
|
|
1232
|
-
appId:app.appId,
|
|
1233
|
-
appRoot:app.appRoot,
|
|
1234
|
-
descriptor:app.descriptor,
|
|
1235
|
-
validation:app.validation??prepared.validation
|
|
1236
|
-
};
|
|
1237
869
|
const release=await packageApp({
|
|
1238
870
|
workspaceRoot:prepared.workspaceRoot,
|
|
1239
871
|
appId:app.appId,
|
|
1240
|
-
sharedPayloadSnapshot,
|
|
1241
|
-
runtimeVerificationState:prepared.runtimeVerificationState??undefined,
|
|
1242
872
|
workspaceOperationLease,
|
|
1243
873
|
signal,
|
|
1244
|
-
onEvent
|
|
1245
|
-
validateSourceState:({signal:validationSignal}={})=>validateDiscoveredApplication({
|
|
1246
|
-
workspaceRoot:sourceState.workspaceRoot,
|
|
1247
|
-
workspaceMode:sourceState.workspaceMode,
|
|
1248
|
-
workspaceConfig:prepared.validation.config,
|
|
1249
|
-
app,
|
|
1250
|
-
signal:validationSignal
|
|
1251
|
-
})
|
|
874
|
+
onEvent
|
|
1252
875
|
});
|
|
1253
|
-
return
|
|
876
|
+
return {
|
|
1254
877
|
appId:app.appId,
|
|
1255
878
|
appRoot:app.appRoot,
|
|
1256
879
|
descriptor:app.descriptor,
|
|
1257
880
|
release,
|
|
1258
|
-
nativeInput:
|
|
881
|
+
nativeInput:{
|
|
1259
882
|
appDescriptor:app.descriptor,
|
|
1260
|
-
appReleaseRoot:path.resolve(prepared.workspaceRoot,release.output),
|
|
1261
|
-
|
|
1262
|
-
}
|
|
1263
|
-
}
|
|
883
|
+
appReleaseRoot:release.outputRoot??path.resolve(prepared.workspaceRoot,release.output),
|
|
884
|
+
release:{manifest:release.manifest,files:[...release.files]}
|
|
885
|
+
}
|
|
886
|
+
};
|
|
1264
887
|
}
|
|
1265
888
|
|
|
1266
889
|
async function executePairedNativeBuild(options,adapter,{
|
|
@@ -1269,12 +892,7 @@ async function executePairedNativeBuild(options,adapter,{
|
|
|
1269
892
|
workspaceOperationLease
|
|
1270
893
|
}={}){
|
|
1271
894
|
const target=options.target??options.targetRequest?.target;
|
|
1272
|
-
const initialPrepared=await preparedWorkspace({
|
|
1273
|
-
...options,
|
|
1274
|
-
deferRuntimeVerification:true,
|
|
1275
|
-
signal,
|
|
1276
|
-
onEvent
|
|
1277
|
-
});
|
|
895
|
+
const initialPrepared=await preparedWorkspace({...options,signal,onEvent});
|
|
1278
896
|
assertIntegratedNativeToolchain({
|
|
1279
897
|
target,
|
|
1280
898
|
workspaceMode:initialPrepared.workspaceMode,
|
|
@@ -1284,7 +902,7 @@ async function executePairedNativeBuild(options,adapter,{
|
|
|
1284
902
|
if(options.dryRun){
|
|
1285
903
|
throw new ArcaneError(
|
|
1286
904
|
ERROR_CODES.usage,
|
|
1287
|
-
`${target} native build does not support --dry-run because
|
|
905
|
+
`${target} native build does not support --dry-run because the native provider needs materialized app files.`
|
|
1288
906
|
);
|
|
1289
907
|
}
|
|
1290
908
|
const requestedOutputRoot=resolveNativeBuildOutputRoot({
|
|
@@ -1302,31 +920,7 @@ async function executePairedNativeBuild(options,adapter,{
|
|
|
1302
920
|
);
|
|
1303
921
|
}
|
|
1304
922
|
const dependencyApps=await nativeDependencyClosure(initialPrepared,{target,signal,onEvent});
|
|
1305
|
-
const
|
|
1306
|
-
...initialPrepared.validation.app.manifest.shared,
|
|
1307
|
-
...dependencyApps.flatMap(app=>app.manifest.shared)
|
|
1308
|
-
])].sort((left,right)=>left.localeCompare(right,'en'));
|
|
1309
|
-
const sharedPayloadSnapshot=await prepareSharedPayloadSnapshot({
|
|
1310
|
-
workspaceRoot:initialPrepared.workspaceRoot,
|
|
1311
|
-
sharedPayloadIds,
|
|
1312
|
-
signal,
|
|
1313
|
-
onEvent
|
|
1314
|
-
});
|
|
1315
|
-
const externalRuntimeState=initialPrepared.workspaceMode==='external'
|
|
1316
|
-
?await externalRuntimeSnapshotReceipt(
|
|
1317
|
-
initialPrepared,
|
|
1318
|
-
sharedPayloadSnapshot,
|
|
1319
|
-
sharedPayloadIds,
|
|
1320
|
-
{signal,onEvent}
|
|
1321
|
-
)
|
|
1322
|
-
:null;
|
|
1323
|
-
const prepared={
|
|
1324
|
-
...initialPrepared,
|
|
1325
|
-
runtimeReceipt:externalRuntimeState?.receipt??null,
|
|
1326
|
-
runtimeVerificationState:externalRuntimeState?.runtimeVerificationState??null,
|
|
1327
|
-
workspaceRuntimeReceipt:
|
|
1328
|
-
externalRuntimeState?.runtimeVerificationState.workspaceRuntimeReceipt??null
|
|
1329
|
-
};
|
|
923
|
+
const prepared=initialPrepared;
|
|
1330
924
|
const selectedRelease=await packageNativeRelease(prepared,{
|
|
1331
925
|
appId:prepared.appId,
|
|
1332
926
|
appRoot:prepared.appRoot,
|
|
@@ -1335,16 +929,16 @@ async function executePairedNativeBuild(options,adapter,{
|
|
|
1335
929
|
descriptorSource:prepared.validation.app.descriptorSource,
|
|
1336
930
|
descriptorPath:prepared.validation.app.descriptorPath,
|
|
1337
931
|
validation:prepared.validation
|
|
1338
|
-
},{
|
|
932
|
+
},{workspaceOperationLease,signal,onEvent});
|
|
1339
933
|
const dependencyReleases=[];
|
|
1340
934
|
for(const dependency of dependencyApps){
|
|
1341
935
|
dependencyReleases.push(await packageNativeRelease(
|
|
1342
936
|
prepared,
|
|
1343
937
|
dependency,
|
|
1344
|
-
{
|
|
938
|
+
{workspaceOperationLease,signal,onEvent}
|
|
1345
939
|
));
|
|
1346
940
|
}
|
|
1347
|
-
const
|
|
941
|
+
const toolchain=await adapter.prepare({
|
|
1348
942
|
toolchainRoot:options.toolchainRoot,
|
|
1349
943
|
targetRequest:options.targetRequest,
|
|
1350
944
|
signal,
|
|
@@ -1354,26 +948,24 @@ async function executePairedNativeBuild(options,adapter,{
|
|
|
1354
948
|
const built=await adapter.build({
|
|
1355
949
|
nativeBuilder:options.nativeBuilder,
|
|
1356
950
|
toolchainRoot:options.toolchainRoot,
|
|
1357
|
-
|
|
951
|
+
toolchain,
|
|
1358
952
|
...selectedRelease.nativeInput,
|
|
1359
953
|
dependencyReleases:dependencyReleases.map(item=>item.nativeInput),
|
|
1360
|
-
|
|
1361
|
-
minimumCoreVersion:prepared.runtimeReceipt?.source?.bundleVersion
|
|
1362
|
-
??ARCANE_MACHINE_BUNDLE_VERSION,
|
|
954
|
+
minimumCoreVersion:ARCANE_MACHINE_BUNDLE_VERSION,
|
|
1363
955
|
protectedRoots,
|
|
1364
956
|
outputRoot,
|
|
1365
957
|
targetRequest:options.targetRequest,
|
|
1366
958
|
signal,
|
|
1367
959
|
onEvent
|
|
1368
960
|
});
|
|
1369
|
-
return
|
|
961
|
+
return {
|
|
1370
962
|
prepared,
|
|
1371
963
|
outputRoot,
|
|
1372
|
-
|
|
964
|
+
toolchain,
|
|
1373
965
|
selectedRelease,
|
|
1374
|
-
dependencyReleases
|
|
966
|
+
dependencyReleases,
|
|
1375
967
|
built
|
|
1376
|
-
}
|
|
968
|
+
};
|
|
1377
969
|
}
|
|
1378
970
|
|
|
1379
971
|
function nativeBuildResult(assembly){
|
|
@@ -1383,9 +975,8 @@ function nativeBuildResult(assembly){
|
|
|
1383
975
|
workspaceRoot:prepared.workspaceRoot,
|
|
1384
976
|
workspaceMode:prepared.workspaceMode,
|
|
1385
977
|
appId:prepared.appId,
|
|
1386
|
-
runtimeContentSha256:prepared.runtimeReceipt?.contentSha256??null,
|
|
1387
978
|
release:assembly.selectedRelease.release,
|
|
1388
|
-
dependencyReleases:assembly.dependencyReleases.map(item=>
|
|
979
|
+
dependencyReleases:assembly.dependencyReleases.map(item=>({
|
|
1389
980
|
appId:item.appId,
|
|
1390
981
|
release:item.release
|
|
1391
982
|
}))
|
|
@@ -1395,7 +986,7 @@ function nativeBuildResult(assembly){
|
|
|
1395
986
|
function usesWorkspaceNativeAssembly(options){
|
|
1396
987
|
return options.nativeBuilder!=null
|
|
1397
988
|
&&typeof options.workspaceRoot==='string'
|
|
1398
|
-
&&options.
|
|
989
|
+
&&options.release==null
|
|
1399
990
|
&&options.appReleaseRoot==null
|
|
1400
991
|
&&options.appDescriptor==null;
|
|
1401
992
|
}
|
|
@@ -1431,18 +1022,15 @@ export async function buildApplication(options={}){
|
|
|
1431
1022
|
({signal,onEvent,workspaceOperationLease})=>buildTarget({
|
|
1432
1023
|
...options,
|
|
1433
1024
|
...prepared,
|
|
1434
|
-
runtimeVerificationState:forwardedRuntimeVerificationState(options,prepared),
|
|
1435
1025
|
signal,
|
|
1436
1026
|
onEvent,
|
|
1437
|
-
workspaceOperationLease
|
|
1438
|
-
validateSourceState:({signal}={})=>validatePreparedRuntime(prepared,{signal})
|
|
1027
|
+
workspaceOperationLease
|
|
1439
1028
|
}),
|
|
1440
1029
|
{...options,workspaceRoot:prepared.workspaceRoot}
|
|
1441
1030
|
);
|
|
1442
1031
|
return {
|
|
1443
1032
|
...result,
|
|
1444
|
-
workspaceMode:prepared.workspaceMode
|
|
1445
|
-
runtimeContentSha256:prepared.runtimeReceipt?.contentSha256??null
|
|
1033
|
+
workspaceMode:prepared.workspaceMode
|
|
1446
1034
|
};
|
|
1447
1035
|
}
|
|
1448
1036
|
|
|
@@ -1463,15 +1051,15 @@ export async function runApplication(options={}){
|
|
|
1463
1051
|
return adapter.run({...selectedOptions,target});
|
|
1464
1052
|
}
|
|
1465
1053
|
if(target!=='browser'){
|
|
1466
|
-
if(usesWorkspaceNativeAssembly(selectedOptions)&&selectedOptions.
|
|
1054
|
+
if(usesWorkspaceNativeAssembly(selectedOptions)&&selectedOptions.artifact==null){
|
|
1467
1055
|
return ownedWork(
|
|
1468
1056
|
'run',
|
|
1469
1057
|
async context=>{
|
|
1470
1058
|
const assembly=await executePairedNativeBuild(selectedOptions,adapter,context);
|
|
1471
1059
|
const launched=await adapter.run({
|
|
1472
1060
|
toolchainRoot:selectedOptions.toolchainRoot,
|
|
1473
|
-
|
|
1474
|
-
|
|
1061
|
+
toolchain:assembly.toolchain,
|
|
1062
|
+
artifact:assembly.built.artifact,
|
|
1475
1063
|
targetRequest:selectedOptions.targetRequest,
|
|
1476
1064
|
signal:context.signal,
|
|
1477
1065
|
onEvent:context.onEvent
|
|
@@ -1491,7 +1079,6 @@ export async function runApplication(options={}){
|
|
|
1491
1079
|
return runTarget({
|
|
1492
1080
|
...selectedOptions,
|
|
1493
1081
|
...prepared,
|
|
1494
|
-
runtimeVerificationState:forwardedRuntimeVerificationState(selectedOptions,prepared),
|
|
1495
1082
|
target
|
|
1496
1083
|
});
|
|
1497
1084
|
}
|
|
@@ -1527,6 +1114,7 @@ export async function executeOperation(command,options={}){
|
|
|
1527
1114
|
const operations={
|
|
1528
1115
|
new:createApplication,
|
|
1529
1116
|
init:initializeApplication,
|
|
1117
|
+
upgrade:upgradeApplication,
|
|
1530
1118
|
doctor:doctorApplication,
|
|
1531
1119
|
'import-map':importMapApplication,
|
|
1532
1120
|
dev:developApplication,
|
|
@@ -1555,10 +1143,11 @@ export async function executeOperation(command,options={}){
|
|
|
1555
1143
|
}
|
|
1556
1144
|
|
|
1557
1145
|
export function createToolchain(defaults={}){
|
|
1558
|
-
return
|
|
1146
|
+
return {
|
|
1559
1147
|
execute:(command,options={})=>executeOperation(command,{...defaults,...options}),
|
|
1560
1148
|
create:options=>createApplication({...defaults,...options}),
|
|
1561
1149
|
init:options=>initializeApplication({...defaults,...options}),
|
|
1150
|
+
upgrade:options=>upgradeApplication({...defaults,...options}),
|
|
1562
1151
|
doctor:options=>doctorApplication({...defaults,...options}),
|
|
1563
1152
|
importMap:options=>importMapApplication({...defaults,...options}),
|
|
1564
1153
|
dev:options=>developApplication({...defaults,...options}),
|
|
@@ -1578,5 +1167,5 @@ export function createToolchain(defaults={}){
|
|
|
1578
1167
|
mail:options=>executeMailCommand({...defaults,...options}),
|
|
1579
1168
|
targets:options=>describeTargets({...defaults,...options}),
|
|
1580
1169
|
repository:options=>repositoryApplication({...defaults,...options})
|
|
1581
|
-
}
|
|
1170
|
+
};
|
|
1582
1171
|
}
|