arcane-os 0.3.0 → 0.3.2
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 +887 -909
- package/browser-runtime/ai/browser-speech-providers.mjs +96 -152
- 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 -146
- package/browser-runtime/ai/speech-worker-runtime.mjs +643 -363
- 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 +112 -68
- 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 +1050 -427
- package/runtime/arcane/modules/AIProviderRuntime.js +658 -363
- 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 +18 -151
- 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 +30 -324
- 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 +40 -62
- 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 +485 -3229
- package/src/process.mjs +5 -10
- package/src/release-bundle.mjs +292 -2405
- package/src/runtime.mjs +76 -396
- package/src/scaffold.mjs +30 -80
- 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 +19 -135
- package/src/testing-loader.mjs +164 -0
- package/src/testing.mjs +1 -1
- package/src/toolchain.mjs +131 -544
- package/src/update-check.mjs +26 -64
- package/src/workspace-operation-lock.mjs +139 -430
- package/src/workspace-runtime.mjs +112 -779
- 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 -187
- package/docs/reference/ai/browser-speech-package-authority.json +0 -835
- package/docs/reference/ai/browser-speech.md +0 -1252
- 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 -677
- package/docs/reference/runtime-components.md +0 -1366
- package/docs/reference/runtime-entities.md +0 -303
- package/docs/reference/runtime-modules.md +0 -2960
- package/docs/reference/sdk-api.md +0 -6694
- 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,35 @@ 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,
|
|
605
318
|
workspaceOperationLease,
|
|
606
319
|
signal,
|
|
607
320
|
onEvent
|
|
@@ -633,6 +346,33 @@ export async function initializeApplication(options={}){
|
|
|
633
346
|
return initWorkspace(options);
|
|
634
347
|
}
|
|
635
348
|
|
|
349
|
+
export async function upgradeApplication(options={}){
|
|
350
|
+
assertApplicationScope(options,'Workspace upgrade');
|
|
351
|
+
const selected=await resolveWorkspace({
|
|
352
|
+
workspaceRoot:options.workspaceRoot,
|
|
353
|
+
appId:options.appId
|
|
354
|
+
});
|
|
355
|
+
if(selected.config.workspaceMode!=='external'){
|
|
356
|
+
throw new ArcaneError(
|
|
357
|
+
ERROR_CODES.policyDenied,
|
|
358
|
+
'Workspace upgrade is available only to installed-SDK external workspaces.'
|
|
359
|
+
);
|
|
360
|
+
}
|
|
361
|
+
const result=await runProcess('npm',['upgrade'],{
|
|
362
|
+
cwd:selected.workspaceRoot,
|
|
363
|
+
signal:options.signal,
|
|
364
|
+
onEvent:options.onEvent
|
|
365
|
+
});
|
|
366
|
+
return {
|
|
367
|
+
schemaVersion:1,
|
|
368
|
+
kind:'arcane-application-upgrade',
|
|
369
|
+
workspaceRoot:selected.workspaceRoot,
|
|
370
|
+
workspaceMode:selected.config.workspaceMode,
|
|
371
|
+
appId:selected.appId,
|
|
372
|
+
...result
|
|
373
|
+
};
|
|
374
|
+
}
|
|
375
|
+
|
|
636
376
|
export async function doctorApplication(options={}){
|
|
637
377
|
const result=await runDoctor(options);
|
|
638
378
|
if(!result.ok){
|
|
@@ -645,6 +385,18 @@ export async function doctorApplication(options={}){
|
|
|
645
385
|
return result;
|
|
646
386
|
}
|
|
647
387
|
|
|
388
|
+
async function runPreparedApplicationTests(prepared,options={}){
|
|
389
|
+
throwIfAborted(options.signal);
|
|
390
|
+
return runApplicationTests({
|
|
391
|
+
workspaceRoot:prepared.workspaceRoot,
|
|
392
|
+
workspaceMode:prepared.workspaceMode,
|
|
393
|
+
appId:prepared.appId,
|
|
394
|
+
appRoot:prepared.appRoot,
|
|
395
|
+
signal:options.signal,
|
|
396
|
+
onEvent:options.onEvent
|
|
397
|
+
});
|
|
398
|
+
}
|
|
399
|
+
|
|
648
400
|
export async function testApplication(options={}){
|
|
649
401
|
throwIfAborted(options.signal);
|
|
650
402
|
if(operationScope(options)==='shared'){
|
|
@@ -656,96 +408,8 @@ export async function testApplication(options={}){
|
|
|
656
408
|
}
|
|
657
409
|
return executeIntegratedSharedOperation('focused-test',options);
|
|
658
410
|
}
|
|
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
|
-
};
|
|
411
|
+
const prepared=await preparedWorkspace({...options,allowMissingManagedImportMap:true});
|
|
412
|
+
return runPreparedApplicationTests(prepared,options);
|
|
749
413
|
}
|
|
750
414
|
|
|
751
415
|
export async function checkApplication(options={}){
|
|
@@ -755,10 +419,15 @@ export async function checkApplication(options={}){
|
|
|
755
419
|
}
|
|
756
420
|
return executeIntegratedSharedOperation('development-check',options);
|
|
757
421
|
}
|
|
758
|
-
const prepared=await preparedWorkspace(options);
|
|
422
|
+
const prepared=await preparedWorkspace({...options,allowMissingManagedImportMap:true});
|
|
759
423
|
const tests=options.skipTests
|
|
760
|
-
?{
|
|
761
|
-
|
|
424
|
+
?{
|
|
425
|
+
passed:true,
|
|
426
|
+
skipped:true,
|
|
427
|
+
testFiles:[],
|
|
428
|
+
output:''
|
|
429
|
+
}
|
|
430
|
+
:await runPreparedApplicationTests(prepared,options);
|
|
762
431
|
await validatePreparedRuntime(prepared,{signal:options.signal});
|
|
763
432
|
return {
|
|
764
433
|
ok:true,
|
|
@@ -766,17 +435,10 @@ export async function checkApplication(options={}){
|
|
|
766
435
|
workspaceRoot:prepared.workspaceRoot,
|
|
767
436
|
appId:prepared.appId,
|
|
768
437
|
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
|
-
},
|
|
438
|
+
runtime:{
|
|
439
|
+
mode:prepared.workspaceMode==='external'?'sdk':'workspace',
|
|
440
|
+
sourceRoot:'arcane'
|
|
441
|
+
},
|
|
780
442
|
checks:prepared.validation.checks,
|
|
781
443
|
tests
|
|
782
444
|
};
|
|
@@ -798,7 +460,6 @@ export async function developApplication(options={}){
|
|
|
798
460
|
workspaceRoot:prepared.workspaceRoot,
|
|
799
461
|
appId:prepared.appId,
|
|
800
462
|
mode:'source',
|
|
801
|
-
workspaceRuntimeReceipt:prepared.workspaceRuntimeReceipt,
|
|
802
463
|
workspaceMode:prepared.workspaceMode,
|
|
803
464
|
...(options.sdkRuntimeSourceRoot===undefined?{}:{
|
|
804
465
|
sdkRuntimeSourceRoot:options.sdkRuntimeSourceRoot
|
|
@@ -819,23 +480,22 @@ export async function packageApplication(options={}){
|
|
|
819
480
|
});
|
|
820
481
|
const release=await ownedWork(
|
|
821
482
|
'package',
|
|
822
|
-
({signal,onEvent,workspaceOperationLease})=>
|
|
483
|
+
async({signal,onEvent,workspaceOperationLease})=>{
|
|
484
|
+
return packageApp({
|
|
823
485
|
workspaceRoot:prepared.workspaceRoot,
|
|
824
486
|
appId:prepared.appId,
|
|
825
487
|
dryRun:Boolean(options.dryRun),
|
|
826
488
|
signal,
|
|
827
489
|
onEvent,
|
|
828
|
-
workspaceOperationLease
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
}),
|
|
490
|
+
workspaceOperationLease
|
|
491
|
+
});
|
|
492
|
+
},
|
|
832
493
|
{...options,workspaceRoot:prepared.workspaceRoot}
|
|
833
494
|
);
|
|
834
495
|
return {
|
|
835
496
|
workspaceRoot:prepared.workspaceRoot,
|
|
836
497
|
workspaceMode:prepared.workspaceMode,
|
|
837
498
|
appId:prepared.appId,
|
|
838
|
-
runtimeContentSha256:prepared.runtimeReceipt?.contentSha256??null,
|
|
839
499
|
release
|
|
840
500
|
};
|
|
841
501
|
}
|
|
@@ -848,7 +508,6 @@ export async function verifyApplication(options={}){
|
|
|
848
508
|
({signal,onEvent})=>verifyApp({
|
|
849
509
|
workspaceRoot:prepared.workspaceRoot,
|
|
850
510
|
appId:prepared.appId,
|
|
851
|
-
runtimeVerificationState:forwardedRuntimeVerificationState(options,prepared),
|
|
852
511
|
signal,
|
|
853
512
|
onEvent
|
|
854
513
|
}),
|
|
@@ -859,7 +518,6 @@ export async function verifyApplication(options={}){
|
|
|
859
518
|
workspaceRoot:prepared.workspaceRoot,
|
|
860
519
|
workspaceMode:prepared.workspaceMode,
|
|
861
520
|
appId:prepared.appId,
|
|
862
|
-
runtimeContentSha256:prepared.runtimeReceipt?.contentSha256??null,
|
|
863
521
|
release
|
|
864
522
|
};
|
|
865
523
|
}
|
|
@@ -876,19 +534,18 @@ export async function bundleApplication(options={}){
|
|
|
876
534
|
const verified=await verifyApp({
|
|
877
535
|
workspaceRoot:prepared.workspaceRoot,
|
|
878
536
|
appId:prepared.appId,
|
|
879
|
-
runtimeVerificationState:forwardedRuntimeVerificationState(options,prepared),
|
|
880
537
|
signal,
|
|
881
538
|
onEvent
|
|
882
539
|
});
|
|
883
540
|
await validatePreparedRuntime(prepared,{signal});
|
|
884
|
-
const releaseRoot=verified.
|
|
541
|
+
const releaseRoot=verified.outputRoot;
|
|
885
542
|
const outputPath=options.artifactPath??path.join(
|
|
886
543
|
path.dirname(releaseRoot),
|
|
887
544
|
`${prepared.appId}-${verified.version}${APP_BUNDLE_EXTENSION}`
|
|
888
545
|
);
|
|
889
546
|
return createAppReleaseBundle({
|
|
890
|
-
receipt:verified.receipt,
|
|
891
547
|
releaseRoot,
|
|
548
|
+
appDescriptor:prepared.descriptor,
|
|
892
549
|
outputPath,
|
|
893
550
|
overwrite:options.overwrite,
|
|
894
551
|
signal,
|
|
@@ -901,7 +558,6 @@ export async function bundleApplication(options={}){
|
|
|
901
558
|
workspaceRoot:prepared.workspaceRoot,
|
|
902
559
|
workspaceMode:prepared.workspaceMode,
|
|
903
560
|
appId:prepared.appId,
|
|
904
|
-
runtimeContentSha256:prepared.runtimeReceipt?.contentSha256??null,
|
|
905
561
|
bundle
|
|
906
562
|
};
|
|
907
563
|
}
|
|
@@ -1059,19 +715,6 @@ export function assertIntegratedPortableToolchain(options={}){
|
|
|
1059
715
|
return assertIntegratedNativeToolchain({...options,target:'portable'});
|
|
1060
716
|
}
|
|
1061
717
|
|
|
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
718
|
export async function verifyNativeArtifact(options={}){
|
|
1076
719
|
const {target,adapter}=targetSelection(options);
|
|
1077
720
|
const targetDescription=await adapter.describe();
|
|
@@ -1106,7 +749,7 @@ async function nativeDependencyClosure(prepared,{target,signal,onEvent}={}){
|
|
|
1106
749
|
if(JSON.stringify(selected.descriptor)!==JSON.stringify(prepared.descriptor)){
|
|
1107
750
|
nativeDependencyError(
|
|
1108
751
|
`The selected app ${prepared.appId} descriptor changed during native build preflight.`,
|
|
1109
|
-
ERROR_CODES.
|
|
752
|
+
ERROR_CODES.workspaceInvalid
|
|
1110
753
|
);
|
|
1111
754
|
}
|
|
1112
755
|
if(!prepared.descriptor.targets.includes(target)){
|
|
@@ -1118,7 +761,6 @@ async function nativeDependencyClosure(prepared,{target,signal,onEvent}={}){
|
|
|
1118
761
|
|
|
1119
762
|
const visiting=new Set([prepared.appId]);
|
|
1120
763
|
const visited=new Set();
|
|
1121
|
-
const discovered=new Set();
|
|
1122
764
|
const dependencies=[];
|
|
1123
765
|
function visit(descriptor){
|
|
1124
766
|
for(const dependencyId of descriptor.native.bundledApps){
|
|
@@ -1138,10 +780,6 @@ async function nativeDependencyClosure(prepared,{target,signal,onEvent}={}){
|
|
|
1138
780
|
ERROR_CODES.targetUnavailable
|
|
1139
781
|
);
|
|
1140
782
|
}
|
|
1141
|
-
if(discovered.size>=64){
|
|
1142
|
-
nativeDependencyError('A native app dependency closure may contain at most 64 apps.');
|
|
1143
|
-
}
|
|
1144
|
-
discovered.add(dependencyId);
|
|
1145
783
|
visiting.add(dependencyId);
|
|
1146
784
|
visit(dependency.descriptor);
|
|
1147
785
|
visiting.delete(dependencyId);
|
|
@@ -1162,13 +800,13 @@ async function nativeDependencyClosure(prepared,{target,signal,onEvent}={}){
|
|
|
1162
800
|
signal,
|
|
1163
801
|
onEvent
|
|
1164
802
|
});
|
|
1165
|
-
validated.push(
|
|
803
|
+
validated.push({
|
|
1166
804
|
...dependency,
|
|
1167
805
|
descriptor:validation.app.descriptor,
|
|
1168
806
|
validation
|
|
1169
|
-
})
|
|
807
|
+
});
|
|
1170
808
|
}
|
|
1171
|
-
return
|
|
809
|
+
return validated;
|
|
1172
810
|
}
|
|
1173
811
|
|
|
1174
812
|
async function externalWorkspaceProtectedRoots(prepared,{signal}={}){
|
|
@@ -1222,45 +860,28 @@ function pathsOverlap(left,right){
|
|
|
1222
860
|
}
|
|
1223
861
|
|
|
1224
862
|
async function packageNativeRelease(prepared,app,{
|
|
1225
|
-
sharedPayloadSnapshot,
|
|
1226
863
|
workspaceOperationLease,
|
|
1227
864
|
signal,
|
|
1228
865
|
onEvent
|
|
1229
866
|
}={}){
|
|
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
867
|
const release=await packageApp({
|
|
1238
868
|
workspaceRoot:prepared.workspaceRoot,
|
|
1239
869
|
appId:app.appId,
|
|
1240
|
-
sharedPayloadSnapshot,
|
|
1241
|
-
runtimeVerificationState:prepared.runtimeVerificationState??undefined,
|
|
1242
870
|
workspaceOperationLease,
|
|
1243
871
|
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
|
-
})
|
|
872
|
+
onEvent
|
|
1252
873
|
});
|
|
1253
|
-
return
|
|
874
|
+
return {
|
|
1254
875
|
appId:app.appId,
|
|
1255
876
|
appRoot:app.appRoot,
|
|
1256
877
|
descriptor:app.descriptor,
|
|
1257
878
|
release,
|
|
1258
|
-
nativeInput:
|
|
879
|
+
nativeInput:{
|
|
1259
880
|
appDescriptor:app.descriptor,
|
|
1260
|
-
appReleaseRoot:path.resolve(prepared.workspaceRoot,release.output),
|
|
1261
|
-
|
|
1262
|
-
}
|
|
1263
|
-
}
|
|
881
|
+
appReleaseRoot:release.outputRoot??path.resolve(prepared.workspaceRoot,release.output),
|
|
882
|
+
release:{manifest:release.manifest,files:[...release.files]}
|
|
883
|
+
}
|
|
884
|
+
};
|
|
1264
885
|
}
|
|
1265
886
|
|
|
1266
887
|
async function executePairedNativeBuild(options,adapter,{
|
|
@@ -1269,12 +890,7 @@ async function executePairedNativeBuild(options,adapter,{
|
|
|
1269
890
|
workspaceOperationLease
|
|
1270
891
|
}={}){
|
|
1271
892
|
const target=options.target??options.targetRequest?.target;
|
|
1272
|
-
const initialPrepared=await preparedWorkspace({
|
|
1273
|
-
...options,
|
|
1274
|
-
deferRuntimeVerification:true,
|
|
1275
|
-
signal,
|
|
1276
|
-
onEvent
|
|
1277
|
-
});
|
|
893
|
+
const initialPrepared=await preparedWorkspace({...options,signal,onEvent});
|
|
1278
894
|
assertIntegratedNativeToolchain({
|
|
1279
895
|
target,
|
|
1280
896
|
workspaceMode:initialPrepared.workspaceMode,
|
|
@@ -1284,7 +900,7 @@ async function executePairedNativeBuild(options,adapter,{
|
|
|
1284
900
|
if(options.dryRun){
|
|
1285
901
|
throw new ArcaneError(
|
|
1286
902
|
ERROR_CODES.usage,
|
|
1287
|
-
`${target} native build does not support --dry-run because
|
|
903
|
+
`${target} native build does not support --dry-run because the native provider needs materialized app files.`
|
|
1288
904
|
);
|
|
1289
905
|
}
|
|
1290
906
|
const requestedOutputRoot=resolveNativeBuildOutputRoot({
|
|
@@ -1302,31 +918,7 @@ async function executePairedNativeBuild(options,adapter,{
|
|
|
1302
918
|
);
|
|
1303
919
|
}
|
|
1304
920
|
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
|
-
};
|
|
921
|
+
const prepared=initialPrepared;
|
|
1330
922
|
const selectedRelease=await packageNativeRelease(prepared,{
|
|
1331
923
|
appId:prepared.appId,
|
|
1332
924
|
appRoot:prepared.appRoot,
|
|
@@ -1335,16 +927,16 @@ async function executePairedNativeBuild(options,adapter,{
|
|
|
1335
927
|
descriptorSource:prepared.validation.app.descriptorSource,
|
|
1336
928
|
descriptorPath:prepared.validation.app.descriptorPath,
|
|
1337
929
|
validation:prepared.validation
|
|
1338
|
-
},{
|
|
930
|
+
},{workspaceOperationLease,signal,onEvent});
|
|
1339
931
|
const dependencyReleases=[];
|
|
1340
932
|
for(const dependency of dependencyApps){
|
|
1341
933
|
dependencyReleases.push(await packageNativeRelease(
|
|
1342
934
|
prepared,
|
|
1343
935
|
dependency,
|
|
1344
|
-
{
|
|
936
|
+
{workspaceOperationLease,signal,onEvent}
|
|
1345
937
|
));
|
|
1346
938
|
}
|
|
1347
|
-
const
|
|
939
|
+
const toolchain=await adapter.prepare({
|
|
1348
940
|
toolchainRoot:options.toolchainRoot,
|
|
1349
941
|
targetRequest:options.targetRequest,
|
|
1350
942
|
signal,
|
|
@@ -1354,26 +946,24 @@ async function executePairedNativeBuild(options,adapter,{
|
|
|
1354
946
|
const built=await adapter.build({
|
|
1355
947
|
nativeBuilder:options.nativeBuilder,
|
|
1356
948
|
toolchainRoot:options.toolchainRoot,
|
|
1357
|
-
|
|
949
|
+
toolchain,
|
|
1358
950
|
...selectedRelease.nativeInput,
|
|
1359
951
|
dependencyReleases:dependencyReleases.map(item=>item.nativeInput),
|
|
1360
|
-
|
|
1361
|
-
minimumCoreVersion:prepared.runtimeReceipt?.source?.bundleVersion
|
|
1362
|
-
??ARCANE_MACHINE_BUNDLE_VERSION,
|
|
952
|
+
minimumCoreVersion:ARCANE_MACHINE_BUNDLE_VERSION,
|
|
1363
953
|
protectedRoots,
|
|
1364
954
|
outputRoot,
|
|
1365
955
|
targetRequest:options.targetRequest,
|
|
1366
956
|
signal,
|
|
1367
957
|
onEvent
|
|
1368
958
|
});
|
|
1369
|
-
return
|
|
959
|
+
return {
|
|
1370
960
|
prepared,
|
|
1371
961
|
outputRoot,
|
|
1372
|
-
|
|
962
|
+
toolchain,
|
|
1373
963
|
selectedRelease,
|
|
1374
|
-
dependencyReleases
|
|
964
|
+
dependencyReleases,
|
|
1375
965
|
built
|
|
1376
|
-
}
|
|
966
|
+
};
|
|
1377
967
|
}
|
|
1378
968
|
|
|
1379
969
|
function nativeBuildResult(assembly){
|
|
@@ -1383,9 +973,8 @@ function nativeBuildResult(assembly){
|
|
|
1383
973
|
workspaceRoot:prepared.workspaceRoot,
|
|
1384
974
|
workspaceMode:prepared.workspaceMode,
|
|
1385
975
|
appId:prepared.appId,
|
|
1386
|
-
runtimeContentSha256:prepared.runtimeReceipt?.contentSha256??null,
|
|
1387
976
|
release:assembly.selectedRelease.release,
|
|
1388
|
-
dependencyReleases:assembly.dependencyReleases.map(item=>
|
|
977
|
+
dependencyReleases:assembly.dependencyReleases.map(item=>({
|
|
1389
978
|
appId:item.appId,
|
|
1390
979
|
release:item.release
|
|
1391
980
|
}))
|
|
@@ -1395,7 +984,7 @@ function nativeBuildResult(assembly){
|
|
|
1395
984
|
function usesWorkspaceNativeAssembly(options){
|
|
1396
985
|
return options.nativeBuilder!=null
|
|
1397
986
|
&&typeof options.workspaceRoot==='string'
|
|
1398
|
-
&&options.
|
|
987
|
+
&&options.release==null
|
|
1399
988
|
&&options.appReleaseRoot==null
|
|
1400
989
|
&&options.appDescriptor==null;
|
|
1401
990
|
}
|
|
@@ -1431,18 +1020,15 @@ export async function buildApplication(options={}){
|
|
|
1431
1020
|
({signal,onEvent,workspaceOperationLease})=>buildTarget({
|
|
1432
1021
|
...options,
|
|
1433
1022
|
...prepared,
|
|
1434
|
-
runtimeVerificationState:forwardedRuntimeVerificationState(options,prepared),
|
|
1435
1023
|
signal,
|
|
1436
1024
|
onEvent,
|
|
1437
|
-
workspaceOperationLease
|
|
1438
|
-
validateSourceState:({signal}={})=>validatePreparedRuntime(prepared,{signal})
|
|
1025
|
+
workspaceOperationLease
|
|
1439
1026
|
}),
|
|
1440
1027
|
{...options,workspaceRoot:prepared.workspaceRoot}
|
|
1441
1028
|
);
|
|
1442
1029
|
return {
|
|
1443
1030
|
...result,
|
|
1444
|
-
workspaceMode:prepared.workspaceMode
|
|
1445
|
-
runtimeContentSha256:prepared.runtimeReceipt?.contentSha256??null
|
|
1031
|
+
workspaceMode:prepared.workspaceMode
|
|
1446
1032
|
};
|
|
1447
1033
|
}
|
|
1448
1034
|
|
|
@@ -1463,15 +1049,15 @@ export async function runApplication(options={}){
|
|
|
1463
1049
|
return adapter.run({...selectedOptions,target});
|
|
1464
1050
|
}
|
|
1465
1051
|
if(target!=='browser'){
|
|
1466
|
-
if(usesWorkspaceNativeAssembly(selectedOptions)&&selectedOptions.
|
|
1052
|
+
if(usesWorkspaceNativeAssembly(selectedOptions)&&selectedOptions.artifact==null){
|
|
1467
1053
|
return ownedWork(
|
|
1468
1054
|
'run',
|
|
1469
1055
|
async context=>{
|
|
1470
1056
|
const assembly=await executePairedNativeBuild(selectedOptions,adapter,context);
|
|
1471
1057
|
const launched=await adapter.run({
|
|
1472
1058
|
toolchainRoot:selectedOptions.toolchainRoot,
|
|
1473
|
-
|
|
1474
|
-
|
|
1059
|
+
toolchain:assembly.toolchain,
|
|
1060
|
+
artifact:assembly.built.artifact,
|
|
1475
1061
|
targetRequest:selectedOptions.targetRequest,
|
|
1476
1062
|
signal:context.signal,
|
|
1477
1063
|
onEvent:context.onEvent
|
|
@@ -1491,7 +1077,6 @@ export async function runApplication(options={}){
|
|
|
1491
1077
|
return runTarget({
|
|
1492
1078
|
...selectedOptions,
|
|
1493
1079
|
...prepared,
|
|
1494
|
-
runtimeVerificationState:forwardedRuntimeVerificationState(selectedOptions,prepared),
|
|
1495
1080
|
target
|
|
1496
1081
|
});
|
|
1497
1082
|
}
|
|
@@ -1527,6 +1112,7 @@ export async function executeOperation(command,options={}){
|
|
|
1527
1112
|
const operations={
|
|
1528
1113
|
new:createApplication,
|
|
1529
1114
|
init:initializeApplication,
|
|
1115
|
+
upgrade:upgradeApplication,
|
|
1530
1116
|
doctor:doctorApplication,
|
|
1531
1117
|
'import-map':importMapApplication,
|
|
1532
1118
|
dev:developApplication,
|
|
@@ -1555,10 +1141,11 @@ export async function executeOperation(command,options={}){
|
|
|
1555
1141
|
}
|
|
1556
1142
|
|
|
1557
1143
|
export function createToolchain(defaults={}){
|
|
1558
|
-
return
|
|
1144
|
+
return {
|
|
1559
1145
|
execute:(command,options={})=>executeOperation(command,{...defaults,...options}),
|
|
1560
1146
|
create:options=>createApplication({...defaults,...options}),
|
|
1561
1147
|
init:options=>initializeApplication({...defaults,...options}),
|
|
1148
|
+
upgrade:options=>upgradeApplication({...defaults,...options}),
|
|
1562
1149
|
doctor:options=>doctorApplication({...defaults,...options}),
|
|
1563
1150
|
importMap:options=>importMapApplication({...defaults,...options}),
|
|
1564
1151
|
dev:options=>developApplication({...defaults,...options}),
|
|
@@ -1578,5 +1165,5 @@ export function createToolchain(defaults={}){
|
|
|
1578
1165
|
mail:options=>executeMailCommand({...defaults,...options}),
|
|
1579
1166
|
targets:options=>describeTargets({...defaults,...options}),
|
|
1580
1167
|
repository:options=>repositoryApplication({...defaults,...options})
|
|
1581
|
-
}
|
|
1168
|
+
};
|
|
1582
1169
|
}
|