arcane-os 0.1.2 → 0.2.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +35 -0
- package/NOTICE +5 -3
- package/README.md +73 -24
- package/browser-runtime/ARCANE_SDK_BROWSER_RELEASE.json +67 -18
- package/browser-runtime/ai/ARCANE_AI_BROWSER_WASM_COMPONENTS.json +16 -5
- package/browser-runtime/ai/browser-kokoro-worker.mjs +3 -0
- package/browser-runtime/ai/browser-speech-artifacts.mjs +1108 -0
- package/browser-runtime/ai/browser-speech-providers.mjs +780 -0
- package/browser-runtime/ai/browser-speech.mjs +9 -0
- package/browser-runtime/ai/browser-wasm-llm-provider.mjs +1537 -167
- package/browser-runtime/ai/browser-wasm.mjs +46 -1
- package/browser-runtime/ai/browser-whisper-worker.mjs +3 -0
- package/browser-runtime/ai/browser-wllama-runtime.mjs +677 -132
- package/browser-runtime/ai/model-controller.mjs +138 -12
- package/browser-runtime/ai/speech-worker-client.mjs +207 -0
- package/browser-runtime/ai/speech-worker-runtime.mjs +516 -0
- package/browser-runtime/ai/wllama/index.mjs +389 -0
- package/docs/architecture.md +132 -22
- package/docs/reference/README.md +1 -1
- package/docs/reference/ai/browser-wasm.md +101 -42
- package/docs/reference/availability-and-normalization.md +19 -5
- package/docs/reference/behavioral-testing.md +18 -5
- package/docs/reference/cli.md +2 -2
- package/docs/reference/inventory/package-api.json +14 -14
- package/docs/reference/protocols.md +4 -4
- package/docs/reference/sdk-api.md +68 -38
- package/docs/work-amplification.md +8 -4
- package/package.json +7 -3
- package/runtime/ARCANE_RUNTIME_RELEASE.json +50 -20
- package/runtime/arcane/components/chat.html +551 -62
- package/runtime/arcane/components/speech.html +1113 -265
- package/runtime/arcane/entities/Chat.js +246 -43
- package/runtime/arcane/modules/AI.js +1394 -162
- package/runtime/arcane/modules/AIProviderRuntime.js +2289 -0
- package/runtime/arcane/modules/AIRuntimeState.js +872 -0
- package/runtime/arcane/modules/ConfiguredAIChatSession.js +382 -31
- package/runtime/arcane/modules/DBOPFSDocumentLibrary.js +1106 -0
- package/runtime/arcane/modules/DocumentLexicalSearch.js +292 -0
- package/runtime/arcane/modules/PersistentAIChatSession.js +268 -0
- package/runtime/arcane/modules/StaticDocumentCatalog.js +25 -206
- package/schemas/arcane-lock.schema.json +10 -6
- package/src/cli/main.mjs +14 -2
- package/src/constants.mjs +1 -1
- package/src/dev-server.mjs +273 -26
- package/src/doctor.mjs +1 -3
- package/src/import-map.mjs +193 -84
- package/src/packager/core.mjs +313 -41
- package/src/runtime.mjs +14 -4
- package/src/scaffold.mjs +45 -17
- package/src/sdk-browser-runtime.mjs +28 -75
- package/src/templates/workspace-template.mjs +27 -8
- package/src/toolchain.mjs +13 -2
- package/src/workspace-runtime.mjs +1 -1
- package/src/workspace.mjs +178 -25
package/src/dev-server.mjs
CHANGED
|
@@ -15,8 +15,9 @@ import {
|
|
|
15
15
|
} from './workspace-runtime.mjs';
|
|
16
16
|
import {verifyRuntime} from './runtime.mjs';
|
|
17
17
|
import {verifySdkBrowserRuntime} from './sdk-browser-runtime.mjs';
|
|
18
|
-
import {resolveWorkspace} from './workspace.mjs';
|
|
18
|
+
import {resolveWorkspace,validateWorkspace} from './workspace.mjs';
|
|
19
19
|
import {createEventQueue} from './event-queue.mjs';
|
|
20
|
+
import {SDK_NAME,SDK_VERSION} from './constants.mjs';
|
|
20
21
|
|
|
21
22
|
const MIME_TYPES=new Map([
|
|
22
23
|
['.css','text/css; charset=utf-8'],
|
|
@@ -44,6 +45,17 @@ const SESSION_COOKIE='Arcane-Dev-Session';
|
|
|
44
45
|
const PRIVATE_SOURCE_SEGMENTS=new Set([
|
|
45
46
|
'arcane-app.json','arcane-package.json','test','tests','scripts','node_modules','dist','local'
|
|
46
47
|
]);
|
|
48
|
+
const SDK_RUNTIME_SOURCE_PROTOCOL='arcane-sdk-runtime-source/1';
|
|
49
|
+
const SDK_RUNTIME_SOURCE_ARCANE_ROOTS=new Set([
|
|
50
|
+
'components','css','entities','img','modules','security'
|
|
51
|
+
]);
|
|
52
|
+
const SDK_RUNTIME_SOURCE_PRIVATE_SEGMENTS=new Set([
|
|
53
|
+
'node_modules','.git','.hg','.svn','cvs'
|
|
54
|
+
]);
|
|
55
|
+
const SDK_RUNTIME_SOURCE_PRIVATE_MANIFESTS=new Set([
|
|
56
|
+
'arcane-app.json','arcane-package.json','arcane.lock.json',
|
|
57
|
+
'arcane_app_release.json','arcane_runtime_release.json','arcane_sdk_browser_release.json'
|
|
58
|
+
]);
|
|
47
59
|
|
|
48
60
|
// This server is a loopback-only development host, not a production policy
|
|
49
61
|
// boundary. The bundled runtime currently needs inline component execution,
|
|
@@ -139,6 +151,173 @@ function inventoryKey(value){
|
|
|
139
151
|
return process.platform==='win32'?value.toLowerCase():value;
|
|
140
152
|
}
|
|
141
153
|
|
|
154
|
+
function canonicalLocationKey(value){
|
|
155
|
+
return inventoryKey(path.resolve(value));
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
function pathIsWithin(root,candidate){
|
|
159
|
+
const relative=path.relative(root,candidate);
|
|
160
|
+
return relative===''||(!path.isAbsolute(relative)&&relative!=='..'
|
|
161
|
+
&&!relative.startsWith(`..${path.sep}`));
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
function pathsOverlap(left,right){
|
|
165
|
+
return pathIsWithin(left,right)||pathIsWithin(right,left);
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
async function canonicalRealDirectory(requested,label){
|
|
169
|
+
let info;
|
|
170
|
+
try{
|
|
171
|
+
info=await lstat(requested);
|
|
172
|
+
}catch{
|
|
173
|
+
fail(`${label} must be an existing real directory.`,'ARCANE_DEV_RUNTIME_SOURCE_INVALID');
|
|
174
|
+
}
|
|
175
|
+
if(info.isSymbolicLink()||!info.isDirectory()){
|
|
176
|
+
fail(`${label} must be an existing real directory.`,'ARCANE_DEV_RUNTIME_SOURCE_INVALID');
|
|
177
|
+
}
|
|
178
|
+
let canonical;
|
|
179
|
+
try{
|
|
180
|
+
canonical=await realpath(requested);
|
|
181
|
+
}catch{
|
|
182
|
+
fail(`${label} could not be resolved as a real directory.`,'ARCANE_DEV_RUNTIME_SOURCE_INVALID');
|
|
183
|
+
}
|
|
184
|
+
if(canonicalLocationKey(canonical)!==canonicalLocationKey(requested)){
|
|
185
|
+
fail(`${label} must not contain a symlink or reparse-point escape.`,'ARCANE_DEV_RUNTIME_SOURCE_INVALID');
|
|
186
|
+
}
|
|
187
|
+
return canonical;
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
function sdkRuntimeSourcePathAllowed(relative,{arcaneRoot=false}={}){
|
|
191
|
+
if(relative.length===0)return false;
|
|
192
|
+
const normalized=relative.map(function normalizeRuntimeSourceSegment(segment){
|
|
193
|
+
return segment.normalize('NFC').toLowerCase();
|
|
194
|
+
});
|
|
195
|
+
if(normalized.some(function runtimeSourceSegmentIsPrivate(segment){
|
|
196
|
+
return segment.startsWith('.')||SDK_RUNTIME_SOURCE_PRIVATE_SEGMENTS.has(segment)
|
|
197
|
+
||SDK_RUNTIME_SOURCE_PRIVATE_MANIFESTS.has(segment);
|
|
198
|
+
}))return false;
|
|
199
|
+
return !arcaneRoot||SDK_RUNTIME_SOURCE_ARCANE_ROOTS.has(normalized[0]);
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
function sdkArcaneSourcePathAllowed(relative){
|
|
203
|
+
return sdkRuntimeSourcePathAllowed(relative,{arcaneRoot:true});
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
function sdkDependencySourcePathAllowed(relative){
|
|
207
|
+
return sdkRuntimeSourcePathAllowed(relative);
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
function sdkBrowserSourcePathAllowed(relative){
|
|
211
|
+
return sdkRuntimeSourcePathAllowed(relative);
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
async function emitRuntimeSourceEvent(onEvent,event){
|
|
215
|
+
if(typeof onEvent==='function')await onEvent(event);
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
async function verifySdkRuntimeSourceRoot(sourceRoot,workspaceRoot,appId,{signal,onEvent}={}){
|
|
219
|
+
throwIfAborted(signal);
|
|
220
|
+
if(typeof sourceRoot!=='string'||!sourceRoot.trim()){
|
|
221
|
+
fail('sdkRuntimeSourceRoot must name an Arcane SDK directory.',
|
|
222
|
+
'ARCANE_DEV_RUNTIME_SOURCE_INVALID');
|
|
223
|
+
}
|
|
224
|
+
const requestedRoot=path.resolve(sourceRoot);
|
|
225
|
+
await emitRuntimeSourceEvent(onEvent,{
|
|
226
|
+
type:'runtime.source.mount.started',
|
|
227
|
+
appId,
|
|
228
|
+
requestedRoot,
|
|
229
|
+
target:'browser'
|
|
230
|
+
});
|
|
231
|
+
const canonicalRoot=await canonicalRealDirectory(requestedRoot,'SDK runtime source root');
|
|
232
|
+
const canonicalWorkspaceRoot=await realpath(workspaceRoot);
|
|
233
|
+
if(pathsOverlap(canonicalRoot,canonicalWorkspaceRoot)){
|
|
234
|
+
fail('SDK runtime source root must not overlap the application workspace.',
|
|
235
|
+
'ARCANE_DEV_RUNTIME_SOURCE_INVALID');
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
let packageFile;
|
|
239
|
+
try{
|
|
240
|
+
packageFile=await openSafeFile(canonicalRoot,['package.json']);
|
|
241
|
+
}catch{
|
|
242
|
+
fail('SDK runtime source package.json must be a readable bounded real file.',
|
|
243
|
+
'ARCANE_DEV_RUNTIME_SOURCE_INVALID');
|
|
244
|
+
}
|
|
245
|
+
if(!packageFile){
|
|
246
|
+
fail('SDK runtime source root must contain a real package.json.',
|
|
247
|
+
'ARCANE_DEV_RUNTIME_SOURCE_INVALID');
|
|
248
|
+
}
|
|
249
|
+
let packageDocument;
|
|
250
|
+
try{
|
|
251
|
+
packageDocument=JSON.parse(packageFile.bytes.toString('utf8'));
|
|
252
|
+
}catch{
|
|
253
|
+
fail('SDK runtime source package.json must be valid JSON.',
|
|
254
|
+
'ARCANE_DEV_RUNTIME_SOURCE_INVALID');
|
|
255
|
+
}
|
|
256
|
+
if(!packageDocument||Array.isArray(packageDocument)||packageDocument.name!==SDK_NAME){
|
|
257
|
+
fail(`SDK runtime source package name must be exactly ${SDK_NAME}.`,
|
|
258
|
+
'ARCANE_DEV_RUNTIME_SOURCE_INVALID');
|
|
259
|
+
}
|
|
260
|
+
if(packageDocument.version!==SDK_VERSION){
|
|
261
|
+
fail(
|
|
262
|
+
`SDK runtime source version must exactly match the executing SDK (${SDK_VERSION}).`,
|
|
263
|
+
'ARCANE_DEV_RUNTIME_VERSION_MISMATCH'
|
|
264
|
+
);
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
const roots=[
|
|
268
|
+
{
|
|
269
|
+
path:'runtime/arcane',
|
|
270
|
+
prefix:['arcane'],
|
|
271
|
+
allow:sdkArcaneSourcePathAllowed
|
|
272
|
+
},
|
|
273
|
+
{
|
|
274
|
+
path:'runtime/strong-type',
|
|
275
|
+
prefix:['arcane','dependencies','strong-type'],
|
|
276
|
+
allow:sdkDependencySourcePathAllowed
|
|
277
|
+
},
|
|
278
|
+
{
|
|
279
|
+
path:'browser-runtime',
|
|
280
|
+
prefix:['arcane','sdk'],
|
|
281
|
+
allow:sdkBrowserSourcePathAllowed
|
|
282
|
+
}
|
|
283
|
+
];
|
|
284
|
+
const mappings=[];
|
|
285
|
+
for(let index=0;index<roots.length;index+=1){
|
|
286
|
+
throwIfAborted(signal);
|
|
287
|
+
const root=roots[index];
|
|
288
|
+
const requested=path.join(canonicalRoot,...root.path.split('/'));
|
|
289
|
+
const canonical=await canonicalRealDirectory(requested,`SDK runtime source ${root.path}`);
|
|
290
|
+
if(!pathIsWithin(canonicalRoot,canonical)){
|
|
291
|
+
fail(`SDK runtime source ${root.path} must remain inside the SDK root.`,
|
|
292
|
+
'ARCANE_DEV_RUNTIME_SOURCE_INVALID');
|
|
293
|
+
}
|
|
294
|
+
mappings.push({prefix:root.prefix,root:canonical,allow:root.allow});
|
|
295
|
+
await emitRuntimeSourceEvent(onEvent,{
|
|
296
|
+
type:'runtime.source.mount.progress',
|
|
297
|
+
current:index+1,
|
|
298
|
+
total:roots.length,
|
|
299
|
+
path:root.path
|
|
300
|
+
});
|
|
301
|
+
}
|
|
302
|
+
const runtime=Object.freeze({
|
|
303
|
+
mode:'sdk-source',
|
|
304
|
+
protocol:SDK_RUNTIME_SOURCE_PROTOCOL,
|
|
305
|
+
sdkVersion:SDK_VERSION,
|
|
306
|
+
mutable:true,
|
|
307
|
+
distributionAuthority:false,
|
|
308
|
+
sourceRoot:canonicalRoot
|
|
309
|
+
});
|
|
310
|
+
await emitRuntimeSourceEvent(onEvent,{
|
|
311
|
+
type:'runtime.source.mount.ready',
|
|
312
|
+
appId,
|
|
313
|
+
canonicalRoot,
|
|
314
|
+
sdkVersion:SDK_VERSION,
|
|
315
|
+
protocol:SDK_RUNTIME_SOURCE_PROTOCOL,
|
|
316
|
+
routeCount:mappings.length
|
|
317
|
+
});
|
|
318
|
+
return {mappings,runtime};
|
|
319
|
+
}
|
|
320
|
+
|
|
142
321
|
function identityMap(identities,prefix=''){
|
|
143
322
|
const normalizedPrefix=prefix?`${prefix}/`:'';
|
|
144
323
|
const result=new Map();
|
|
@@ -346,8 +525,34 @@ function sharedPathAllowed(relative,route){
|
|
|
346
525
|
});
|
|
347
526
|
}
|
|
348
527
|
|
|
349
|
-
async function sourceRoutes(workspaceRoot,appId,{
|
|
528
|
+
async function sourceRoutes(workspaceRoot,appId,{
|
|
529
|
+
workspaceRuntimeReceipt,
|
|
530
|
+
sdkRuntimeSourceRoot,
|
|
531
|
+
signal,
|
|
532
|
+
onEvent
|
|
533
|
+
}){
|
|
350
534
|
const resolved=await resolveWorkspace({workspaceRoot,appId});
|
|
535
|
+
const appMapping={
|
|
536
|
+
prefix:['apps',resolved.appId],
|
|
537
|
+
root:resolved.appRoot,
|
|
538
|
+
allow:relative=>sourcePathAllowed(relative,resolved.app.manifest)
|
|
539
|
+
};
|
|
540
|
+
if(sdkRuntimeSourceRoot!==undefined){
|
|
541
|
+
const sdkSource=await verifySdkRuntimeSourceRoot(
|
|
542
|
+
sdkRuntimeSourceRoot,
|
|
543
|
+
resolved.workspaceRoot,
|
|
544
|
+
resolved.appId,
|
|
545
|
+
{signal,onEvent}
|
|
546
|
+
);
|
|
547
|
+
return {
|
|
548
|
+
workspaceRoot:resolved.workspaceRoot,
|
|
549
|
+
workspaceMode:resolved.config.workspaceMode,
|
|
550
|
+
appId:resolved.appId,
|
|
551
|
+
startPath:`/apps/${resolved.appId}/${resolved.app.manifest.entry}`,
|
|
552
|
+
runtime:sdkSource.runtime,
|
|
553
|
+
mappings:[appMapping,...sdkSource.mappings]
|
|
554
|
+
};
|
|
555
|
+
}
|
|
351
556
|
if(resolved.config.workspaceMode==='integrated'){
|
|
352
557
|
return {
|
|
353
558
|
workspaceRoot:resolved.workspaceRoot,
|
|
@@ -355,11 +560,7 @@ async function sourceRoutes(workspaceRoot,appId,{workspaceRuntimeReceipt,signal}
|
|
|
355
560
|
appId:resolved.appId,
|
|
356
561
|
startPath:`/apps/${resolved.appId}/${resolved.app.manifest.entry}`,
|
|
357
562
|
mappings:[
|
|
358
|
-
|
|
359
|
-
prefix:['apps',resolved.appId],
|
|
360
|
-
root:resolved.appRoot,
|
|
361
|
-
allow:relative=>sourcePathAllowed(relative,resolved.app.manifest)
|
|
362
|
-
},
|
|
563
|
+
appMapping,
|
|
363
564
|
...resolved.config.sharedPayloads['browser-runtime'].map(route=>({
|
|
364
565
|
prefix:route.destination.split('/'),
|
|
365
566
|
root:path.join(resolved.workspaceRoot,...route.source.split('/')),
|
|
@@ -369,24 +570,29 @@ async function sourceRoutes(workspaceRoot,appId,{workspaceRuntimeReceipt,signal}
|
|
|
369
570
|
};
|
|
370
571
|
}
|
|
371
572
|
const runtimeRoot=path.join(resolved.workspaceRoot,'arcane');
|
|
573
|
+
const validation=await validateWorkspace({
|
|
574
|
+
workspaceRoot:resolved.workspaceRoot,
|
|
575
|
+
appId:resolved.appId,
|
|
576
|
+
allowMissingManagedImportMap:true,
|
|
577
|
+
signal
|
|
578
|
+
});
|
|
579
|
+
const sdkInstallation=validation.sdkInstallation;
|
|
580
|
+
if(!sdkInstallation
|
|
581
|
+
||typeof sdkInstallation.runtimeRoot!=='string'
|
|
582
|
+
||typeof sdkInstallation.browserRuntimeRoot!=='string'){
|
|
583
|
+
fail(
|
|
584
|
+
'Validated external workspace is missing its bound SDK installation authority.',
|
|
585
|
+
'ARCANE_WORKSPACE_INVALID'
|
|
586
|
+
);
|
|
587
|
+
}
|
|
372
588
|
let verified=workspaceRuntimeReceipt;
|
|
373
589
|
if(!verified){
|
|
374
|
-
const sdkRuntimeRoot=
|
|
375
|
-
resolved.workspaceRoot,
|
|
376
|
-
'node_modules',
|
|
377
|
-
'arcane-os',
|
|
378
|
-
'runtime'
|
|
379
|
-
);
|
|
590
|
+
const sdkRuntimeRoot=sdkInstallation.runtimeRoot;
|
|
380
591
|
const sdkRuntimeReceipt=await verifyRuntime({
|
|
381
592
|
runtimeRoot:sdkRuntimeRoot,
|
|
382
593
|
signal
|
|
383
594
|
});
|
|
384
|
-
const sdkBrowserRuntimeRoot=
|
|
385
|
-
resolved.workspaceRoot,
|
|
386
|
-
'node_modules',
|
|
387
|
-
'arcane-os',
|
|
388
|
-
'browser-runtime'
|
|
389
|
-
);
|
|
595
|
+
const sdkBrowserRuntimeRoot=sdkInstallation.browserRuntimeRoot;
|
|
390
596
|
const sdkBrowserRuntimeReceipt=await verifySdkBrowserRuntime({
|
|
391
597
|
browserRuntimeRoot:sdkBrowserRuntimeRoot,
|
|
392
598
|
signal
|
|
@@ -404,6 +610,17 @@ async function sourceRoutes(workspaceRoot,appId,{workspaceRuntimeReceipt,signal}
|
|
|
404
610
|
workspaceRoot:resolved.workspaceRoot,
|
|
405
611
|
signal
|
|
406
612
|
});
|
|
613
|
+
if(typeof verified.sourceRuntimeLocation!=='string'
|
|
614
|
+
||typeof verified.sourceBrowserRuntimeLocation!=='string'
|
|
615
|
+
||canonicalLocationKey(verified.sourceRuntimeLocation)
|
|
616
|
+
!==canonicalLocationKey(sdkInstallation.runtimeRoot)
|
|
617
|
+
||canonicalLocationKey(verified.sourceBrowserRuntimeLocation)
|
|
618
|
+
!==canonicalLocationKey(sdkInstallation.browserRuntimeRoot)){
|
|
619
|
+
fail(
|
|
620
|
+
'Workspace runtime receipt sources do not match the bound SDK installation authority.',
|
|
621
|
+
'ARCANE_INTEGRITY_FAILED'
|
|
622
|
+
);
|
|
623
|
+
}
|
|
407
624
|
const arcaneIdentities=identityMap(verified.identities);
|
|
408
625
|
return {
|
|
409
626
|
workspaceRoot:resolved.workspaceRoot,
|
|
@@ -411,11 +628,7 @@ async function sourceRoutes(workspaceRoot,appId,{workspaceRuntimeReceipt,signal}
|
|
|
411
628
|
appId:resolved.appId,
|
|
412
629
|
startPath:`/apps/${resolved.appId}/${resolved.app.manifest.entry}`,
|
|
413
630
|
mappings:[
|
|
414
|
-
|
|
415
|
-
prefix:['apps',resolved.appId],
|
|
416
|
-
root:resolved.appRoot,
|
|
417
|
-
allow:relative=>sourcePathAllowed(relative,resolved.app.manifest)
|
|
418
|
-
},
|
|
631
|
+
appMapping,
|
|
419
632
|
{
|
|
420
633
|
prefix:['arcane'],
|
|
421
634
|
root:runtimeRoot,
|
|
@@ -506,18 +719,33 @@ async function startOwnedDevServer({
|
|
|
506
719
|
port=0,
|
|
507
720
|
signal,
|
|
508
721
|
workspaceRuntimeReceipt,
|
|
722
|
+
sdkRuntimeSourceRoot,
|
|
509
723
|
releaseReceipt
|
|
510
724
|
}={},events,releaseSignal){
|
|
511
725
|
throwIfAborted(signal);
|
|
512
726
|
if(mode!=='source'&&mode!=='packaged')fail(`Unsupported server mode: ${String(mode)}.`,'ARCANE_USAGE');
|
|
727
|
+
if(sdkRuntimeSourceRoot!==undefined&&mode!=='source'){
|
|
728
|
+
fail('sdkRuntimeSourceRoot is supported only in source development mode.','ARCANE_USAGE');
|
|
729
|
+
}
|
|
513
730
|
if(host!=='127.0.0.1'&&host!=='::1'){
|
|
514
731
|
fail('Development server host must be a numeric loopback address (127.0.0.1 or ::1).','ARCANE_POLICY_DENIED');
|
|
515
732
|
}
|
|
516
733
|
if(!Number.isInteger(port)||port<0||port>65535)fail('port must be an integer from 0 through 65535.','ARCANE_USAGE');
|
|
517
|
-
|
|
734
|
+
const requestedRuntimeMode=mode==='source'&&sdkRuntimeSourceRoot!==undefined
|
|
735
|
+
?'sdk-source'
|
|
736
|
+
:null;
|
|
737
|
+
await events.send({
|
|
738
|
+
type:'server.starting',
|
|
739
|
+
mode,
|
|
740
|
+
host,
|
|
741
|
+
port,
|
|
742
|
+
appId,
|
|
743
|
+
...(requestedRuntimeMode?{runtimeMode:requestedRuntimeMode}:{})
|
|
744
|
+
});
|
|
518
745
|
const routeSet=mode==='source'
|
|
519
746
|
?await sourceRoutes(workspaceRoot,appId,{
|
|
520
747
|
workspaceRuntimeReceipt,
|
|
748
|
+
sdkRuntimeSourceRoot,
|
|
521
749
|
signal,
|
|
522
750
|
onEvent:event=>events.send(event)
|
|
523
751
|
})
|
|
@@ -647,6 +875,17 @@ async function startOwnedDevServer({
|
|
|
647
875
|
while(requestTasks.size>0){
|
|
648
876
|
await Promise.allSettled([...requestTasks]);
|
|
649
877
|
}
|
|
878
|
+
if(routeSet.runtime?.mode==='sdk-source'){
|
|
879
|
+
await events.send({
|
|
880
|
+
type:'runtime.source.mount.stopped',
|
|
881
|
+
appId:routeSet.appId,
|
|
882
|
+
reason:events.error||operationalError
|
|
883
|
+
?'failed'
|
|
884
|
+
:signal?.aborted
|
|
885
|
+
?'cancelled'
|
|
886
|
+
:'closed'
|
|
887
|
+
});
|
|
888
|
+
}
|
|
650
889
|
await events.send({
|
|
651
890
|
type:'server.stopped',
|
|
652
891
|
host:address.address,
|
|
@@ -695,6 +934,10 @@ async function startOwnedDevServer({
|
|
|
695
934
|
mode,
|
|
696
935
|
workspaceRoot:routeSet.workspaceRoot,
|
|
697
936
|
appId:routeSet.appId,
|
|
937
|
+
...(routeSet.runtime?{
|
|
938
|
+
runtimeMode:routeSet.runtime.mode,
|
|
939
|
+
runtime:routeSet.runtime
|
|
940
|
+
}:{}),
|
|
698
941
|
host:address.address,
|
|
699
942
|
port:address.port,
|
|
700
943
|
origin,
|
|
@@ -711,7 +954,11 @@ async function startOwnedDevServer({
|
|
|
711
954
|
host:result.host,
|
|
712
955
|
port:result.port,
|
|
713
956
|
url,
|
|
714
|
-
appId:result.appId
|
|
957
|
+
appId:result.appId,
|
|
958
|
+
...(routeSet.runtime?{
|
|
959
|
+
runtimeMode:routeSet.runtime.mode,
|
|
960
|
+
runtime:routeSet.runtime
|
|
961
|
+
}:{})
|
|
715
962
|
});
|
|
716
963
|
throwIfAborted(signal);
|
|
717
964
|
}catch(error){
|
package/src/doctor.mjs
CHANGED
|
@@ -290,9 +290,7 @@ export async function runDoctor({
|
|
|
290
290
|
));
|
|
291
291
|
}else if(result.workspaceMode==='external'){
|
|
292
292
|
try{
|
|
293
|
-
const
|
|
294
|
-
const runtimeRoot=path.join(installedRoot,'runtime');
|
|
295
|
-
const browserRuntimeRoot=path.join(installedRoot,'browser-runtime');
|
|
293
|
+
const {runtimeRoot,browserRuntimeRoot}=result.sdkInstallation;
|
|
296
294
|
const runtimeReceipt=await verifyRuntime({runtimeRoot,signal,onEvent});
|
|
297
295
|
const sdkBrowserRuntimeReceipt=await verifySdkBrowserRuntime({
|
|
298
296
|
browserRuntimeRoot,
|