arcane-os 0.3.4 → 0.3.6
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 +22 -0
- package/README.md +7 -7
- package/browser-runtime/ai/browser-wasm-llm-provider.mjs +315 -119
- package/browser-runtime/ai/model-controller.mjs +439 -95
- package/package.json +1 -1
- package/runtime/arcane/components/assistant-panel.html +2 -1
- package/runtime/arcane/components/chat.html +469 -220
- package/runtime/arcane/components/speech.html +33 -13
- package/runtime/arcane/components/voice-transcription.html +27 -3
- package/runtime/arcane/entities/Chat.js +165 -97
- package/runtime/arcane/entities/IntentEnvelope.js +52 -118
- package/runtime/arcane/entities/TWiNPolicyDecision.js +33 -130
- package/runtime/arcane/entities/User.js +38 -44
- package/runtime/arcane/modules/AI.js +569 -302
- package/runtime/arcane/modules/AIProviderRuntime.js +776 -151
- package/runtime/arcane/modules/AIRuntimeState.js +22 -24
- package/runtime/arcane/modules/ApiModelDatabase.js +54 -48
- package/runtime/arcane/modules/CaseEvidenceIndexer.js +6 -10
- package/runtime/arcane/modules/CommunicationHub.js +90 -94
- package/runtime/arcane/modules/ComponentContracts.js +23 -9
- package/runtime/arcane/modules/ConfiguredAIChatSession.js +77 -77
- package/runtime/arcane/modules/ConversationTimebox.js +76 -104
- package/runtime/arcane/modules/DBLS.js +14 -12
- package/runtime/arcane/modules/DBOPFS.js +20 -15
- package/runtime/arcane/modules/Errors.js +196 -436
- package/runtime/arcane/modules/HTMLImport.js +49 -32
- package/runtime/arcane/modules/Ollama.js +16 -14
- package/runtime/arcane/modules/PersistentAIChatSession.js +174 -93
- package/runtime/arcane/modules/RecordReviewStore.js +40 -35
- package/runtime/arcane/modules/TerminalClient.js +12 -14
- package/runtime/arcane/modules/ThemeBootstrap.js +7 -7
- package/runtime/arcane/modules/ThemeManager.js +5 -5
- package/runtime/arcane/modules/TimeGuard.js +5 -65
- package/runtime/arcane/modules/WaitForComponent.js +43 -40
- package/src/installed-sdk-runtime.mjs +11 -1
|
@@ -4,17 +4,17 @@ const CONVERSATION_TIMEBOX_TOOL_NAME='conversation_timebox';
|
|
|
4
4
|
const CONVERSATION_TIMEBOX_TICK_MS=1000;
|
|
5
5
|
const MAX_DATE_MILLISECONDS=8_640_000_000_000_000;
|
|
6
6
|
|
|
7
|
-
|
|
7
|
+
const conversationTimeboxEventTypes={
|
|
8
8
|
change:'conversation-timebox-change'
|
|
9
|
-
}
|
|
9
|
+
};
|
|
10
10
|
|
|
11
|
-
|
|
11
|
+
const conversationTimeboxErrorCodes={
|
|
12
12
|
disposed:'ARCANE_CONVERSATION_TIMEBOX_DISPOSED',
|
|
13
13
|
subscriptionHandlerInvalid:'ARCANE_CONVERSATION_TIMEBOX_SUBSCRIPTION_HANDLER_INVALID',
|
|
14
14
|
subscriptionOptionsInvalid:'ARCANE_CONVERSATION_TIMEBOX_SUBSCRIPTION_OPTIONS_INVALID'
|
|
15
|
-
}
|
|
15
|
+
};
|
|
16
16
|
|
|
17
|
-
|
|
17
|
+
const conversationTimeboxReasons={
|
|
18
18
|
deadlineReached:'conversation-timebox-deadline-reached',
|
|
19
19
|
disposed:'conversation-timebox-disposed',
|
|
20
20
|
elapsedTimeAdvanced:'conversation-timebox-elapsed-time-advanced',
|
|
@@ -23,47 +23,49 @@ export const CONVERSATION_TIMEBOX_REASONS=Object.freeze({
|
|
|
23
23
|
limitSet:'conversation-timebox-limit-set',
|
|
24
24
|
snapshotReplayed:'conversation-timebox-snapshot-replayed',
|
|
25
25
|
started:'conversation-timebox-started'
|
|
26
|
-
}
|
|
26
|
+
};
|
|
27
|
+
|
|
28
|
+
export const CONVERSATION_TIMEBOX_EVENT_TYPES={...conversationTimeboxEventTypes};
|
|
29
|
+
export const CONVERSATION_TIMEBOX_ERROR_CODES={...conversationTimeboxErrorCodes};
|
|
30
|
+
export const CONVERSATION_TIMEBOX_REASONS={...conversationTimeboxReasons};
|
|
27
31
|
|
|
28
|
-
const CONVERSATION_TIMEBOX_OPENING_INSTRUCTION=`Before any other intake question, ask exactly one timing question: "Do you have a limited amount of time to talk right now?" Ask no other question in that opening reply, and wait for the answer before continuing the app's normal intake. The elapsed conversation timer is already visible. A time limit applies only to this conversation. Never infer, round, or invent a duration. The conversation_timebox tool is available on every turn. When the user explicitly sets a duration, call it with action "set" and convert the exact stated duration to whole milliseconds. When the user explicitly adds time, call it with action "adjust" and convert the exact added duration to whole milliseconds. When the user explicitly says there is no limit, asks to remove it, or chooses to continue after a due check without setting another duration, call it with action "clear". Every call must include a nonempty message containing the brief plain-language progress or next-step text shown to the user; do not claim the time check changed before the tool result confirms it. A duration is always sent as duration_milliseconds; for example, 75 seconds is 75000 and 10 minutes is 600000. If the duration is vague or ranged, ask one focused question and do not call the tool yet.
|
|
32
|
+
const CONVERSATION_TIMEBOX_OPENING_INSTRUCTION=`Before any other intake question, ask exactly one timing question: "Do you have a limited amount of time to talk right now?" Ask no other question in that opening reply, and wait for the answer before continuing the app's normal intake. The elapsed conversation timer is already visible. A time limit applies only to this conversation. Never infer, round, or invent a duration. The conversation_timebox tool is available on every turn. When the user explicitly sets a duration, call it with action "set" and convert the exact stated duration to whole milliseconds. When the user explicitly adds time, call it with action "adjust" and convert the exact added duration to whole milliseconds. When the user explicitly says there is no limit, asks to remove it, or chooses to continue after a due check without setting another duration, call it with action "clear". Every call must include a nonempty message containing the brief plain-language progress or next-step text shown to the user; do not claim the time check changed before the tool result confirms it. A duration is always sent as duration_milliseconds; for example, 75 seconds is 75000 and 10 minutes is 600000. If the duration is vague or ranged, ask one focused question and do not call the tool yet. Adapt the pace and prioritize the most important next action within an active limit without skipping safety. A message that the agreed time check is due is a check-in, not a request to end: ask whether the user wants to end now or continue, and do not assume their choice.`;
|
|
29
33
|
|
|
30
34
|
const CONVERSATION_TIMEBOX_LIMIT_MESSAGE='The agreed conversation time check is due. Please ask whether I want to end now or continue, and do not assume my choice or set another limit unless I explicitly state one.';
|
|
31
35
|
|
|
32
|
-
const conversationTimeboxTool=
|
|
36
|
+
const conversationTimeboxTool={
|
|
33
37
|
type:'function',
|
|
34
|
-
function:
|
|
38
|
+
function:{
|
|
35
39
|
name:CONVERSATION_TIMEBOX_TOOL_NAME,
|
|
36
|
-
description:'Control the current conversation time check whenever the user explicitly sets, adds, removes, or continues past it. Use
|
|
37
|
-
parameters:
|
|
40
|
+
description:'Control the current conversation time check whenever the user explicitly sets, adds, removes, or continues past it. Use action "set" to replace the deadline relative to now, "adjust" to add time to the active deadline, and "clear" to remove the deadline, including continuing after a due check without a new duration. Convert exact stated units to whole milliseconds; never infer, round, or choose a default.',
|
|
41
|
+
parameters:{
|
|
38
42
|
type:'object',
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
action:Object.freeze({
|
|
43
|
+
properties:{
|
|
44
|
+
action:{
|
|
42
45
|
type:'string',
|
|
43
|
-
enum:
|
|
46
|
+
enum:['set','adjust','clear'],
|
|
44
47
|
description:'Set a new deadline, add time to the active deadline, or clear the deadline.'
|
|
45
|
-
}
|
|
48
|
+
},
|
|
46
49
|
message:{
|
|
47
50
|
type:'string',
|
|
48
51
|
minLength:1,
|
|
49
52
|
description:'Brief plain-language progress or next-step text shown to the user for this tool call. Do not claim the time check changed before the tool result confirms it.'
|
|
50
53
|
},
|
|
51
|
-
duration_milliseconds:
|
|
54
|
+
duration_milliseconds:{
|
|
52
55
|
type:'integer',
|
|
53
56
|
minimum:0,
|
|
54
57
|
description:'The exact positive whole-millisecond duration. Required for "set" and "adjust"; ignored for "clear". Examples: 75 seconds = 75000; 10 minutes = 600000.'
|
|
55
|
-
}
|
|
56
|
-
}
|
|
57
|
-
required:
|
|
58
|
-
}
|
|
59
|
-
}
|
|
60
|
-
}
|
|
58
|
+
}
|
|
59
|
+
},
|
|
60
|
+
required:['action','message']
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
};
|
|
61
64
|
|
|
62
65
|
function isPlainRecord(value){
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
&&Object.getPrototypeOf(value)===Object.prototype;
|
|
66
|
+
if(!value||typeof value!=='object'||Array.isArray(value))return false;
|
|
67
|
+
const prototype=Object.getPrototypeOf(value);
|
|
68
|
+
return prototype===Object.prototype||prototype===null;
|
|
67
69
|
}
|
|
68
70
|
|
|
69
71
|
function parseToolArguments(value){
|
|
@@ -89,14 +91,6 @@ function parseToolArguments(value){
|
|
|
89
91
|
|
|
90
92
|
function normalizeConversationTimeboxCommand(value){
|
|
91
93
|
const input=parseToolArguments(value);
|
|
92
|
-
const allowed=new Set(['action','duration_milliseconds','message']);
|
|
93
|
-
const unsupported=Object.keys(input).find(function findUnsupportedTimeboxField(key){
|
|
94
|
-
return !allowed.has(key);
|
|
95
|
-
});
|
|
96
|
-
|
|
97
|
-
if(unsupported){
|
|
98
|
-
throw new TypeError(`Unsupported conversation timebox field: ${unsupported}`);
|
|
99
|
-
}
|
|
100
94
|
if(!['set','adjust','clear'].includes(input.action)){
|
|
101
95
|
throw new TypeError('Conversation timebox action must be "set", "adjust", or "clear".');
|
|
102
96
|
}
|
|
@@ -104,16 +98,17 @@ function normalizeConversationTimeboxCommand(value){
|
|
|
104
98
|
throw new TypeError('Conversation timebox message must contain user-facing text.');
|
|
105
99
|
}
|
|
106
100
|
if(input.action==='clear'){
|
|
107
|
-
return
|
|
101
|
+
return {...input,action:'clear',message:input.message};
|
|
108
102
|
}
|
|
109
103
|
if(!Number.isSafeInteger(input.duration_milliseconds)||input.duration_milliseconds<=0){
|
|
110
104
|
throw new TypeError('duration_milliseconds must be an explicit positive whole number.');
|
|
111
105
|
}
|
|
112
|
-
return
|
|
106
|
+
return {
|
|
107
|
+
...input,
|
|
113
108
|
action:input.action,
|
|
114
109
|
durationMilliseconds:input.duration_milliseconds,
|
|
115
110
|
message:input.message
|
|
116
|
-
}
|
|
111
|
+
};
|
|
117
112
|
}
|
|
118
113
|
|
|
119
114
|
function appendConversationTimeboxOpeningInstruction(message=''){
|
|
@@ -195,16 +190,12 @@ function normalizeSubscriptionOptions(value={}){
|
|
|
195
190
|
if(!isPlainRecord(value)){
|
|
196
191
|
throw conversationTimeboxError(
|
|
197
192
|
'Conversation timebox subscription options must be a plain object.',
|
|
198
|
-
|
|
193
|
+
conversationTimeboxErrorCodes.subscriptionOptionsInvalid,
|
|
199
194
|
'conversation-timebox-subscription-options-invalid',
|
|
200
195
|
TypeError
|
|
201
196
|
);
|
|
202
197
|
}
|
|
203
|
-
|
|
204
|
-
return key!=='once'&&key!=='signal';
|
|
205
|
-
});
|
|
206
|
-
if(unsupported!==undefined||(
|
|
207
|
-
value.once!==undefined
|
|
198
|
+
if((value.once!==undefined
|
|
208
199
|
&&typeof value.once!=='boolean'
|
|
209
200
|
)||(
|
|
210
201
|
value.signal!==undefined
|
|
@@ -212,13 +203,13 @@ function normalizeSubscriptionOptions(value={}){
|
|
|
212
203
|
&&!isAbortSignal(value.signal)
|
|
213
204
|
)){
|
|
214
205
|
throw conversationTimeboxError(
|
|
215
|
-
'Conversation timebox
|
|
216
|
-
|
|
206
|
+
'Conversation timebox subscription once must be boolean and signal must be an AbortSignal.',
|
|
207
|
+
conversationTimeboxErrorCodes.subscriptionOptionsInvalid,
|
|
217
208
|
'conversation-timebox-subscription-options-invalid',
|
|
218
209
|
TypeError
|
|
219
210
|
);
|
|
220
211
|
}
|
|
221
|
-
return
|
|
212
|
+
return {once:value.once===true,signal:value.signal??null};
|
|
222
213
|
}
|
|
223
214
|
|
|
224
215
|
function defaultClock(){
|
|
@@ -285,14 +276,6 @@ class ConversationTimebox{
|
|
|
285
276
|
if(!isPlainRecord(options)){
|
|
286
277
|
throw new TypeError('Conversation timebox options must be a plain object.');
|
|
287
278
|
}
|
|
288
|
-
const allowed=new Set(['cancel','clock','onListenerError','schedule','tickMs']);
|
|
289
|
-
const unsupported=Object.keys(options).find(function findUnsupportedTimeboxOption(key){
|
|
290
|
-
return !allowed.has(key);
|
|
291
|
-
});
|
|
292
|
-
if(unsupported){
|
|
293
|
-
throw new TypeError(`Unsupported conversation timebox option: ${unsupported}`);
|
|
294
|
-
}
|
|
295
|
-
|
|
296
279
|
this.#clock=options.clock??defaultClock;
|
|
297
280
|
this.#schedule=options.schedule??defaultSchedule;
|
|
298
281
|
this.#cancel=options.cancel??defaultCancel;
|
|
@@ -309,12 +292,12 @@ class ConversationTimebox{
|
|
|
309
292
|
throw new TypeError(`${name} must be a function.`);
|
|
310
293
|
}
|
|
311
294
|
}
|
|
312
|
-
if(!Number.
|
|
313
|
-
throw new RangeError('tickMs must be
|
|
295
|
+
if(!Number.isFinite(this.#tickMs)||this.#tickMs<=0){
|
|
296
|
+
throw new RangeError('tickMs must be a positive finite number.');
|
|
314
297
|
}
|
|
315
298
|
this.#events=createArcaneEventSource(this,{
|
|
316
299
|
source:'conversation-timebox',
|
|
317
|
-
eventTypes:Object.
|
|
300
|
+
eventTypes:Object.values(conversationTimeboxEventTypes),
|
|
318
301
|
onListenerError
|
|
319
302
|
});
|
|
320
303
|
}
|
|
@@ -333,7 +316,7 @@ class ConversationTimebox{
|
|
|
333
316
|
return this.snapshot();
|
|
334
317
|
}
|
|
335
318
|
const now=this.#readClock();
|
|
336
|
-
this.#startAt(now,true,
|
|
319
|
+
this.#startAt(now,true,conversationTimeboxReasons.started);
|
|
337
320
|
return this.snapshot();
|
|
338
321
|
}
|
|
339
322
|
|
|
@@ -352,7 +335,7 @@ class ConversationTimebox{
|
|
|
352
335
|
throw new RangeError('The requested conversation duration exceeds the supported date range.');
|
|
353
336
|
}
|
|
354
337
|
if(this.#startedAtMs===null){
|
|
355
|
-
this.#startAt(now,false,
|
|
338
|
+
this.#startAt(now,false,conversationTimeboxReasons.started);
|
|
356
339
|
}
|
|
357
340
|
|
|
358
341
|
this.#durationMilliseconds=milliseconds;
|
|
@@ -361,7 +344,7 @@ class ConversationTimebox{
|
|
|
361
344
|
this.#dueRevision=null;
|
|
362
345
|
this.#revision++;
|
|
363
346
|
this.#nowMs=now;
|
|
364
|
-
this.#notify('change',
|
|
347
|
+
this.#notify('change',conversationTimeboxReasons.limitSet,commandSource);
|
|
365
348
|
return this.snapshot();
|
|
366
349
|
}
|
|
367
350
|
|
|
@@ -390,7 +373,7 @@ class ConversationTimebox{
|
|
|
390
373
|
this.#dueRevision=null;
|
|
391
374
|
this.#revision++;
|
|
392
375
|
this.#nowMs=now;
|
|
393
|
-
this.#notify('change',
|
|
376
|
+
this.#notify('change',conversationTimeboxReasons.limitAdjusted,commandSource);
|
|
394
377
|
return this.snapshot();
|
|
395
378
|
}
|
|
396
379
|
|
|
@@ -409,7 +392,7 @@ class ConversationTimebox{
|
|
|
409
392
|
this.#dueRevision=null;
|
|
410
393
|
this.#revision++;
|
|
411
394
|
this.#nowMs=this.#readClock();
|
|
412
|
-
this.#notify('change',
|
|
395
|
+
this.#notify('change',conversationTimeboxReasons.limitCleared,commandSource);
|
|
413
396
|
return this.snapshot();
|
|
414
397
|
}
|
|
415
398
|
|
|
@@ -436,7 +419,7 @@ class ConversationTimebox{
|
|
|
436
419
|
if(typeof listener!=='function'){
|
|
437
420
|
throw conversationTimeboxError(
|
|
438
421
|
'Conversation timebox listener must be a function.',
|
|
439
|
-
|
|
422
|
+
conversationTimeboxErrorCodes.subscriptionHandlerInvalid,
|
|
440
423
|
'conversation-timebox-subscription-handler-invalid',
|
|
441
424
|
TypeError
|
|
442
425
|
);
|
|
@@ -447,7 +430,7 @@ class ConversationTimebox{
|
|
|
447
430
|
listener(event.detail.state,event.detail.event);
|
|
448
431
|
}
|
|
449
432
|
const unsubscribe=this.#events.on(
|
|
450
|
-
|
|
433
|
+
conversationTimeboxEventTypes.change,
|
|
451
434
|
forwardConversationTimeboxChange,
|
|
452
435
|
normalized
|
|
453
436
|
);
|
|
@@ -455,12 +438,12 @@ class ConversationTimebox{
|
|
|
455
438
|
try{
|
|
456
439
|
listener(
|
|
457
440
|
this.snapshot(),
|
|
458
|
-
|
|
441
|
+
{
|
|
459
442
|
type:'snapshot',
|
|
460
|
-
reason:
|
|
443
|
+
reason:conversationTimeboxReasons.snapshotReplayed,
|
|
461
444
|
revision:this.#revision,
|
|
462
445
|
commandSource:null
|
|
463
|
-
}
|
|
446
|
+
}
|
|
464
447
|
);
|
|
465
448
|
}catch(error){
|
|
466
449
|
unsubscribe();
|
|
@@ -487,7 +470,7 @@ class ConversationTimebox{
|
|
|
487
470
|
?'armed'
|
|
488
471
|
:'unlimited';
|
|
489
472
|
|
|
490
|
-
return
|
|
473
|
+
return {
|
|
491
474
|
status,
|
|
492
475
|
startedAtMs:this.#startedAtMs,
|
|
493
476
|
elapsedMs,
|
|
@@ -497,7 +480,7 @@ class ConversationTimebox{
|
|
|
497
480
|
remainingMs,
|
|
498
481
|
revision:this.#revision,
|
|
499
482
|
dueRevision:this.#dueRevision
|
|
500
|
-
}
|
|
483
|
+
};
|
|
501
484
|
}
|
|
502
485
|
|
|
503
486
|
dispose(){
|
|
@@ -509,7 +492,7 @@ class ConversationTimebox{
|
|
|
509
492
|
this.#intervalHandle=null;
|
|
510
493
|
}
|
|
511
494
|
this.#disposed=true;
|
|
512
|
-
this.#notify('change',
|
|
495
|
+
this.#notify('change',conversationTimeboxReasons.disposed);
|
|
513
496
|
const finalSnapshot=this.snapshot();
|
|
514
497
|
this.#events.dispose();
|
|
515
498
|
return finalSnapshot;
|
|
@@ -519,8 +502,8 @@ class ConversationTimebox{
|
|
|
519
502
|
if(this.#disposed){
|
|
520
503
|
throw conversationTimeboxError(
|
|
521
504
|
'The conversation timebox has been disposed.',
|
|
522
|
-
|
|
523
|
-
|
|
505
|
+
conversationTimeboxErrorCodes.disposed,
|
|
506
|
+
conversationTimeboxReasons.disposed
|
|
524
507
|
);
|
|
525
508
|
}
|
|
526
509
|
}
|
|
@@ -563,31 +546,31 @@ class ConversationTimebox{
|
|
|
563
546
|
this.#notify(
|
|
564
547
|
becameDue?'due':'tick',
|
|
565
548
|
becameDue
|
|
566
|
-
?
|
|
567
|
-
:
|
|
549
|
+
?conversationTimeboxReasons.deadlineReached
|
|
550
|
+
:conversationTimeboxReasons.elapsedTimeAdvanced
|
|
568
551
|
);
|
|
569
552
|
}
|
|
570
553
|
|
|
571
554
|
#notify(type,reason,commandSource=null){
|
|
572
555
|
const state=this.snapshot();
|
|
573
|
-
const event=
|
|
556
|
+
const event={
|
|
574
557
|
type,
|
|
575
558
|
reason,
|
|
576
559
|
revision:this.#revision,
|
|
577
560
|
commandSource
|
|
578
|
-
}
|
|
561
|
+
};
|
|
579
562
|
const operationId=`${this.#events.instanceId}:change:${(++this.#operationSequence).toString(36)}`;
|
|
580
563
|
this.#events.dispatch(
|
|
581
|
-
|
|
582
|
-
|
|
564
|
+
conversationTimeboxEventTypes.change,
|
|
565
|
+
{state:{...state},event:{...event}},
|
|
583
566
|
{
|
|
584
567
|
operationId,
|
|
585
|
-
publicDetail:
|
|
568
|
+
publicDetail:{
|
|
586
569
|
reason,
|
|
587
570
|
status:state.status,
|
|
588
571
|
revision:state.revision,
|
|
589
572
|
commandSource
|
|
590
|
-
}
|
|
573
|
+
}
|
|
591
574
|
}
|
|
592
575
|
);
|
|
593
576
|
}
|
|
@@ -602,41 +585,30 @@ function consumeConversationTimeboxCall(calls,controller){
|
|
|
602
585
|
}
|
|
603
586
|
const remainingCalls={...calls};
|
|
604
587
|
if(!Object.hasOwn(remainingCalls,CONVERSATION_TIMEBOX_TOOL_NAME)){
|
|
605
|
-
return
|
|
588
|
+
return {
|
|
606
589
|
handled:false,
|
|
607
|
-
remainingCalls
|
|
590
|
+
remainingCalls,
|
|
608
591
|
result:null
|
|
609
|
-
}
|
|
592
|
+
};
|
|
610
593
|
}
|
|
611
594
|
|
|
612
595
|
const argumentsValue=remainingCalls[CONVERSATION_TIMEBOX_TOOL_NAME];
|
|
613
596
|
delete remainingCalls[CONVERSATION_TIMEBOX_TOOL_NAME];
|
|
614
|
-
if(Object.keys(remainingCalls).length){
|
|
615
|
-
const reason=new TypeError(
|
|
616
|
-
'The conversation timebox must be the sole tool call in a response.'
|
|
617
|
-
);
|
|
618
|
-
reason.code='CONVERSATION_TIMEBOX_MUST_BE_SOLE_CALL';
|
|
619
|
-
return Object.freeze({
|
|
620
|
-
handled:true,
|
|
621
|
-
remainingCalls:Object.freeze({}),
|
|
622
|
-
result:Object.freeze({status:'rejected',reason})
|
|
623
|
-
});
|
|
624
|
-
}
|
|
625
597
|
try{
|
|
626
|
-
return
|
|
598
|
+
return {
|
|
627
599
|
handled:true,
|
|
628
|
-
remainingCalls
|
|
629
|
-
result:
|
|
600
|
+
remainingCalls,
|
|
601
|
+
result:{
|
|
630
602
|
status:'fulfilled',
|
|
631
603
|
value:controller.applyCommand(argumentsValue)
|
|
632
|
-
}
|
|
633
|
-
}
|
|
604
|
+
}
|
|
605
|
+
};
|
|
634
606
|
}catch(reason){
|
|
635
|
-
return
|
|
607
|
+
return {
|
|
636
608
|
handled:true,
|
|
637
|
-
remainingCalls
|
|
638
|
-
result:
|
|
639
|
-
}
|
|
609
|
+
remainingCalls,
|
|
610
|
+
result:{status:'rejected',reason}
|
|
611
|
+
};
|
|
640
612
|
}
|
|
641
613
|
}
|
|
642
614
|
|
|
@@ -8,12 +8,14 @@ import {
|
|
|
8
8
|
} from 'arcane-os/event-manager';
|
|
9
9
|
|
|
10
10
|
const PUBLISH_DBLS_READY=Symbol('publish-dbls-ready');
|
|
11
|
-
|
|
11
|
+
const dblsEventTypes={
|
|
12
12
|
ready:'dbls-ready'
|
|
13
|
-
}
|
|
14
|
-
|
|
13
|
+
};
|
|
14
|
+
const dblsReasons={
|
|
15
15
|
ready:'local-storage-adapter-ready'
|
|
16
|
-
}
|
|
16
|
+
};
|
|
17
|
+
export const DBLS_EVENT_TYPES={...dblsEventTypes};
|
|
18
|
+
export const DBLS_REASONS={...dblsReasons};
|
|
17
19
|
|
|
18
20
|
class DBLS {
|
|
19
21
|
#events;
|
|
@@ -43,7 +45,7 @@ class DBLS {
|
|
|
43
45
|
this.storagePrefix=`${APP_LOCAL_STORAGE_PREFIX}${this.applicationId}:`;
|
|
44
46
|
this.#events=createArcaneEventSource(this,{
|
|
45
47
|
source:'dbls',
|
|
46
|
-
eventTypes:Object.
|
|
48
|
+
eventTypes:Object.values(dblsEventTypes)
|
|
47
49
|
});
|
|
48
50
|
}
|
|
49
51
|
|
|
@@ -173,21 +175,21 @@ class DBLS {
|
|
|
173
175
|
}
|
|
174
176
|
|
|
175
177
|
[PUBLISH_DBLS_READY](){
|
|
176
|
-
const detail=
|
|
178
|
+
const detail={
|
|
177
179
|
dbls:this,
|
|
178
180
|
applicationId:this.applicationId,
|
|
179
|
-
reason:
|
|
180
|
-
}
|
|
181
|
+
reason:dblsReasons.ready
|
|
182
|
+
};
|
|
181
183
|
const {occurrence}=this.#events.dispatch(
|
|
182
|
-
|
|
184
|
+
dblsEventTypes.ready,
|
|
183
185
|
detail,
|
|
184
186
|
{
|
|
185
187
|
operationId:`dbls-ready-${this.#events.instanceId}`,
|
|
186
|
-
publicDetail:
|
|
188
|
+
publicDetail:{
|
|
187
189
|
applicationId:this.applicationId,
|
|
188
190
|
ready:true,
|
|
189
|
-
reason:
|
|
190
|
-
}
|
|
191
|
+
reason:dblsReasons.ready
|
|
192
|
+
}
|
|
191
193
|
}
|
|
192
194
|
);
|
|
193
195
|
projectArcaneDOMEvent(window,occurrence);
|
|
@@ -6,14 +6,16 @@ import {
|
|
|
6
6
|
} from 'arcane-os/event-manager';
|
|
7
7
|
const is=new Is(false);
|
|
8
8
|
|
|
9
|
-
|
|
9
|
+
const dbopfsEventTypes={
|
|
10
10
|
ready:'dbopfs-ready'
|
|
11
|
-
}
|
|
12
|
-
|
|
11
|
+
};
|
|
12
|
+
const dbopfsReasons={
|
|
13
13
|
ready:'opfs-database-ready'
|
|
14
|
-
}
|
|
14
|
+
};
|
|
15
|
+
export const DBOPFS_EVENT_TYPES={...dbopfsEventTypes};
|
|
16
|
+
export const DBOPFS_REASONS={...dbopfsReasons};
|
|
15
17
|
|
|
16
|
-
const DEFAULT_TABLE_DIRECTORIES=
|
|
18
|
+
const DEFAULT_TABLE_DIRECTORIES={
|
|
17
19
|
users:'users',
|
|
18
20
|
scores:'scores',
|
|
19
21
|
chats:'chats',
|
|
@@ -26,7 +28,7 @@ const DEFAULT_TABLE_DIRECTORIES=Object.freeze({
|
|
|
26
28
|
reports:'reports',
|
|
27
29
|
errors:'errors',
|
|
28
30
|
memories:'memory'
|
|
29
|
-
}
|
|
31
|
+
};
|
|
30
32
|
|
|
31
33
|
function parseFileValue(fileName='',textContent=''){
|
|
32
34
|
let value=textContent;
|
|
@@ -42,9 +44,12 @@ function parseFileValue(fileName='',textContent=''){
|
|
|
42
44
|
case 'ndjson':
|
|
43
45
|
value=[];
|
|
44
46
|
for(const row of textContent.split('\n')){
|
|
47
|
+
if(!row.trim())continue;
|
|
45
48
|
try{
|
|
46
49
|
value.push(JSON.parse(row.trim()));
|
|
47
|
-
}catch{
|
|
50
|
+
}catch{
|
|
51
|
+
value.push(row);
|
|
52
|
+
}
|
|
48
53
|
}
|
|
49
54
|
break;
|
|
50
55
|
}
|
|
@@ -285,7 +290,7 @@ class DBOPFS {
|
|
|
285
290
|
|
|
286
291
|
this.#events=createArcaneEventSource(this,{
|
|
287
292
|
source:'dbopfs',
|
|
288
|
-
eventTypes:Object.
|
|
293
|
+
eventTypes:Object.values(dbopfsEventTypes)
|
|
289
294
|
});
|
|
290
295
|
this.readyPromise=this.#init(options);
|
|
291
296
|
}
|
|
@@ -312,21 +317,21 @@ class DBOPFS {
|
|
|
312
317
|
this.ready=true;
|
|
313
318
|
|
|
314
319
|
const {occurrence}=this.#events.dispatch(
|
|
315
|
-
|
|
316
|
-
|
|
320
|
+
dbopfsEventTypes.ready,
|
|
321
|
+
{
|
|
317
322
|
dbopfs:this,
|
|
318
323
|
applicationId:this.#applicationId,
|
|
319
324
|
storagePath:this.#storagePath,
|
|
320
|
-
reason:
|
|
321
|
-
}
|
|
325
|
+
reason:dbopfsReasons.ready
|
|
326
|
+
},
|
|
322
327
|
{
|
|
323
328
|
operationId:`dbopfs-ready-${this.#events.instanceId}`,
|
|
324
|
-
publicDetail:
|
|
329
|
+
publicDetail:{
|
|
325
330
|
applicationId:this.#applicationId,
|
|
326
331
|
ready:true,
|
|
327
|
-
reason:
|
|
332
|
+
reason:dbopfsReasons.ready,
|
|
328
333
|
storagePath:this.#storagePath
|
|
329
|
-
}
|
|
334
|
+
}
|
|
330
335
|
}
|
|
331
336
|
);
|
|
332
337
|
projectArcaneDOMEvent(window,occurrence);
|