arcane-os 0.5.8 → 0.5.9
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 +16 -0
- package/README.md +32 -27
- package/browser-runtime/ai/browser-speech-artifacts.mjs +23 -1683
- package/browser-runtime/ai/browser-speech-providers.mjs +353 -143
- package/browser-runtime/ai/browser-wasm-llm-provider.mjs +32 -324
- package/browser-runtime/ai/speech-worker-client.mjs +51 -14
- package/browser-runtime/ai/speech-worker-runtime.mjs +45 -1072
- package/browser-runtime/dependencies/strong-type/package.json +22 -23
- package/browser-runtime/event-manager.mjs +27 -41
- package/package.json +2 -3
- package/runtime/arcane/components/chat.html +1 -1
- package/runtime/arcane/components/speech.html +8 -38
- package/runtime/arcane/components/voice-transcription.html +1 -1
- package/runtime/arcane/css/theme.css +1 -1
- package/runtime/arcane/entities/Chat.js +12 -7
- package/runtime/arcane/modules/AI.js +506 -391
- package/runtime/arcane/modules/AIPreferenceTuple.js +1 -1
- package/runtime/arcane/modules/AIProviderRuntime.js +129 -68
- package/runtime/arcane/modules/AIRuntimeState.js +2 -18
- package/runtime/arcane/modules/BrowserTestSuite.js +2 -5
- package/runtime/arcane/modules/CalculatorEngine.js +0 -4
- package/runtime/arcane/modules/ChatRecords.js +169 -1
- package/runtime/arcane/modules/CommunicationHub.js +0 -19
- package/runtime/arcane/modules/ConfiguredAIChatSession.js +28 -25
- package/runtime/arcane/modules/DBOPFSDocumentLibrary.js +4 -5
- package/runtime/arcane/modules/DocumentLexicalSearch.js +1 -1
- package/runtime/arcane/modules/Errors.js +6 -19
- package/runtime/arcane/modules/Mail.js +1 -2
- package/runtime/arcane/modules/MailTransport.mjs +1 -3
- package/runtime/arcane/modules/OllamaModelIdentifier.js +1 -1
- package/runtime/arcane/modules/PersistentAIChatSession.js +5 -5
- package/runtime/arcane/modules/ScreenCapture.js +2 -4
- package/runtime/arcane/modules/SpeechPlayback.js +0 -27
- package/runtime/arcane/modules/WaitForComponent.js +0 -1
- package/src/app-descriptor.mjs +1 -1
- package/src/doctor.mjs +1 -3
- package/src/event-manager.mjs +27 -41
- package/src/import-map.mjs +1 -1
- package/src/index.mjs +2 -9
- package/src/installed-sdk-runtime.mjs +1 -11
- package/src/mail-api.mjs +0 -1
- package/src/native-provider-loader.mjs +0 -9
- package/src/scaffold.mjs +9 -21
- package/src/toolchain.mjs +5 -28
- package/src/workspace-runtime.mjs +0 -4
- package/src/workspace.mjs +2 -23
|
@@ -7,7 +7,6 @@ const communicationHubEvents={
|
|
|
7
7
|
refreshCancelled:'communications-refresh-cancelled',
|
|
8
8
|
refreshCompleted:'communications-refresh-completed',
|
|
9
9
|
refreshFailed:'communications-refresh-failed',
|
|
10
|
-
refreshLegacy:'communications-refresh',
|
|
11
10
|
refreshPartiallyCompleted:'communications-refresh-partially-completed',
|
|
12
11
|
refreshStarted:'communications-refresh-started'
|
|
13
12
|
};
|
|
@@ -465,14 +464,6 @@ export default class CommunicationHub extends EventTarget{
|
|
|
465
464
|
state,
|
|
466
465
|
threadCount:threads.length
|
|
467
466
|
};
|
|
468
|
-
const legacyDetail={
|
|
469
|
-
errors:[...returnedErrors],
|
|
470
|
-
threads:[...returnedThreads]
|
|
471
|
-
};
|
|
472
|
-
const legacyPublicDetail={
|
|
473
|
-
...publicDetail,
|
|
474
|
-
failures:publicDetail.failures.map(copyProviderFailure)
|
|
475
|
-
};
|
|
476
467
|
operation.terminal=true;
|
|
477
468
|
this.#clearRefreshOperation(operation);
|
|
478
469
|
this.#events.dispatch(
|
|
@@ -483,16 +474,6 @@ export default class CommunicationHub extends EventTarget{
|
|
|
483
474
|
publicDetail
|
|
484
475
|
}
|
|
485
476
|
);
|
|
486
|
-
if(!this.#events.disposed){
|
|
487
|
-
this.#events.dispatch(
|
|
488
|
-
communicationHubEvents.refreshLegacy,
|
|
489
|
-
legacyDetail,
|
|
490
|
-
{
|
|
491
|
-
operationId:operation.operationId,
|
|
492
|
-
publicDetail:legacyPublicDetail
|
|
493
|
-
}
|
|
494
|
-
);
|
|
495
|
-
}
|
|
496
477
|
return {threads:returnedThreads,errors:returnedErrors};
|
|
497
478
|
}catch(error){
|
|
498
479
|
if(operation.terminal){
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import {recurringChatMessages} from './ChatRecords.js';
|
|
2
|
+
|
|
1
3
|
const FORBIDDEN_REQUEST_FIELDS=new Set([
|
|
2
4
|
'messages',
|
|
3
5
|
'onChunk',
|
|
@@ -254,19 +256,20 @@ function cloneMessage(value){
|
|
|
254
256
|
}
|
|
255
257
|
|
|
256
258
|
function publicMessage(value){
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
259
|
+
const copy=cloneMessage(value);
|
|
260
|
+
if(copy.role==='tool'){
|
|
261
|
+
delete copy.message;
|
|
262
|
+
delete copy.name;
|
|
263
|
+
delete copy.status;
|
|
264
|
+
}
|
|
265
|
+
delete copy.memory_excluded;
|
|
266
|
+
delete copy.persistence_excluded;
|
|
267
|
+
delete copy.persistence_message;
|
|
268
|
+
delete copy.persistence_name;
|
|
269
|
+
delete copy.persistence_status;
|
|
270
|
+
delete copy.timestamp;
|
|
271
|
+
delete copy.ui_hidden;
|
|
272
|
+
return copy;
|
|
270
273
|
}
|
|
271
274
|
|
|
272
275
|
function normalizeInitialMessages(value){
|
|
@@ -493,12 +496,13 @@ function normalizeResponse(response){
|
|
|
493
496
|
}
|
|
494
497
|
|
|
495
498
|
/**
|
|
496
|
-
* Maintains
|
|
499
|
+
* Maintains complete ordinary visible recurring conversation content plus only
|
|
500
|
+
* the active structural protocol required by a configured chat provider.
|
|
497
501
|
*
|
|
498
502
|
* This module performs no persistence, streaming, tool execution, rendering, or
|
|
499
503
|
* provider selection. Applications own their prompt policy and may supply an
|
|
500
504
|
* asynchronous contextBuilder that returns additional system text for each send.
|
|
501
|
-
*
|
|
505
|
+
* The response-length preference is accepted without changing or shortening
|
|
502
506
|
* the caller's prompt. A configured chat function may return either the normalized
|
|
503
507
|
* session response or a non-stream OpenAI-compatible completion.
|
|
504
508
|
*/
|
|
@@ -516,9 +520,6 @@ export default class ConfiguredAIChatSession{
|
|
|
516
520
|
'chat',
|
|
517
521
|
'contextBuilder',
|
|
518
522
|
'initialMessages',
|
|
519
|
-
'maxContextCharacters',
|
|
520
|
-
'maxMessageCharacters',
|
|
521
|
-
'maxMessages',
|
|
522
523
|
'request',
|
|
523
524
|
'responseLength',
|
|
524
525
|
'systemPrompt',
|
|
@@ -545,8 +546,10 @@ export default class ConfiguredAIChatSession{
|
|
|
545
546
|
this.#request={...request};
|
|
546
547
|
this.#systemPrompt=systemPrompt;
|
|
547
548
|
const initialMessages=normalizeInitialMessages(options.initialMessages);
|
|
548
|
-
|
|
549
|
-
|
|
549
|
+
this.#conversation=recurringChatMessages(
|
|
550
|
+
initialMessages,
|
|
551
|
+
{settleCompleteToolTail:true},
|
|
552
|
+
);
|
|
550
553
|
}
|
|
551
554
|
|
|
552
555
|
history(){
|
|
@@ -732,11 +735,11 @@ export default class ConfiguredAIChatSession{
|
|
|
732
735
|
const response=normalizeResponse(providerResponse);
|
|
733
736
|
if(options.signal?.aborted) throw abortError();
|
|
734
737
|
const retainedConversation=this.#conversation.map(cloneMessage);
|
|
735
|
-
const
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
|
|
738
|
+
const nextConversation=recurringChatMessages([
|
|
739
|
+
...retainedConversation,
|
|
740
|
+
...inputMessages,
|
|
741
|
+
response.message,
|
|
742
|
+
]);
|
|
740
743
|
let settled=false;
|
|
741
744
|
return {
|
|
742
745
|
response,
|
|
@@ -732,7 +732,7 @@ class DBOPFSDocumentLibrary{
|
|
|
732
732
|
|
|
733
733
|
async search(query,options={}){
|
|
734
734
|
if(!isPlainRecord(options)) fail('Document search options must be a plain object.');
|
|
735
|
-
assertKnownKeys(options,new Set(['kinds','
|
|
735
|
+
assertKnownKeys(options,new Set(['kinds','signal','tags']),'Document search options');
|
|
736
736
|
if(!signalLike(options.signal)) fail('signal must be an AbortSignal.');
|
|
737
737
|
const corpus=await this.#corpus(options.signal);
|
|
738
738
|
const search=new DocumentLexicalSearch(corpus.records);
|
|
@@ -863,7 +863,7 @@ class DBOPFSDocumentLibrary{
|
|
|
863
863
|
|
|
864
864
|
async buildContext(query,options={}){
|
|
865
865
|
if(!isPlainRecord(options)) fail('Document context options must be a plain object.');
|
|
866
|
-
assertKnownKeys(options,new Set(['
|
|
866
|
+
assertKnownKeys(options,new Set(['signal']),'Document context options');
|
|
867
867
|
if(!signalLike(options.signal)) fail('signal must be an AbortSignal.');
|
|
868
868
|
const result=await this.search(query,{signal:options.signal});
|
|
869
869
|
const preamble='DBOPFS DOCUMENT CONTEXT\n';
|
|
@@ -895,9 +895,8 @@ class DBOPFSDocumentLibrary{
|
|
|
895
895
|
|
|
896
896
|
createContextBuilder(options={}){
|
|
897
897
|
if(!isPlainRecord(options)) fail('Context builder options must be a plain object.');
|
|
898
|
-
assertKnownKeys(options,new Set(
|
|
899
|
-
|
|
900
|
-
return async({input,signal}={})=>(await this.buildContext(input,{...settings,signal})).text;
|
|
898
|
+
assertKnownKeys(options,new Set(),'Context builder options');
|
|
899
|
+
return async({input,signal}={})=>(await this.buildContext(input,{signal})).text;
|
|
901
900
|
}
|
|
902
901
|
}
|
|
903
902
|
|
|
@@ -203,7 +203,7 @@ class DocumentLexicalSearch{
|
|
|
203
203
|
|
|
204
204
|
search(query,options={}){
|
|
205
205
|
if(!isPlainRecord(options)) fail('Search options must be a plain object.','DOCUMENT_SEARCH_INVALID_QUERY');
|
|
206
|
-
const unknown=Object.keys(options).find(key=>!['kinds','
|
|
206
|
+
const unknown=Object.keys(options).find(key=>!['kinds','tags'].includes(key));
|
|
207
207
|
if(unknown) fail(`Search options contain an unsupported field: ${unknown}.`,'DOCUMENT_SEARCH_INVALID_QUERY');
|
|
208
208
|
return this.rank(query,{
|
|
209
209
|
kinds:options.kinds,
|
|
@@ -129,15 +129,7 @@ export function normalizeRejectionEvent(event={},target=globalThis.window){
|
|
|
129
129
|
};
|
|
130
130
|
}
|
|
131
131
|
|
|
132
|
-
|
|
133
|
-
* Return a fresh opaque occurrence identifier for legacy callers of the former
|
|
134
|
-
* fingerprint helper. The incident is intentionally not read: identifiers do
|
|
135
|
-
* not group, admit, or derive identity from error content.
|
|
136
|
-
*
|
|
137
|
-
* @param {Object} incident
|
|
138
|
-
* @returns {string}
|
|
139
|
-
*/
|
|
140
|
-
export function fingerprintIncident(_incident){
|
|
132
|
+
function nextErrorOccurrenceId(){
|
|
141
133
|
runtimeOccurrenceSequence+=1;
|
|
142
134
|
return `error-${RUNTIME_OCCURRENCE_PREFIX}-${runtimeOccurrenceSequence.toString(36)}`;
|
|
143
135
|
}
|
|
@@ -517,9 +509,9 @@ class Errors {
|
|
|
517
509
|
&& storedRecord.occurrenceId.trim()
|
|
518
510
|
)
|
|
519
511
|
? storedRecord.occurrenceId
|
|
520
|
-
:
|
|
512
|
+
: nextErrorOccurrenceId();
|
|
521
513
|
while(this.pending.has(occurrenceId)){
|
|
522
|
-
occurrenceId=
|
|
514
|
+
occurrenceId=nextErrorOccurrenceId();
|
|
523
515
|
}
|
|
524
516
|
const record={
|
|
525
517
|
capturedAt,
|
|
@@ -656,9 +648,9 @@ class Errors {
|
|
|
656
648
|
return false;
|
|
657
649
|
}
|
|
658
650
|
|
|
659
|
-
let occurrenceId=
|
|
651
|
+
let occurrenceId=nextErrorOccurrenceId();
|
|
660
652
|
while(this.pending.has(occurrenceId)){
|
|
661
|
-
occurrenceId=
|
|
653
|
+
occurrenceId=nextErrorOccurrenceId();
|
|
662
654
|
}
|
|
663
655
|
const incidentKind=incident?.type==='unhandledrejection'
|
|
664
656
|
?'unhandled-promise-rejection'
|
|
@@ -675,12 +667,11 @@ class Errors {
|
|
|
675
667
|
this.#operationSequence+=1;
|
|
676
668
|
this.#events.dispatch(
|
|
677
669
|
eventType,
|
|
678
|
-
{id:occurrenceId,
|
|
670
|
+
{id:occurrenceId,code,kind:incidentKind,reason},
|
|
679
671
|
{
|
|
680
672
|
operationId:`global-error-handler-${this.#events.instanceId}-${this.#operationSequence.toString(36)}`,
|
|
681
673
|
publicDetail:{
|
|
682
674
|
id:occurrenceId,
|
|
683
|
-
fingerprint:occurrenceId,
|
|
684
675
|
code,
|
|
685
676
|
kind:incidentKind,
|
|
686
677
|
reason
|
|
@@ -750,10 +741,6 @@ class Errors {
|
|
|
750
741
|
return true;
|
|
751
742
|
}
|
|
752
743
|
|
|
753
|
-
flushFingerprint(fingerprint){
|
|
754
|
-
return this.flushOccurrence(fingerprint);
|
|
755
|
-
}
|
|
756
|
-
|
|
757
744
|
buildNotification(record){
|
|
758
745
|
const subject=record.incident?.type==='unhandledrejection'
|
|
759
746
|
? 'ARCANE JS UNHANDLED REJECTION'
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import {createArcaneEventSource} from 'arcane-os/event-manager';
|
|
2
2
|
import MailOutbox from './MailOutbox.mjs';
|
|
3
3
|
import {
|
|
4
|
-
DEFAULT_MAIL_REQUEST_TIMEOUT_MS,
|
|
5
4
|
sendMailReport,
|
|
6
5
|
} from './MailTransport.mjs';
|
|
7
6
|
|
|
@@ -258,7 +257,7 @@ export function resolveMailConfig(
|
|
|
258
257
|
: defaultMailEndpoint(location,supplied.baseDomain||declaredMailBaseDomain(document)),
|
|
259
258
|
requestTimeout:Number.isFinite(supplied.requestTimeout)
|
|
260
259
|
? supplied.requestTimeout
|
|
261
|
-
:
|
|
260
|
+
: null,
|
|
262
261
|
});
|
|
263
262
|
}
|
|
264
263
|
|
|
@@ -1,5 +1,3 @@
|
|
|
1
|
-
export const DEFAULT_MAIL_REQUEST_TIMEOUT_MS=null;
|
|
2
|
-
|
|
3
1
|
const REPORT_KEY_PATTERN=/^[a-zA-Z0-9._:-]+$/;
|
|
4
2
|
const REQUEST_ID_PATTERN=/^[a-zA-Z0-9-]+$/;
|
|
5
3
|
const PROVIDER_ID_PATTERN=/^[a-zA-Z0-9._:-]+$/;
|
|
@@ -223,7 +221,7 @@ export async function sendMailReport({
|
|
|
223
221
|
fetchImpl=globalThis.fetch,
|
|
224
222
|
report,
|
|
225
223
|
reportKey,
|
|
226
|
-
requestTimeout=
|
|
224
|
+
requestTimeout=null,
|
|
227
225
|
serializedReport,
|
|
228
226
|
signal,
|
|
229
227
|
}){
|
|
@@ -10,7 +10,7 @@ export function normalizeOllamaModelIdentifier(value){
|
|
|
10
10
|
if(typeof value!=='string'||value!==value.trim()){
|
|
11
11
|
return null;
|
|
12
12
|
}
|
|
13
|
-
if(!OLLAMA_MODEL_IDENTIFIER.test(value)||value.toUpperCase()==='
|
|
13
|
+
if(!OLLAMA_MODEL_IDENTIFIER.test(value)||value.toUpperCase()==='TWIN'){
|
|
14
14
|
return null;
|
|
15
15
|
}
|
|
16
16
|
return value;
|
|
@@ -344,8 +344,8 @@ class PersistentAIChatSession{
|
|
|
344
344
|
assertKnownKeys(
|
|
345
345
|
options,
|
|
346
346
|
new Set([
|
|
347
|
-
'ai','chat','chatEntity','chatFileName','contextBuilder','loadExisting','
|
|
348
|
-
'
|
|
347
|
+
'ai','chat','chatEntity','chatFileName','contextBuilder','loadExisting','memory',
|
|
348
|
+
'request','responseLength','systemPrompt'
|
|
349
349
|
]),
|
|
350
350
|
'Persistent chat options',
|
|
351
351
|
);
|
|
@@ -632,9 +632,9 @@ class PersistentAIChatSession{
|
|
|
632
632
|
if(streamState) this.#activeStream=streamState;
|
|
633
633
|
try{
|
|
634
634
|
prepared=await this.#configured.prepare(
|
|
635
|
-
settings.
|
|
636
|
-
?settings.
|
|
637
|
-
:settings.
|
|
635
|
+
settings.entityRequestMessages.length===1
|
|
636
|
+
?settings.entityRequestMessages[0]
|
|
637
|
+
:settings.entityRequestMessages,
|
|
638
638
|
{request:settings.request,signal:settings.signal},
|
|
639
639
|
);
|
|
640
640
|
}finally{
|
|
@@ -1197,11 +1197,9 @@ export default class ScreenCapture extends EventTarget{
|
|
|
1197
1197
|
return operation.stopCallPromise;
|
|
1198
1198
|
}
|
|
1199
1199
|
|
|
1200
|
-
async prepare(stream,optionsValue={}
|
|
1200
|
+
async prepare(stream,optionsValue={}){
|
|
1201
1201
|
this.#assertOpen();
|
|
1202
|
-
const options=
|
|
1203
|
-
?optionsRecord(legacyOptionsValue,'Screen capture display options')
|
|
1204
|
-
:optionsRecord(optionsValue,'Screen capture display options');
|
|
1202
|
+
const options=optionsRecord(optionsValue,'Screen capture display options');
|
|
1205
1203
|
if(options.signal?.aborted)throw abortError(options.signal.reason);
|
|
1206
1204
|
let video;
|
|
1207
1205
|
try{
|
|
@@ -1,17 +1,5 @@
|
|
|
1
1
|
import {createArcaneEventSource} from 'arcane-os/event-manager';
|
|
2
2
|
|
|
3
|
-
const SPEECH_VOICE_OPTIONS=[
|
|
4
|
-
{value:'alloy',label:'Alloy'},
|
|
5
|
-
{value:'ash',label:'Ash'},
|
|
6
|
-
{value:'ballad',label:'Ballad'},
|
|
7
|
-
{value:'coral',label:'Coral'},
|
|
8
|
-
{value:'echo',label:'Echo'},
|
|
9
|
-
{value:'fable',label:'Fable'},
|
|
10
|
-
{value:'nova',label:'Nova'},
|
|
11
|
-
{value:'onyx',label:'Onyx'},
|
|
12
|
-
{value:'sage',label:'Sage'},
|
|
13
|
-
{value:'shimmer',label:'Shimmer'}
|
|
14
|
-
];
|
|
15
3
|
const SUPERSEDED={superseded:true};
|
|
16
4
|
const SPEECH_PLAYBACK_STATE_EVENT='speech-playback-state';
|
|
17
5
|
const SPEECH_PLAYBACK_FAILURE_REASONS={
|
|
@@ -29,10 +17,6 @@ const WAV_AUDIO_CONTENT_TYPES=new Set([
|
|
|
29
17
|
]);
|
|
30
18
|
const queuesBySpeechClient=new WeakMap();
|
|
31
19
|
|
|
32
|
-
const SPEECH_VOICE_ALIASES=new Set(
|
|
33
|
-
SPEECH_VOICE_OPTIONS.map(function voiceAlias(option){return option.value;})
|
|
34
|
-
);
|
|
35
|
-
|
|
36
20
|
function splitSpeechText(value=''){
|
|
37
21
|
const text=String(value??'');
|
|
38
22
|
return text.trim()?[text]:[];
|
|
@@ -333,7 +317,6 @@ class SpeechPlayback{
|
|
|
333
317
|
voice=null,
|
|
334
318
|
responseFormat=null,
|
|
335
319
|
speed=1,
|
|
336
|
-
onState=function noop(){},
|
|
337
320
|
createObjectURL,
|
|
338
321
|
revokeObjectURL,
|
|
339
322
|
delay,
|
|
@@ -355,7 +338,6 @@ class SpeechPlayback{
|
|
|
355
338
|
eventTypes:[SPEECH_PLAYBACK_STATE_EVENT]
|
|
356
339
|
}
|
|
357
340
|
);
|
|
358
|
-
this.onState=onState;
|
|
359
341
|
this.createObjectURL=createObjectURL||function createAudioURL(blob){return URL.createObjectURL(blob);};
|
|
360
342
|
this.revokeObjectURL=revokeObjectURL||function revokeAudioURL(url){URL.revokeObjectURL(url);};
|
|
361
343
|
this.delay=delay||function playbackDelay(duration,signal){
|
|
@@ -446,12 +428,6 @@ class SpeechPlayback{
|
|
|
446
428
|
}
|
|
447
429
|
);
|
|
448
430
|
}
|
|
449
|
-
try{
|
|
450
|
-
this.onState(detail);
|
|
451
|
-
}catch(error){
|
|
452
|
-
if(typeof globalThis.reportError==='function')globalThis.reportError(error);
|
|
453
|
-
else console.error(error);
|
|
454
|
-
}
|
|
455
431
|
return detail;
|
|
456
432
|
}
|
|
457
433
|
|
|
@@ -860,14 +836,11 @@ class SpeechPlayback{
|
|
|
860
836
|
this.audio.removeEventListener('error',this.boundError);
|
|
861
837
|
this.destroyed=true;
|
|
862
838
|
this.events.dispose();
|
|
863
|
-
this.onState=function destroyedSpeechPlaybackStateObserver(){};
|
|
864
839
|
return true;
|
|
865
840
|
}
|
|
866
841
|
}
|
|
867
842
|
|
|
868
843
|
export {
|
|
869
|
-
SPEECH_VOICE_ALIASES,
|
|
870
|
-
SPEECH_VOICE_OPTIONS,
|
|
871
844
|
SPEECH_PLAYBACK_STATE_EVENT,
|
|
872
845
|
SpeechPlayback,
|
|
873
846
|
splitSpeechText
|
package/src/app-descriptor.mjs
CHANGED
|
@@ -437,7 +437,7 @@ export async function loadAppDescriptor({workspaceRoot,appRoot,appId,packageMani
|
|
|
437
437
|
const nativeDescriptor=isObject(registry?.apps?.[appId])?registry.apps[appId]:undefined;
|
|
438
438
|
return completeValue({
|
|
439
439
|
descriptor:synthesizedDescriptor(packageManifest,nativeDescriptor),
|
|
440
|
-
source:nativeDescriptor?'
|
|
440
|
+
source:nativeDescriptor?'registry-projection':'package-projection',
|
|
441
441
|
descriptorPath:null
|
|
442
442
|
});
|
|
443
443
|
}
|
package/src/doctor.mjs
CHANGED
|
@@ -269,9 +269,7 @@ export async function runDoctor({
|
|
|
269
269
|
checks.push(check(
|
|
270
270
|
'workspace-runtime',
|
|
271
271
|
'pass',
|
|
272
|
-
|
|
273
|
-
?'The legacy integrated Arcane runtime routes are valid.'
|
|
274
|
-
:'The integrated physical browser-runtime routes are valid.',
|
|
272
|
+
'The integrated physical browser-runtime routes are valid.',
|
|
275
273
|
{details:{layout}}
|
|
276
274
|
));
|
|
277
275
|
}
|
package/src/event-manager.mjs
CHANGED
|
@@ -28,7 +28,6 @@ export const ARCANE_EVENT_AUTHORITY_KIND='arcane-event-authority';
|
|
|
28
28
|
export const ARCANE_EVENT_SOURCE_KIND='arcane-event-source';
|
|
29
29
|
export const ARCANE_EVENT_LISTENER_ERROR_EVENT='arcane.event.listener.error';
|
|
30
30
|
export const ARCANE_EVENT_SOURCE_DISPOSED_EVENT='arcane.event.source.disposed';
|
|
31
|
-
const ARCANE_EVENT_TARGET_COMPATIBILITY_SOURCE='event-target-compatibility';
|
|
32
31
|
const ARCANE_EVENT_NAME_PATTERN=/^[a-z][a-z0-9]*(?:[.-][a-z0-9]+)*$/u;
|
|
33
32
|
const ARCANE_EVENT_CHANNEL_PREFIX='arcane.event.authority.internal:';
|
|
34
33
|
const ARCANE_EVENT_PROJECTION_KEYS=[
|
|
@@ -36,23 +35,13 @@ const ARCANE_EVENT_PROJECTION_KEYS=[
|
|
|
36
35
|
];
|
|
37
36
|
const ARCANE_EVENT_REQUIRED_AUTHORITY_API=[
|
|
38
37
|
'on','once','off','reset','emit','instrument','forward','subscribe','createSource',
|
|
39
|
-
'projectDOMEvent','isOccurrence','addEventListener','removeEventListener'
|
|
38
|
+
'projectDOMEvent','isOccurrence','addEventListener','removeEventListener'
|
|
40
39
|
];
|
|
41
40
|
const EVENT_MANAGER_BUS_ON=Symbol('EventManager.busOn');
|
|
42
41
|
const EVENT_MANAGER_BUS_OFF=Symbol('EventManager.busOff');
|
|
43
42
|
const EVENT_MANAGER_DISPATCH=Symbol('EventManager.dispatch');
|
|
44
43
|
|
|
45
44
|
const ARCANE_EVENT_ERRORS={
|
|
46
|
-
ARCANE_EVENT_AUTHORITY_ACCESSOR_COLLISION:
|
|
47
|
-
'globalThis.arcaneEvents must be an own data property.',
|
|
48
|
-
ARCANE_EVENT_AUTHORITY_VALUE_COLLISION:
|
|
49
|
-
'globalThis.arcaneEvents is occupied by an unbranded value.',
|
|
50
|
-
ARCANE_EVENT_AUTHORITY_DESCRIPTOR_MISMATCH:
|
|
51
|
-
'The globalThis.arcaneEvents property, authority brand, or protocol descriptor is incompatible.',
|
|
52
|
-
ARCANE_EVENT_AUTHORITY_PROTOCOL_MISMATCH:
|
|
53
|
-
'globalThis.arcaneEvents uses an incompatible authority protocol.',
|
|
54
|
-
ARCANE_EVENT_AUTHORITY_API_MISMATCH:
|
|
55
|
-
'globalThis.arcaneEvents does not expose the required authority API.',
|
|
56
45
|
ARCANE_EVENT_AUTHORITY_INSTALL_FAILED:
|
|
57
46
|
'The Arcane event authority could not be installed on globalThis.',
|
|
58
47
|
ARCANE_EVENT_SOURCE_INVALID:
|
|
@@ -63,8 +52,6 @@ const ARCANE_EVENT_ERRORS={
|
|
|
63
52
|
'The Arcane event source is disposed.',
|
|
64
53
|
ARCANE_EVENT_SOURCE_EVENT_TYPE_UNDECLARED:
|
|
65
54
|
'The Arcane event source cannot publish an undeclared event type.',
|
|
66
|
-
ARCANE_EVENT_COMPATIBILITY_DETAIL_INVALID:
|
|
67
|
-
'Arcane event compatibility detail must be safely shallow-copyable.',
|
|
68
55
|
ARCANE_EVENT_OCCURRENCE_INVALID:
|
|
69
56
|
'The Arcane event occurrence value or creation options are invalid.',
|
|
70
57
|
ARCANE_EVENT_OCCURRENCE_SEQUENCE_EXHAUSTED:
|
|
@@ -74,7 +61,7 @@ const ARCANE_EVENT_ERRORS={
|
|
|
74
61
|
ARCANE_EVENT_LISTENER_CALLBACK_FAILED:
|
|
75
62
|
'An Arcane event listener threw during observational delivery.',
|
|
76
63
|
ARCANE_EVENT_DOM_DETAIL_COLLISION:
|
|
77
|
-
'Arcane DOM projection metadata conflicts with
|
|
64
|
+
'Arcane DOM projection metadata conflicts with source detail.',
|
|
78
65
|
ARCANE_EVENT_DOM_TARGET_INVALID:
|
|
79
66
|
'Arcane DOM projection requires a target with dispatchEvent and CustomEvent support.',
|
|
80
67
|
ARCANE_EVENT_DOM_OPTIONS_INVALID:
|
|
@@ -88,7 +75,7 @@ const ARCANE_EVENT_ERRORS={
|
|
|
88
75
|
ARCANE_EVENT_SUBSCRIPTION_SIGNAL_INVALID:
|
|
89
76
|
'Arcane event subscription signal must be an AbortSignal.',
|
|
90
77
|
ARCANE_EVENT_DISPATCH_EVENT_INVALID:
|
|
91
|
-
'
|
|
78
|
+
'dispatchEvent requires an Event-like object with a valid type and data detail.'
|
|
92
79
|
};
|
|
93
80
|
export const ARCANE_EVENT_ERROR_CODES=Object.fromEntries(
|
|
94
81
|
Object.keys(ARCANE_EVENT_ERRORS).map(code=>[code,code])
|
|
@@ -1345,7 +1332,7 @@ function createArcaneEventAuthority(){
|
|
|
1345
1332
|
const compatibilityByOccurrence=new WeakMap();
|
|
1346
1333
|
const sourceRecordByOccurrence=new WeakMap();
|
|
1347
1334
|
const authorityTargetListeners=[];
|
|
1348
|
-
const
|
|
1335
|
+
const directListeners=[];
|
|
1349
1336
|
let occurrenceSequence=0;
|
|
1350
1337
|
let sourceSequence=0;
|
|
1351
1338
|
let reportingListenerError=false;
|
|
@@ -1664,9 +1651,9 @@ function createArcaneEventAuthority(){
|
|
|
1664
1651
|
record.unsubscribe();
|
|
1665
1652
|
}
|
|
1666
1653
|
|
|
1667
|
-
function dispatchEventLike(value,sourceRecord
|
|
1654
|
+
function dispatchEventLike(value,sourceRecord){
|
|
1668
1655
|
const admitted=eventLikeRecord(value);
|
|
1669
|
-
if(sourceRecord
|
|
1656
|
+
if(!sourceRecord.eventTypes.has(admitted.type)){
|
|
1670
1657
|
throw eventAuthorityError('ARCANE_EVENT_SOURCE_EVENT_TYPE_UNDECLARED');
|
|
1671
1658
|
}
|
|
1672
1659
|
const detail=compatibilityDetail(admitted.detail);
|
|
@@ -1679,8 +1666,8 @@ function createArcaneEventAuthority(){
|
|
|
1679
1666
|
const publication=dispatchOccurrence({
|
|
1680
1667
|
type:admitted.type,
|
|
1681
1668
|
sourceRecord,
|
|
1682
|
-
source:sourceRecord
|
|
1683
|
-
instanceId:sourceRecord
|
|
1669
|
+
source:sourceRecord.source,
|
|
1670
|
+
instanceId:sourceRecord.instanceId,
|
|
1684
1671
|
compatibility:detail,
|
|
1685
1672
|
publicDetail:detail,
|
|
1686
1673
|
operationId,
|
|
@@ -1943,43 +1930,43 @@ function createArcaneEventAuthority(){
|
|
|
1943
1930
|
return accepted&&!occurrence.defaultPrevented;
|
|
1944
1931
|
}
|
|
1945
1932
|
|
|
1946
|
-
function
|
|
1933
|
+
function safeDirectOn(type,handler,once=false){
|
|
1947
1934
|
const admittedType=type==='*'?'*':eventName(type);
|
|
1948
1935
|
const admitted=eventListener(handler);
|
|
1949
1936
|
if(typeof once!=='boolean'){
|
|
1950
1937
|
throw eventAuthorityError('ARCANE_EVENT_SUBSCRIPTION_OPTIONS_INVALID',undefined,TypeError);
|
|
1951
1938
|
}
|
|
1952
1939
|
const record={type:admittedType,identity:admitted.identity,wrapper:null};
|
|
1953
|
-
function
|
|
1954
|
-
if(once)
|
|
1940
|
+
function safeDirectListener(value,...rest){
|
|
1941
|
+
if(once)removeDirectRecord(record);
|
|
1955
1942
|
try{admitted.invoke(value,manager,...rest);}
|
|
1956
1943
|
catch(error){reportListenerFailure(error,null,null);}
|
|
1957
1944
|
}
|
|
1958
|
-
record.wrapper=
|
|
1959
|
-
|
|
1960
|
-
manager[EVENT_MANAGER_BUS_ON](admittedType,
|
|
1945
|
+
record.wrapper=safeDirectListener;
|
|
1946
|
+
directListeners.push(record);
|
|
1947
|
+
manager[EVENT_MANAGER_BUS_ON](admittedType,safeDirectListener);
|
|
1961
1948
|
return manager;
|
|
1962
1949
|
}
|
|
1963
1950
|
|
|
1964
|
-
function
|
|
1965
|
-
const index=
|
|
1951
|
+
function removeDirectRecord(record){
|
|
1952
|
+
const index=directListeners.indexOf(record);
|
|
1966
1953
|
if(index<0)return false;
|
|
1967
|
-
|
|
1954
|
+
directListeners.splice(index,1);
|
|
1968
1955
|
manager[EVENT_MANAGER_BUS_OFF](record.type,record.wrapper);
|
|
1969
1956
|
return true;
|
|
1970
1957
|
}
|
|
1971
1958
|
|
|
1972
|
-
function
|
|
1959
|
+
function safeDirectOff(type='*',handler='*'){
|
|
1973
1960
|
const admittedType=type==='*'?'*':eventName(type);
|
|
1974
|
-
const selected=
|
|
1961
|
+
const selected=directListeners.filter(record=>(admittedType==='*'||record.type===admittedType)
|
|
1975
1962
|
&&(handler==='*'||record.identity===handler));
|
|
1976
1963
|
if(handler!=='*')eventListener(handler);
|
|
1977
|
-
for(const record of selected)
|
|
1964
|
+
for(const record of selected)removeDirectRecord(record);
|
|
1978
1965
|
return manager;
|
|
1979
1966
|
}
|
|
1980
1967
|
|
|
1981
|
-
function
|
|
1982
|
-
for(const record of [...
|
|
1968
|
+
function safeDirectReset(){
|
|
1969
|
+
for(const record of [...directListeners])removeDirectRecord(record);
|
|
1983
1970
|
return manager;
|
|
1984
1971
|
}
|
|
1985
1972
|
|
|
@@ -1987,10 +1974,10 @@ function createArcaneEventAuthority(){
|
|
|
1987
1974
|
[ARCANE_EVENT_AUTHORITY_BRAND]:ARCANE_EVENT_AUTHORITY_PROTOCOL,
|
|
1988
1975
|
protocol:ARCANE_EVENT_AUTHORITY_PROTOCOL,
|
|
1989
1976
|
descriptor,
|
|
1990
|
-
on:
|
|
1991
|
-
once:(type,handler)=>
|
|
1992
|
-
off:
|
|
1993
|
-
reset:
|
|
1977
|
+
on:safeDirectOn,
|
|
1978
|
+
once:(type,handler)=>safeDirectOn(type,handler,true),
|
|
1979
|
+
off:safeDirectOff,
|
|
1980
|
+
reset:safeDirectReset,
|
|
1994
1981
|
subscribe,
|
|
1995
1982
|
createSource,
|
|
1996
1983
|
projectDOMEvent,
|
|
@@ -2007,8 +1994,7 @@ function createArcaneEventAuthority(){
|
|
|
2007
1994
|
},
|
|
2008
1995
|
removeEventListener(type,handler,options){
|
|
2009
1996
|
removeEventTargetListener(authorityTargetListeners,type,handler,options);
|
|
2010
|
-
}
|
|
2011
|
-
dispatchEvent:value=>dispatchEventLike(value)
|
|
1997
|
+
}
|
|
2012
1998
|
});
|
|
2013
1999
|
return manager;
|
|
2014
2000
|
}
|
package/src/import-map.mjs
CHANGED
|
@@ -82,7 +82,7 @@ function normalizedDocumentPaths(entry,documents){
|
|
|
82
82
|
function decodedEscape(source,index){
|
|
83
83
|
const character=source[index];
|
|
84
84
|
if(/[1-9]/u.test(character)||(character==='0'&&/[0-9]/u.test(source[index+1]??''))){
|
|
85
|
-
fail('Import-map scan found
|
|
85
|
+
fail('Import-map scan found an octal or decimal string escape.');
|
|
86
86
|
}
|
|
87
87
|
const simple={b:'\b',f:'\f',n:'\n',r:'\r',t:'\t',v:'\v','0':'\0'};
|
|
88
88
|
if(Object.hasOwn(simple,character))return {value:simple[character],next:index+1};
|
package/src/index.mjs
CHANGED
|
@@ -74,9 +74,7 @@ export {
|
|
|
74
74
|
export {runDoctor,assessArcaneOllama} from './doctor.mjs';
|
|
75
75
|
export {
|
|
76
76
|
ARCANE_NATIVE_PROVIDER_PATHS,
|
|
77
|
-
|
|
78
|
-
loadArcaneNativeProvider,
|
|
79
|
-
loadArcanePortableProvider
|
|
77
|
+
loadArcaneNativeProvider
|
|
80
78
|
} from './native-provider-loader.mjs';
|
|
81
79
|
export {
|
|
82
80
|
ARCANE_INTEGRATED_PROVIDER_RELATIVE_PATH,
|
|
@@ -99,7 +97,6 @@ export {
|
|
|
99
97
|
} from './targets/index.mjs';
|
|
100
98
|
export {
|
|
101
99
|
assertIntegratedNativeToolchain,
|
|
102
|
-
assertIntegratedPortableToolchain,
|
|
103
100
|
buildApplication,
|
|
104
101
|
bundleApplication,
|
|
105
102
|
checkApplication,
|
|
@@ -117,7 +114,6 @@ export {
|
|
|
117
114
|
planApplication,
|
|
118
115
|
prepareNativeTarget,
|
|
119
116
|
resolveNativeBuildOutputRoot,
|
|
120
|
-
resolvePortableBuildOutputRoot,
|
|
121
117
|
repositoryApplication,
|
|
122
118
|
runApplication,
|
|
123
119
|
testApplication,
|
|
@@ -138,10 +134,7 @@ export {
|
|
|
138
134
|
loadSdkBrowserRuntimeRelease,
|
|
139
135
|
readSdkBrowserRuntimeFile
|
|
140
136
|
} from './sdk-browser-runtime.mjs';
|
|
141
|
-
export {
|
|
142
|
-
materializeWorkspaceRuntime,
|
|
143
|
-
materializeWorkspaceRuntimeContent
|
|
144
|
-
} from './workspace-runtime.mjs';
|
|
137
|
+
export {materializeWorkspaceRuntimeContent} from './workspace-runtime.mjs';
|
|
145
138
|
export {
|
|
146
139
|
discoverApps,
|
|
147
140
|
inspectWorkspaceProfile,
|