arcane-os 0.69.0 → 0.71.0
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 +28 -0
- package/README.md +1 -1
- package/browser-runtime/ai/browser-decisions.mjs +46 -2
- package/browser-runtime/ai/browser-speech-artifacts.mjs +58 -62
- package/browser-runtime/ai/browser-speech-providers.mjs +3 -0
- package/browser-runtime/ai/browser-wasm-llm-provider.mjs +76 -164
- package/browser-runtime/ai/dbopfs-model-parts.mjs +344 -0
- package/browser-runtime/ai/dbopfs-model-resources.mjs +190 -0
- package/browser-runtime/ai/decision-runtime.mjs +17 -1
- package/browser-runtime/ai/decision-worker.mjs +21 -1
- package/browser-runtime/ai/model-resource-bridge.mjs +231 -0
- package/browser-runtime/ai/speech-worker-client.mjs +68 -28
- package/browser-runtime/ai/speech-worker-runtime.mjs +212 -97
- package/browser-runtime/core/contracts.mjs +1 -1
- package/docs/reference/README.md +2 -0
- package/docs/reference/ai/browser-decisions.md +57 -3
- package/docs/reference/ai/browser-speech.md +45 -17
- package/docs/reference/ai/browser-wasm.md +28 -20
- package/docs/reference/core-native-packaging.md +13 -0
- package/docs/reference/core-runtime.md +9 -0
- package/docs/reference/core-shared-host.md +190 -0
- package/docs/reference/inventory/package-api.json +3 -3
- package/docs/reference/inventory/runtime-components.json +2 -2
- package/docs/reference/inventory/runtime-modules.json +6 -6
- package/docs/reference/runtime-components.md +35 -1
- package/docs/reference/runtime-modules.md +97 -7
- package/docs/reference/sdk-api.md +69 -31
- package/package.json +2 -2
- package/runtime/arcane/components/theme-switcher.html +4 -4
- package/runtime/arcane/modules/AI.js +2 -18
- package/runtime/arcane/modules/AIProviderRuntime.js +77 -3
- package/runtime/arcane/modules/DBOPFS.js +180 -26
- package/src/core/host.mjs +2 -0
- package/src/core/runtime.mjs +9 -4
- package/src/core/services/packaged-web.mjs +8 -1
- package/src/core/shared-host.mjs +500 -0
- package/src/native/portable-layout.mjs +66 -34
|
@@ -8,7 +8,8 @@ import {
|
|
|
8
8
|
const is=new Is(false);
|
|
9
9
|
|
|
10
10
|
const dbopfsEventTypes={
|
|
11
|
-
ready:'dbopfs-ready'
|
|
11
|
+
ready:'dbopfs-ready',
|
|
12
|
+
change:'dbopfs-change'
|
|
12
13
|
};
|
|
13
14
|
const dbopfsReasons={
|
|
14
15
|
ready:'opfs-database-ready'
|
|
@@ -117,6 +118,13 @@ if(navigator.storage?.persist){
|
|
|
117
118
|
class DBOPFS {
|
|
118
119
|
|
|
119
120
|
#events;
|
|
121
|
+
#changeChannel=null;
|
|
122
|
+
#changeOriginId=globalThis.crypto?.randomUUID?.()
|
|
123
|
+
||`dbopfs-${Date.now()}-${Math.random().toString(36).slice(2)}`;
|
|
124
|
+
#changeSequence=0;
|
|
125
|
+
#changeWindow=window;
|
|
126
|
+
#changesSuspended=false;
|
|
127
|
+
#cacheStates=new Map();
|
|
120
128
|
|
|
121
129
|
/** @type {FileSystemDirectoryHandle|Object} */
|
|
122
130
|
#db={}
|
|
@@ -286,6 +294,113 @@ class DBOPFS {
|
|
|
286
294
|
return `${tableName}:${fileName}`
|
|
287
295
|
}
|
|
288
296
|
|
|
297
|
+
#fileCacheState(tableName,fileName){
|
|
298
|
+
const directoryName=directoryNameForTable(tableName);
|
|
299
|
+
let table=this.#cacheStates.get(directoryName);
|
|
300
|
+
if(!table){
|
|
301
|
+
table=new Map();
|
|
302
|
+
this.#cacheStates.set(directoryName,table);
|
|
303
|
+
}
|
|
304
|
+
let state=table.get(fileName);
|
|
305
|
+
if(!state){
|
|
306
|
+
state={revision:0};
|
|
307
|
+
table.set(fileName,state);
|
|
308
|
+
}
|
|
309
|
+
return state;
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
#forgetFile(tableName,fileName,retire=false){
|
|
313
|
+
const directoryName=directoryNameForTable(tableName);
|
|
314
|
+
const registeredTableName=tableNameForDirectory(directoryName);
|
|
315
|
+
const states=this.#cacheStates.get(directoryName);
|
|
316
|
+
const state=states?.get(fileName);
|
|
317
|
+
if(state)state.revision+=1;
|
|
318
|
+
if(retire&&states){
|
|
319
|
+
states.delete(fileName);
|
|
320
|
+
if(states.size===0)this.#cacheStates.delete(directoryName);
|
|
321
|
+
}
|
|
322
|
+
for(const name of new Set([tableName,directoryName,registeredTableName])){
|
|
323
|
+
if(this.#tables[name])delete this.#tables[name][fileName];
|
|
324
|
+
}
|
|
325
|
+
}
|
|
326
|
+
|
|
327
|
+
#openChangeChannel(){
|
|
328
|
+
if(this.#changesSuspended||this.#changeChannel||!this.#applicationId)return;
|
|
329
|
+
const Channel=this.#changeWindow.BroadcastChannel;
|
|
330
|
+
if(!is.function(Channel))return;
|
|
331
|
+
try{
|
|
332
|
+
const channel=new Channel(`arcane.dbopfs.changes:${this.#storagePath}`);
|
|
333
|
+
const database=this;
|
|
334
|
+
channel.onmessage=function receiveCommittedChange(event){
|
|
335
|
+
const change=event.data;
|
|
336
|
+
if(!change||change.applicationId!==database.#applicationId
|
|
337
|
+
||change.storagePath!==database.#storagePath
|
|
338
|
+
||change.originId===database.#changeOriginId)return;
|
|
339
|
+
if(!['write','append','delete','table-delete'].includes(change.action)
|
|
340
|
+
||typeof change.tableName!=='string'
|
|
341
|
+
||typeof change.directoryName!=='string'
|
|
342
|
+
||typeof change.changeId!=='string'
|
|
343
|
+
||(change.action!=='table-delete'&&typeof change.fileName!=='string'))return;
|
|
344
|
+
database.#receiveChange(change);
|
|
345
|
+
};
|
|
346
|
+
channel.onmessageerror=function reportChangeMessageError(event){
|
|
347
|
+
arcaneLogging.error('DBOPFS could not receive a committed-change notification.',event);
|
|
348
|
+
};
|
|
349
|
+
this.#changeChannel=channel;
|
|
350
|
+
}catch(error){
|
|
351
|
+
arcaneLogging.error('DBOPFS cross-document notifications are unavailable; local storage remains available.',error);
|
|
352
|
+
}
|
|
353
|
+
}
|
|
354
|
+
|
|
355
|
+
#closeChangeChannel(){
|
|
356
|
+
if(!this.#changeChannel)return;
|
|
357
|
+
this.#changeChannel.onmessage=null;
|
|
358
|
+
this.#changeChannel.onmessageerror=null;
|
|
359
|
+
this.#changeChannel.close();
|
|
360
|
+
this.#changeChannel=null;
|
|
361
|
+
}
|
|
362
|
+
|
|
363
|
+
#receiveChange(change){
|
|
364
|
+
if(change.action==='table-delete'){
|
|
365
|
+
this.#forgetTable(change.tableName,change.directoryName,tableNameForDirectory(change.directoryName));
|
|
366
|
+
}else{
|
|
367
|
+
this.#forgetFile(change.tableName,change.fileName,change.action==='delete');
|
|
368
|
+
}
|
|
369
|
+
this.#events.dispatch(dbopfsEventTypes.change,{...change,remote:true},{operationId:change.changeId});
|
|
370
|
+
}
|
|
371
|
+
|
|
372
|
+
#commitChange(tableName,fileName,action){
|
|
373
|
+
const directoryName=directoryNameForTable(tableName);
|
|
374
|
+
const registeredTableName=tableNameForDirectory(directoryName);
|
|
375
|
+
if(action==='table-delete'){
|
|
376
|
+
this.#forgetTable(tableName,directoryName,registeredTableName);
|
|
377
|
+
}else{
|
|
378
|
+
this.#forgetFile(tableName,fileName,action==='delete');
|
|
379
|
+
}
|
|
380
|
+
this.#changeSequence+=1;
|
|
381
|
+
const change={
|
|
382
|
+
applicationId:this.#applicationId,
|
|
383
|
+
storagePath:this.#storagePath,
|
|
384
|
+
tableName:registeredTableName,
|
|
385
|
+
directoryName,
|
|
386
|
+
fileName,
|
|
387
|
+
action,
|
|
388
|
+
originId:this.#changeOriginId,
|
|
389
|
+
sequence:this.#changeSequence,
|
|
390
|
+
changeId:`${this.#changeOriginId}:${this.#changeSequence}`
|
|
391
|
+
};
|
|
392
|
+
// Notify the remote transport before synchronous local observers can
|
|
393
|
+
// start another mutation. Transport failure cannot undo a saved record.
|
|
394
|
+
if(this.#changeChannel){
|
|
395
|
+
try{
|
|
396
|
+
this.#changeChannel.postMessage(change);
|
|
397
|
+
}catch(error){
|
|
398
|
+
arcaneLogging.error('DBOPFS saved a change whose cross-document notification failed.',error);
|
|
399
|
+
}
|
|
400
|
+
}
|
|
401
|
+
this.#events.dispatch(dbopfsEventTypes.change,{...change,remote:false},{operationId:change.changeId});
|
|
402
|
+
}
|
|
403
|
+
|
|
289
404
|
/**
|
|
290
405
|
* Invalidates every known cache key for one logical/physical table pair.
|
|
291
406
|
* @private
|
|
@@ -294,6 +409,7 @@ class DBOPFS {
|
|
|
294
409
|
* @param {string} registeredTableName
|
|
295
410
|
*/
|
|
296
411
|
#forgetTable(tableName,directoryName,registeredTableName){
|
|
412
|
+
this.#cacheStates.delete(directoryName);
|
|
297
413
|
for(const name of new Set([
|
|
298
414
|
tableName,
|
|
299
415
|
directoryName,
|
|
@@ -320,6 +436,22 @@ class DBOPFS {
|
|
|
320
436
|
source:'dbopfs',
|
|
321
437
|
eventTypes:Object.values(dbopfsEventTypes)
|
|
322
438
|
});
|
|
439
|
+
const database=this;
|
|
440
|
+
this.#changeWindow.addEventListener('pagehide',function suspendDBOPFSChanges(){
|
|
441
|
+
database.#changesSuspended=true;
|
|
442
|
+
database.#closeChangeChannel();
|
|
443
|
+
});
|
|
444
|
+
this.#changeWindow.addEventListener('pageshow',function resumeDBOPFSChanges(){
|
|
445
|
+
if(!database.#changesSuspended)return;
|
|
446
|
+
database.#changesSuspended=false;
|
|
447
|
+
// Notifications have no history. Discard only this page's cached
|
|
448
|
+
// views after suspension; storage and committed events are unchanged.
|
|
449
|
+
database.#tables={};
|
|
450
|
+
database.#tableHandles={};
|
|
451
|
+
database.#tableHandlePromises={};
|
|
452
|
+
database.#cacheStates.clear();
|
|
453
|
+
database.#openChangeChannel();
|
|
454
|
+
});
|
|
323
455
|
this.readyPromise=this.#init(options);
|
|
324
456
|
}
|
|
325
457
|
|
|
@@ -340,6 +472,7 @@ class DBOPFS {
|
|
|
340
472
|
this.#applicationId=scope.applicationId;
|
|
341
473
|
this.#storagePath=scope.path;
|
|
342
474
|
this.#db=scope.directory;
|
|
475
|
+
this.#openChangeChannel();
|
|
343
476
|
|
|
344
477
|
this.ready=true;
|
|
345
478
|
|
|
@@ -382,6 +515,17 @@ class DBOPFS {
|
|
|
382
515
|
return this.#storagePath;
|
|
383
516
|
}
|
|
384
517
|
|
|
518
|
+
/**
|
|
519
|
+
* Observes committed record/table changes through the canonical event owner.
|
|
520
|
+
* Subscription is live-only; it does not replay records or load a table.
|
|
521
|
+
* @param {function} listener Receives an event whose detail is change metadata.
|
|
522
|
+
* @param {{signal?:AbortSignal,once?:boolean}} options
|
|
523
|
+
* @returns {function} Idempotent unsubscribe with a matching dispose method.
|
|
524
|
+
*/
|
|
525
|
+
subscribeChanges(listener,options={}){
|
|
526
|
+
return this.#events.subscribe(dbopfsEventTypes.change,listener,options);
|
|
527
|
+
}
|
|
528
|
+
|
|
385
529
|
/**
|
|
386
530
|
* Returns in-memory table cache.
|
|
387
531
|
*
|
|
@@ -444,7 +588,9 @@ class DBOPFS {
|
|
|
444
588
|
{create:true}
|
|
445
589
|
).then(
|
|
446
590
|
function registerRequestedTable(handle){
|
|
447
|
-
this.#
|
|
591
|
+
if(this.#tableHandlePromises[registeredTableName]===handlePromise){
|
|
592
|
+
this.#tableHandles[registeredTableName]=handle;
|
|
593
|
+
}
|
|
448
594
|
return handle;
|
|
449
595
|
}.bind(this)
|
|
450
596
|
);
|
|
@@ -489,6 +635,10 @@ class DBOPFS {
|
|
|
489
635
|
dataToWrite=JSON.stringify(dataToWrite)
|
|
490
636
|
}
|
|
491
637
|
|
|
638
|
+
const cacheState=this.#fileCacheState(tableName,fileName);
|
|
639
|
+
const cacheRevision=cacheState.revision;
|
|
640
|
+
const result=append?true:parseFileValue(fileName,String(dataToWrite));
|
|
641
|
+
|
|
492
642
|
try{
|
|
493
643
|
await this.writeFile(
|
|
494
644
|
tableName,
|
|
@@ -497,20 +647,20 @@ class DBOPFS {
|
|
|
497
647
|
append
|
|
498
648
|
);
|
|
499
649
|
|
|
500
|
-
if(append)
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
this.#tables[tableName][fileName]=
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
);
|
|
650
|
+
if(!append&&this.#fileCacheState(tableName,fileName)===cacheState
|
|
651
|
+
&&cacheState.revision<=cacheRevision+1){
|
|
652
|
+
if(!this.#tables[tableName])this.#tables[tableName]={};
|
|
653
|
+
this.#tables[tableName][fileName]=result;
|
|
654
|
+
}
|
|
655
|
+
if(append&&cacheState.revision===cacheRevision){
|
|
656
|
+
this.#forgetFile(tableName,fileName);
|
|
507
657
|
}
|
|
508
658
|
}catch(error){
|
|
509
659
|
arcaneLogging.error(`Error writing file '${fileName}' to table '${tableName}':`,error)
|
|
510
660
|
throw error
|
|
511
661
|
}
|
|
512
662
|
|
|
513
|
-
return
|
|
663
|
+
return result
|
|
514
664
|
}.bind(this)
|
|
515
665
|
)
|
|
516
666
|
|
|
@@ -547,12 +697,14 @@ class DBOPFS {
|
|
|
547
697
|
);
|
|
548
698
|
|
|
549
699
|
if(!is.function(handle.createWritable)){
|
|
550
|
-
|
|
700
|
+
await this.#writeFileWithWorker(
|
|
551
701
|
table.name,
|
|
552
702
|
fileName,
|
|
553
703
|
fileData,
|
|
554
704
|
append
|
|
555
705
|
);
|
|
706
|
+
this.#commitChange(tableName,fileName,append?'append':'write');
|
|
707
|
+
return true;
|
|
556
708
|
}
|
|
557
709
|
|
|
558
710
|
const writable=await handle.createWritable(
|
|
@@ -572,6 +724,7 @@ class DBOPFS {
|
|
|
572
724
|
|
|
573
725
|
await writable.write(blob);
|
|
574
726
|
await writable.close();
|
|
727
|
+
this.#commitChange(tableName,fileName,append?'append':'write');
|
|
575
728
|
|
|
576
729
|
return true
|
|
577
730
|
}
|
|
@@ -669,6 +822,8 @@ class DBOPFS {
|
|
|
669
822
|
*/
|
|
670
823
|
async get(tableName='',fileName='',force=false){
|
|
671
824
|
if(force||!this.#tables[tableName]?.[fileName]){
|
|
825
|
+
const cacheState=this.#fileCacheState(tableName,fileName);
|
|
826
|
+
const cacheRevision=cacheState.revision;
|
|
672
827
|
try{
|
|
673
828
|
const file=await this.readFile(tableName,fileName)
|
|
674
829
|
const textContent=await file.text()
|
|
@@ -677,12 +832,15 @@ class DBOPFS {
|
|
|
677
832
|
this.#tables[tableName]={}
|
|
678
833
|
}
|
|
679
834
|
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
835
|
+
const value=parseFileValue(fileName,textContent);
|
|
836
|
+
if(this.#fileCacheState(tableName,fileName)===cacheState
|
|
837
|
+
&&cacheState.revision===cacheRevision){
|
|
838
|
+
this.#tables[tableName][fileName]=value;
|
|
839
|
+
}
|
|
840
|
+
return value;
|
|
684
841
|
}catch(error){
|
|
685
842
|
if(error.name==='NotFoundError'){
|
|
843
|
+
this.#forgetFile(tableName,fileName,true);
|
|
686
844
|
return null
|
|
687
845
|
}
|
|
688
846
|
|
|
@@ -788,15 +946,13 @@ class DBOPFS {
|
|
|
788
946
|
|
|
789
947
|
try{
|
|
790
948
|
await table.removeEntry(fileName)
|
|
949
|
+
this.#commitChange(tableName,fileName,'delete');
|
|
791
950
|
}catch(error){
|
|
792
951
|
if(error.name!=='NotFoundError'){
|
|
793
952
|
arcaneLogging.error(error)
|
|
794
953
|
throw error
|
|
795
954
|
}
|
|
796
|
-
|
|
797
|
-
|
|
798
|
-
if(this.#tables[tableName]){
|
|
799
|
-
delete this.#tables[tableName][fileName]
|
|
955
|
+
this.#forgetFile(tableName,fileName,true);
|
|
800
956
|
}
|
|
801
957
|
|
|
802
958
|
return true
|
|
@@ -831,13 +987,9 @@ class DBOPFS {
|
|
|
831
987
|
|
|
832
988
|
try{
|
|
833
989
|
await this.#db.removeEntry(directoryName,{recursive:true})
|
|
834
|
-
|
|
835
|
-
delete this.#tables[tableName]
|
|
836
|
-
delete this.#tables[directoryName]
|
|
837
|
-
delete this.#tables[registeredTableName]
|
|
838
|
-
delete this.#tableHandles[registeredTableName]
|
|
839
|
-
delete this.#tableHandlePromises[registeredTableName]
|
|
990
|
+
this.#commitChange(tableName,null,'table-delete');
|
|
840
991
|
}catch(error){
|
|
992
|
+
if(error.name==='NotFoundError')this.#forgetTable(tableName,directoryName,registeredTableName);
|
|
841
993
|
arcaneLogging.error(error)
|
|
842
994
|
}
|
|
843
995
|
|
|
@@ -894,7 +1046,7 @@ class DBOPFS {
|
|
|
894
1046
|
}
|
|
895
1047
|
}
|
|
896
1048
|
|
|
897
|
-
this.#
|
|
1049
|
+
this.#commitChange(tableName,null,'table-delete');
|
|
898
1050
|
|
|
899
1051
|
return {
|
|
900
1052
|
status:'removed',
|
|
@@ -916,11 +1068,13 @@ class DBOPFS {
|
|
|
916
1068
|
|
|
917
1069
|
for await(const [name]of this.#db.entries()){
|
|
918
1070
|
await this.#db.removeEntry(name,{recursive:true})
|
|
1071
|
+
this.#commitChange(name,null,'table-delete');
|
|
919
1072
|
}
|
|
920
1073
|
|
|
921
1074
|
this.#tables={}
|
|
922
1075
|
this.#tableHandles={}
|
|
923
1076
|
this.#tableHandlePromises={}
|
|
1077
|
+
this.#cacheStates.clear();
|
|
924
1078
|
this.#writeLocks={}
|
|
925
1079
|
|
|
926
1080
|
return this
|
package/src/core/host.mjs
CHANGED
|
@@ -3,6 +3,8 @@ import Is from 'strong-type';
|
|
|
3
3
|
import {createCoreRuntime} from './runtime.mjs';
|
|
4
4
|
import {startCoreStdio} from './stdio.mjs';
|
|
5
5
|
|
|
6
|
+
export {startSharedCoreHost, connectSharedCoreHost, runSharedCoreHost, startSharedCoreBridge} from './shared-host.mjs';
|
|
7
|
+
|
|
6
8
|
const is = new Is(false);
|
|
7
9
|
|
|
8
10
|
/**
|
package/src/core/runtime.mjs
CHANGED
|
@@ -109,7 +109,12 @@ class CoreRuntime {
|
|
|
109
109
|
}
|
|
110
110
|
|
|
111
111
|
emit(event, data) {
|
|
112
|
-
|
|
112
|
+
return this.#emit(event, data);
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
#emit(event, data, requestId) {
|
|
116
|
+
const frame = {protocol: CORE_PROTOCOL, type: 'event', event, data,
|
|
117
|
+
...(requestId === undefined ? {} : {requestId}), time: new Date().toISOString()};
|
|
113
118
|
this.#events.dispatch(FRAME_EVENT, frame);
|
|
114
119
|
return frame;
|
|
115
120
|
}
|
|
@@ -158,7 +163,7 @@ class CoreRuntime {
|
|
|
158
163
|
return service.definition;
|
|
159
164
|
}
|
|
160
165
|
|
|
161
|
-
#serviceContext(service) {
|
|
166
|
+
#serviceContext(service, requestId) {
|
|
162
167
|
const runtime = this;
|
|
163
168
|
return {
|
|
164
169
|
application: this.#application,
|
|
@@ -167,7 +172,7 @@ class CoreRuntime {
|
|
|
167
172
|
return runtime.getService(name);
|
|
168
173
|
},
|
|
169
174
|
emit(event, data) {
|
|
170
|
-
return runtime
|
|
175
|
+
return runtime.#emit(event, data, requestId);
|
|
171
176
|
}
|
|
172
177
|
};
|
|
173
178
|
}
|
|
@@ -295,7 +300,7 @@ class CoreRuntime {
|
|
|
295
300
|
const result = await handle.call(
|
|
296
301
|
service.definition,
|
|
297
302
|
frame.parameters,
|
|
298
|
-
{...runtime.#serviceContext(service), requestId: frame.id, signal: controller.signal}
|
|
303
|
+
{...runtime.#serviceContext(service, frame.id), requestId: frame.id, signal: controller.signal}
|
|
299
304
|
);
|
|
300
305
|
aborted(controller);
|
|
301
306
|
return result;
|
|
@@ -8,8 +8,10 @@ export function createPackagedWebService({artifactRoot}, context = {}) {
|
|
|
8
8
|
let server;
|
|
9
9
|
let closing = false;
|
|
10
10
|
let lifetime;
|
|
11
|
+
let current = null;
|
|
11
12
|
return {
|
|
12
13
|
name: 'packaged-web',
|
|
14
|
+
current() { return current === null ? null : {...current}; },
|
|
13
15
|
async start(runtime) {
|
|
14
16
|
const manifest = JSON.parse(await readFile(path.join(artifactRoot, 'arcane-native.json'), 'utf8'));
|
|
15
17
|
// The launcher chooses app state independently of its installation.
|
|
@@ -48,9 +50,11 @@ export function createPackagedWebService({artifactRoot}, context = {}) {
|
|
|
48
50
|
await writeFile(originFile, JSON.stringify({host: '127.0.0.1', port: server.port}) + '\n', {flag: 'wx'});
|
|
49
51
|
}
|
|
50
52
|
const url = new URL(manifest.start, server.origin).href;
|
|
51
|
-
|
|
53
|
+
current = {origin: server.origin, url, port: server.port};
|
|
54
|
+
runtime.emit('core.web.ready', {...current});
|
|
52
55
|
lifetime = server.lifecycle.then(
|
|
53
56
|
function packagedServerEnded() {
|
|
57
|
+
current = null;
|
|
54
58
|
if (!closing) {
|
|
55
59
|
runtime.emit('core.web.failed', serializeCoreError(
|
|
56
60
|
new Error('The packaged application listener closed unexpectedly.')
|
|
@@ -58,6 +62,7 @@ export function createPackagedWebService({artifactRoot}, context = {}) {
|
|
|
58
62
|
}
|
|
59
63
|
},
|
|
60
64
|
function packagedServerFailed(error) {
|
|
65
|
+
current = null;
|
|
61
66
|
if (!closing) runtime.emit('core.web.failed', serializeCoreError(error));
|
|
62
67
|
throw error;
|
|
63
68
|
}
|
|
@@ -66,6 +71,7 @@ export function createPackagedWebService({artifactRoot}, context = {}) {
|
|
|
66
71
|
// now; the native diagnostic event owns immediate reporting.
|
|
67
72
|
lifetime.catch(function observePackagedServerFailure() {});
|
|
68
73
|
} catch (error) {
|
|
74
|
+
current = null;
|
|
69
75
|
closing = true;
|
|
70
76
|
if (server) {
|
|
71
77
|
try { await server.close(); }
|
|
@@ -78,6 +84,7 @@ export function createPackagedWebService({artifactRoot}, context = {}) {
|
|
|
78
84
|
},
|
|
79
85
|
async drain() {
|
|
80
86
|
closing = true;
|
|
87
|
+
current = null;
|
|
81
88
|
if (!server) return;
|
|
82
89
|
const results = await Promise.allSettled([server.close(), server.closed, lifetime]);
|
|
83
90
|
const failures = [...new Set(results.filter(function rejected(result) {
|