arcane-os 0.2.2 → 0.3.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 +29 -0
- package/README.md +8 -8
- package/browser-runtime/ARCANE_SDK_BROWSER_RELEASE.json +29 -22
- package/browser-runtime/ai/ARCANE_AI_BROWSER_SPEECH_COMPONENTS.json +203 -0
- package/browser-runtime/ai/browser-kokoro-worker.mjs +11 -2
- package/browser-runtime/ai/browser-speech-artifacts.mjs +3230 -397
- package/browser-runtime/ai/browser-speech-providers.mjs +1141 -157
- package/browser-runtime/ai/browser-speech.mjs +2 -0
- package/browser-runtime/ai/browser-whisper-worker.mjs +11 -2
- package/browser-runtime/ai/model-controller.mjs +285 -95
- package/browser-runtime/ai/speech-worker-client.mjs +247 -32
- package/browser-runtime/ai/speech-worker-runtime.mjs +2310 -167
- package/browser-runtime/event-manager.mjs +1097 -1
- package/docs/architecture.md +2 -2
- package/docs/event-manager.md +155 -27
- package/docs/reference/README.md +27 -27
- package/docs/reference/ai/browser-speech-package-authority.json +835 -0
- package/docs/reference/ai/browser-speech.md +1162 -246
- package/docs/reference/ai/browser-wasm.md +18 -7
- package/docs/reference/availability-and-normalization.md +6 -3
- package/docs/reference/behavioral-testing.md +29 -6
- package/docs/reference/cli.md +117 -9
- package/docs/reference/core/arcane-ai-contracts.md +1 -1
- package/docs/reference/event-manager.md +577 -32
- package/docs/reference/inventory/package-api.json +478 -2
- package/docs/reference/inventory/runtime-components.json +108 -44
- package/docs/reference/inventory/runtime-modules.json +131 -53
- package/docs/reference/mail.md +316 -0
- package/docs/reference/protocols.md +157 -43
- package/docs/reference/runtime-components.md +258 -83
- package/docs/reference/runtime-modules.md +613 -77
- package/docs/reference/sdk-api.md +1014 -25
- package/package.json +5 -4
- package/runtime/ARCANE_RUNTIME_RELEASE.json +145 -140
- package/runtime/arcane/components/app-bar.html +34 -13
- package/runtime/arcane/components/assistant-panel.html +110 -57
- package/runtime/arcane/components/calculator.html +7 -4
- package/runtime/arcane/components/chart.html +58 -17
- package/runtime/arcane/components/chat.html +606 -136
- package/runtime/arcane/components/conversation-view.html +13 -6
- package/runtime/arcane/components/dashboard-config.html +96 -59
- package/runtime/arcane/components/data-maintenance.html +69 -14
- package/runtime/arcane/components/data-view.html +53 -7
- package/runtime/arcane/components/directory-picker.html +118 -32
- package/runtime/arcane/components/document-inspector.html +47 -10
- package/runtime/arcane/components/file-drop.html +81 -35
- package/runtime/arcane/components/file-inspector.html +72 -22
- package/runtime/arcane/components/file-manager.html +374 -79
- package/runtime/arcane/components/integration-settings.html +12 -5
- package/runtime/arcane/components/local-ai-status.html +48 -19
- package/runtime/arcane/components/markdown-document.html +161 -68
- package/runtime/arcane/components/markdown-editor.html +110 -33
- package/runtime/arcane/components/media-embed.html +8 -5
- package/runtime/arcane/components/modal.html +15 -5
- package/runtime/arcane/components/output-panel.html +28 -23
- package/runtime/arcane/components/preferences-form.html +22 -4
- package/runtime/arcane/components/record-timeline.html +18 -2
- package/runtime/arcane/components/relationship-board.html +23 -3
- package/runtime/arcane/components/screen-capture.html +10 -4
- package/runtime/arcane/components/source-code-viewer.html +76 -9
- package/runtime/arcane/components/source-explanation.html +23 -3
- package/runtime/arcane/components/speech.html +462 -384
- package/runtime/arcane/components/summary-strip.html +22 -11
- package/runtime/arcane/components/table.html +39 -21
- package/runtime/arcane/components/task-progress.html +79 -21
- package/runtime/arcane/components/terminal-workspace.html +7 -4
- package/runtime/arcane/components/theme-editor.html +7 -3
- package/runtime/arcane/components/unified-inbox.html +9 -4
- package/runtime/arcane/components/voice-transcription.html +639 -98
- package/runtime/arcane/components/weather-widget.html +5 -3
- package/runtime/arcane/components/web-navigator.html +48 -8
- package/runtime/arcane/entities/Chat.js +1 -1
- package/runtime/arcane/entities/User.js +110 -23
- package/runtime/arcane/modules/AI.js +2109 -130
- package/runtime/arcane/modules/AIProviderRuntime.js +720 -13
- package/runtime/arcane/modules/AIRuntimeState.js +109 -52
- package/runtime/arcane/modules/ApiModelDatabase.js +390 -17
- package/runtime/arcane/modules/BrowserTestSuite.js +205 -28
- package/runtime/arcane/modules/CalculatorEngine.js +63 -3
- package/runtime/arcane/modules/CommunicationAppController.js +588 -28
- package/runtime/arcane/modules/CommunicationHub.js +590 -10
- package/runtime/arcane/modules/ComponentContracts.js +470 -0
- package/runtime/arcane/modules/ConversationTimebox.js +152 -33
- package/runtime/arcane/modules/DBLS.js +40 -7
- package/runtime/arcane/modules/DBOPFS.js +35 -11
- package/runtime/arcane/modules/DataMaintenance.js +12 -2
- package/runtime/arcane/modules/Errors.js +65 -7
- package/runtime/arcane/modules/HTMLImport.js +198 -14
- package/runtime/arcane/modules/LocalAIReadinessController.js +208 -29
- package/runtime/arcane/modules/Mail.js +738 -115
- package/runtime/arcane/modules/MailOutbox.mjs +1395 -0
- package/runtime/arcane/modules/MailTransport.mjs +197 -39
- package/runtime/arcane/modules/Ollama.js +36 -1
- package/runtime/arcane/modules/OpenMeteoWeatherProvider.js +583 -7
- package/runtime/arcane/modules/PreferenceStore.js +367 -33
- package/runtime/arcane/modules/RecordReviewStore.js +322 -23
- package/runtime/arcane/modules/ScreenCapture.js +1397 -15
- package/runtime/arcane/modules/SpeechPlayback.js +438 -41
- package/runtime/arcane/modules/TerminalClient.js +277 -12
- package/runtime/arcane/modules/ThemeBootstrap.js +80 -6
- package/runtime/arcane/modules/ThemeManager.js +39 -7
- package/runtime/arcane/modules/TimeGuard.js +131 -20
- package/runtime/arcane/modules/WaitForComponent.js +386 -33
- package/schemas/arcane-lock.schema.json +2 -2
- package/src/cli/main.mjs +435 -9
- package/src/event-manager.mjs +1097 -1
- package/src/import-map.mjs +21 -3
- package/src/index.mjs +13 -0
- package/src/installed-sdk-runtime.mjs +112 -0
- package/src/mail-api.mjs +22 -0
- package/src/mail-credentials.mjs +667 -0
- package/src/mail-server.mjs +1769 -0
- package/src/mail.mjs +261 -0
- package/src/sdk-browser-runtime.mjs +85 -41
- package/src/testing-loader.mjs +7 -0
- package/src/toolchain.mjs +3 -0
- package/src/workspace.mjs +1 -1
package/src/event-manager.mjs
CHANGED
|
@@ -13,6 +13,10 @@ export {
|
|
|
13
13
|
} from './dom-event-instrumentation.mjs';
|
|
14
14
|
|
|
15
15
|
export const ARCANE_EVENT_STACK_PROTOCOL='arcane-event-stack/1';
|
|
16
|
+
export const ARCANE_EVENT_AUTHORITY_PROTOCOL='arcane-event-authority/1';
|
|
17
|
+
export const ARCANE_EVENT_OCCURRENCE_PROTOCOL='arcane-event-occurrence/1';
|
|
18
|
+
export const ARCANE_EVENT_SOURCE_PROTOCOL='arcane-event-source/1';
|
|
19
|
+
export const ARCANE_EVENT_AUTHORITY_BRAND=Symbol.for('arcane-os.arcane-events-authority');
|
|
16
20
|
export const TIME_TRAVEL_SEEK_EVENT='arcane.time-travel.seek';
|
|
17
21
|
export const PLAYBACK_STARTED_EVENT='arcane.time-travel.playback.started';
|
|
18
22
|
export const PLAYBACK_RECORD_EVENT='arcane.time-travel.playback.record';
|
|
@@ -21,6 +25,76 @@ export const PLAYBACK_CANCELLED_EVENT='arcane.time-travel.playback.cancelled';
|
|
|
21
25
|
export const PLAYBACK_FAILED_EVENT='arcane.time-travel.playback.failed';
|
|
22
26
|
export const TIME_TRAVEL_OVERFLOW_EVENT='arcane.time-travel.overflow';
|
|
23
27
|
|
|
28
|
+
export const ARCANE_EVENT_AUTHORITY_KIND='arcane-event-authority';
|
|
29
|
+
export const ARCANE_EVENT_SOURCE_KIND='arcane-event-source';
|
|
30
|
+
export const ARCANE_EVENT_LISTENER_ERROR_EVENT='arcane.event.listener.error';
|
|
31
|
+
export const ARCANE_EVENT_SOURCE_DISPOSED_EVENT='arcane.event.source.disposed';
|
|
32
|
+
const ARCANE_EVENT_TARGET_COMPATIBILITY_SOURCE='event-target-compatibility';
|
|
33
|
+
const ARCANE_EVENT_NAME_PATTERN=/^[a-z][a-z0-9]*(?:[.-][a-z0-9]+)*$/u;
|
|
34
|
+
const ARCANE_EVENT_CHANNEL_PREFIX='arcane.event.authority.internal:';
|
|
35
|
+
const ARCANE_EVENT_PROJECTION_KEYS=Object.freeze([
|
|
36
|
+
'occurrenceId','arcaneSource','instanceId','operationId'
|
|
37
|
+
]);
|
|
38
|
+
const ARCANE_EVENT_REQUIRED_AUTHORITY_API=Object.freeze([
|
|
39
|
+
'on','once','off','reset','emit','instrument','forward','subscribe','createSource',
|
|
40
|
+
'projectDOMEvent','isOccurrence','addEventListener','removeEventListener','dispatchEvent'
|
|
41
|
+
]);
|
|
42
|
+
const EVENT_MANAGER_BUS_ON=Symbol('EventManager.busOn');
|
|
43
|
+
const EVENT_MANAGER_BUS_OFF=Symbol('EventManager.busOff');
|
|
44
|
+
const EVENT_MANAGER_DISPATCH=Symbol('EventManager.dispatch');
|
|
45
|
+
|
|
46
|
+
const ARCANE_EVENT_ERRORS=Object.freeze({
|
|
47
|
+
ARCANE_EVENT_AUTHORITY_ACCESSOR_COLLISION:
|
|
48
|
+
'globalThis.arcaneEvents must be an own data property.',
|
|
49
|
+
ARCANE_EVENT_AUTHORITY_VALUE_COLLISION:
|
|
50
|
+
'globalThis.arcaneEvents is occupied by an unbranded value.',
|
|
51
|
+
ARCANE_EVENT_AUTHORITY_DESCRIPTOR_MISMATCH:
|
|
52
|
+
'The globalThis.arcaneEvents property, authority brand, or protocol descriptor is incompatible.',
|
|
53
|
+
ARCANE_EVENT_AUTHORITY_PROTOCOL_MISMATCH:
|
|
54
|
+
'globalThis.arcaneEvents uses an incompatible authority protocol.',
|
|
55
|
+
ARCANE_EVENT_AUTHORITY_API_MISMATCH:
|
|
56
|
+
'globalThis.arcaneEvents does not expose the required authority API.',
|
|
57
|
+
ARCANE_EVENT_AUTHORITY_INSTALL_FAILED:
|
|
58
|
+
'The Arcane event authority could not be installed on globalThis.',
|
|
59
|
+
ARCANE_EVENT_SOURCE_INVALID:
|
|
60
|
+
'Arcane event source options are invalid.',
|
|
61
|
+
ARCANE_EVENT_SOURCE_ALREADY_REGISTERED:
|
|
62
|
+
'The owner already has an active Arcane event source.',
|
|
63
|
+
ARCANE_EVENT_SOURCE_DISPOSED:
|
|
64
|
+
'The Arcane event source is disposed.',
|
|
65
|
+
ARCANE_EVENT_SOURCE_EVENT_TYPE_UNDECLARED:
|
|
66
|
+
'The Arcane event source cannot publish an undeclared event type.',
|
|
67
|
+
ARCANE_EVENT_COMPATIBILITY_DETAIL_INVALID:
|
|
68
|
+
'Arcane event compatibility detail must be immutable or safely shallow-copyable.',
|
|
69
|
+
ARCANE_EVENT_OCCURRENCE_INVALID:
|
|
70
|
+
'The Arcane event occurrence value or creation options are invalid.',
|
|
71
|
+
ARCANE_EVENT_OCCURRENCE_SEQUENCE_EXHAUSTED:
|
|
72
|
+
'The Arcane event occurrence sequence is exhausted.',
|
|
73
|
+
ARCANE_EVENT_SOURCE_SEQUENCE_EXHAUSTED:
|
|
74
|
+
'The Arcane event source sequence is exhausted.',
|
|
75
|
+
ARCANE_EVENT_LISTENER_CALLBACK_FAILED:
|
|
76
|
+
'An Arcane event listener threw during observational delivery.',
|
|
77
|
+
ARCANE_EVENT_DOM_DETAIL_COLLISION:
|
|
78
|
+
'Arcane DOM projection metadata conflicts with compatibility detail.',
|
|
79
|
+
ARCANE_EVENT_DOM_TARGET_INVALID:
|
|
80
|
+
'Arcane DOM projection requires a target with dispatchEvent and CustomEvent support.',
|
|
81
|
+
ARCANE_EVENT_DOM_OPTIONS_INVALID:
|
|
82
|
+
'Arcane DOM projection options are invalid.',
|
|
83
|
+
ARCANE_EVENT_SUBSCRIPTION_TYPE_INVALID:
|
|
84
|
+
'Arcane event subscription type must be a nonempty trimmed string.',
|
|
85
|
+
ARCANE_EVENT_SUBSCRIPTION_HANDLER_INVALID:
|
|
86
|
+
'Arcane event subscription handler must be a function or EventListener object.',
|
|
87
|
+
ARCANE_EVENT_SUBSCRIPTION_OPTIONS_INVALID:
|
|
88
|
+
'Arcane event subscription options are invalid.',
|
|
89
|
+
ARCANE_EVENT_SUBSCRIPTION_SIGNAL_INVALID:
|
|
90
|
+
'Arcane event subscription signal must be an AbortSignal.',
|
|
91
|
+
ARCANE_EVENT_DISPATCH_EVENT_INVALID:
|
|
92
|
+
'arcaneEvents.dispatchEvent requires an Event-like object with a valid type and data detail.'
|
|
93
|
+
});
|
|
94
|
+
export const ARCANE_EVENT_ERROR_CODES=Object.freeze(Object.fromEntries(
|
|
95
|
+
Object.keys(ARCANE_EVENT_ERRORS).map(code=>[code,code])
|
|
96
|
+
));
|
|
97
|
+
|
|
24
98
|
const SENSITIVE_KEY_PATTERN=/(?:authorization|cookie|credential|pass(?:word|phrase)?|private.?key|secret|session.?token|token|api.?key)/iu;
|
|
25
99
|
const PRIVATE_CONTENT_KEY_PATTERN=/^(?:data|detail|key)$/iu;
|
|
26
100
|
const INTERNAL_STACK_PATTERN=/(?:EventManager\.|#dispatch|event-manager\.mjs)/u;
|
|
@@ -899,6 +973,20 @@ export class EventManager{
|
|
|
899
973
|
get history(){return Object.freeze([...this.#history]);}
|
|
900
974
|
get domInstrumentation(){return this.#domInstrumentation;}
|
|
901
975
|
|
|
976
|
+
[EVENT_MANAGER_BUS_ON](type,handler,once=false){
|
|
977
|
+
this.#bus.on(type,handler,once);
|
|
978
|
+
return this;
|
|
979
|
+
}
|
|
980
|
+
|
|
981
|
+
[EVENT_MANAGER_BUS_OFF](type,handler='*'){
|
|
982
|
+
this.#bus.off(type,handler);
|
|
983
|
+
return this;
|
|
984
|
+
}
|
|
985
|
+
|
|
986
|
+
[EVENT_MANAGER_DISPATCH](type,payload,metadata={}){
|
|
987
|
+
return this.#dispatch(type,[payload],metadata);
|
|
988
|
+
}
|
|
989
|
+
|
|
902
990
|
on(type,handler,once=false){
|
|
903
991
|
this.#bus.on(type,handler,once);
|
|
904
992
|
return this;
|
|
@@ -1339,4 +1427,1012 @@ export function createEventManager(options){
|
|
|
1339
1427
|
return new EventManager(options);
|
|
1340
1428
|
}
|
|
1341
1429
|
|
|
1342
|
-
|
|
1430
|
+
function eventAuthorityError(code,cause,ErrorType=Error){
|
|
1431
|
+
const message=ARCANE_EVENT_ERRORS[code]??'The Arcane event authority failed.';
|
|
1432
|
+
const error=cause===undefined
|
|
1433
|
+
?new ErrorType(message)
|
|
1434
|
+
:new ErrorType(message,{cause});
|
|
1435
|
+
error.code=code;
|
|
1436
|
+
return error;
|
|
1437
|
+
}
|
|
1438
|
+
|
|
1439
|
+
function eventName(value,code='ARCANE_EVENT_SUBSCRIPTION_TYPE_INVALID'){
|
|
1440
|
+
if(typeof value!=='string'
|
|
1441
|
+
||value.trim()!==value
|
|
1442
|
+
||value.length<1
|
|
1443
|
+
||value.length>128
|
|
1444
|
+
||!ARCANE_EVENT_NAME_PATTERN.test(value)){
|
|
1445
|
+
throw eventAuthorityError(code,undefined,TypeError);
|
|
1446
|
+
}
|
|
1447
|
+
return value;
|
|
1448
|
+
}
|
|
1449
|
+
|
|
1450
|
+
function eventDataOptions(value,allowed,code){
|
|
1451
|
+
if(value===undefined)return Object.create(null);
|
|
1452
|
+
if(!value||typeof value!=='object'||Array.isArray(value)){
|
|
1453
|
+
throw eventAuthorityError(code,undefined,TypeError);
|
|
1454
|
+
}
|
|
1455
|
+
const prototype=Object.getPrototypeOf(value);
|
|
1456
|
+
if(prototype!==Object.prototype&&prototype!==null){
|
|
1457
|
+
throw eventAuthorityError(code,undefined,TypeError);
|
|
1458
|
+
}
|
|
1459
|
+
const result=Object.create(null);
|
|
1460
|
+
for(const key of Reflect.ownKeys(value)){
|
|
1461
|
+
if(typeof key!=='string'||!allowed.has(key)){
|
|
1462
|
+
throw eventAuthorityError(code,undefined,TypeError);
|
|
1463
|
+
}
|
|
1464
|
+
const descriptor=Object.getOwnPropertyDescriptor(value,key);
|
|
1465
|
+
if(!descriptor||!('value' in descriptor)){
|
|
1466
|
+
throw eventAuthorityError(code,undefined,TypeError);
|
|
1467
|
+
}
|
|
1468
|
+
result[key]=descriptor.value;
|
|
1469
|
+
}
|
|
1470
|
+
return result;
|
|
1471
|
+
}
|
|
1472
|
+
|
|
1473
|
+
function eventSignal(value){
|
|
1474
|
+
if(value===undefined||value===null)return null;
|
|
1475
|
+
if(!value
|
|
1476
|
+
||typeof value!=='object'
|
|
1477
|
+
||typeof value.aborted!=='boolean'
|
|
1478
|
+
||typeof value.addEventListener!=='function'
|
|
1479
|
+
||typeof value.removeEventListener!=='function'){
|
|
1480
|
+
throw eventAuthorityError(
|
|
1481
|
+
'ARCANE_EVENT_SUBSCRIPTION_SIGNAL_INVALID',
|
|
1482
|
+
undefined,
|
|
1483
|
+
TypeError
|
|
1484
|
+
);
|
|
1485
|
+
}
|
|
1486
|
+
return value;
|
|
1487
|
+
}
|
|
1488
|
+
|
|
1489
|
+
function eventListener(value){
|
|
1490
|
+
if(typeof value==='function'){
|
|
1491
|
+
return Object.freeze({
|
|
1492
|
+
identity:value,
|
|
1493
|
+
invoke(event,thisArg,...rest){return value.call(thisArg,event,...rest);}
|
|
1494
|
+
});
|
|
1495
|
+
}
|
|
1496
|
+
if(value&&typeof value==='object'&&typeof value.handleEvent==='function'){
|
|
1497
|
+
return Object.freeze({
|
|
1498
|
+
identity:value,
|
|
1499
|
+
invoke(event){return value.handleEvent(event);}
|
|
1500
|
+
});
|
|
1501
|
+
}
|
|
1502
|
+
throw eventAuthorityError(
|
|
1503
|
+
'ARCANE_EVENT_SUBSCRIPTION_HANDLER_INVALID',
|
|
1504
|
+
undefined,
|
|
1505
|
+
TypeError
|
|
1506
|
+
);
|
|
1507
|
+
}
|
|
1508
|
+
|
|
1509
|
+
function eventTargetListener(value){
|
|
1510
|
+
if(typeof value==='function'){
|
|
1511
|
+
return Object.freeze({
|
|
1512
|
+
identity:value,
|
|
1513
|
+
invoke(event,thisArg,...rest){return value.call(thisArg,event,...rest);}
|
|
1514
|
+
});
|
|
1515
|
+
}
|
|
1516
|
+
if(value&&typeof value==='object'&&typeof value.handleEvent==='function'){
|
|
1517
|
+
return Object.freeze({
|
|
1518
|
+
identity:value,
|
|
1519
|
+
invoke(event){return value.handleEvent(event);}
|
|
1520
|
+
});
|
|
1521
|
+
}
|
|
1522
|
+
return null;
|
|
1523
|
+
}
|
|
1524
|
+
|
|
1525
|
+
function compatibilityDetail(value){
|
|
1526
|
+
if(value===null||(typeof value!=='object'&&typeof value!=='function'))return value;
|
|
1527
|
+
if(Object.isFrozen(value))return value;
|
|
1528
|
+
if(Array.isArray(value))return Object.freeze(value.slice());
|
|
1529
|
+
const prototype=Object.getPrototypeOf(value);
|
|
1530
|
+
if(prototype!==Object.prototype&&prototype!==null)return value;
|
|
1531
|
+
const copy=prototype===null?Object.create(null):{};
|
|
1532
|
+
for(const key of Reflect.ownKeys(value)){
|
|
1533
|
+
const descriptor=Object.getOwnPropertyDescriptor(value,key);
|
|
1534
|
+
if(!descriptor||!('value' in descriptor)){
|
|
1535
|
+
throw eventAuthorityError(
|
|
1536
|
+
'ARCANE_EVENT_COMPATIBILITY_DETAIL_INVALID',
|
|
1537
|
+
undefined,
|
|
1538
|
+
TypeError
|
|
1539
|
+
);
|
|
1540
|
+
}
|
|
1541
|
+
Object.defineProperty(copy,key,{
|
|
1542
|
+
value:descriptor.value,
|
|
1543
|
+
enumerable:descriptor.enumerable,
|
|
1544
|
+
configurable:false,
|
|
1545
|
+
writable:false
|
|
1546
|
+
});
|
|
1547
|
+
}
|
|
1548
|
+
return Object.freeze(copy);
|
|
1549
|
+
}
|
|
1550
|
+
|
|
1551
|
+
function eventTargetOptions(value){
|
|
1552
|
+
if(value===undefined)return Object.freeze({capture:false,once:false,signal:null});
|
|
1553
|
+
if(typeof value==='boolean'){
|
|
1554
|
+
return Object.freeze({capture:value,once:false,signal:null});
|
|
1555
|
+
}
|
|
1556
|
+
const options=eventDataOptions(
|
|
1557
|
+
value,
|
|
1558
|
+
new Set(['capture','once','passive','signal']),
|
|
1559
|
+
'ARCANE_EVENT_SUBSCRIPTION_OPTIONS_INVALID'
|
|
1560
|
+
);
|
|
1561
|
+
for(const key of ['capture','once','passive']){
|
|
1562
|
+
if(options[key]!==undefined&&typeof options[key]!=='boolean'){
|
|
1563
|
+
throw eventAuthorityError(
|
|
1564
|
+
'ARCANE_EVENT_SUBSCRIPTION_OPTIONS_INVALID',
|
|
1565
|
+
undefined,
|
|
1566
|
+
TypeError
|
|
1567
|
+
);
|
|
1568
|
+
}
|
|
1569
|
+
}
|
|
1570
|
+
return Object.freeze({
|
|
1571
|
+
capture:options.capture===true,
|
|
1572
|
+
once:options.once===true,
|
|
1573
|
+
signal:eventSignal(options.signal)
|
|
1574
|
+
});
|
|
1575
|
+
}
|
|
1576
|
+
|
|
1577
|
+
function subscriptionOptions(value){
|
|
1578
|
+
const options=eventDataOptions(
|
|
1579
|
+
value,
|
|
1580
|
+
new Set(['once','signal']),
|
|
1581
|
+
'ARCANE_EVENT_SUBSCRIPTION_OPTIONS_INVALID'
|
|
1582
|
+
);
|
|
1583
|
+
if(options.once!==undefined&&typeof options.once!=='boolean'){
|
|
1584
|
+
throw eventAuthorityError(
|
|
1585
|
+
'ARCANE_EVENT_SUBSCRIPTION_OPTIONS_INVALID',
|
|
1586
|
+
undefined,
|
|
1587
|
+
TypeError
|
|
1588
|
+
);
|
|
1589
|
+
}
|
|
1590
|
+
return Object.freeze({
|
|
1591
|
+
once:options.once===true,
|
|
1592
|
+
signal:eventSignal(options.signal)
|
|
1593
|
+
});
|
|
1594
|
+
}
|
|
1595
|
+
|
|
1596
|
+
function defineDisposable(unsubscribe){
|
|
1597
|
+
Object.defineProperty(unsubscribe,'dispose',{
|
|
1598
|
+
value:unsubscribe,
|
|
1599
|
+
enumerable:false,
|
|
1600
|
+
configurable:false,
|
|
1601
|
+
writable:false
|
|
1602
|
+
});
|
|
1603
|
+
return unsubscribe;
|
|
1604
|
+
}
|
|
1605
|
+
|
|
1606
|
+
function eventLikeRecord(value){
|
|
1607
|
+
try{
|
|
1608
|
+
if(!value||typeof value!=='object'||Array.isArray(value))throw new TypeError();
|
|
1609
|
+
const EventConstructor=globalThis.Event;
|
|
1610
|
+
if(typeof EventConstructor==='function'&&value instanceof EventConstructor){
|
|
1611
|
+
if(!('detail' in value))throw new TypeError();
|
|
1612
|
+
return {
|
|
1613
|
+
type:eventName(value.type,'ARCANE_EVENT_DISPATCH_EVENT_INVALID'),
|
|
1614
|
+
detail:value.detail,
|
|
1615
|
+
cancelable:value.cancelable===true,
|
|
1616
|
+
defaultPrevented:value.defaultPrevented===true,
|
|
1617
|
+
preventDefault:typeof value.preventDefault==='function'
|
|
1618
|
+
?()=>value.preventDefault()
|
|
1619
|
+
:null
|
|
1620
|
+
};
|
|
1621
|
+
}
|
|
1622
|
+
const typeDescriptor=Object.getOwnPropertyDescriptor(value,'type');
|
|
1623
|
+
const detailDescriptor=Object.getOwnPropertyDescriptor(value,'detail');
|
|
1624
|
+
const cancelableDescriptor=Object.getOwnPropertyDescriptor(value,'cancelable');
|
|
1625
|
+
const preventedDescriptor=Object.getOwnPropertyDescriptor(value,'defaultPrevented');
|
|
1626
|
+
if(!typeDescriptor||!('value' in typeDescriptor)
|
|
1627
|
+
||!detailDescriptor||!('value' in detailDescriptor)
|
|
1628
|
+
||(cancelableDescriptor&&!('value' in cancelableDescriptor))
|
|
1629
|
+
||(preventedDescriptor&&!('value' in preventedDescriptor))){
|
|
1630
|
+
throw new TypeError();
|
|
1631
|
+
}
|
|
1632
|
+
return {
|
|
1633
|
+
type:eventName(typeDescriptor.value,'ARCANE_EVENT_DISPATCH_EVENT_INVALID'),
|
|
1634
|
+
detail:detailDescriptor?.value,
|
|
1635
|
+
cancelable:cancelableDescriptor?.value===true,
|
|
1636
|
+
defaultPrevented:preventedDescriptor?.value===true,
|
|
1637
|
+
preventDefault:typeof value.preventDefault==='function'
|
|
1638
|
+
?()=>value.preventDefault()
|
|
1639
|
+
:null
|
|
1640
|
+
};
|
|
1641
|
+
}catch(error){
|
|
1642
|
+
if(error?.code==='ARCANE_EVENT_DISPATCH_EVENT_INVALID')throw error;
|
|
1643
|
+
throw eventAuthorityError(
|
|
1644
|
+
'ARCANE_EVENT_DISPATCH_EVENT_INVALID',
|
|
1645
|
+
error,
|
|
1646
|
+
TypeError
|
|
1647
|
+
);
|
|
1648
|
+
}
|
|
1649
|
+
}
|
|
1650
|
+
|
|
1651
|
+
function createArcaneEventAuthority(){
|
|
1652
|
+
const manager=new EventManager();
|
|
1653
|
+
const sourceByOwner=new WeakMap();
|
|
1654
|
+
const occurrences=new WeakSet();
|
|
1655
|
+
const canonicalByView=new WeakMap();
|
|
1656
|
+
const compatibilityByOccurrence=new WeakMap();
|
|
1657
|
+
const sourceRecordByOccurrence=new WeakMap();
|
|
1658
|
+
const authorityTargetListeners=[];
|
|
1659
|
+
const legacyListeners=[];
|
|
1660
|
+
let occurrenceSequence=0;
|
|
1661
|
+
let sourceSequence=0;
|
|
1662
|
+
let reportingListenerError=false;
|
|
1663
|
+
let canonicalDispatchDepth=0;
|
|
1664
|
+
const pendingChannelRemovals=[];
|
|
1665
|
+
|
|
1666
|
+
const descriptor=Object.freeze({
|
|
1667
|
+
kind:ARCANE_EVENT_AUTHORITY_KIND,
|
|
1668
|
+
protocol:ARCANE_EVENT_AUTHORITY_PROTOCOL,
|
|
1669
|
+
realm:'current'
|
|
1670
|
+
});
|
|
1671
|
+
|
|
1672
|
+
function nextOccurrenceId(){
|
|
1673
|
+
if(occurrenceSequence===Number.MAX_SAFE_INTEGER){
|
|
1674
|
+
throw eventAuthorityError('ARCANE_EVENT_OCCURRENCE_SEQUENCE_EXHAUSTED');
|
|
1675
|
+
}
|
|
1676
|
+
occurrenceSequence+=1;
|
|
1677
|
+
return `arcane-event-${occurrenceSequence.toString(36)}`;
|
|
1678
|
+
}
|
|
1679
|
+
|
|
1680
|
+
function nextSourceId(){
|
|
1681
|
+
if(sourceSequence===Number.MAX_SAFE_INTEGER){
|
|
1682
|
+
throw eventAuthorityError('ARCANE_EVENT_SOURCE_SEQUENCE_EXHAUSTED');
|
|
1683
|
+
}
|
|
1684
|
+
sourceSequence+=1;
|
|
1685
|
+
return `arcane-source-${sourceSequence.toString(36)}`;
|
|
1686
|
+
}
|
|
1687
|
+
|
|
1688
|
+
function directListenerFailure(error){
|
|
1689
|
+
try{
|
|
1690
|
+
if(typeof globalThis.reportError==='function'){
|
|
1691
|
+
globalThis.reportError(error);
|
|
1692
|
+
return;
|
|
1693
|
+
}
|
|
1694
|
+
}catch{}
|
|
1695
|
+
try{globalThis.console?.error?.('Arcane event listener failed.',error);}
|
|
1696
|
+
catch{}
|
|
1697
|
+
}
|
|
1698
|
+
|
|
1699
|
+
function publicEventDetail(value){
|
|
1700
|
+
return frozenSnapshot(value??{}, {
|
|
1701
|
+
redactSensitive:true,
|
|
1702
|
+
captureStacks:false,
|
|
1703
|
+
maxDepth:16,
|
|
1704
|
+
maxEntries:256,
|
|
1705
|
+
maxStringLength:2_048
|
|
1706
|
+
});
|
|
1707
|
+
}
|
|
1708
|
+
|
|
1709
|
+
function canonicalOccurrence({
|
|
1710
|
+
type,
|
|
1711
|
+
source,
|
|
1712
|
+
instanceId,
|
|
1713
|
+
operationId,
|
|
1714
|
+
detail,
|
|
1715
|
+
cancelable,
|
|
1716
|
+
defaultPrevented=false
|
|
1717
|
+
}){
|
|
1718
|
+
let prevented=cancelable&&defaultPrevented;
|
|
1719
|
+
const occurrence={};
|
|
1720
|
+
Object.defineProperties(occurrence,{
|
|
1721
|
+
protocol:{value:ARCANE_EVENT_OCCURRENCE_PROTOCOL,enumerable:true},
|
|
1722
|
+
occurrenceId:{value:nextOccurrenceId(),enumerable:true},
|
|
1723
|
+
type:{value:type,enumerable:true},
|
|
1724
|
+
source:{value:source,enumerable:true},
|
|
1725
|
+
instanceId:{value:instanceId,enumerable:true},
|
|
1726
|
+
operationId:{value:operationId,enumerable:true},
|
|
1727
|
+
detail:{value:detail,enumerable:true},
|
|
1728
|
+
cancelable:{value:cancelable,enumerable:true},
|
|
1729
|
+
defaultPrevented:{get(){return prevented;},enumerable:true},
|
|
1730
|
+
preventDefault:{
|
|
1731
|
+
value:function preventArcaneEventDefault(){
|
|
1732
|
+
if(cancelable)prevented=true;
|
|
1733
|
+
},
|
|
1734
|
+
enumerable:true
|
|
1735
|
+
}
|
|
1736
|
+
});
|
|
1737
|
+
Object.freeze(occurrence);
|
|
1738
|
+
occurrences.add(occurrence);
|
|
1739
|
+
return occurrence;
|
|
1740
|
+
}
|
|
1741
|
+
|
|
1742
|
+
function compatibilityView(occurrence,detail,target=null){
|
|
1743
|
+
const view={};
|
|
1744
|
+
Object.defineProperties(view,{
|
|
1745
|
+
protocol:{value:occurrence.protocol,enumerable:true},
|
|
1746
|
+
occurrenceId:{value:occurrence.occurrenceId,enumerable:true},
|
|
1747
|
+
type:{value:occurrence.type,enumerable:true},
|
|
1748
|
+
source:{value:occurrence.source,enumerable:true},
|
|
1749
|
+
instanceId:{value:occurrence.instanceId,enumerable:true},
|
|
1750
|
+
operationId:{value:occurrence.operationId,enumerable:true},
|
|
1751
|
+
detail:{value:detail,enumerable:true},
|
|
1752
|
+
target:{value:target,enumerable:true},
|
|
1753
|
+
currentTarget:{value:target,enumerable:true},
|
|
1754
|
+
cancelable:{value:occurrence.cancelable,enumerable:true},
|
|
1755
|
+
defaultPrevented:{get(){return occurrence.defaultPrevented;},enumerable:true},
|
|
1756
|
+
preventDefault:{value:()=>occurrence.preventDefault(),enumerable:true}
|
|
1757
|
+
});
|
|
1758
|
+
Object.freeze(view);
|
|
1759
|
+
canonicalByView.set(view,occurrence);
|
|
1760
|
+
return view;
|
|
1761
|
+
}
|
|
1762
|
+
|
|
1763
|
+
function removeChannelListener(channel,handler){
|
|
1764
|
+
if(canonicalDispatchDepth>0){
|
|
1765
|
+
pendingChannelRemovals.push(Object.freeze({channel,handler}));
|
|
1766
|
+
return;
|
|
1767
|
+
}
|
|
1768
|
+
manager[EVENT_MANAGER_BUS_OFF](channel,handler);
|
|
1769
|
+
}
|
|
1770
|
+
|
|
1771
|
+
function flushChannelRemovals(){
|
|
1772
|
+
if(canonicalDispatchDepth>0)return;
|
|
1773
|
+
for(const {channel,handler} of pendingChannelRemovals.splice(0)){
|
|
1774
|
+
manager[EVENT_MANAGER_BUS_OFF](channel,handler);
|
|
1775
|
+
}
|
|
1776
|
+
}
|
|
1777
|
+
|
|
1778
|
+
function dispatchChannel(channel,value,metadata){
|
|
1779
|
+
canonicalDispatchDepth+=1;
|
|
1780
|
+
try{return manager[EVENT_MANAGER_DISPATCH](channel,value,metadata);}
|
|
1781
|
+
finally{
|
|
1782
|
+
canonicalDispatchDepth-=1;
|
|
1783
|
+
flushChannelRemovals();
|
|
1784
|
+
}
|
|
1785
|
+
}
|
|
1786
|
+
|
|
1787
|
+
function subscribeChannel(channel,handler,options,{
|
|
1788
|
+
thisArg=undefined,
|
|
1789
|
+
sourceRecord=null,
|
|
1790
|
+
select=value=>value,
|
|
1791
|
+
onRemove=null
|
|
1792
|
+
}={}){
|
|
1793
|
+
const admitted=eventListener(handler);
|
|
1794
|
+
const normalized=subscriptionOptions(options);
|
|
1795
|
+
let active=false;
|
|
1796
|
+
let abortHandler=null;
|
|
1797
|
+
function unsubscribeArcaneEvent(){
|
|
1798
|
+
if(!active)return false;
|
|
1799
|
+
active=false;
|
|
1800
|
+
removeChannelListener(channel,deliverArcaneEvent);
|
|
1801
|
+
if(abortHandler){
|
|
1802
|
+
normalized.signal?.removeEventListener('abort',abortHandler);
|
|
1803
|
+
abortHandler=null;
|
|
1804
|
+
}
|
|
1805
|
+
onRemove?.(unsubscribeArcaneEvent);
|
|
1806
|
+
return true;
|
|
1807
|
+
}
|
|
1808
|
+
defineDisposable(unsubscribeArcaneEvent);
|
|
1809
|
+
if(normalized.signal?.aborted)return unsubscribeArcaneEvent;
|
|
1810
|
+
function deliverArcaneEvent(value){
|
|
1811
|
+
if(!active)return;
|
|
1812
|
+
if(normalized.once)unsubscribeArcaneEvent();
|
|
1813
|
+
const delivered=select(value);
|
|
1814
|
+
try{admitted.invoke(delivered,thisArg);}
|
|
1815
|
+
catch(error){reportListenerFailure(error,delivered,sourceRecord);}
|
|
1816
|
+
}
|
|
1817
|
+
manager[EVENT_MANAGER_BUS_ON](channel,deliverArcaneEvent);
|
|
1818
|
+
active=true;
|
|
1819
|
+
if(normalized.signal){
|
|
1820
|
+
abortHandler=unsubscribeArcaneEvent;
|
|
1821
|
+
normalized.signal.addEventListener('abort',abortHandler,{once:true});
|
|
1822
|
+
}
|
|
1823
|
+
return unsubscribeArcaneEvent;
|
|
1824
|
+
}
|
|
1825
|
+
|
|
1826
|
+
function reportListenerFailure(error,event,sourceRecord){
|
|
1827
|
+
const occurrence=occurrences.has(event)
|
|
1828
|
+
?event
|
|
1829
|
+
:canonicalByView.get(event)??null;
|
|
1830
|
+
const ownerRecord=sourceRecord??(occurrence
|
|
1831
|
+
?sourceRecordByOccurrence.get(occurrence)??null
|
|
1832
|
+
:null);
|
|
1833
|
+
if(reportingListenerError){
|
|
1834
|
+
directListenerFailure(error);
|
|
1835
|
+
return;
|
|
1836
|
+
}
|
|
1837
|
+
reportingListenerError=true;
|
|
1838
|
+
let errorOccurrence=null;
|
|
1839
|
+
try{
|
|
1840
|
+
const detail=Object.freeze({
|
|
1841
|
+
code:'ARCANE_EVENT_LISTENER_CALLBACK_FAILED',
|
|
1842
|
+
reason:'listener-threw',
|
|
1843
|
+
eventType:occurrence?.type??null,
|
|
1844
|
+
occurrenceId:occurrence?.occurrenceId??null,
|
|
1845
|
+
source:occurrence?.source??ownerRecord?.source??'event-authority',
|
|
1846
|
+
instanceId:occurrence?.instanceId??ownerRecord?.instanceId??null,
|
|
1847
|
+
operationId:occurrence?.operationId??null
|
|
1848
|
+
});
|
|
1849
|
+
errorOccurrence=dispatchOccurrence({
|
|
1850
|
+
type:ARCANE_EVENT_LISTENER_ERROR_EVENT,
|
|
1851
|
+
sourceRecord:null,
|
|
1852
|
+
source:'event-authority',
|
|
1853
|
+
instanceId:'arcane-source-authority',
|
|
1854
|
+
compatibility:detail,
|
|
1855
|
+
publicDetail:detail,
|
|
1856
|
+
operationId:occurrence?.operationId??null,
|
|
1857
|
+
cancelable:false
|
|
1858
|
+
}).occurrence;
|
|
1859
|
+
}catch(reportingError){
|
|
1860
|
+
directListenerFailure(reportingError);
|
|
1861
|
+
}
|
|
1862
|
+
directListenerFailure(error);
|
|
1863
|
+
try{ownerRecord?.onListenerError?.(error,errorOccurrence);}
|
|
1864
|
+
catch(callbackError){directListenerFailure(callbackError);}
|
|
1865
|
+
reportingListenerError=false;
|
|
1866
|
+
}
|
|
1867
|
+
|
|
1868
|
+
function globalChannel(type){return `${ARCANE_EVENT_CHANNEL_PREFIX}global:${type}`;}
|
|
1869
|
+
function sourceChannel(instanceId,type){
|
|
1870
|
+
return `${ARCANE_EVENT_CHANNEL_PREFIX}source:${instanceId}:${type}`;
|
|
1871
|
+
}
|
|
1872
|
+
|
|
1873
|
+
function dispatchOccurrence({
|
|
1874
|
+
type,
|
|
1875
|
+
sourceRecord,
|
|
1876
|
+
source,
|
|
1877
|
+
instanceId,
|
|
1878
|
+
compatibility,
|
|
1879
|
+
publicDetail,
|
|
1880
|
+
operationId=null,
|
|
1881
|
+
cancelable=false,
|
|
1882
|
+
defaultPrevented=false
|
|
1883
|
+
}){
|
|
1884
|
+
const admittedType=eventName(type,'ARCANE_EVENT_OCCURRENCE_INVALID');
|
|
1885
|
+
const admittedCompatibility=compatibilityDetail(compatibility);
|
|
1886
|
+
const occurrence=canonicalOccurrence({
|
|
1887
|
+
type:admittedType,
|
|
1888
|
+
source,
|
|
1889
|
+
instanceId,
|
|
1890
|
+
operationId,
|
|
1891
|
+
detail:publicEventDetail(publicDetail),
|
|
1892
|
+
cancelable,
|
|
1893
|
+
defaultPrevented
|
|
1894
|
+
});
|
|
1895
|
+
const view=compatibilityView(
|
|
1896
|
+
occurrence,
|
|
1897
|
+
admittedCompatibility,
|
|
1898
|
+
sourceRecord?.owner??null
|
|
1899
|
+
);
|
|
1900
|
+
compatibilityByOccurrence.set(occurrence,admittedCompatibility);
|
|
1901
|
+
if(sourceRecord)sourceRecordByOccurrence.set(occurrence,sourceRecord);
|
|
1902
|
+
dispatchChannel(globalChannel(admittedType),occurrence,{
|
|
1903
|
+
source:'event-authority',
|
|
1904
|
+
category:'semantic'
|
|
1905
|
+
});
|
|
1906
|
+
if(sourceRecord){
|
|
1907
|
+
dispatchChannel(
|
|
1908
|
+
sourceChannel(instanceId,admittedType),
|
|
1909
|
+
view,
|
|
1910
|
+
{source,category:'semantic',correlationId:operationId}
|
|
1911
|
+
);
|
|
1912
|
+
}
|
|
1913
|
+
return Object.freeze({occurrence,accepted:!occurrence.defaultPrevented});
|
|
1914
|
+
}
|
|
1915
|
+
|
|
1916
|
+
function subscribe(type,handler,options){
|
|
1917
|
+
const admittedType=eventName(type);
|
|
1918
|
+
return subscribeChannel(globalChannel(admittedType),handler,options,{
|
|
1919
|
+
thisArg:manager
|
|
1920
|
+
});
|
|
1921
|
+
}
|
|
1922
|
+
|
|
1923
|
+
function addEventTargetListener(registrations,type,handler,options,subscribeWith,thisArg){
|
|
1924
|
+
const admittedType=eventName(type);
|
|
1925
|
+
const admitted=eventTargetListener(handler);
|
|
1926
|
+
if(!admitted)return;
|
|
1927
|
+
const normalized=eventTargetOptions(options);
|
|
1928
|
+
if(normalized.signal?.aborted)return;
|
|
1929
|
+
if(registrations.some(record=>record.type===admittedType
|
|
1930
|
+
&&record.identity===admitted.identity
|
|
1931
|
+
&&record.capture===normalized.capture))return;
|
|
1932
|
+
const record={
|
|
1933
|
+
type:admittedType,
|
|
1934
|
+
identity:admitted.identity,
|
|
1935
|
+
capture:normalized.capture,
|
|
1936
|
+
unsubscribe:null
|
|
1937
|
+
};
|
|
1938
|
+
const unsubscribe=subscribeWith(
|
|
1939
|
+
admittedType,
|
|
1940
|
+
function deliverEventTargetOccurrence(event){
|
|
1941
|
+
if(normalized.once){
|
|
1942
|
+
const index=registrations.indexOf(record);
|
|
1943
|
+
if(index>=0)registrations.splice(index,1);
|
|
1944
|
+
record.unsubscribe?.();
|
|
1945
|
+
}
|
|
1946
|
+
return admitted.invoke(event,thisArg);
|
|
1947
|
+
},
|
|
1948
|
+
{once:false,signal:normalized.signal}
|
|
1949
|
+
);
|
|
1950
|
+
record.unsubscribe=unsubscribe;
|
|
1951
|
+
registrations.push(record);
|
|
1952
|
+
if(normalized.signal){
|
|
1953
|
+
normalized.signal.addEventListener('abort',function removeAbortedEventTargetRecord(){
|
|
1954
|
+
const index=registrations.indexOf(record);
|
|
1955
|
+
if(index>=0)registrations.splice(index,1);
|
|
1956
|
+
},{once:true});
|
|
1957
|
+
}
|
|
1958
|
+
}
|
|
1959
|
+
|
|
1960
|
+
function removeEventTargetListener(registrations,type,handler,options){
|
|
1961
|
+
const admittedType=eventName(type);
|
|
1962
|
+
const admitted=eventTargetListener(handler);
|
|
1963
|
+
if(!admitted)return;
|
|
1964
|
+
const normalized=eventTargetOptions(options);
|
|
1965
|
+
const index=registrations.findIndex(record=>record.type===admittedType
|
|
1966
|
+
&&record.identity===admitted.identity
|
|
1967
|
+
&&record.capture===normalized.capture);
|
|
1968
|
+
if(index<0)return;
|
|
1969
|
+
const [record]=registrations.splice(index,1);
|
|
1970
|
+
record.unsubscribe();
|
|
1971
|
+
}
|
|
1972
|
+
|
|
1973
|
+
function dispatchEventLike(value,sourceRecord=null){
|
|
1974
|
+
const admitted=eventLikeRecord(value);
|
|
1975
|
+
if(sourceRecord&&!sourceRecord.eventTypes.has(admitted.type)){
|
|
1976
|
+
throw eventAuthorityError('ARCANE_EVENT_SOURCE_EVENT_TYPE_UNDECLARED');
|
|
1977
|
+
}
|
|
1978
|
+
const detail=compatibilityDetail(admitted.detail);
|
|
1979
|
+
const operationId=detail&&typeof detail==='object'
|
|
1980
|
+
&&typeof detail.operationId==='string'
|
|
1981
|
+
&&detail.operationId.trim()===detail.operationId
|
|
1982
|
+
&&detail.operationId
|
|
1983
|
+
?detail.operationId
|
|
1984
|
+
:null;
|
|
1985
|
+
const publication=dispatchOccurrence({
|
|
1986
|
+
type:admitted.type,
|
|
1987
|
+
sourceRecord,
|
|
1988
|
+
source:sourceRecord?.source??ARCANE_EVENT_TARGET_COMPATIBILITY_SOURCE,
|
|
1989
|
+
instanceId:sourceRecord?.instanceId??'arcane-source-compatibility',
|
|
1990
|
+
compatibility:detail,
|
|
1991
|
+
publicDetail:detail,
|
|
1992
|
+
operationId,
|
|
1993
|
+
cancelable:admitted.cancelable,
|
|
1994
|
+
defaultPrevented:admitted.defaultPrevented
|
|
1995
|
+
});
|
|
1996
|
+
if(publication.occurrence.defaultPrevented)admitted.preventDefault?.();
|
|
1997
|
+
return !publication.occurrence.defaultPrevented;
|
|
1998
|
+
}
|
|
1999
|
+
|
|
2000
|
+
function createSource(owner,options){
|
|
2001
|
+
if(!owner||(typeof owner!=='object'&&typeof owner!=='function')){
|
|
2002
|
+
throw eventAuthorityError('ARCANE_EVENT_SOURCE_INVALID',undefined,TypeError);
|
|
2003
|
+
}
|
|
2004
|
+
const admitted=eventDataOptions(
|
|
2005
|
+
options,
|
|
2006
|
+
new Set(['source','eventTypes','onListenerError']),
|
|
2007
|
+
'ARCANE_EVENT_SOURCE_INVALID'
|
|
2008
|
+
);
|
|
2009
|
+
const source=eventName(admitted.source,'ARCANE_EVENT_SOURCE_INVALID');
|
|
2010
|
+
if(!Array.isArray(admitted.eventTypes)
|
|
2011
|
+
||admitted.eventTypes.length<1
|
|
2012
|
+
||admitted.eventTypes.length>256){
|
|
2013
|
+
throw eventAuthorityError('ARCANE_EVENT_SOURCE_INVALID',undefined,TypeError);
|
|
2014
|
+
}
|
|
2015
|
+
const eventTypes=[];
|
|
2016
|
+
const seen=new Set();
|
|
2017
|
+
for(const type of admitted.eventTypes){
|
|
2018
|
+
const normalized=eventName(type,'ARCANE_EVENT_SOURCE_INVALID');
|
|
2019
|
+
if(seen.has(normalized)){
|
|
2020
|
+
throw eventAuthorityError('ARCANE_EVENT_SOURCE_INVALID',undefined,TypeError);
|
|
2021
|
+
}
|
|
2022
|
+
seen.add(normalized);
|
|
2023
|
+
eventTypes.push(normalized);
|
|
2024
|
+
}
|
|
2025
|
+
if(admitted.onListenerError!==undefined
|
|
2026
|
+
&&typeof admitted.onListenerError!=='function'){
|
|
2027
|
+
throw eventAuthorityError('ARCANE_EVENT_SOURCE_INVALID',undefined,TypeError);
|
|
2028
|
+
}
|
|
2029
|
+
const existing=sourceByOwner.get(owner);
|
|
2030
|
+
if(existing&&!existing.disposed){
|
|
2031
|
+
throw eventAuthorityError('ARCANE_EVENT_SOURCE_ALREADY_REGISTERED');
|
|
2032
|
+
}
|
|
2033
|
+
const record={
|
|
2034
|
+
owner,
|
|
2035
|
+
source,
|
|
2036
|
+
instanceId:nextSourceId(),
|
|
2037
|
+
eventTypes:new Set(eventTypes),
|
|
2038
|
+
onListenerError:admitted.onListenerError??null,
|
|
2039
|
+
subscriptions:new Set(),
|
|
2040
|
+
targetListeners:[],
|
|
2041
|
+
disposing:false,
|
|
2042
|
+
disposed:false,
|
|
2043
|
+
handle:null
|
|
2044
|
+
};
|
|
2045
|
+
function assertOpen(){
|
|
2046
|
+
if(record.disposing||record.disposed){
|
|
2047
|
+
throw eventAuthorityError('ARCANE_EVENT_SOURCE_DISPOSED');
|
|
2048
|
+
}
|
|
2049
|
+
}
|
|
2050
|
+
function sourceSubscribe(type,handler,subscribeOptions){
|
|
2051
|
+
assertOpen();
|
|
2052
|
+
const admittedType=eventName(type);
|
|
2053
|
+
if(!record.eventTypes.has(admittedType)
|
|
2054
|
+
&&admittedType!==ARCANE_EVENT_SOURCE_DISPOSED_EVENT){
|
|
2055
|
+
throw eventAuthorityError('ARCANE_EVENT_SOURCE_EVENT_TYPE_UNDECLARED');
|
|
2056
|
+
}
|
|
2057
|
+
let unsubscribe;
|
|
2058
|
+
unsubscribe=subscribeChannel(
|
|
2059
|
+
sourceChannel(record.instanceId,admittedType),
|
|
2060
|
+
handler,
|
|
2061
|
+
subscribeOptions,
|
|
2062
|
+
{
|
|
2063
|
+
thisArg:record.owner,
|
|
2064
|
+
sourceRecord:record,
|
|
2065
|
+
onRemove(){record.subscriptions.delete(unsubscribe);}
|
|
2066
|
+
}
|
|
2067
|
+
);
|
|
2068
|
+
record.subscriptions.add(unsubscribe);
|
|
2069
|
+
return unsubscribe;
|
|
2070
|
+
}
|
|
2071
|
+
function dispatch(type,detail,dispatchOptions){
|
|
2072
|
+
assertOpen();
|
|
2073
|
+
const admittedType=eventName(type,'ARCANE_EVENT_SOURCE_EVENT_TYPE_UNDECLARED');
|
|
2074
|
+
if(!record.eventTypes.has(admittedType)){
|
|
2075
|
+
throw eventAuthorityError('ARCANE_EVENT_SOURCE_EVENT_TYPE_UNDECLARED');
|
|
2076
|
+
}
|
|
2077
|
+
const normalized=eventDataOptions(
|
|
2078
|
+
dispatchOptions,
|
|
2079
|
+
new Set(['operationId','publicDetail','cancelable']),
|
|
2080
|
+
'ARCANE_EVENT_OCCURRENCE_INVALID'
|
|
2081
|
+
);
|
|
2082
|
+
const operationId=normalized.operationId??null;
|
|
2083
|
+
if(operationId!==null&&(typeof operationId!=='string'
|
|
2084
|
+
||operationId.trim()!==operationId
|
|
2085
|
+
||operationId.length<1
|
|
2086
|
+
||operationId.length>256)){
|
|
2087
|
+
throw eventAuthorityError('ARCANE_EVENT_OCCURRENCE_INVALID',undefined,TypeError);
|
|
2088
|
+
}
|
|
2089
|
+
if(normalized.cancelable!==undefined&&typeof normalized.cancelable!=='boolean'){
|
|
2090
|
+
throw eventAuthorityError('ARCANE_EVENT_OCCURRENCE_INVALID',undefined,TypeError);
|
|
2091
|
+
}
|
|
2092
|
+
return dispatchOccurrence({
|
|
2093
|
+
type:admittedType,
|
|
2094
|
+
sourceRecord:record,
|
|
2095
|
+
source:record.source,
|
|
2096
|
+
instanceId:record.instanceId,
|
|
2097
|
+
compatibility:detail,
|
|
2098
|
+
publicDetail:normalized.publicDetail??{},
|
|
2099
|
+
operationId,
|
|
2100
|
+
cancelable:normalized.cancelable===true
|
|
2101
|
+
});
|
|
2102
|
+
}
|
|
2103
|
+
function dispose(){
|
|
2104
|
+
if(record.disposed||record.disposing)return false;
|
|
2105
|
+
record.disposing=true;
|
|
2106
|
+
try{
|
|
2107
|
+
dispatchOccurrence({
|
|
2108
|
+
type:ARCANE_EVENT_SOURCE_DISPOSED_EVENT,
|
|
2109
|
+
sourceRecord:record,
|
|
2110
|
+
source:record.source,
|
|
2111
|
+
instanceId:record.instanceId,
|
|
2112
|
+
compatibility:Object.freeze({
|
|
2113
|
+
source:record.source,
|
|
2114
|
+
instanceId:record.instanceId,
|
|
2115
|
+
reason:'source-disposed'
|
|
2116
|
+
}),
|
|
2117
|
+
publicDetail:Object.freeze({reason:'source-disposed'}),
|
|
2118
|
+
operationId:null,
|
|
2119
|
+
cancelable:false
|
|
2120
|
+
});
|
|
2121
|
+
return true;
|
|
2122
|
+
}finally{
|
|
2123
|
+
record.disposed=true;
|
|
2124
|
+
for(const unsubscribe of [...record.subscriptions])unsubscribe();
|
|
2125
|
+
record.targetListeners.length=0;
|
|
2126
|
+
sourceByOwner.delete(owner);
|
|
2127
|
+
record.disposing=false;
|
|
2128
|
+
}
|
|
2129
|
+
}
|
|
2130
|
+
const sourceDescriptor=Object.freeze({
|
|
2131
|
+
kind:ARCANE_EVENT_SOURCE_KIND,
|
|
2132
|
+
protocol:ARCANE_EVENT_SOURCE_PROTOCOL,
|
|
2133
|
+
source,
|
|
2134
|
+
instanceId:record.instanceId,
|
|
2135
|
+
eventTypes:Object.freeze([...eventTypes,ARCANE_EVENT_SOURCE_DISPOSED_EVENT])
|
|
2136
|
+
});
|
|
2137
|
+
const handle={
|
|
2138
|
+
protocol:ARCANE_EVENT_SOURCE_PROTOCOL,
|
|
2139
|
+
descriptor:sourceDescriptor,
|
|
2140
|
+
source,
|
|
2141
|
+
instanceId:record.instanceId,
|
|
2142
|
+
eventTypes:sourceDescriptor.eventTypes,
|
|
2143
|
+
subscribe:sourceSubscribe,
|
|
2144
|
+
on:sourceSubscribe,
|
|
2145
|
+
once(type,handler,options={}){
|
|
2146
|
+
const normalized=subscriptionOptions(options);
|
|
2147
|
+
return sourceSubscribe(type,handler,{
|
|
2148
|
+
once:true,
|
|
2149
|
+
signal:normalized.signal
|
|
2150
|
+
});
|
|
2151
|
+
},
|
|
2152
|
+
addEventListener(type,handler,options){
|
|
2153
|
+
assertOpen();
|
|
2154
|
+
addEventTargetListener(
|
|
2155
|
+
record.targetListeners,
|
|
2156
|
+
type,
|
|
2157
|
+
handler,
|
|
2158
|
+
options,
|
|
2159
|
+
sourceSubscribe,
|
|
2160
|
+
record.owner
|
|
2161
|
+
);
|
|
2162
|
+
},
|
|
2163
|
+
removeEventListener(type,handler,options){
|
|
2164
|
+
removeEventTargetListener(record.targetListeners,type,handler,options);
|
|
2165
|
+
},
|
|
2166
|
+
dispatch,
|
|
2167
|
+
dispatchEvent(value){assertOpen();return dispatchEventLike(value,record);},
|
|
2168
|
+
dispose,
|
|
2169
|
+
destroy:dispose
|
|
2170
|
+
};
|
|
2171
|
+
Object.defineProperty(handle,'disposed',{
|
|
2172
|
+
get(){return record.disposing||record.disposed;},
|
|
2173
|
+
enumerable:true
|
|
2174
|
+
});
|
|
2175
|
+
record.handle=Object.freeze(handle);
|
|
2176
|
+
sourceByOwner.set(owner,record);
|
|
2177
|
+
return record.handle;
|
|
2178
|
+
}
|
|
2179
|
+
|
|
2180
|
+
function projectDOMEvent(target,occurrence,options){
|
|
2181
|
+
if(!occurrences.has(occurrence)){
|
|
2182
|
+
throw eventAuthorityError('ARCANE_EVENT_OCCURRENCE_INVALID',undefined,TypeError);
|
|
2183
|
+
}
|
|
2184
|
+
if(occurrence.defaultPrevented)return false;
|
|
2185
|
+
const admitted=eventDataOptions(
|
|
2186
|
+
options,
|
|
2187
|
+
new Set(['type','bubbles','composed','cancelable']),
|
|
2188
|
+
'ARCANE_EVENT_DOM_OPTIONS_INVALID'
|
|
2189
|
+
);
|
|
2190
|
+
const type=admitted.type===undefined
|
|
2191
|
+
?occurrence.type
|
|
2192
|
+
:eventName(admitted.type,'ARCANE_EVENT_DOM_OPTIONS_INVALID');
|
|
2193
|
+
for(const key of ['bubbles','composed','cancelable']){
|
|
2194
|
+
if(admitted[key]!==undefined&&typeof admitted[key]!=='boolean'){
|
|
2195
|
+
throw eventAuthorityError('ARCANE_EVENT_DOM_OPTIONS_INVALID',undefined,TypeError);
|
|
2196
|
+
}
|
|
2197
|
+
}
|
|
2198
|
+
if(!target||typeof target.dispatchEvent!=='function'
|
|
2199
|
+
||typeof globalThis.CustomEvent!=='function'){
|
|
2200
|
+
throw eventAuthorityError('ARCANE_EVENT_DOM_TARGET_INVALID',undefined,TypeError);
|
|
2201
|
+
}
|
|
2202
|
+
const compatibility=compatibilityByOccurrence.get(occurrence);
|
|
2203
|
+
let detail;
|
|
2204
|
+
const compatibilityPrototype=compatibility&&typeof compatibility==='object'
|
|
2205
|
+
?Object.getPrototypeOf(compatibility)
|
|
2206
|
+
:undefined;
|
|
2207
|
+
if(compatibility&&typeof compatibility==='object'
|
|
2208
|
+
&&!Array.isArray(compatibility)
|
|
2209
|
+
&&(compatibilityPrototype===Object.prototype||compatibilityPrototype===null)){
|
|
2210
|
+
detail={};
|
|
2211
|
+
for(const key of Reflect.ownKeys(compatibility)){
|
|
2212
|
+
const descriptor=Object.getOwnPropertyDescriptor(compatibility,key);
|
|
2213
|
+
if(!descriptor||!('value' in descriptor)){
|
|
2214
|
+
throw eventAuthorityError('ARCANE_EVENT_COMPATIBILITY_DETAIL_INVALID');
|
|
2215
|
+
}
|
|
2216
|
+
Object.defineProperty(detail,key,{
|
|
2217
|
+
value:descriptor.value,
|
|
2218
|
+
enumerable:descriptor.enumerable,
|
|
2219
|
+
configurable:false,
|
|
2220
|
+
writable:false
|
|
2221
|
+
});
|
|
2222
|
+
}
|
|
2223
|
+
}else{
|
|
2224
|
+
detail={value:compatibility};
|
|
2225
|
+
}
|
|
2226
|
+
const metadata={
|
|
2227
|
+
occurrenceId:occurrence.occurrenceId,
|
|
2228
|
+
arcaneSource:occurrence.source,
|
|
2229
|
+
instanceId:occurrence.instanceId,
|
|
2230
|
+
operationId:occurrence.operationId
|
|
2231
|
+
};
|
|
2232
|
+
for(const key of ARCANE_EVENT_PROJECTION_KEYS){
|
|
2233
|
+
if(Object.hasOwn(detail,key)&&detail[key]!==metadata[key]){
|
|
2234
|
+
throw eventAuthorityError('ARCANE_EVENT_DOM_DETAIL_COLLISION');
|
|
2235
|
+
}
|
|
2236
|
+
Object.defineProperty(detail,key,{
|
|
2237
|
+
value:metadata[key],
|
|
2238
|
+
enumerable:true,
|
|
2239
|
+
configurable:false,
|
|
2240
|
+
writable:false
|
|
2241
|
+
});
|
|
2242
|
+
}
|
|
2243
|
+
if(!Object.hasOwn(detail,'source')){
|
|
2244
|
+
Object.defineProperty(detail,'source',{
|
|
2245
|
+
value:metadata.arcaneSource,
|
|
2246
|
+
enumerable:true,
|
|
2247
|
+
configurable:false,
|
|
2248
|
+
writable:false
|
|
2249
|
+
});
|
|
2250
|
+
}
|
|
2251
|
+
Object.freeze(detail);
|
|
2252
|
+
const cancelable=admitted.cancelable??occurrence.cancelable;
|
|
2253
|
+
const event=new CustomEvent(type,{
|
|
2254
|
+
detail,
|
|
2255
|
+
bubbles:admitted.bubbles===true,
|
|
2256
|
+
composed:admitted.composed===true,
|
|
2257
|
+
cancelable
|
|
2258
|
+
});
|
|
2259
|
+
const accepted=target.dispatchEvent(event)!==false&&!event.defaultPrevented;
|
|
2260
|
+
if(!accepted&&occurrence.cancelable)occurrence.preventDefault();
|
|
2261
|
+
return accepted&&!occurrence.defaultPrevented;
|
|
2262
|
+
}
|
|
2263
|
+
|
|
2264
|
+
function safeLegacyOn(type,handler,once=false){
|
|
2265
|
+
const admittedType=type==='*'?'*':eventName(type);
|
|
2266
|
+
const admitted=eventListener(handler);
|
|
2267
|
+
if(typeof once!=='boolean'){
|
|
2268
|
+
throw eventAuthorityError('ARCANE_EVENT_SUBSCRIPTION_OPTIONS_INVALID',undefined,TypeError);
|
|
2269
|
+
}
|
|
2270
|
+
const record={type:admittedType,identity:admitted.identity,wrapper:null};
|
|
2271
|
+
function safeLegacyListener(value,...rest){
|
|
2272
|
+
if(once)removeLegacyRecord(record);
|
|
2273
|
+
try{admitted.invoke(value,manager,...rest);}
|
|
2274
|
+
catch(error){reportListenerFailure(error,null,null);}
|
|
2275
|
+
}
|
|
2276
|
+
record.wrapper=safeLegacyListener;
|
|
2277
|
+
legacyListeners.push(record);
|
|
2278
|
+
manager[EVENT_MANAGER_BUS_ON](admittedType,safeLegacyListener);
|
|
2279
|
+
return manager;
|
|
2280
|
+
}
|
|
2281
|
+
|
|
2282
|
+
function removeLegacyRecord(record){
|
|
2283
|
+
const index=legacyListeners.indexOf(record);
|
|
2284
|
+
if(index<0)return false;
|
|
2285
|
+
legacyListeners.splice(index,1);
|
|
2286
|
+
manager[EVENT_MANAGER_BUS_OFF](record.type,record.wrapper);
|
|
2287
|
+
return true;
|
|
2288
|
+
}
|
|
2289
|
+
|
|
2290
|
+
function safeLegacyOff(type='*',handler='*'){
|
|
2291
|
+
const admittedType=type==='*'?'*':eventName(type);
|
|
2292
|
+
const selected=legacyListeners.filter(record=>(admittedType==='*'||record.type===admittedType)
|
|
2293
|
+
&&(handler==='*'||record.identity===handler));
|
|
2294
|
+
if(handler!=='*')eventListener(handler);
|
|
2295
|
+
for(const record of selected)removeLegacyRecord(record);
|
|
2296
|
+
return manager;
|
|
2297
|
+
}
|
|
2298
|
+
|
|
2299
|
+
function safeLegacyReset(){
|
|
2300
|
+
for(const record of [...legacyListeners])removeLegacyRecord(record);
|
|
2301
|
+
return manager;
|
|
2302
|
+
}
|
|
2303
|
+
|
|
2304
|
+
Object.defineProperties(manager,{
|
|
2305
|
+
[ARCANE_EVENT_AUTHORITY_BRAND]:{
|
|
2306
|
+
value:ARCANE_EVENT_AUTHORITY_PROTOCOL,
|
|
2307
|
+
enumerable:false,
|
|
2308
|
+
configurable:false,
|
|
2309
|
+
writable:false
|
|
2310
|
+
},
|
|
2311
|
+
protocol:{value:ARCANE_EVENT_AUTHORITY_PROTOCOL,enumerable:true},
|
|
2312
|
+
descriptor:{value:descriptor,enumerable:true},
|
|
2313
|
+
on:{value:safeLegacyOn},
|
|
2314
|
+
once:{value:(type,handler)=>safeLegacyOn(type,handler,true)},
|
|
2315
|
+
off:{value:safeLegacyOff},
|
|
2316
|
+
reset:{value:safeLegacyReset},
|
|
2317
|
+
subscribe:{value:subscribe,enumerable:true},
|
|
2318
|
+
createSource:{value:createSource,enumerable:true},
|
|
2319
|
+
projectDOMEvent:{value:projectDOMEvent,enumerable:true},
|
|
2320
|
+
isOccurrence:{
|
|
2321
|
+
value:value=>occurrences.has(value)||canonicalByView.has(value),
|
|
2322
|
+
enumerable:true
|
|
2323
|
+
},
|
|
2324
|
+
addEventListener:{
|
|
2325
|
+
value(type,handler,options){
|
|
2326
|
+
addEventTargetListener(
|
|
2327
|
+
authorityTargetListeners,
|
|
2328
|
+
type,
|
|
2329
|
+
handler,
|
|
2330
|
+
options,
|
|
2331
|
+
subscribe,
|
|
2332
|
+
manager
|
|
2333
|
+
);
|
|
2334
|
+
},
|
|
2335
|
+
enumerable:true
|
|
2336
|
+
},
|
|
2337
|
+
removeEventListener:{
|
|
2338
|
+
value(type,handler,options){
|
|
2339
|
+
removeEventTargetListener(authorityTargetListeners,type,handler,options);
|
|
2340
|
+
},
|
|
2341
|
+
enumerable:true
|
|
2342
|
+
},
|
|
2343
|
+
dispatchEvent:{value:value=>dispatchEventLike(value),enumerable:true}
|
|
2344
|
+
});
|
|
2345
|
+
return Object.freeze(manager);
|
|
2346
|
+
}
|
|
2347
|
+
|
|
2348
|
+
function validateInstalledArcaneEventAuthority(value,descriptor){
|
|
2349
|
+
if(!descriptor||!('value' in descriptor)){
|
|
2350
|
+
throw eventAuthorityError('ARCANE_EVENT_AUTHORITY_ACCESSOR_COLLISION');
|
|
2351
|
+
}
|
|
2352
|
+
if(descriptor.enumerable!==false
|
|
2353
|
+
||descriptor.writable!==false
|
|
2354
|
+
||descriptor.configurable!==false){
|
|
2355
|
+
throw eventAuthorityError('ARCANE_EVENT_AUTHORITY_DESCRIPTOR_MISMATCH');
|
|
2356
|
+
}
|
|
2357
|
+
if(!value||(typeof value!=='object'&&typeof value!=='function')){
|
|
2358
|
+
throw eventAuthorityError('ARCANE_EVENT_AUTHORITY_VALUE_COLLISION');
|
|
2359
|
+
}
|
|
2360
|
+
const brand=Object.getOwnPropertyDescriptor(value,ARCANE_EVENT_AUTHORITY_BRAND);
|
|
2361
|
+
if(!brand||!('value' in brand)){
|
|
2362
|
+
throw eventAuthorityError('ARCANE_EVENT_AUTHORITY_VALUE_COLLISION');
|
|
2363
|
+
}
|
|
2364
|
+
if(brand.enumerable!==false
|
|
2365
|
+
||brand.writable!==false
|
|
2366
|
+
||brand.configurable!==false){
|
|
2367
|
+
throw eventAuthorityError('ARCANE_EVENT_AUTHORITY_DESCRIPTOR_MISMATCH');
|
|
2368
|
+
}
|
|
2369
|
+
const protocol=Object.getOwnPropertyDescriptor(value,'protocol');
|
|
2370
|
+
if(!protocol||!('value' in protocol)){
|
|
2371
|
+
throw eventAuthorityError('ARCANE_EVENT_AUTHORITY_API_MISMATCH');
|
|
2372
|
+
}
|
|
2373
|
+
if(brand.value!==ARCANE_EVENT_AUTHORITY_PROTOCOL
|
|
2374
|
+
||protocol.value!==ARCANE_EVENT_AUTHORITY_PROTOCOL){
|
|
2375
|
+
throw eventAuthorityError('ARCANE_EVENT_AUTHORITY_PROTOCOL_MISMATCH');
|
|
2376
|
+
}
|
|
2377
|
+
let current=value;
|
|
2378
|
+
const callables=new Map();
|
|
2379
|
+
try{
|
|
2380
|
+
while(current!==null&&callables.size<ARCANE_EVENT_REQUIRED_AUTHORITY_API.length){
|
|
2381
|
+
for(const name of ARCANE_EVENT_REQUIRED_AUTHORITY_API){
|
|
2382
|
+
if(callables.has(name))continue;
|
|
2383
|
+
const method=Object.getOwnPropertyDescriptor(current,name);
|
|
2384
|
+
if(method)callables.set(name,method);
|
|
2385
|
+
}
|
|
2386
|
+
current=Object.getPrototypeOf(current);
|
|
2387
|
+
}
|
|
2388
|
+
}catch(error){
|
|
2389
|
+
throw eventAuthorityError('ARCANE_EVENT_AUTHORITY_API_MISMATCH',error);
|
|
2390
|
+
}
|
|
2391
|
+
if(ARCANE_EVENT_REQUIRED_AUTHORITY_API.some(name=>{
|
|
2392
|
+
const method=callables.get(name);
|
|
2393
|
+
return !method||!('value' in method)||typeof method.value!=='function';
|
|
2394
|
+
})){
|
|
2395
|
+
throw eventAuthorityError('ARCANE_EVENT_AUTHORITY_API_MISMATCH');
|
|
2396
|
+
}
|
|
2397
|
+
if(protocol.enumerable!==true
|
|
2398
|
+
||protocol.writable!==false
|
|
2399
|
+
||protocol.configurable!==false){
|
|
2400
|
+
throw eventAuthorityError('ARCANE_EVENT_AUTHORITY_DESCRIPTOR_MISMATCH');
|
|
2401
|
+
}
|
|
2402
|
+
return value;
|
|
2403
|
+
}
|
|
2404
|
+
|
|
2405
|
+
function installArcaneEventAuthority(){
|
|
2406
|
+
const own=Object.getOwnPropertyDescriptor(globalThis,'arcaneEvents');
|
|
2407
|
+
if(own)return validateInstalledArcaneEventAuthority(own.value,own);
|
|
2408
|
+
if('arcaneEvents' in globalThis){
|
|
2409
|
+
throw eventAuthorityError('ARCANE_EVENT_AUTHORITY_VALUE_COLLISION');
|
|
2410
|
+
}
|
|
2411
|
+
const authority=createArcaneEventAuthority();
|
|
2412
|
+
try{
|
|
2413
|
+
Object.defineProperty(globalThis,'arcaneEvents',{
|
|
2414
|
+
value:authority,
|
|
2415
|
+
enumerable:false,
|
|
2416
|
+
configurable:false,
|
|
2417
|
+
writable:false
|
|
2418
|
+
});
|
|
2419
|
+
}catch(error){
|
|
2420
|
+
throw eventAuthorityError('ARCANE_EVENT_AUTHORITY_INSTALL_FAILED',error);
|
|
2421
|
+
}
|
|
2422
|
+
const installed=Object.getOwnPropertyDescriptor(globalThis,'arcaneEvents');
|
|
2423
|
+
return validateInstalledArcaneEventAuthority(installed?.value,installed);
|
|
2424
|
+
}
|
|
2425
|
+
|
|
2426
|
+
export const arcaneEvents=installArcaneEventAuthority();
|
|
2427
|
+
|
|
2428
|
+
export function createArcaneEventSource(owner,options){
|
|
2429
|
+
return arcaneEvents.createSource(owner,options);
|
|
2430
|
+
}
|
|
2431
|
+
|
|
2432
|
+
export function projectArcaneDOMEvent(target,occurrence,options){
|
|
2433
|
+
return arcaneEvents.projectDOMEvent(target,occurrence,options);
|
|
2434
|
+
}
|
|
2435
|
+
|
|
2436
|
+
export function isArcaneEventOccurrence(value){
|
|
2437
|
+
return arcaneEvents.isOccurrence(value);
|
|
2438
|
+
}
|