arcane-os 0.3.0 → 0.3.2
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 +27 -0
- package/README.md +86 -117
- package/bin/arcane-test.mjs +170 -46
- package/browser-runtime/ai/browser-speech-artifacts.mjs +887 -909
- package/browser-runtime/ai/browser-speech-providers.mjs +96 -152
- package/browser-runtime/ai/browser-wasm-llm-provider.mjs +627 -819
- package/browser-runtime/ai/browser-wasm.mjs +24 -35
- package/browser-runtime/ai/browser-wllama-runtime.mjs +64 -316
- package/browser-runtime/ai/model-controller.mjs +584 -181
- package/browser-runtime/ai/speech-worker-client.mjs +8 -146
- package/browser-runtime/ai/speech-worker-runtime.mjs +643 -363
- package/browser-runtime/dom-event-instrumentation.mjs +55 -147
- package/browser-runtime/event-manager.mjs +239 -624
- package/package.json +5 -6
- package/runtime/arcane/components/app-bar.html +3 -15
- package/runtime/arcane/components/assistant-panel.html +10 -10
- package/runtime/arcane/components/calculator.html +1 -1
- package/runtime/arcane/components/chat.html +1359 -135
- package/runtime/arcane/components/conversation-view.html +2 -2
- package/runtime/arcane/components/document-inspector.html +11 -17
- package/runtime/arcane/components/file-manager.html +13 -56
- package/runtime/arcane/components/markdown-document.html +82 -281
- package/runtime/arcane/components/markdown-editor.html +7 -10
- package/runtime/arcane/components/media-embed.html +6 -6
- package/runtime/arcane/components/screen-capture.html +4 -4
- package/runtime/arcane/components/source-explanation.html +2 -2
- package/runtime/arcane/components/speech.html +112 -68
- package/runtime/arcane/components/terminal-workspace.html +4 -4
- package/runtime/arcane/components/theme-editor.html +1 -1
- package/runtime/arcane/components/unified-inbox.html +2 -2
- package/runtime/arcane/components/voice-transcription.html +31 -21
- package/runtime/arcane/entities/Calculation.js +2 -3
- package/runtime/arcane/entities/Chat.js +228 -43
- package/runtime/arcane/entities/Preference.js +3 -5
- package/runtime/arcane/entities/Weather.js +5 -5
- package/runtime/arcane/modules/AI.js +1050 -427
- package/runtime/arcane/modules/AIProviderRuntime.js +658 -363
- package/runtime/arcane/modules/AIResponseLength.js +9 -19
- package/runtime/arcane/modules/AIRuntimeState.js +109 -72
- package/runtime/arcane/modules/ArcaneNavigationPolicy.js +45 -32
- package/runtime/arcane/modules/BrowserTestSuite.js +78 -122
- package/runtime/arcane/modules/CalculatorEngine.js +9 -9
- package/runtime/arcane/modules/CommunicationAppController.js +3 -7
- package/runtime/arcane/modules/ComponentContracts.js +30 -32
- package/runtime/arcane/modules/ConfiguredAIChatSession.js +281 -230
- package/runtime/arcane/modules/ConversationActionItems.js +26 -59
- package/runtime/arcane/modules/ConversationClosingReport.js +34 -61
- package/runtime/arcane/modules/ConversationTimebox.js +27 -15
- package/runtime/arcane/modules/DBOPFSDocumentLibrary.js +152 -344
- package/runtime/arcane/modules/DocumentLexicalSearch.js +25 -91
- package/runtime/arcane/modules/HTMLImport.js +54 -1
- package/runtime/arcane/modules/IsolatedModelQuestionRunner.js +40 -203
- package/runtime/arcane/modules/LocalAIReadiness.js +40 -60
- package/runtime/arcane/modules/LocalAIReadinessController.js +15 -13
- package/runtime/arcane/modules/MD.js +1 -45
- package/runtime/arcane/modules/Mail.js +51 -103
- package/runtime/arcane/modules/MailOutbox.mjs +95 -193
- package/runtime/arcane/modules/MailTransport.mjs +36 -57
- package/runtime/arcane/modules/ModelDefinition.js +22 -106
- package/runtime/arcane/modules/OpenMeteoWeatherProvider.js +39 -101
- package/runtime/arcane/modules/PersistentAIChatSession.js +281 -18
- package/runtime/arcane/modules/PreferenceStore.js +102 -30
- package/runtime/arcane/modules/RiskSignalAnalyzer.js +8 -9
- package/runtime/arcane/modules/ScopedOPFSCache.js +7 -42
- package/runtime/arcane/modules/ScreenCapture.js +175 -128
- package/runtime/arcane/modules/SpeechPlayback.js +46 -149
- package/runtime/arcane/modules/StaticDocumentCatalog.js +173 -407
- package/runtime/arcane/modules/ToolCallRouter.js +25 -12
- package/runtime/arcane/modules/YouTubeMedia.js +6 -5
- package/schemas/arcane-app-bundle.schema.json +13 -78
- package/schemas/arcane-app.schema.json +9 -25
- package/schemas/arcane-lock.schema.json +18 -151
- package/schemas/arcane-package.schema.json +2 -16
- package/schemas/native-build-plan.schema.json +119 -122
- package/src/app-descriptor.mjs +75 -132
- package/src/application-tests.mjs +200 -0
- package/src/cli/main.mjs +27 -46
- package/src/constants.mjs +3 -4
- package/src/dev-server.mjs +30 -324
- package/src/doctor.mjs +92 -154
- package/src/dom-event-instrumentation.mjs +55 -147
- package/src/errors.mjs +2 -3
- package/src/event-manager.mjs +239 -624
- package/src/event-queue.mjs +3 -3
- package/src/import-map.mjs +273 -1028
- package/src/index.mjs +14 -16
- package/src/installed-sdk-runtime.mjs +40 -62
- package/src/integrated-provider-loader.mjs +53 -382
- package/src/mail-api.mjs +0 -2
- package/src/mail-server.mjs +224 -580
- package/src/mail.mjs +4 -10
- package/src/native-plan.mjs +163 -598
- package/src/native-provider-loader.mjs +104 -1063
- package/src/packager/core.mjs +485 -3229
- package/src/process.mjs +5 -10
- package/src/release-bundle.mjs +292 -2405
- package/src/runtime.mjs +76 -396
- package/src/scaffold.mjs +30 -80
- package/src/sdk-browser-runtime.mjs +70 -626
- package/src/source-server.mjs +588 -0
- package/src/targets/index.mjs +78 -188
- package/src/templates/workspace-template.mjs +19 -135
- package/src/testing-loader.mjs +164 -0
- package/src/testing.mjs +1 -1
- package/src/toolchain.mjs +131 -544
- package/src/update-check.mjs +26 -64
- package/src/workspace-operation-lock.mjs +139 -430
- package/src/workspace-runtime.mjs +112 -779
- package/src/workspace.mjs +40 -302
- package/browser-runtime/ARCANE_SDK_BROWSER_RELEASE.json +0 -218
- package/browser-runtime/ai/ARCANE_AI_BROWSER_SPEECH_COMPONENTS.json +0 -203
- package/browser-runtime/ai/ARCANE_AI_BROWSER_WASM_COMPONENTS.json +0 -80
- package/browser-runtime/ai/internal/sha256.mjs +0 -166
- package/docs/architecture.md +0 -344
- package/docs/compatibility.md +0 -36
- package/docs/event-manager.md +0 -294
- package/docs/platform-targets.md +0 -108
- package/docs/publishing.md +0 -201
- package/docs/reference/README.md +0 -187
- package/docs/reference/ai/browser-speech-package-authority.json +0 -835
- package/docs/reference/ai/browser-speech.md +0 -1252
- package/docs/reference/ai/browser-wasm.md +0 -530
- package/docs/reference/arcane-ollama.md +0 -288
- package/docs/reference/availability-and-normalization.md +0 -183
- package/docs/reference/behavioral-testing.md +0 -133
- package/docs/reference/cli.md +0 -779
- package/docs/reference/core/README.md +0 -62
- package/docs/reference/core/arcane-ai-contracts.md +0 -907
- package/docs/reference/core/arcane-api.md +0 -601
- package/docs/reference/core/arcane-entities.md +0 -65
- package/docs/reference/core/arcane-events.md +0 -134
- package/docs/reference/core/ollama-module.md +0 -181
- package/docs/reference/core/reference/arcane-api/ai-and-ollama.md +0 -1909
- package/docs/reference/core/reference/arcane-api/applications-terminal-capabilities.md +0 -1057
- package/docs/reference/core/reference/arcane-api/core-and-events.md +0 -320
- package/docs/reference/core/reference/arcane-api/filesystem-storage-preferences-appearance.md +0 -610
- package/docs/reference/core/reference/arcane-api/namespaces.md +0 -1157
- package/docs/reference/core/reference/arcane-api/platform-installation-users-system.md +0 -1423
- package/docs/reference/core/reference/arcane-api/session-provisioning-diagnostics-development.md +0 -315
- package/docs/reference/event-manager.md +0 -1511
- package/docs/reference/inventory/package-api.json +0 -3284
- package/docs/reference/inventory/runtime-components.json +0 -1011
- package/docs/reference/inventory/runtime-entities.json +0 -26
- package/docs/reference/inventory/runtime-modules.json +0 -1431
- package/docs/reference/mail.md +0 -316
- package/docs/reference/protocols.md +0 -677
- package/docs/reference/runtime-components.md +0 -1366
- package/docs/reference/runtime-entities.md +0 -303
- package/docs/reference/runtime-modules.md +0 -2960
- package/docs/reference/sdk-api.md +0 -6694
- package/docs/roadmap.md +0 -79
- package/docs/work-amplification.md +0 -129
- package/runtime/ARCANE_RUNTIME_RELEASE.json +0 -826
package/src/event-manager.mjs
CHANGED
|
@@ -23,7 +23,6 @@ export const PLAYBACK_RECORD_EVENT='arcane.time-travel.playback.record';
|
|
|
23
23
|
export const PLAYBACK_COMPLETED_EVENT='arcane.time-travel.playback.completed';
|
|
24
24
|
export const PLAYBACK_CANCELLED_EVENT='arcane.time-travel.playback.cancelled';
|
|
25
25
|
export const PLAYBACK_FAILED_EVENT='arcane.time-travel.playback.failed';
|
|
26
|
-
export const TIME_TRAVEL_OVERFLOW_EVENT='arcane.time-travel.overflow';
|
|
27
26
|
|
|
28
27
|
export const ARCANE_EVENT_AUTHORITY_KIND='arcane-event-authority';
|
|
29
28
|
export const ARCANE_EVENT_SOURCE_KIND='arcane-event-source';
|
|
@@ -32,18 +31,18 @@ export const ARCANE_EVENT_SOURCE_DISPOSED_EVENT='arcane.event.source.disposed';
|
|
|
32
31
|
const ARCANE_EVENT_TARGET_COMPATIBILITY_SOURCE='event-target-compatibility';
|
|
33
32
|
const ARCANE_EVENT_NAME_PATTERN=/^[a-z][a-z0-9]*(?:[.-][a-z0-9]+)*$/u;
|
|
34
33
|
const ARCANE_EVENT_CHANNEL_PREFIX='arcane.event.authority.internal:';
|
|
35
|
-
const ARCANE_EVENT_PROJECTION_KEYS=
|
|
34
|
+
const ARCANE_EVENT_PROJECTION_KEYS=[
|
|
36
35
|
'occurrenceId','arcaneSource','instanceId','operationId'
|
|
37
|
-
]
|
|
38
|
-
const ARCANE_EVENT_REQUIRED_AUTHORITY_API=
|
|
36
|
+
];
|
|
37
|
+
const ARCANE_EVENT_REQUIRED_AUTHORITY_API=[
|
|
39
38
|
'on','once','off','reset','emit','instrument','forward','subscribe','createSource',
|
|
40
39
|
'projectDOMEvent','isOccurrence','addEventListener','removeEventListener','dispatchEvent'
|
|
41
|
-
]
|
|
40
|
+
];
|
|
42
41
|
const EVENT_MANAGER_BUS_ON=Symbol('EventManager.busOn');
|
|
43
42
|
const EVENT_MANAGER_BUS_OFF=Symbol('EventManager.busOff');
|
|
44
43
|
const EVENT_MANAGER_DISPATCH=Symbol('EventManager.dispatch');
|
|
45
44
|
|
|
46
|
-
const ARCANE_EVENT_ERRORS=
|
|
45
|
+
const ARCANE_EVENT_ERRORS={
|
|
47
46
|
ARCANE_EVENT_AUTHORITY_ACCESSOR_COLLISION:
|
|
48
47
|
'globalThis.arcaneEvents must be an own data property.',
|
|
49
48
|
ARCANE_EVENT_AUTHORITY_VALUE_COLLISION:
|
|
@@ -65,7 +64,7 @@ const ARCANE_EVENT_ERRORS=Object.freeze({
|
|
|
65
64
|
ARCANE_EVENT_SOURCE_EVENT_TYPE_UNDECLARED:
|
|
66
65
|
'The Arcane event source cannot publish an undeclared event type.',
|
|
67
66
|
ARCANE_EVENT_COMPATIBILITY_DETAIL_INVALID:
|
|
68
|
-
'Arcane event compatibility detail must be
|
|
67
|
+
'Arcane event compatibility detail must be safely shallow-copyable.',
|
|
69
68
|
ARCANE_EVENT_OCCURRENCE_INVALID:
|
|
70
69
|
'The Arcane event occurrence value or creation options are invalid.',
|
|
71
70
|
ARCANE_EVENT_OCCURRENCE_SEQUENCE_EXHAUSTED:
|
|
@@ -90,30 +89,21 @@ const ARCANE_EVENT_ERRORS=Object.freeze({
|
|
|
90
89
|
'Arcane event subscription signal must be an AbortSignal.',
|
|
91
90
|
ARCANE_EVENT_DISPATCH_EVENT_INVALID:
|
|
92
91
|
'arcaneEvents.dispatchEvent requires an Event-like object with a valid type and data detail.'
|
|
93
|
-
}
|
|
94
|
-
export const ARCANE_EVENT_ERROR_CODES=Object.
|
|
92
|
+
};
|
|
93
|
+
export const ARCANE_EVENT_ERROR_CODES=Object.fromEntries(
|
|
95
94
|
Object.keys(ARCANE_EVENT_ERRORS).map(code=>[code,code])
|
|
96
|
-
)
|
|
97
|
-
|
|
98
|
-
const
|
|
99
|
-
const
|
|
100
|
-
const INTERNAL_STACK_PATTERN=/(?:EventManager\.|#dispatch|event-manager\.mjs)/u;
|
|
101
|
-
const URL_PATTERN=/\b(?:blob|data|file|ftp|ftps|http|https|ws|wss):[^\s<>'"\])}]+/giu;
|
|
102
|
-
const DEFAULT_MAX_EVENTS=10_000;
|
|
103
|
-
const DEFAULT_MAX_SNAPSHOT_DEPTH=50;
|
|
104
|
-
const DEFAULT_MAX_SNAPSHOT_ENTRIES=1_000;
|
|
105
|
-
const DEFAULT_MAX_SNAPSHOT_STRING_LENGTH=10_000;
|
|
106
|
-
const MIN_SNAPSHOT_STRING_LENGTH=64;
|
|
107
|
-
const DOCUMENT_KEYS=Object.freeze(['protocol','sessionId','createdAt','events']);
|
|
108
|
-
const RECORD_KEYS=Object.freeze([
|
|
95
|
+
);
|
|
96
|
+
|
|
97
|
+
const DOCUMENT_KEYS=['protocol','sessionId','createdAt','events'];
|
|
98
|
+
const RECORD_KEYS=[
|
|
109
99
|
'protocol','sessionId','id','sequence','timestamp','monotonicMs','type','source',
|
|
110
100
|
'category','correlationId','causationId','parentSequence','depth','stack','payload',
|
|
111
101
|
'metadata','status','completedAt','durationMs','error'
|
|
112
|
-
]
|
|
102
|
+
];
|
|
113
103
|
const EVENT_STATUSES=new Set(['dispatching','completed','failed']);
|
|
114
104
|
const DATE_TO_ISO=Date.prototype.toISOString;
|
|
115
105
|
const REGEXP_SOURCE_GETTER=Object.getOwnPropertyDescriptor(RegExp.prototype,'source')?.get;
|
|
116
|
-
const REGEXP_FLAG_GETTERS=
|
|
106
|
+
const REGEXP_FLAG_GETTERS=[
|
|
117
107
|
['d',Object.getOwnPropertyDescriptor(RegExp.prototype,'hasIndices')?.get],
|
|
118
108
|
['g',Object.getOwnPropertyDescriptor(RegExp.prototype,'global')?.get],
|
|
119
109
|
['i',Object.getOwnPropertyDescriptor(RegExp.prototype,'ignoreCase')?.get],
|
|
@@ -122,7 +112,7 @@ const REGEXP_FLAG_GETTERS=Object.freeze([
|
|
|
122
112
|
['u',Object.getOwnPropertyDescriptor(RegExp.prototype,'unicode')?.get],
|
|
123
113
|
['v',Object.getOwnPropertyDescriptor(RegExp.prototype,'unicodeSets')?.get],
|
|
124
114
|
['y',Object.getOwnPropertyDescriptor(RegExp.prototype,'sticky')?.get]
|
|
125
|
-
]
|
|
115
|
+
];
|
|
126
116
|
const MAP_ENTRIES=Map.prototype.entries;
|
|
127
117
|
const MAP_SIZE_GETTER=Object.getOwnPropertyDescriptor(Map.prototype,'size')?.get;
|
|
128
118
|
const SET_VALUES=Set.prototype.values;
|
|
@@ -134,10 +124,6 @@ const TYPED_ARRAY_VALUES=TYPED_ARRAY_PROTOTYPE.values;
|
|
|
134
124
|
const TYPED_ARRAY_TAG_GETTER=
|
|
135
125
|
Object.getOwnPropertyDescriptor(TYPED_ARRAY_PROTOTYPE,Symbol.toStringTag)?.get;
|
|
136
126
|
const DATA_VIEW_BUFFER_GETTER=Object.getOwnPropertyDescriptor(DataView.prototype,'buffer')?.get;
|
|
137
|
-
const DATA_VIEW_BYTE_LENGTH_GETTER=
|
|
138
|
-
Object.getOwnPropertyDescriptor(DataView.prototype,'byteLength')?.get;
|
|
139
|
-
const DATA_VIEW_BYTE_OFFSET_GETTER=
|
|
140
|
-
Object.getOwnPropertyDescriptor(DataView.prototype,'byteOffset')?.get;
|
|
141
127
|
|
|
142
128
|
function dataObject(entries=[]){
|
|
143
129
|
const result=Object.create(null);
|
|
@@ -169,26 +155,10 @@ function taggedSnapshot(type,entries=[]){
|
|
|
169
155
|
return snapshotObject([['$type',type],...entries]);
|
|
170
156
|
}
|
|
171
157
|
|
|
172
|
-
function
|
|
173
|
-
let current=value;
|
|
174
|
-
while(current!==null&&(typeof current==='object'||typeof current==='function')){
|
|
175
|
-
const descriptor=Object.getOwnPropertyDescriptor(current,key);
|
|
176
|
-
if(descriptor){
|
|
177
|
-
return 'value' in descriptor
|
|
178
|
-
?{found:true,readable:true,value:descriptor.value}
|
|
179
|
-
:{found:true,readable:false,value:undefined};
|
|
180
|
-
}
|
|
181
|
-
if(!inherited)break;
|
|
182
|
-
current=Object.getPrototypeOf(current);
|
|
183
|
-
}
|
|
184
|
-
return {found:false,readable:false,value:undefined};
|
|
185
|
-
}
|
|
186
|
-
|
|
187
|
-
function safeDataString(value,key,{fallback='',inherited=false}={}){
|
|
158
|
+
function safeDataString(value,key,{fallback=''}={}){
|
|
188
159
|
try{
|
|
189
|
-
const
|
|
190
|
-
if(
|
|
191
|
-
if(property.readable&&typeof property.value==='string')return property.value;
|
|
160
|
+
const current=Reflect.get(value,key);
|
|
161
|
+
if(typeof current==='string')return current;
|
|
192
162
|
}catch{}
|
|
193
163
|
return fallback;
|
|
194
164
|
}
|
|
@@ -201,13 +171,11 @@ function regexpFlags(value){
|
|
|
201
171
|
return result;
|
|
202
172
|
}
|
|
203
173
|
|
|
204
|
-
function
|
|
205
|
-
|
|
206
|
-
if(redactSensitive)result=result.replace(URL_PATTERN,'[REDACTED URL]');
|
|
207
|
-
return result.length<=maxLength?result:`${result.slice(0,maxLength)}…`;
|
|
174
|
+
function safeString(value){
|
|
175
|
+
return String(value);
|
|
208
176
|
}
|
|
209
177
|
|
|
210
|
-
function safeErrorText(error
|
|
178
|
+
function safeErrorText(error){
|
|
211
179
|
let text='Snapshot capture failed.';
|
|
212
180
|
try{
|
|
213
181
|
if(error!==null&&(typeof error==='object'||typeof error==='function')){
|
|
@@ -217,7 +185,7 @@ function safeErrorText(error,maxLength,{redactSensitive=true}={}){
|
|
|
217
185
|
text=String(error);
|
|
218
186
|
}
|
|
219
187
|
}catch{}
|
|
220
|
-
try{return
|
|
188
|
+
try{return safeString(text);}
|
|
221
189
|
catch{return 'Snapshot capture failed.';}
|
|
222
190
|
}
|
|
223
191
|
|
|
@@ -249,75 +217,56 @@ function defaultMonotonicClock(){
|
|
|
249
217
|
|
|
250
218
|
function sourceStack(){
|
|
251
219
|
const stack=new Error('Arcane event source').stack;
|
|
252
|
-
|
|
253
|
-
const lines=stack.split(/\r?\n/u);
|
|
254
|
-
const filtered=[lines[0],...lines.slice(1).filter(line=>!INTERNAL_STACK_PATTERN.test(line))];
|
|
255
|
-
return filtered.join('\n');
|
|
220
|
+
return typeof stack==='string'?stack:null;
|
|
256
221
|
}
|
|
257
222
|
|
|
258
223
|
function snapshot(value,{
|
|
259
|
-
redactSensitive=true,
|
|
260
|
-
captureStacks=false,
|
|
261
|
-
maxDepth=DEFAULT_MAX_SNAPSHOT_DEPTH,
|
|
262
|
-
maxEntries=DEFAULT_MAX_SNAPSHOT_ENTRIES,
|
|
263
|
-
maxStringLength=DEFAULT_MAX_SNAPSHOT_STRING_LENGTH,
|
|
264
224
|
key='',
|
|
265
225
|
path='$',
|
|
266
226
|
depth=0,
|
|
267
227
|
seen=new Map()
|
|
268
228
|
}={}){
|
|
269
|
-
if(redactSensitive&&key
|
|
270
|
-
&&(SENSITIVE_KEY_PATTERN.test(key)||PRIVATE_CONTENT_KEY_PATTERN.test(key))){
|
|
271
|
-
return '[REDACTED]';
|
|
272
|
-
}
|
|
273
229
|
if(value===null||value===undefined||typeof value==='boolean')return value;
|
|
274
|
-
if(typeof value==='string')return
|
|
230
|
+
if(typeof value==='string')return safeString(value);
|
|
275
231
|
if(typeof value==='number')return Number.isFinite(value)
|
|
276
232
|
?value
|
|
277
233
|
:taggedSnapshot('number',[['value',String(value)]]);
|
|
278
234
|
if(typeof value==='bigint')return taggedSnapshot('bigint',[[
|
|
279
|
-
'value',
|
|
235
|
+
'value',safeString(value.toString())
|
|
280
236
|
]]);
|
|
281
237
|
if(typeof value==='symbol')return taggedSnapshot('symbol',[[
|
|
282
238
|
'value',value.description===undefined
|
|
283
239
|
?null
|
|
284
|
-
:
|
|
240
|
+
:safeString(value.description)
|
|
285
241
|
]]);
|
|
286
242
|
if(typeof value==='function'){
|
|
287
243
|
const name=safeDataString(value,'name');
|
|
288
244
|
return taggedSnapshot('function',[[
|
|
289
|
-
'name',name?
|
|
245
|
+
'name',name?safeString(name):null
|
|
290
246
|
]]);
|
|
291
247
|
}
|
|
292
|
-
if(depth>=maxDepth)return taggedSnapshot('depth-limit',[[
|
|
293
|
-
'path',boundedString(path,maxStringLength,{redactSensitive})
|
|
294
|
-
]]);
|
|
295
248
|
if(seen.has(value))return snapshotObject([[
|
|
296
|
-
'$ref',
|
|
249
|
+
'$ref',safeString(seen.get(value))
|
|
297
250
|
]]);
|
|
298
251
|
seen.set(value,path);
|
|
299
252
|
|
|
300
253
|
const next=(item,itemKey,itemPath)=>{
|
|
301
254
|
try{
|
|
302
255
|
return snapshot(item,{
|
|
303
|
-
redactSensitive,captureStacks,maxDepth,maxEntries,maxStringLength,
|
|
304
256
|
key:itemKey,
|
|
305
|
-
path:
|
|
257
|
+
path:safeString(itemPath),
|
|
306
258
|
depth:depth+1,
|
|
307
259
|
seen
|
|
308
260
|
});
|
|
309
261
|
}catch(error){
|
|
310
262
|
return snapshotFailure(error,{
|
|
311
|
-
redactSensitive,maxStringLength,
|
|
312
263
|
path:itemPath
|
|
313
264
|
});
|
|
314
265
|
}
|
|
315
266
|
};
|
|
316
267
|
if(value instanceof Date)return taggedSnapshot('date',[['value',DATE_TO_ISO.call(value)]]);
|
|
317
268
|
if(value instanceof RegExp)return taggedSnapshot('regexp',[
|
|
318
|
-
['source',
|
|
319
|
-
REGEXP_SOURCE_GETTER.call(value),maxStringLength,{redactSensitive}
|
|
320
|
-
)],
|
|
269
|
+
['source',safeString(REGEXP_SOURCE_GETTER.call(value))],
|
|
321
270
|
['flags',regexpFlags(value)]
|
|
322
271
|
]);
|
|
323
272
|
if(value instanceof Error){
|
|
@@ -325,101 +274,75 @@ function snapshot(value,{
|
|
|
325
274
|
const message=safeDataString(value,'message');
|
|
326
275
|
const stack=safeDataString(value,'stack');
|
|
327
276
|
const entries=[
|
|
328
|
-
['name',
|
|
329
|
-
['message',
|
|
330
|
-
['stack',
|
|
331
|
-
?boundedString(stack,maxStringLength,{redactSensitive})
|
|
332
|
-
:null]
|
|
277
|
+
['name',safeString(name||'Error')],
|
|
278
|
+
['message',safeString(message)],
|
|
279
|
+
['stack',stack?safeString(stack):null]
|
|
333
280
|
];
|
|
334
281
|
let causeDescriptor;
|
|
335
282
|
try{causeDescriptor=Object.getOwnPropertyDescriptor(value,'cause');}catch{}
|
|
336
283
|
if(causeDescriptor){
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
284
|
+
let cause;
|
|
285
|
+
try{cause=Reflect.get(value,'cause');}
|
|
286
|
+
catch(error){cause=snapshotFailure(error,{path:`${path}.cause`});}
|
|
287
|
+
entries.push(['cause',next(cause,'cause',`${path}.cause`)]);
|
|
340
288
|
}
|
|
341
289
|
return taggedSnapshot('error',entries);
|
|
342
290
|
}
|
|
343
291
|
if(Array.isArray(value)){
|
|
344
292
|
const result=[];
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
?descriptor.value
|
|
350
|
-
:taggedSnapshot('unreadable',[['error','Accessor properties are not evaluated.']]);
|
|
293
|
+
for(let index=0;index<value.length;index+=1){
|
|
294
|
+
let item;
|
|
295
|
+
try{item=Reflect.get(value,String(index));}
|
|
296
|
+
catch(error){item=snapshotFailure(error,{path:`${path}[${index}]`});}
|
|
351
297
|
result.push(next(item,String(index),`${path}[${index}]`));
|
|
352
298
|
}
|
|
353
|
-
if(value.length>maxEntries){
|
|
354
|
-
result.push(taggedSnapshot('entries-truncated',[
|
|
355
|
-
['omitted',value.length-maxEntries]
|
|
356
|
-
]));
|
|
357
|
-
}
|
|
358
299
|
return result;
|
|
359
300
|
}
|
|
360
301
|
if(value instanceof Map){
|
|
361
302
|
const entries=[];
|
|
362
303
|
let index=0;
|
|
363
304
|
for(const [mapKey,item] of MAP_ENTRIES.call(value)){
|
|
364
|
-
if(index>=maxEntries)break;
|
|
365
305
|
entries.push([
|
|
366
306
|
next(mapKey,'mapKey',`${path}.entries[${index}].key`),
|
|
367
307
|
next(item,'value',`${path}.entries[${index}].value`)
|
|
368
308
|
]);
|
|
369
309
|
index+=1;
|
|
370
310
|
}
|
|
371
|
-
|
|
372
|
-
return taggedSnapshot('map',[
|
|
373
|
-
['entries',entries],
|
|
374
|
-
...(size>index?[['omitted',size-index]]:[])
|
|
375
|
-
]);
|
|
311
|
+
return taggedSnapshot('map',[['entries',entries]]);
|
|
376
312
|
}
|
|
377
313
|
if(value instanceof Set){
|
|
378
314
|
const values=[];
|
|
379
315
|
let index=0;
|
|
380
316
|
for(const item of SET_VALUES.call(value)){
|
|
381
|
-
if(index>=maxEntries)break;
|
|
382
317
|
values.push(next(item,String(index),`${path}.values[${index}]`));
|
|
383
318
|
index+=1;
|
|
384
319
|
}
|
|
385
|
-
|
|
386
|
-
return taggedSnapshot('set',[
|
|
387
|
-
['values',values],
|
|
388
|
-
...(size>index?[['omitted',size-index]]:[])
|
|
389
|
-
]);
|
|
320
|
+
return taggedSnapshot('set',[['values',values]]);
|
|
390
321
|
}
|
|
391
322
|
if(ArrayBuffer.isView(value)){
|
|
392
323
|
const dataView=value instanceof DataView;
|
|
393
|
-
const length=dataView
|
|
394
|
-
?DATA_VIEW_BYTE_LENGTH_GETTER.call(value)
|
|
395
|
-
:TYPED_ARRAY_LENGTH_GETTER.call(value);
|
|
396
324
|
let values;
|
|
397
325
|
let type='DataView';
|
|
398
326
|
if(dataView){
|
|
399
327
|
const buffer=DATA_VIEW_BUFFER_GETTER.call(value);
|
|
400
|
-
|
|
401
|
-
values=Array.from(new Uint8Array(buffer,byteOffset,Math.min(length,maxEntries)));
|
|
328
|
+
values=Array.from(new Uint8Array(buffer));
|
|
402
329
|
}else{
|
|
330
|
+
const length=TYPED_ARRAY_LENGTH_GETTER.call(value);
|
|
403
331
|
type=TYPED_ARRAY_TAG_GETTER.call(value)??'TypedArray';
|
|
404
332
|
values=[];
|
|
405
333
|
const iterator=TYPED_ARRAY_VALUES.call(value);
|
|
406
|
-
while(values.length<
|
|
334
|
+
while(values.length<length){
|
|
407
335
|
const step=iterator.next();
|
|
408
336
|
if(step.done)break;
|
|
409
337
|
values.push(step.value);
|
|
410
338
|
}
|
|
411
339
|
}
|
|
412
|
-
return taggedSnapshot(type,[
|
|
413
|
-
['values',values],
|
|
414
|
-
...(length>maxEntries?[['omitted',length-maxEntries]]:[])
|
|
415
|
-
]);
|
|
340
|
+
return taggedSnapshot(type,[['values',values]]);
|
|
416
341
|
}
|
|
417
342
|
if(value instanceof ArrayBuffer){
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
...(bytes.length>maxEntries?[['omitted',bytes.length-maxEntries]]:[])
|
|
422
|
-
]);
|
|
343
|
+
return taggedSnapshot('ArrayBuffer',[[
|
|
344
|
+
'values',Array.from(new Uint8Array(value))
|
|
345
|
+
]]);
|
|
423
346
|
}
|
|
424
347
|
|
|
425
348
|
const result=snapshotObject();
|
|
@@ -428,13 +351,12 @@ function snapshot(value,{
|
|
|
428
351
|
const descriptor=Object.getOwnPropertyDescriptor(value,property);
|
|
429
352
|
return descriptor?.enumerable===true;
|
|
430
353
|
});
|
|
431
|
-
for(let index=0;index<
|
|
354
|
+
for(let index=0;index<properties.length;index+=1){
|
|
432
355
|
const property=properties[index];
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
let outputKey=boundedString(property,maxStringLength,{redactSensitive:false});
|
|
356
|
+
let item;
|
|
357
|
+
try{item=Reflect.get(value,property);}
|
|
358
|
+
catch(error){item=snapshotFailure(error,{path:`${path}.${property}`});}
|
|
359
|
+
let outputKey=safeString(property);
|
|
438
360
|
if(Object.hasOwn(result,outputKey))outputKey=`$arcaneCollision:${String(index)}`;
|
|
439
361
|
Object.defineProperty(result,outputKey,{
|
|
440
362
|
value:next(item,property,`${path}.${property}`),
|
|
@@ -443,49 +365,27 @@ function snapshot(value,{
|
|
|
443
365
|
writable:true
|
|
444
366
|
});
|
|
445
367
|
}
|
|
446
|
-
if(properties.length>maxEntries){
|
|
447
|
-
Object.defineProperty(result,'$arcaneTruncated',{
|
|
448
|
-
value:snapshotObject([['omitted',properties.length-maxEntries]]),
|
|
449
|
-
enumerable:true,
|
|
450
|
-
configurable:true,
|
|
451
|
-
writable:true
|
|
452
|
-
});
|
|
453
|
-
}
|
|
454
368
|
return result;
|
|
455
369
|
}
|
|
456
370
|
|
|
457
|
-
function snapshotFailure(error,{
|
|
458
|
-
redactSensitive=true,
|
|
459
|
-
maxStringLength=DEFAULT_MAX_SNAPSHOT_STRING_LENGTH,
|
|
460
|
-
path='$'
|
|
461
|
-
}={}){
|
|
371
|
+
function snapshotFailure(error,{path='$'}={}){
|
|
462
372
|
const name=safeDataString(error,'name',{fallback:'Error',inherited:true})||'Error';
|
|
463
373
|
return taggedSnapshot('snapshot-failed',[
|
|
464
|
-
['name',
|
|
465
|
-
['message',safeErrorText(error
|
|
466
|
-
['path',
|
|
374
|
+
['name',safeString(name)],
|
|
375
|
+
['message',safeErrorText(error)],
|
|
376
|
+
['path',safeString(path)]
|
|
467
377
|
]);
|
|
468
378
|
}
|
|
469
379
|
|
|
470
|
-
function
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
for(const property of Reflect.ownKeys(value)){
|
|
474
|
-
const descriptor=Object.getOwnPropertyDescriptor(value,property);
|
|
475
|
-
if(descriptor&&'value' in descriptor)deepFreeze(descriptor.value,seen);
|
|
476
|
-
}
|
|
477
|
-
return Object.freeze(value);
|
|
380
|
+
function completeSnapshot(value,options){
|
|
381
|
+
try{return snapshot(value,options);}
|
|
382
|
+
catch(error){return snapshotFailure(error,options);}
|
|
478
383
|
}
|
|
479
384
|
|
|
480
|
-
function
|
|
481
|
-
|
|
482
|
-
catch(error){return deepFreeze(snapshotFailure(error,options));}
|
|
483
|
-
}
|
|
484
|
-
|
|
485
|
-
function frozenErrorSnapshot(value,options){
|
|
486
|
-
const captured=frozenSnapshot(value,options);
|
|
385
|
+
function completeErrorSnapshot(value,options){
|
|
386
|
+
const captured=completeSnapshot(value,options);
|
|
487
387
|
if(captured&&typeof captured==='object'&&!Array.isArray(captured))return captured;
|
|
488
|
-
return
|
|
388
|
+
return taggedSnapshot('thrown',[['value',captured]]);
|
|
489
389
|
}
|
|
490
390
|
|
|
491
391
|
function normalizeMetadata(metadata){
|
|
@@ -559,12 +459,11 @@ function exactDataObject(value,expectedKeys,label){
|
|
|
559
459
|
}
|
|
560
460
|
}
|
|
561
461
|
|
|
562
|
-
function denseArrayValues(value,label
|
|
462
|
+
function denseArrayValues(value,label){
|
|
563
463
|
try{
|
|
564
464
|
if(!Array.isArray(value)||!Number.isSafeInteger(value.length)||value.length<0){
|
|
565
465
|
invalidStack(label);
|
|
566
466
|
}
|
|
567
|
-
if(maxLength!==undefined&&value.length>maxLength)invalidStack(label);
|
|
568
467
|
const keys=Reflect.ownKeys(value);
|
|
569
468
|
if(keys.some(key=>typeof key!=='string'))invalidStack(label);
|
|
570
469
|
const expected=new Set(['length']);
|
|
@@ -586,9 +485,6 @@ function denseArrayValues(value,label,{maxLength}={}){
|
|
|
586
485
|
}
|
|
587
486
|
|
|
588
487
|
function cloneImportedValue(value,{
|
|
589
|
-
maxDepth,
|
|
590
|
-
maxEntries,
|
|
591
|
-
maxStringLength,
|
|
592
488
|
path='$',
|
|
593
489
|
depth=0,
|
|
594
490
|
seen=new WeakSet()
|
|
@@ -598,23 +494,14 @@ function cloneImportedValue(value,{
|
|
|
598
494
|
if(!Number.isFinite(value))invalidStack(`Event stack value at ${path}`);
|
|
599
495
|
return value;
|
|
600
496
|
}
|
|
601
|
-
if(typeof value==='string')
|
|
602
|
-
if(value.length>maxStringLength+1
|
|
603
|
-
||(value.length===maxStringLength+1&&!value.endsWith('…'))){
|
|
604
|
-
invalidStack(`Event stack value at ${path}`);
|
|
605
|
-
}
|
|
606
|
-
return value;
|
|
607
|
-
}
|
|
497
|
+
if(typeof value==='string')return value;
|
|
608
498
|
if(!value||typeof value!=='object')invalidStack(`Event stack value at ${path}`);
|
|
609
|
-
if(
|
|
499
|
+
if(seen.has(value))invalidStack(`Event stack value at ${path}`);
|
|
610
500
|
seen.add(value);
|
|
611
501
|
|
|
612
502
|
if(Array.isArray(value)){
|
|
613
|
-
const items=denseArrayValues(value,`Event stack array at ${path}
|
|
614
|
-
maxLength:maxEntries+1
|
|
615
|
-
});
|
|
503
|
+
const items=denseArrayValues(value,`Event stack array at ${path}`);
|
|
616
504
|
return items.map((item,index)=>cloneImportedValue(item,{
|
|
617
|
-
maxDepth,maxEntries,maxStringLength,
|
|
618
505
|
path:`${path}[${String(index)}]`,
|
|
619
506
|
depth:depth+1,
|
|
620
507
|
seen
|
|
@@ -630,16 +517,11 @@ function cloneImportedValue(value,{
|
|
|
630
517
|
throw new TypeError(`Event stack value at ${path} is invalid.`,{cause:error});
|
|
631
518
|
}
|
|
632
519
|
if((prototype!==Object.prototype&&prototype!==null)
|
|
633
|
-
||keys.some(key=>typeof key!=='string')
|
|
634
|
-
||keys.length>maxEntries+1){
|
|
520
|
+
||keys.some(key=>typeof key!=='string')){
|
|
635
521
|
invalidStack(`Event stack value at ${path}`);
|
|
636
522
|
}
|
|
637
523
|
const result=dataObject();
|
|
638
524
|
for(const key of keys){
|
|
639
|
-
if(key.length>maxStringLength+1
|
|
640
|
-
||(key.length===maxStringLength+1&&!key.endsWith('…'))){
|
|
641
|
-
invalidStack(`Event stack value at ${path}`);
|
|
642
|
-
}
|
|
643
525
|
let descriptor;
|
|
644
526
|
try{descriptor=Object.getOwnPropertyDescriptor(value,key);}catch(error){
|
|
645
527
|
throw new TypeError(`Event stack value at ${path} is invalid.`,{cause:error});
|
|
@@ -649,7 +531,6 @@ function cloneImportedValue(value,{
|
|
|
649
531
|
}
|
|
650
532
|
Object.defineProperty(result,key,{
|
|
651
533
|
value:cloneImportedValue(descriptor.value,{
|
|
652
|
-
maxDepth,maxEntries,maxStringLength,
|
|
653
534
|
path:`${path}.${key}`,
|
|
654
535
|
depth:depth+1,
|
|
655
536
|
seen
|
|
@@ -671,21 +552,16 @@ function canonicalTimestamp(value,label){
|
|
|
671
552
|
return milliseconds;
|
|
672
553
|
}
|
|
673
554
|
|
|
674
|
-
function
|
|
555
|
+
function recordString(value,label,{nullable=false,empty=true}={}){
|
|
675
556
|
if(nullable&&value===null)return null;
|
|
676
|
-
if(typeof value!=='string'||(!empty&&!value)
|
|
677
|
-
||value.length>maxStringLength+1
|
|
678
|
-
||(value.length===maxStringLength+1&&!value.endsWith('…'))){
|
|
557
|
+
if(typeof value!=='string'||(!empty&&!value)){
|
|
679
558
|
invalidStack(label);
|
|
680
559
|
}
|
|
681
560
|
return value;
|
|
682
561
|
}
|
|
683
562
|
|
|
684
563
|
function validateRecord(record,index,{
|
|
685
|
-
sessionId
|
|
686
|
-
maxDepth,
|
|
687
|
-
maxEntries,
|
|
688
|
-
maxStringLength
|
|
564
|
+
sessionId
|
|
689
565
|
}){
|
|
690
566
|
const label=`Event stack record ${String(index)}`;
|
|
691
567
|
const fields=exactDataObject(record,RECORD_KEYS,label);
|
|
@@ -701,15 +577,15 @@ function validateRecord(record,index,{
|
|
|
701
577
|
||fields.monotonicMs<0){
|
|
702
578
|
invalidStack(`${label} monotonic timing`);
|
|
703
579
|
}
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
580
|
+
recordString(fields.type,`${label} type`);
|
|
581
|
+
recordString(fields.source,`${label} source`,{empty:false});
|
|
582
|
+
recordString(fields.category,`${label} category`,{
|
|
707
583
|
nullable:true,empty:false
|
|
708
584
|
});
|
|
709
|
-
|
|
585
|
+
recordString(fields.correlationId,`${label} correlation`,{
|
|
710
586
|
nullable:true,empty:false
|
|
711
587
|
});
|
|
712
|
-
|
|
588
|
+
recordString(fields.causationId,`${label} causation`,{
|
|
713
589
|
nullable:true,empty:false
|
|
714
590
|
});
|
|
715
591
|
if(fields.parentSequence!==null
|
|
@@ -721,20 +597,16 @@ function validateRecord(record,index,{
|
|
|
721
597
|
||(fields.parentSequence===null)!==(fields.depth===0)){
|
|
722
598
|
invalidStack(`${label} depth`);
|
|
723
599
|
}
|
|
724
|
-
|
|
600
|
+
recordString(fields.stack,`${label} stack`,{nullable:true});
|
|
725
601
|
if(!EVENT_STATUSES.has(fields.status))invalidStack(`${label} status`);
|
|
726
602
|
|
|
727
|
-
const payloadValues=denseArrayValues(fields.payload,`${label} payload
|
|
728
|
-
maxLength:maxEntries+1
|
|
729
|
-
});
|
|
603
|
+
const payloadValues=denseArrayValues(fields.payload,`${label} payload`);
|
|
730
604
|
const payload=payloadValues.map((item,payloadIndex)=>cloneImportedValue(item,{
|
|
731
|
-
maxDepth,maxEntries,maxStringLength,
|
|
732
605
|
path:`$.events[${String(index)}].payload[${String(payloadIndex)}]`,
|
|
733
606
|
depth:1,
|
|
734
607
|
seen:new WeakSet()
|
|
735
608
|
}));
|
|
736
609
|
const metadata=cloneImportedValue(fields.metadata,{
|
|
737
|
-
maxDepth,maxEntries,maxStringLength,
|
|
738
610
|
path:`$.events[${String(index)}].metadata`,
|
|
739
611
|
depth:0,
|
|
740
612
|
seen:new WeakSet()
|
|
@@ -763,7 +635,6 @@ function validateRecord(record,index,{
|
|
|
763
635
|
if(fields.error!==null)invalidStack(`${label} error`);
|
|
764
636
|
}else{
|
|
765
637
|
error=cloneImportedValue(fields.error,{
|
|
766
|
-
maxDepth,maxEntries,maxStringLength,
|
|
767
638
|
path:`$.events[${String(index)}].error`,
|
|
768
639
|
depth:0,
|
|
769
640
|
seen:new WeakSet()
|
|
@@ -798,21 +669,7 @@ function validateRecord(record,index,{
|
|
|
798
669
|
]);
|
|
799
670
|
}
|
|
800
671
|
|
|
801
|
-
export function parseEventStack(source
|
|
802
|
-
maxEvents=DEFAULT_MAX_EVENTS,
|
|
803
|
-
maxSnapshotDepth=DEFAULT_MAX_SNAPSHOT_DEPTH,
|
|
804
|
-
maxSnapshotEntries=DEFAULT_MAX_SNAPSHOT_ENTRIES,
|
|
805
|
-
maxSnapshotStringLength=DEFAULT_MAX_SNAPSHOT_STRING_LENGTH
|
|
806
|
-
}={}){
|
|
807
|
-
if(!Number.isSafeInteger(maxEvents)||maxEvents<1
|
|
808
|
-
||!Number.isSafeInteger(maxSnapshotDepth)||maxSnapshotDepth<1
|
|
809
|
-
||!Number.isSafeInteger(maxSnapshotEntries)||maxSnapshotEntries<1
|
|
810
|
-
||!Number.isSafeInteger(maxSnapshotStringLength)
|
|
811
|
-
||maxSnapshotStringLength<MIN_SNAPSHOT_STRING_LENGTH){
|
|
812
|
-
throw new RangeError(
|
|
813
|
-
'Event stack import limits must be positive safe integers and the string limit must be at least 64.'
|
|
814
|
-
);
|
|
815
|
-
}
|
|
672
|
+
export function parseEventStack(source){
|
|
816
673
|
let document=source;
|
|
817
674
|
if(typeof source==='string'){
|
|
818
675
|
try{document=JSON.parse(source);}catch(error){
|
|
@@ -821,23 +678,15 @@ export function parseEventStack(source,{
|
|
|
821
678
|
}
|
|
822
679
|
const fields=exactDataObject(document,DOCUMENT_KEYS,'The event stack document');
|
|
823
680
|
if(fields.protocol!==ARCANE_EVENT_STACK_PROTOCOL
|
|
824
|
-
||typeof fields.sessionId!=='string'||!fields.sessionId
|
|
825
|
-
||fields.sessionId.length>256){
|
|
681
|
+
||typeof fields.sessionId!=='string'||!fields.sessionId){
|
|
826
682
|
invalidStack('The event stack document');
|
|
827
683
|
}
|
|
828
684
|
canonicalTimestamp(fields.createdAt,'The event stack creation timestamp');
|
|
829
|
-
const sourceEvents=denseArrayValues(fields.events,'The event stack events'
|
|
830
|
-
maxLength:maxEvents+1
|
|
831
|
-
});
|
|
685
|
+
const sourceEvents=denseArrayValues(fields.events,'The event stack events');
|
|
832
686
|
let previous=0;
|
|
833
687
|
const bySequence=new Map();
|
|
834
688
|
const events=sourceEvents.map((record,index)=>{
|
|
835
|
-
const validated=validateRecord(record,index,{
|
|
836
|
-
sessionId:fields.sessionId,
|
|
837
|
-
maxDepth:maxSnapshotDepth,
|
|
838
|
-
maxEntries:maxSnapshotEntries,
|
|
839
|
-
maxStringLength:maxSnapshotStringLength
|
|
840
|
-
});
|
|
689
|
+
const validated=validateRecord(record,index,{sessionId:fields.sessionId});
|
|
841
690
|
if(validated.sequence<=previous){
|
|
842
691
|
throw new TypeError('Event stack sequences must be strictly increasing.');
|
|
843
692
|
}
|
|
@@ -851,67 +700,22 @@ export function parseEventStack(source,{
|
|
|
851
700
|
bySequence.set(validated.sequence,validated);
|
|
852
701
|
return validated;
|
|
853
702
|
});
|
|
854
|
-
|
|
855
|
-
for(let index=0;index<events.length;index+=1){
|
|
856
|
-
if(events[index].type===TIME_TRAVEL_OVERFLOW_EVENT)overflowIndexes.push(index);
|
|
857
|
-
}
|
|
858
|
-
if(overflowIndexes.length>1
|
|
859
|
-
||(overflowIndexes.length===1&&overflowIndexes[0]!==events.length-1)
|
|
860
|
-
||(events.length>maxEvents
|
|
861
|
-
&&(events.length!==maxEvents+1||overflowIndexes[0]!==events.length-1))){
|
|
862
|
-
invalidStack('The event stack overflow history');
|
|
863
|
-
}
|
|
864
|
-
if(overflowIndexes.length===1){
|
|
865
|
-
const overflow=events.at(-1);
|
|
866
|
-
const payload=denseArrayValues(
|
|
867
|
-
overflow.payload,'The event stack overflow payload',{maxLength:1}
|
|
868
|
-
);
|
|
869
|
-
if(payload.length!==1)invalidStack('The event stack overflow payload');
|
|
870
|
-
const counts=exactDataObject(
|
|
871
|
-
payload[0],['maxEvents','retainedEvents'],'The event stack overflow payload counts'
|
|
872
|
-
);
|
|
873
|
-
const metadata=exactDataObject(
|
|
874
|
-
overflow.metadata,['maxEvents'],'The event stack overflow metadata'
|
|
875
|
-
);
|
|
876
|
-
const retainedEvents=events.length-1;
|
|
877
|
-
if(overflow.source!=='event-manager'||overflow.category!=='overflow'
|
|
878
|
-
||overflow.correlationId!==null||overflow.causationId!==null
|
|
879
|
-
||overflow.parentSequence!==null||overflow.depth!==0||overflow.stack!==null
|
|
880
|
-
||overflow.status!=='completed'||overflow.completedAt!==overflow.timestamp
|
|
881
|
-
||overflow.durationMs!==0||overflow.error!==null
|
|
882
|
-
||!Number.isSafeInteger(counts.maxEvents)||counts.maxEvents<1
|
|
883
|
-
||!Number.isSafeInteger(counts.retainedEvents)||counts.retainedEvents<1
|
|
884
|
-
||counts.maxEvents!==counts.retainedEvents
|
|
885
|
-
||metadata.maxEvents!==counts.maxEvents
|
|
886
|
-
||retainedEvents!==counts.retainedEvents
|
|
887
|
-
||overflow.sequence!==retainedEvents+1
|
|
888
|
-
||counts.maxEvents>maxEvents){
|
|
889
|
-
invalidStack('The event stack overflow record');
|
|
890
|
-
}
|
|
891
|
-
}
|
|
892
|
-
return deepFreeze(dataObject([
|
|
703
|
+
return dataObject([
|
|
893
704
|
['protocol',ARCANE_EVENT_STACK_PROTOCOL],
|
|
894
705
|
['sessionId',fields.sessionId],
|
|
895
706
|
['createdAt',fields.createdAt],
|
|
896
707
|
['events',events]
|
|
897
|
-
])
|
|
708
|
+
]);
|
|
898
709
|
}
|
|
899
710
|
|
|
900
711
|
export class EventManager{
|
|
901
712
|
#activeDispatch=[];
|
|
902
713
|
#bus=new EventPubSub();
|
|
903
|
-
#captureStacks;
|
|
904
714
|
#clock;
|
|
905
715
|
#cursor=0;
|
|
906
716
|
#domInstrumentation=null;
|
|
907
717
|
#history=[];
|
|
908
|
-
#maxEvents;
|
|
909
|
-
#maxSnapshotDepth;
|
|
910
|
-
#maxSnapshotEntries;
|
|
911
|
-
#maxSnapshotStringLength;
|
|
912
718
|
#now;
|
|
913
|
-
#overflowed=false;
|
|
914
|
-
#redactSensitive;
|
|
915
719
|
#replaying=false;
|
|
916
720
|
#sequence=0;
|
|
917
721
|
#sessionId;
|
|
@@ -920,41 +724,19 @@ export class EventManager{
|
|
|
920
724
|
constructor({
|
|
921
725
|
timeTravel=false,
|
|
922
726
|
dom=null,
|
|
923
|
-
captureStacks=false,
|
|
924
|
-
redactSensitive=true,
|
|
925
|
-
maxEvents=DEFAULT_MAX_EVENTS,
|
|
926
|
-
maxSnapshotDepth=DEFAULT_MAX_SNAPSHOT_DEPTH,
|
|
927
|
-
maxSnapshotEntries=DEFAULT_MAX_SNAPSHOT_ENTRIES,
|
|
928
|
-
maxSnapshotStringLength=DEFAULT_MAX_SNAPSHOT_STRING_LENGTH,
|
|
929
727
|
clock=()=>new Date(),
|
|
930
728
|
now=defaultMonotonicClock,
|
|
931
729
|
sessionId=sessionIdentifier()
|
|
932
730
|
}={}){
|
|
933
|
-
if(typeof timeTravel!=='boolean'
|
|
934
|
-
||typeof redactSensitive!=='boolean'){
|
|
731
|
+
if(typeof timeTravel!=='boolean'){
|
|
935
732
|
throw new TypeError('EventManager flags must be boolean values.');
|
|
936
733
|
}
|
|
937
734
|
if(typeof clock!=='function'||typeof now!=='function'){
|
|
938
735
|
throw new TypeError('EventManager clocks must be functions.');
|
|
939
736
|
}
|
|
940
|
-
if(
|
|
941
|
-
||!Number.isSafeInteger(maxSnapshotDepth)||maxSnapshotDepth<1
|
|
942
|
-
||!Number.isSafeInteger(maxSnapshotEntries)||maxSnapshotEntries<1
|
|
943
|
-
||!Number.isSafeInteger(maxSnapshotStringLength)
|
|
944
|
-
||maxSnapshotStringLength<MIN_SNAPSHOT_STRING_LENGTH){
|
|
945
|
-
throw new RangeError(
|
|
946
|
-
'EventManager retention limits must be positive safe integers and the string limit must be at least 64.'
|
|
947
|
-
);
|
|
948
|
-
}
|
|
949
|
-
if(typeof sessionId!=='string'||!sessionId||sessionId.length>256){
|
|
737
|
+
if(typeof sessionId!=='string'||!sessionId){
|
|
950
738
|
throw new TypeError('EventManager sessionId must be a non-empty string.');
|
|
951
739
|
}
|
|
952
|
-
this.#captureStacks=captureStacks;
|
|
953
|
-
this.#redactSensitive=redactSensitive;
|
|
954
|
-
this.#maxEvents=maxEvents;
|
|
955
|
-
this.#maxSnapshotDepth=maxSnapshotDepth;
|
|
956
|
-
this.#maxSnapshotEntries=maxSnapshotEntries;
|
|
957
|
-
this.#maxSnapshotStringLength=maxSnapshotStringLength;
|
|
958
740
|
this.#clock=clock;
|
|
959
741
|
this.#now=now;
|
|
960
742
|
this.#sessionId=sessionId;
|
|
@@ -968,9 +750,7 @@ export class EventManager{
|
|
|
968
750
|
get replaying(){return this.#replaying;}
|
|
969
751
|
get cursor(){return this.#cursor;}
|
|
970
752
|
get eventCount(){return this.#history.length;}
|
|
971
|
-
get
|
|
972
|
-
get overflowed(){return this.#overflowed;}
|
|
973
|
-
get history(){return Object.freeze([...this.#history]);}
|
|
753
|
+
get history(){return [...this.#history];}
|
|
974
754
|
get domInstrumentation(){return this.#domInstrumentation;}
|
|
975
755
|
|
|
976
756
|
[EVENT_MANAGER_BUS_ON](type,handler,once=false){
|
|
@@ -1028,25 +808,14 @@ export class EventManager{
|
|
|
1028
808
|
return this;
|
|
1029
809
|
}
|
|
1030
810
|
let recording=this.#timeTravelEnabled&&!this.#replaying;
|
|
1031
|
-
if(recording&&this.#history.length>=this.#maxEvents){
|
|
1032
|
-
this.#recordOverflow();
|
|
1033
|
-
recording=false;
|
|
1034
|
-
}
|
|
1035
811
|
let draft=null;
|
|
1036
812
|
let startedMonotonic=null;
|
|
1037
813
|
if(recording){
|
|
1038
814
|
try{
|
|
1039
815
|
const timestamp=clockDate(this.#clock).toISOString();
|
|
1040
816
|
startedMonotonic=monotonicValue(this.#now);
|
|
1041
|
-
const
|
|
1042
|
-
|
|
1043
|
-
captureStacks:this.#captureStacks,
|
|
1044
|
-
maxDepth:this.#maxSnapshotDepth,
|
|
1045
|
-
maxEntries:this.#maxSnapshotEntries,
|
|
1046
|
-
maxStringLength:this.#maxSnapshotStringLength
|
|
1047
|
-
};
|
|
1048
|
-
const payloadSnapshot=frozenSnapshot(payload,snapshotOptions);
|
|
1049
|
-
const metadataSnapshot=frozenSnapshot(metadata,snapshotOptions);
|
|
817
|
+
const payloadSnapshot=completeSnapshot(payload);
|
|
818
|
+
const metadataSnapshot=completeSnapshot(metadata);
|
|
1050
819
|
const safeMetadata=metadataSnapshot&&typeof metadataSnapshot==='object'
|
|
1051
820
|
&&!Array.isArray(metadataSnapshot)
|
|
1052
821
|
?metadataSnapshot
|
|
@@ -1054,14 +823,10 @@ export class EventManager{
|
|
|
1054
823
|
const sequence=this.#sequence+1;
|
|
1055
824
|
const parentSequence=this.#activeDispatch.at(-1)??null;
|
|
1056
825
|
let stack=null;
|
|
1057
|
-
|
|
1058
|
-
|
|
1059
|
-
|
|
1060
|
-
|
|
1061
|
-
});
|
|
1062
|
-
}catch{
|
|
1063
|
-
stack='[STACK CAPTURE FAILED]';
|
|
1064
|
-
}
|
|
826
|
+
try{
|
|
827
|
+
stack=safeString(sourceStack()??'');
|
|
828
|
+
}catch{
|
|
829
|
+
stack='[STACK CAPTURE FAILED]';
|
|
1065
830
|
}
|
|
1066
831
|
draft={
|
|
1067
832
|
protocol:ARCANE_EVENT_STACK_PROTOCOL,
|
|
@@ -1070,42 +835,33 @@ export class EventManager{
|
|
|
1070
835
|
sequence,
|
|
1071
836
|
timestamp,
|
|
1072
837
|
monotonicMs:startedMonotonic,
|
|
1073
|
-
type:
|
|
1074
|
-
redactSensitive:this.#redactSensitive
|
|
1075
|
-
}),
|
|
838
|
+
type:safeString(type),
|
|
1076
839
|
source:typeof safeMetadata.source==='string'&&safeMetadata.source
|
|
1077
|
-
?
|
|
1078
|
-
redactSensitive:this.#redactSensitive
|
|
1079
|
-
})
|
|
840
|
+
?safeString(safeMetadata.source)
|
|
1080
841
|
:'application',
|
|
1081
842
|
category:typeof safeMetadata.category==='string'&&safeMetadata.category
|
|
1082
|
-
?
|
|
1083
|
-
redactSensitive:this.#redactSensitive
|
|
1084
|
-
})
|
|
843
|
+
?safeString(safeMetadata.category)
|
|
1085
844
|
:null,
|
|
1086
845
|
correlationId:typeof safeMetadata.correlationId==='string'
|
|
1087
846
|
&&safeMetadata.correlationId
|
|
1088
|
-
?
|
|
1089
|
-
redactSensitive:this.#redactSensitive
|
|
1090
|
-
}):null,
|
|
847
|
+
?safeString(safeMetadata.correlationId):null,
|
|
1091
848
|
causationId:typeof safeMetadata.causationId==='string'
|
|
1092
849
|
&&safeMetadata.causationId
|
|
1093
|
-
?
|
|
1094
|
-
|
|
1095
|
-
}):(parentSequence===null?null:`${this.#sessionId}:${parentSequence}`),
|
|
850
|
+
?safeString(safeMetadata.causationId)
|
|
851
|
+
:(parentSequence===null?null:`${this.#sessionId}:${parentSequence}`),
|
|
1096
852
|
parentSequence,
|
|
1097
853
|
depth:this.#activeDispatch.length,
|
|
1098
854
|
stack,
|
|
1099
855
|
payload:Array.isArray(payloadSnapshot)
|
|
1100
856
|
?payloadSnapshot
|
|
1101
|
-
:
|
|
857
|
+
:[payloadSnapshot],
|
|
1102
858
|
metadata:safeMetadata,
|
|
1103
859
|
status:'dispatching',
|
|
1104
860
|
completedAt:null,
|
|
1105
861
|
durationMs:null,
|
|
1106
862
|
error:null
|
|
1107
863
|
};
|
|
1108
|
-
this.#history.push(
|
|
864
|
+
this.#history.push({...draft});
|
|
1109
865
|
this.#sequence=sequence;
|
|
1110
866
|
this.#cursor=sequence;
|
|
1111
867
|
this.#activeDispatch.push(sequence);
|
|
@@ -1137,47 +893,6 @@ export class EventManager{
|
|
|
1137
893
|
return this;
|
|
1138
894
|
}
|
|
1139
895
|
|
|
1140
|
-
#recordOverflow(){
|
|
1141
|
-
this.#overflowed=true;
|
|
1142
|
-
this.#timeTravelEnabled=false;
|
|
1143
|
-
try{this.#domInstrumentation?.stop({emitLifecycle:false});}catch{}
|
|
1144
|
-
let timestamp;
|
|
1145
|
-
let monotonicMs;
|
|
1146
|
-
try{timestamp=clockDate(this.#clock).toISOString();}
|
|
1147
|
-
catch{timestamp=new Date().toISOString();}
|
|
1148
|
-
try{monotonicMs=monotonicValue(this.#now);}
|
|
1149
|
-
catch{monotonicMs=Math.max(0,Number(this.#history.at(-1)?.monotonicMs??0));}
|
|
1150
|
-
const sequence=++this.#sequence;
|
|
1151
|
-
const payload=deepFreeze([snapshotObject([
|
|
1152
|
-
['maxEvents',this.#maxEvents],
|
|
1153
|
-
['retainedEvents',this.#history.length]
|
|
1154
|
-
])]);
|
|
1155
|
-
const record=deepFreeze({
|
|
1156
|
-
protocol:ARCANE_EVENT_STACK_PROTOCOL,
|
|
1157
|
-
sessionId:this.#sessionId,
|
|
1158
|
-
id:`${this.#sessionId}:${sequence}`,
|
|
1159
|
-
sequence,
|
|
1160
|
-
timestamp,
|
|
1161
|
-
monotonicMs,
|
|
1162
|
-
type:TIME_TRAVEL_OVERFLOW_EVENT,
|
|
1163
|
-
source:'event-manager',
|
|
1164
|
-
category:'overflow',
|
|
1165
|
-
correlationId:null,
|
|
1166
|
-
causationId:null,
|
|
1167
|
-
parentSequence:null,
|
|
1168
|
-
depth:0,
|
|
1169
|
-
stack:null,
|
|
1170
|
-
payload,
|
|
1171
|
-
metadata:deepFreeze(snapshotObject([['maxEvents',this.#maxEvents]])),
|
|
1172
|
-
status:'completed',
|
|
1173
|
-
completedAt:timestamp,
|
|
1174
|
-
durationMs:0,
|
|
1175
|
-
error:null
|
|
1176
|
-
});
|
|
1177
|
-
this.#history.push(record);
|
|
1178
|
-
this.#cursor=sequence;
|
|
1179
|
-
}
|
|
1180
|
-
|
|
1181
896
|
#finalize(draft,startedMonotonic,status,error){
|
|
1182
897
|
try{
|
|
1183
898
|
const index=this.#history.findIndex(record=>record.sequence===draft.sequence);
|
|
@@ -1193,26 +908,17 @@ export class EventManager{
|
|
|
1193
908
|
try{
|
|
1194
909
|
durationMs=Math.max(0,monotonicValue(this.#now)-startedMonotonic);
|
|
1195
910
|
}catch{}
|
|
1196
|
-
this.#history[index]=
|
|
911
|
+
this.#history[index]={
|
|
1197
912
|
...draft,
|
|
1198
913
|
status,
|
|
1199
914
|
completedAt,
|
|
1200
915
|
durationMs,
|
|
1201
|
-
error:error===null?null:
|
|
1202
|
-
|
|
1203
|
-
captureStacks:this.#captureStacks,
|
|
1204
|
-
maxDepth:this.#maxSnapshotDepth,
|
|
1205
|
-
maxEntries:this.#maxSnapshotEntries,
|
|
1206
|
-
maxStringLength:this.#maxSnapshotStringLength
|
|
1207
|
-
})
|
|
1208
|
-
});
|
|
916
|
+
error:error===null?null:completeErrorSnapshot(error)
|
|
917
|
+
};
|
|
1209
918
|
}catch{}
|
|
1210
919
|
}
|
|
1211
920
|
|
|
1212
921
|
enableTimeTravel({dom}={}){
|
|
1213
|
-
if(this.#overflowed){
|
|
1214
|
-
throw new Error('Clear the overflowed event history before enabling time travel again.');
|
|
1215
|
-
}
|
|
1216
922
|
const wasEnabled=this.#timeTravelEnabled;
|
|
1217
923
|
this.#timeTravelEnabled=true;
|
|
1218
924
|
try{
|
|
@@ -1243,7 +949,7 @@ export class EventManager{
|
|
|
1243
949
|
}
|
|
1244
950
|
try{
|
|
1245
951
|
if(this.#timeTravelEnabled)replacement.start();
|
|
1246
|
-
if(!this.#timeTravelEnabled
|
|
952
|
+
if(!this.#timeTravelEnabled){
|
|
1247
953
|
replacement.stop({emitLifecycle:false});
|
|
1248
954
|
}
|
|
1249
955
|
}catch(error){
|
|
@@ -1287,7 +993,6 @@ export class EventManager{
|
|
|
1287
993
|
this.#sequence=0;
|
|
1288
994
|
this.#cursor=0;
|
|
1289
995
|
this.#activeDispatch=[];
|
|
1290
|
-
this.#overflowed=false;
|
|
1291
996
|
if(newSession)this.#sessionId=sessionIdentifier();
|
|
1292
997
|
return this;
|
|
1293
998
|
}
|
|
@@ -1298,10 +1003,10 @@ export class EventManager{
|
|
|
1298
1003
|
||(type!==null&&typeof type!=='string')){
|
|
1299
1004
|
throw new TypeError('The event stack range is invalid.');
|
|
1300
1005
|
}
|
|
1301
|
-
return
|
|
1006
|
+
return this.#history.filter(record=>
|
|
1302
1007
|
record.sequence>=fromSequence&&record.sequence<=toSequence
|
|
1303
1008
|
&&(type===null||record.type===type)
|
|
1304
|
-
)
|
|
1009
|
+
);
|
|
1305
1010
|
}
|
|
1306
1011
|
|
|
1307
1012
|
exportStack({space=2}={}){
|
|
@@ -1351,12 +1056,7 @@ export class EventManager{
|
|
|
1351
1056
|
if(this.#replaying)throw new Error('Event playback is already active.');
|
|
1352
1057
|
const document=stack===null
|
|
1353
1058
|
?{protocol:ARCANE_EVENT_STACK_PROTOCOL,sessionId:this.#sessionId,events:this.#history}
|
|
1354
|
-
:parseEventStack(stack
|
|
1355
|
-
maxEvents:this.#maxEvents,
|
|
1356
|
-
maxSnapshotDepth:this.#maxSnapshotDepth,
|
|
1357
|
-
maxSnapshotEntries:this.#maxSnapshotEntries,
|
|
1358
|
-
maxSnapshotStringLength:this.#maxSnapshotStringLength
|
|
1359
|
-
});
|
|
1059
|
+
:parseEventStack(stack);
|
|
1360
1060
|
const records=document.events.filter(record=>
|
|
1361
1061
|
record.sequence>=fromSequence&&record.sequence<=toSequence
|
|
1362
1062
|
);
|
|
@@ -1393,29 +1093,23 @@ export class EventManager{
|
|
|
1393
1093
|
this.#cursor=record.sequence;
|
|
1394
1094
|
delivered+=1;
|
|
1395
1095
|
}
|
|
1396
|
-
const result=
|
|
1096
|
+
const result={
|
|
1397
1097
|
sessionId:document.sessionId,
|
|
1398
1098
|
delivered,
|
|
1399
1099
|
cursor:this.#cursor,
|
|
1400
1100
|
completed:true
|
|
1401
|
-
}
|
|
1101
|
+
};
|
|
1402
1102
|
this.#bus.emit(PLAYBACK_COMPLETED_EVENT,result);
|
|
1403
1103
|
return result;
|
|
1404
1104
|
}catch(error){
|
|
1405
1105
|
const cancelled=signal?.aborted||error?.name==='AbortError';
|
|
1406
|
-
this.#bus.emit(cancelled?PLAYBACK_CANCELLED_EVENT:PLAYBACK_FAILED_EVENT,
|
|
1106
|
+
this.#bus.emit(cancelled?PLAYBACK_CANCELLED_EVENT:PLAYBACK_FAILED_EVENT,{
|
|
1407
1107
|
sessionId:document.sessionId,
|
|
1408
1108
|
delivered,
|
|
1409
1109
|
cursor:this.#cursor,
|
|
1410
1110
|
completed:false,
|
|
1411
|
-
error:
|
|
1412
|
-
|
|
1413
|
-
captureStacks:this.#captureStacks,
|
|
1414
|
-
maxDepth:this.#maxSnapshotDepth,
|
|
1415
|
-
maxEntries:this.#maxSnapshotEntries,
|
|
1416
|
-
maxStringLength:this.#maxSnapshotStringLength
|
|
1417
|
-
})
|
|
1418
|
-
}));
|
|
1111
|
+
error:completeSnapshot(error)
|
|
1112
|
+
});
|
|
1419
1113
|
throw error;
|
|
1420
1114
|
}finally{
|
|
1421
1115
|
this.#replaying=false;
|
|
@@ -1440,7 +1134,6 @@ function eventName(value,code='ARCANE_EVENT_SUBSCRIPTION_TYPE_INVALID'){
|
|
|
1440
1134
|
if(typeof value!=='string'
|
|
1441
1135
|
||value.trim()!==value
|
|
1442
1136
|
||value.length<1
|
|
1443
|
-
||value.length>128
|
|
1444
1137
|
||!ARCANE_EVENT_NAME_PATTERN.test(value)){
|
|
1445
1138
|
throw eventAuthorityError(code,undefined,TypeError);
|
|
1446
1139
|
}
|
|
@@ -1488,16 +1181,16 @@ function eventSignal(value){
|
|
|
1488
1181
|
|
|
1489
1182
|
function eventListener(value){
|
|
1490
1183
|
if(typeof value==='function'){
|
|
1491
|
-
return
|
|
1184
|
+
return {
|
|
1492
1185
|
identity:value,
|
|
1493
1186
|
invoke(event,thisArg,...rest){return value.call(thisArg,event,...rest);}
|
|
1494
|
-
}
|
|
1187
|
+
};
|
|
1495
1188
|
}
|
|
1496
1189
|
if(value&&typeof value==='object'&&typeof value.handleEvent==='function'){
|
|
1497
|
-
return
|
|
1190
|
+
return {
|
|
1498
1191
|
identity:value,
|
|
1499
1192
|
invoke(event){return value.handleEvent(event);}
|
|
1500
|
-
}
|
|
1193
|
+
};
|
|
1501
1194
|
}
|
|
1502
1195
|
throw eventAuthorityError(
|
|
1503
1196
|
'ARCANE_EVENT_SUBSCRIPTION_HANDLER_INVALID',
|
|
@@ -1508,50 +1201,46 @@ function eventListener(value){
|
|
|
1508
1201
|
|
|
1509
1202
|
function eventTargetListener(value){
|
|
1510
1203
|
if(typeof value==='function'){
|
|
1511
|
-
return
|
|
1204
|
+
return {
|
|
1512
1205
|
identity:value,
|
|
1513
1206
|
invoke(event,thisArg,...rest){return value.call(thisArg,event,...rest);}
|
|
1514
|
-
}
|
|
1207
|
+
};
|
|
1515
1208
|
}
|
|
1516
1209
|
if(value&&typeof value==='object'&&typeof value.handleEvent==='function'){
|
|
1517
|
-
return
|
|
1210
|
+
return {
|
|
1518
1211
|
identity:value,
|
|
1519
1212
|
invoke(event){return value.handleEvent(event);}
|
|
1520
|
-
}
|
|
1213
|
+
};
|
|
1521
1214
|
}
|
|
1522
1215
|
return null;
|
|
1523
1216
|
}
|
|
1524
1217
|
|
|
1525
1218
|
function compatibilityDetail(value){
|
|
1526
1219
|
if(value===null||(typeof value!=='object'&&typeof value!=='function'))return value;
|
|
1527
|
-
if(
|
|
1528
|
-
if(Array.isArray(value))return Object.freeze(value.slice());
|
|
1220
|
+
if(Array.isArray(value))return value.slice();
|
|
1529
1221
|
const prototype=Object.getPrototypeOf(value);
|
|
1530
1222
|
if(prototype!==Object.prototype&&prototype!==null)return value;
|
|
1531
1223
|
const copy=prototype===null?Object.create(null):{};
|
|
1532
1224
|
for(const key of Reflect.ownKeys(value)){
|
|
1533
1225
|
const descriptor=Object.getOwnPropertyDescriptor(value,key);
|
|
1534
|
-
if(!descriptor
|
|
1535
|
-
|
|
1536
|
-
|
|
1537
|
-
|
|
1538
|
-
TypeError
|
|
1539
|
-
);
|
|
1540
|
-
}
|
|
1226
|
+
if(!descriptor)continue;
|
|
1227
|
+
let item;
|
|
1228
|
+
try{item=Reflect.get(value,key);}
|
|
1229
|
+
catch(error){item=snapshotFailure(error,{path:`$.${String(key)}`});}
|
|
1541
1230
|
Object.defineProperty(copy,key,{
|
|
1542
|
-
value:
|
|
1231
|
+
value:item,
|
|
1543
1232
|
enumerable:descriptor.enumerable,
|
|
1544
|
-
configurable:
|
|
1545
|
-
writable:
|
|
1233
|
+
configurable:true,
|
|
1234
|
+
writable:true
|
|
1546
1235
|
});
|
|
1547
1236
|
}
|
|
1548
|
-
return
|
|
1237
|
+
return copy;
|
|
1549
1238
|
}
|
|
1550
1239
|
|
|
1551
1240
|
function eventTargetOptions(value){
|
|
1552
|
-
if(value===undefined)return
|
|
1241
|
+
if(value===undefined)return {capture:false,once:false,signal:null};
|
|
1553
1242
|
if(typeof value==='boolean'){
|
|
1554
|
-
return
|
|
1243
|
+
return {capture:value,once:false,signal:null};
|
|
1555
1244
|
}
|
|
1556
1245
|
const options=eventDataOptions(
|
|
1557
1246
|
value,
|
|
@@ -1567,11 +1256,11 @@ function eventTargetOptions(value){
|
|
|
1567
1256
|
);
|
|
1568
1257
|
}
|
|
1569
1258
|
}
|
|
1570
|
-
return
|
|
1259
|
+
return {
|
|
1571
1260
|
capture:options.capture===true,
|
|
1572
1261
|
once:options.once===true,
|
|
1573
1262
|
signal:eventSignal(options.signal)
|
|
1574
|
-
}
|
|
1263
|
+
};
|
|
1575
1264
|
}
|
|
1576
1265
|
|
|
1577
1266
|
function subscriptionOptions(value){
|
|
@@ -1587,18 +1276,18 @@ function subscriptionOptions(value){
|
|
|
1587
1276
|
TypeError
|
|
1588
1277
|
);
|
|
1589
1278
|
}
|
|
1590
|
-
return
|
|
1279
|
+
return {
|
|
1591
1280
|
once:options.once===true,
|
|
1592
1281
|
signal:eventSignal(options.signal)
|
|
1593
|
-
}
|
|
1282
|
+
};
|
|
1594
1283
|
}
|
|
1595
1284
|
|
|
1596
1285
|
function defineDisposable(unsubscribe){
|
|
1597
1286
|
Object.defineProperty(unsubscribe,'dispose',{
|
|
1598
1287
|
value:unsubscribe,
|
|
1599
1288
|
enumerable:false,
|
|
1600
|
-
configurable:
|
|
1601
|
-
writable:
|
|
1289
|
+
configurable:true,
|
|
1290
|
+
writable:true
|
|
1602
1291
|
});
|
|
1603
1292
|
return unsubscribe;
|
|
1604
1293
|
}
|
|
@@ -1663,11 +1352,11 @@ function createArcaneEventAuthority(){
|
|
|
1663
1352
|
let canonicalDispatchDepth=0;
|
|
1664
1353
|
const pendingChannelRemovals=[];
|
|
1665
1354
|
|
|
1666
|
-
const descriptor=
|
|
1355
|
+
const descriptor={
|
|
1667
1356
|
kind:ARCANE_EVENT_AUTHORITY_KIND,
|
|
1668
1357
|
protocol:ARCANE_EVENT_AUTHORITY_PROTOCOL,
|
|
1669
1358
|
realm:'current'
|
|
1670
|
-
}
|
|
1359
|
+
};
|
|
1671
1360
|
|
|
1672
1361
|
function nextOccurrenceId(){
|
|
1673
1362
|
if(occurrenceSequence===Number.MAX_SAFE_INTEGER){
|
|
@@ -1697,13 +1386,17 @@ function createArcaneEventAuthority(){
|
|
|
1697
1386
|
}
|
|
1698
1387
|
|
|
1699
1388
|
function publicEventDetail(value){
|
|
1700
|
-
return
|
|
1701
|
-
|
|
1702
|
-
|
|
1703
|
-
|
|
1704
|
-
|
|
1705
|
-
|
|
1706
|
-
|
|
1389
|
+
return completeSnapshot(value??{});
|
|
1390
|
+
}
|
|
1391
|
+
|
|
1392
|
+
function completeEventDetail(compatibility,publicDetail){
|
|
1393
|
+
if(publicDetail===undefined)return compatibility??{};
|
|
1394
|
+
const compatibilityRecord=compatibility&&typeof compatibility==='object'
|
|
1395
|
+
&&!Array.isArray(compatibility);
|
|
1396
|
+
const publicRecord=publicDetail&&typeof publicDetail==='object'
|
|
1397
|
+
&&!Array.isArray(publicDetail);
|
|
1398
|
+
if(compatibilityRecord&&publicRecord)return {...compatibility,...publicDetail};
|
|
1399
|
+
return {compatibility,publicDetail};
|
|
1707
1400
|
}
|
|
1708
1401
|
|
|
1709
1402
|
function canonicalOccurrence({
|
|
@@ -1718,23 +1411,24 @@ function createArcaneEventAuthority(){
|
|
|
1718
1411
|
let prevented=cancelable&&defaultPrevented;
|
|
1719
1412
|
const occurrence={};
|
|
1720
1413
|
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},
|
|
1414
|
+
protocol:{value:ARCANE_EVENT_OCCURRENCE_PROTOCOL,enumerable:true,writable:true,configurable:true},
|
|
1415
|
+
occurrenceId:{value:nextOccurrenceId(),enumerable:true,writable:true,configurable:true},
|
|
1416
|
+
type:{value:type,enumerable:true,writable:true,configurable:true},
|
|
1417
|
+
source:{value:source,enumerable:true,writable:true,configurable:true},
|
|
1418
|
+
instanceId:{value:instanceId,enumerable:true,writable:true,configurable:true},
|
|
1419
|
+
operationId:{value:operationId,enumerable:true,writable:true,configurable:true},
|
|
1420
|
+
detail:{value:detail,enumerable:true,writable:true,configurable:true},
|
|
1421
|
+
cancelable:{value:cancelable,enumerable:true,writable:true,configurable:true},
|
|
1422
|
+
defaultPrevented:{get(){return prevented;},enumerable:true,configurable:true},
|
|
1730
1423
|
preventDefault:{
|
|
1731
1424
|
value:function preventArcaneEventDefault(){
|
|
1732
1425
|
if(cancelable)prevented=true;
|
|
1733
1426
|
},
|
|
1734
|
-
enumerable:true
|
|
1427
|
+
enumerable:true,
|
|
1428
|
+
writable:true,
|
|
1429
|
+
configurable:true
|
|
1735
1430
|
}
|
|
1736
1431
|
});
|
|
1737
|
-
Object.freeze(occurrence);
|
|
1738
1432
|
occurrences.add(occurrence);
|
|
1739
1433
|
return occurrence;
|
|
1740
1434
|
}
|
|
@@ -1742,27 +1436,26 @@ function createArcaneEventAuthority(){
|
|
|
1742
1436
|
function compatibilityView(occurrence,detail,target=null){
|
|
1743
1437
|
const view={};
|
|
1744
1438
|
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}
|
|
1439
|
+
protocol:{value:occurrence.protocol,enumerable:true,writable:true,configurable:true},
|
|
1440
|
+
occurrenceId:{value:occurrence.occurrenceId,enumerable:true,writable:true,configurable:true},
|
|
1441
|
+
type:{value:occurrence.type,enumerable:true,writable:true,configurable:true},
|
|
1442
|
+
source:{value:occurrence.source,enumerable:true,writable:true,configurable:true},
|
|
1443
|
+
instanceId:{value:occurrence.instanceId,enumerable:true,writable:true,configurable:true},
|
|
1444
|
+
operationId:{value:occurrence.operationId,enumerable:true,writable:true,configurable:true},
|
|
1445
|
+
detail:{value:detail,enumerable:true,writable:true,configurable:true},
|
|
1446
|
+
target:{value:target,enumerable:true,writable:true,configurable:true},
|
|
1447
|
+
currentTarget:{value:target,enumerable:true,writable:true,configurable:true},
|
|
1448
|
+
cancelable:{value:occurrence.cancelable,enumerable:true,writable:true,configurable:true},
|
|
1449
|
+
defaultPrevented:{get(){return occurrence.defaultPrevented;},enumerable:true,configurable:true},
|
|
1450
|
+
preventDefault:{value:()=>occurrence.preventDefault(),enumerable:true,writable:true,configurable:true}
|
|
1757
1451
|
});
|
|
1758
|
-
Object.freeze(view);
|
|
1759
1452
|
canonicalByView.set(view,occurrence);
|
|
1760
1453
|
return view;
|
|
1761
1454
|
}
|
|
1762
1455
|
|
|
1763
1456
|
function removeChannelListener(channel,handler){
|
|
1764
1457
|
if(canonicalDispatchDepth>0){
|
|
1765
|
-
pendingChannelRemovals.push(
|
|
1458
|
+
pendingChannelRemovals.push({channel,handler});
|
|
1766
1459
|
return;
|
|
1767
1460
|
}
|
|
1768
1461
|
manager[EVENT_MANAGER_BUS_OFF](channel,handler);
|
|
@@ -1837,15 +1530,16 @@ function createArcaneEventAuthority(){
|
|
|
1837
1530
|
reportingListenerError=true;
|
|
1838
1531
|
let errorOccurrence=null;
|
|
1839
1532
|
try{
|
|
1840
|
-
const detail=
|
|
1533
|
+
const detail={
|
|
1841
1534
|
code:'ARCANE_EVENT_LISTENER_CALLBACK_FAILED',
|
|
1842
1535
|
reason:'listener-threw',
|
|
1843
1536
|
eventType:occurrence?.type??null,
|
|
1844
1537
|
occurrenceId:occurrence?.occurrenceId??null,
|
|
1845
1538
|
source:occurrence?.source??ownerRecord?.source??'event-authority',
|
|
1846
1539
|
instanceId:occurrence?.instanceId??ownerRecord?.instanceId??null,
|
|
1847
|
-
operationId:occurrence?.operationId??null
|
|
1848
|
-
|
|
1540
|
+
operationId:occurrence?.operationId??null,
|
|
1541
|
+
error
|
|
1542
|
+
};
|
|
1849
1543
|
errorOccurrence=dispatchOccurrence({
|
|
1850
1544
|
type:ARCANE_EVENT_LISTENER_ERROR_EVENT,
|
|
1851
1545
|
sourceRecord:null,
|
|
@@ -1888,7 +1582,7 @@ function createArcaneEventAuthority(){
|
|
|
1888
1582
|
source,
|
|
1889
1583
|
instanceId,
|
|
1890
1584
|
operationId,
|
|
1891
|
-
detail:publicEventDetail(publicDetail),
|
|
1585
|
+
detail:publicEventDetail(completeEventDetail(compatibility,publicDetail)),
|
|
1892
1586
|
cancelable,
|
|
1893
1587
|
defaultPrevented
|
|
1894
1588
|
});
|
|
@@ -1910,7 +1604,7 @@ function createArcaneEventAuthority(){
|
|
|
1910
1604
|
{source,category:'semantic',correlationId:operationId}
|
|
1911
1605
|
);
|
|
1912
1606
|
}
|
|
1913
|
-
return
|
|
1607
|
+
return {occurrence,accepted:!occurrence.defaultPrevented};
|
|
1914
1608
|
}
|
|
1915
1609
|
|
|
1916
1610
|
function subscribe(type,handler,options){
|
|
@@ -2008,8 +1702,7 @@ function createArcaneEventAuthority(){
|
|
|
2008
1702
|
);
|
|
2009
1703
|
const source=eventName(admitted.source,'ARCANE_EVENT_SOURCE_INVALID');
|
|
2010
1704
|
if(!Array.isArray(admitted.eventTypes)
|
|
2011
|
-
||admitted.eventTypes.length<1
|
|
2012
|
-
||admitted.eventTypes.length>256){
|
|
1705
|
+
||admitted.eventTypes.length<1){
|
|
2013
1706
|
throw eventAuthorityError('ARCANE_EVENT_SOURCE_INVALID',undefined,TypeError);
|
|
2014
1707
|
}
|
|
2015
1708
|
const eventTypes=[];
|
|
@@ -2082,8 +1775,7 @@ function createArcaneEventAuthority(){
|
|
|
2082
1775
|
const operationId=normalized.operationId??null;
|
|
2083
1776
|
if(operationId!==null&&(typeof operationId!=='string'
|
|
2084
1777
|
||operationId.trim()!==operationId
|
|
2085
|
-
||operationId.length<1
|
|
2086
|
-
||operationId.length>256)){
|
|
1778
|
+
||operationId.length<1)){
|
|
2087
1779
|
throw eventAuthorityError('ARCANE_EVENT_OCCURRENCE_INVALID',undefined,TypeError);
|
|
2088
1780
|
}
|
|
2089
1781
|
if(normalized.cancelable!==undefined&&typeof normalized.cancelable!=='boolean'){
|
|
@@ -2095,7 +1787,7 @@ function createArcaneEventAuthority(){
|
|
|
2095
1787
|
source:record.source,
|
|
2096
1788
|
instanceId:record.instanceId,
|
|
2097
1789
|
compatibility:detail,
|
|
2098
|
-
publicDetail:normalized.publicDetail
|
|
1790
|
+
publicDetail:normalized.publicDetail,
|
|
2099
1791
|
operationId,
|
|
2100
1792
|
cancelable:normalized.cancelable===true
|
|
2101
1793
|
});
|
|
@@ -2109,12 +1801,12 @@ function createArcaneEventAuthority(){
|
|
|
2109
1801
|
sourceRecord:record,
|
|
2110
1802
|
source:record.source,
|
|
2111
1803
|
instanceId:record.instanceId,
|
|
2112
|
-
compatibility:
|
|
1804
|
+
compatibility:{
|
|
2113
1805
|
source:record.source,
|
|
2114
1806
|
instanceId:record.instanceId,
|
|
2115
1807
|
reason:'source-disposed'
|
|
2116
|
-
}
|
|
2117
|
-
publicDetail:
|
|
1808
|
+
},
|
|
1809
|
+
publicDetail:{reason:'source-disposed'},
|
|
2118
1810
|
operationId:null,
|
|
2119
1811
|
cancelable:false
|
|
2120
1812
|
});
|
|
@@ -2127,13 +1819,13 @@ function createArcaneEventAuthority(){
|
|
|
2127
1819
|
record.disposing=false;
|
|
2128
1820
|
}
|
|
2129
1821
|
}
|
|
2130
|
-
const sourceDescriptor=
|
|
1822
|
+
const sourceDescriptor={
|
|
2131
1823
|
kind:ARCANE_EVENT_SOURCE_KIND,
|
|
2132
1824
|
protocol:ARCANE_EVENT_SOURCE_PROTOCOL,
|
|
2133
1825
|
source,
|
|
2134
1826
|
instanceId:record.instanceId,
|
|
2135
|
-
eventTypes:
|
|
2136
|
-
}
|
|
1827
|
+
eventTypes:[...eventTypes,ARCANE_EVENT_SOURCE_DISPOSED_EVENT]
|
|
1828
|
+
};
|
|
2137
1829
|
const handle={
|
|
2138
1830
|
protocol:ARCANE_EVENT_SOURCE_PROTOCOL,
|
|
2139
1831
|
descriptor:sourceDescriptor,
|
|
@@ -2172,7 +1864,7 @@ function createArcaneEventAuthority(){
|
|
|
2172
1864
|
get(){return record.disposing||record.disposed;},
|
|
2173
1865
|
enumerable:true
|
|
2174
1866
|
});
|
|
2175
|
-
record.handle=
|
|
1867
|
+
record.handle=handle;
|
|
2176
1868
|
sourceByOwner.set(owner,record);
|
|
2177
1869
|
return record.handle;
|
|
2178
1870
|
}
|
|
@@ -2210,14 +1902,15 @@ function createArcaneEventAuthority(){
|
|
|
2210
1902
|
detail={};
|
|
2211
1903
|
for(const key of Reflect.ownKeys(compatibility)){
|
|
2212
1904
|
const descriptor=Object.getOwnPropertyDescriptor(compatibility,key);
|
|
2213
|
-
if(!descriptor
|
|
2214
|
-
|
|
2215
|
-
}
|
|
1905
|
+
if(!descriptor)continue;
|
|
1906
|
+
let item;
|
|
1907
|
+
try{item=Reflect.get(compatibility,key);}
|
|
1908
|
+
catch(error){item=snapshotFailure(error,{path:`$.${String(key)}`});}
|
|
2216
1909
|
Object.defineProperty(detail,key,{
|
|
2217
|
-
value:
|
|
1910
|
+
value:item,
|
|
2218
1911
|
enumerable:descriptor.enumerable,
|
|
2219
|
-
configurable:
|
|
2220
|
-
writable:
|
|
1912
|
+
configurable:true,
|
|
1913
|
+
writable:true
|
|
2221
1914
|
});
|
|
2222
1915
|
}
|
|
2223
1916
|
}else{
|
|
@@ -2233,22 +1926,11 @@ function createArcaneEventAuthority(){
|
|
|
2233
1926
|
if(Object.hasOwn(detail,key)&&detail[key]!==metadata[key]){
|
|
2234
1927
|
throw eventAuthorityError('ARCANE_EVENT_DOM_DETAIL_COLLISION');
|
|
2235
1928
|
}
|
|
2236
|
-
|
|
2237
|
-
value:metadata[key],
|
|
2238
|
-
enumerable:true,
|
|
2239
|
-
configurable:false,
|
|
2240
|
-
writable:false
|
|
2241
|
-
});
|
|
1929
|
+
detail[key]=metadata[key];
|
|
2242
1930
|
}
|
|
2243
1931
|
if(!Object.hasOwn(detail,'source')){
|
|
2244
|
-
|
|
2245
|
-
value:metadata.arcaneSource,
|
|
2246
|
-
enumerable:true,
|
|
2247
|
-
configurable:false,
|
|
2248
|
-
writable:false
|
|
2249
|
-
});
|
|
1932
|
+
detail.source=metadata.arcaneSource;
|
|
2250
1933
|
}
|
|
2251
|
-
Object.freeze(detail);
|
|
2252
1934
|
const cancelable=admitted.cancelable??occurrence.cancelable;
|
|
2253
1935
|
const event=new CustomEvent(type,{
|
|
2254
1936
|
detail,
|
|
@@ -2301,126 +1983,59 @@ function createArcaneEventAuthority(){
|
|
|
2301
1983
|
return manager;
|
|
2302
1984
|
}
|
|
2303
1985
|
|
|
2304
|
-
Object.
|
|
2305
|
-
[ARCANE_EVENT_AUTHORITY_BRAND]:
|
|
2306
|
-
|
|
2307
|
-
|
|
2308
|
-
|
|
2309
|
-
|
|
2310
|
-
|
|
2311
|
-
|
|
2312
|
-
|
|
2313
|
-
|
|
2314
|
-
|
|
2315
|
-
|
|
2316
|
-
|
|
2317
|
-
|
|
2318
|
-
|
|
2319
|
-
|
|
2320
|
-
|
|
2321
|
-
|
|
2322
|
-
|
|
2323
|
-
|
|
2324
|
-
|
|
2325
|
-
value(type,handler,options){
|
|
2326
|
-
addEventTargetListener(
|
|
2327
|
-
authorityTargetListeners,
|
|
2328
|
-
type,
|
|
2329
|
-
handler,
|
|
2330
|
-
options,
|
|
2331
|
-
subscribe,
|
|
2332
|
-
manager
|
|
2333
|
-
);
|
|
2334
|
-
},
|
|
2335
|
-
enumerable:true
|
|
1986
|
+
Object.assign(manager,{
|
|
1987
|
+
[ARCANE_EVENT_AUTHORITY_BRAND]:ARCANE_EVENT_AUTHORITY_PROTOCOL,
|
|
1988
|
+
protocol:ARCANE_EVENT_AUTHORITY_PROTOCOL,
|
|
1989
|
+
descriptor,
|
|
1990
|
+
on:safeLegacyOn,
|
|
1991
|
+
once:(type,handler)=>safeLegacyOn(type,handler,true),
|
|
1992
|
+
off:safeLegacyOff,
|
|
1993
|
+
reset:safeLegacyReset,
|
|
1994
|
+
subscribe,
|
|
1995
|
+
createSource,
|
|
1996
|
+
projectDOMEvent,
|
|
1997
|
+
isOccurrence:value=>occurrences.has(value)||canonicalByView.has(value),
|
|
1998
|
+
addEventListener(type,handler,options){
|
|
1999
|
+
addEventTargetListener(
|
|
2000
|
+
authorityTargetListeners,
|
|
2001
|
+
type,
|
|
2002
|
+
handler,
|
|
2003
|
+
options,
|
|
2004
|
+
subscribe,
|
|
2005
|
+
manager
|
|
2006
|
+
);
|
|
2336
2007
|
},
|
|
2337
|
-
removeEventListener
|
|
2338
|
-
|
|
2339
|
-
removeEventTargetListener(authorityTargetListeners,type,handler,options);
|
|
2340
|
-
},
|
|
2341
|
-
enumerable:true
|
|
2008
|
+
removeEventListener(type,handler,options){
|
|
2009
|
+
removeEventTargetListener(authorityTargetListeners,type,handler,options);
|
|
2342
2010
|
},
|
|
2343
|
-
dispatchEvent:
|
|
2011
|
+
dispatchEvent:value=>dispatchEventLike(value)
|
|
2344
2012
|
});
|
|
2345
|
-
return
|
|
2013
|
+
return manager;
|
|
2346
2014
|
}
|
|
2347
2015
|
|
|
2348
|
-
function
|
|
2349
|
-
|
|
2350
|
-
|
|
2351
|
-
|
|
2352
|
-
|
|
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;
|
|
2016
|
+
function usableArcaneEventAuthority(value){
|
|
2017
|
+
return Boolean(value)
|
|
2018
|
+
&&(typeof value==='object'||typeof value==='function')
|
|
2019
|
+
&&value.protocol===ARCANE_EVENT_AUTHORITY_PROTOCOL
|
|
2020
|
+
&&ARCANE_EVENT_REQUIRED_AUTHORITY_API.every(name=>typeof value[name]==='function');
|
|
2403
2021
|
}
|
|
2404
2022
|
|
|
2405
2023
|
function installArcaneEventAuthority(){
|
|
2406
|
-
|
|
2407
|
-
|
|
2408
|
-
if(
|
|
2409
|
-
throw eventAuthorityError('ARCANE_EVENT_AUTHORITY_VALUE_COLLISION');
|
|
2410
|
-
}
|
|
2024
|
+
let existing=null;
|
|
2025
|
+
try{existing=globalThis.arcaneEvents??null;}catch{}
|
|
2026
|
+
if(usableArcaneEventAuthority(existing))return existing;
|
|
2411
2027
|
const authority=createArcaneEventAuthority();
|
|
2412
2028
|
try{
|
|
2413
2029
|
Object.defineProperty(globalThis,'arcaneEvents',{
|
|
2414
2030
|
value:authority,
|
|
2415
2031
|
enumerable:false,
|
|
2416
|
-
configurable:
|
|
2417
|
-
writable:
|
|
2032
|
+
configurable:true,
|
|
2033
|
+
writable:true
|
|
2418
2034
|
});
|
|
2419
2035
|
}catch(error){
|
|
2420
2036
|
throw eventAuthorityError('ARCANE_EVENT_AUTHORITY_INSTALL_FAILED',error);
|
|
2421
2037
|
}
|
|
2422
|
-
|
|
2423
|
-
return validateInstalledArcaneEventAuthority(installed?.value,installed);
|
|
2038
|
+
return authority;
|
|
2424
2039
|
}
|
|
2425
2040
|
|
|
2426
2041
|
export const arcaneEvents=installArcaneEventAuthority();
|