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.
Files changed (117) hide show
  1. package/CHANGELOG.md +29 -0
  2. package/README.md +8 -8
  3. package/browser-runtime/ARCANE_SDK_BROWSER_RELEASE.json +29 -22
  4. package/browser-runtime/ai/ARCANE_AI_BROWSER_SPEECH_COMPONENTS.json +203 -0
  5. package/browser-runtime/ai/browser-kokoro-worker.mjs +11 -2
  6. package/browser-runtime/ai/browser-speech-artifacts.mjs +3230 -397
  7. package/browser-runtime/ai/browser-speech-providers.mjs +1141 -157
  8. package/browser-runtime/ai/browser-speech.mjs +2 -0
  9. package/browser-runtime/ai/browser-whisper-worker.mjs +11 -2
  10. package/browser-runtime/ai/model-controller.mjs +285 -95
  11. package/browser-runtime/ai/speech-worker-client.mjs +247 -32
  12. package/browser-runtime/ai/speech-worker-runtime.mjs +2310 -167
  13. package/browser-runtime/event-manager.mjs +1097 -1
  14. package/docs/architecture.md +2 -2
  15. package/docs/event-manager.md +155 -27
  16. package/docs/reference/README.md +27 -27
  17. package/docs/reference/ai/browser-speech-package-authority.json +835 -0
  18. package/docs/reference/ai/browser-speech.md +1162 -246
  19. package/docs/reference/ai/browser-wasm.md +18 -7
  20. package/docs/reference/availability-and-normalization.md +6 -3
  21. package/docs/reference/behavioral-testing.md +29 -6
  22. package/docs/reference/cli.md +117 -9
  23. package/docs/reference/core/arcane-ai-contracts.md +1 -1
  24. package/docs/reference/event-manager.md +577 -32
  25. package/docs/reference/inventory/package-api.json +478 -2
  26. package/docs/reference/inventory/runtime-components.json +108 -44
  27. package/docs/reference/inventory/runtime-modules.json +131 -53
  28. package/docs/reference/mail.md +316 -0
  29. package/docs/reference/protocols.md +157 -43
  30. package/docs/reference/runtime-components.md +258 -83
  31. package/docs/reference/runtime-modules.md +613 -77
  32. package/docs/reference/sdk-api.md +1014 -25
  33. package/package.json +5 -4
  34. package/runtime/ARCANE_RUNTIME_RELEASE.json +145 -140
  35. package/runtime/arcane/components/app-bar.html +34 -13
  36. package/runtime/arcane/components/assistant-panel.html +110 -57
  37. package/runtime/arcane/components/calculator.html +7 -4
  38. package/runtime/arcane/components/chart.html +58 -17
  39. package/runtime/arcane/components/chat.html +606 -136
  40. package/runtime/arcane/components/conversation-view.html +13 -6
  41. package/runtime/arcane/components/dashboard-config.html +96 -59
  42. package/runtime/arcane/components/data-maintenance.html +69 -14
  43. package/runtime/arcane/components/data-view.html +53 -7
  44. package/runtime/arcane/components/directory-picker.html +118 -32
  45. package/runtime/arcane/components/document-inspector.html +47 -10
  46. package/runtime/arcane/components/file-drop.html +81 -35
  47. package/runtime/arcane/components/file-inspector.html +72 -22
  48. package/runtime/arcane/components/file-manager.html +374 -79
  49. package/runtime/arcane/components/integration-settings.html +12 -5
  50. package/runtime/arcane/components/local-ai-status.html +48 -19
  51. package/runtime/arcane/components/markdown-document.html +161 -68
  52. package/runtime/arcane/components/markdown-editor.html +110 -33
  53. package/runtime/arcane/components/media-embed.html +8 -5
  54. package/runtime/arcane/components/modal.html +15 -5
  55. package/runtime/arcane/components/output-panel.html +28 -23
  56. package/runtime/arcane/components/preferences-form.html +22 -4
  57. package/runtime/arcane/components/record-timeline.html +18 -2
  58. package/runtime/arcane/components/relationship-board.html +23 -3
  59. package/runtime/arcane/components/screen-capture.html +10 -4
  60. package/runtime/arcane/components/source-code-viewer.html +76 -9
  61. package/runtime/arcane/components/source-explanation.html +23 -3
  62. package/runtime/arcane/components/speech.html +462 -384
  63. package/runtime/arcane/components/summary-strip.html +22 -11
  64. package/runtime/arcane/components/table.html +39 -21
  65. package/runtime/arcane/components/task-progress.html +79 -21
  66. package/runtime/arcane/components/terminal-workspace.html +7 -4
  67. package/runtime/arcane/components/theme-editor.html +7 -3
  68. package/runtime/arcane/components/unified-inbox.html +9 -4
  69. package/runtime/arcane/components/voice-transcription.html +639 -98
  70. package/runtime/arcane/components/weather-widget.html +5 -3
  71. package/runtime/arcane/components/web-navigator.html +48 -8
  72. package/runtime/arcane/entities/Chat.js +1 -1
  73. package/runtime/arcane/entities/User.js +110 -23
  74. package/runtime/arcane/modules/AI.js +2109 -130
  75. package/runtime/arcane/modules/AIProviderRuntime.js +720 -13
  76. package/runtime/arcane/modules/AIRuntimeState.js +109 -52
  77. package/runtime/arcane/modules/ApiModelDatabase.js +390 -17
  78. package/runtime/arcane/modules/BrowserTestSuite.js +205 -28
  79. package/runtime/arcane/modules/CalculatorEngine.js +63 -3
  80. package/runtime/arcane/modules/CommunicationAppController.js +588 -28
  81. package/runtime/arcane/modules/CommunicationHub.js +590 -10
  82. package/runtime/arcane/modules/ComponentContracts.js +470 -0
  83. package/runtime/arcane/modules/ConversationTimebox.js +152 -33
  84. package/runtime/arcane/modules/DBLS.js +40 -7
  85. package/runtime/arcane/modules/DBOPFS.js +35 -11
  86. package/runtime/arcane/modules/DataMaintenance.js +12 -2
  87. package/runtime/arcane/modules/Errors.js +65 -7
  88. package/runtime/arcane/modules/HTMLImport.js +198 -14
  89. package/runtime/arcane/modules/LocalAIReadinessController.js +208 -29
  90. package/runtime/arcane/modules/Mail.js +738 -115
  91. package/runtime/arcane/modules/MailOutbox.mjs +1395 -0
  92. package/runtime/arcane/modules/MailTransport.mjs +197 -39
  93. package/runtime/arcane/modules/Ollama.js +36 -1
  94. package/runtime/arcane/modules/OpenMeteoWeatherProvider.js +583 -7
  95. package/runtime/arcane/modules/PreferenceStore.js +367 -33
  96. package/runtime/arcane/modules/RecordReviewStore.js +322 -23
  97. package/runtime/arcane/modules/ScreenCapture.js +1397 -15
  98. package/runtime/arcane/modules/SpeechPlayback.js +438 -41
  99. package/runtime/arcane/modules/TerminalClient.js +277 -12
  100. package/runtime/arcane/modules/ThemeBootstrap.js +80 -6
  101. package/runtime/arcane/modules/ThemeManager.js +39 -7
  102. package/runtime/arcane/modules/TimeGuard.js +131 -20
  103. package/runtime/arcane/modules/WaitForComponent.js +386 -33
  104. package/schemas/arcane-lock.schema.json +2 -2
  105. package/src/cli/main.mjs +435 -9
  106. package/src/event-manager.mjs +1097 -1
  107. package/src/import-map.mjs +21 -3
  108. package/src/index.mjs +13 -0
  109. package/src/installed-sdk-runtime.mjs +112 -0
  110. package/src/mail-api.mjs +22 -0
  111. package/src/mail-credentials.mjs +667 -0
  112. package/src/mail-server.mjs +1769 -0
  113. package/src/mail.mjs +261 -0
  114. package/src/sdk-browser-runtime.mjs +85 -41
  115. package/src/testing-loader.mjs +7 -0
  116. package/src/toolchain.mjs +3 -0
  117. package/src/workspace.mjs +1 -1
@@ -1,6 +1,126 @@
1
+ import {createArcaneEventSource} from 'arcane-os/event-manager';
1
2
  import Preference,{preferenceSchema} from '../entities/Preference.js';
2
3
  import {resolveApplicationLocalStorageKey} from './AppDataScope.js';
3
4
 
5
+ export const PREFERENCE_STORE_ERROR_CODES=Object.freeze({
6
+ adapterInvalid:'ARCANE_PREFERENCE_STORE_ADAPTER_INVALID',
7
+ disposed:'ARCANE_PREFERENCE_STORE_DISPOSED',
8
+ eventDetailInvalid:'ARCANE_PREFERENCE_EVENT_DETAIL_INVALID',
9
+ keyUnknown:'ARCANE_PREFERENCE_KEY_UNKNOWN',
10
+ operationAborted:'ARCANE_PREFERENCE_STORE_OPERATION_ABORTED',
11
+ operationOptionsInvalid:'ARCANE_PREFERENCE_STORE_OPERATION_OPTIONS_INVALID',
12
+ valuesInvalid:'ARCANE_PREFERENCE_VALUES_INVALID'
13
+ });
14
+
15
+ export const PREFERENCE_STORE_EVENT_TYPES=Object.freeze({
16
+ change:'preference-change',
17
+ load:'preference-load',
18
+ reset:'preference-reset'
19
+ });
20
+
21
+ function preferenceStoreError(code,reason,message,ErrorType=Error,cause){
22
+ const error=new ErrorType(message);
23
+ error.code=code;
24
+ error.reason=reason;
25
+ if(cause!==undefined) error.cause=cause;
26
+ return error;
27
+ }
28
+
29
+ function disposedError(){
30
+ return preferenceStoreError(
31
+ PREFERENCE_STORE_ERROR_CODES.disposed,
32
+ 'preference-store-disposed',
33
+ 'The preference store has been disposed.'
34
+ );
35
+ }
36
+
37
+ function operationAbortedError(reason){
38
+ const error=preferenceStoreError(
39
+ PREFERENCE_STORE_ERROR_CODES.operationAborted,
40
+ 'preference-operation-aborted',
41
+ 'The preference operation was aborted.',
42
+ Error,
43
+ reason
44
+ );
45
+ error.name='AbortError';
46
+ return error;
47
+ }
48
+
49
+ function isPlainRecord(value){
50
+ if(!value||typeof value!=='object'||Array.isArray(value)) return false;
51
+ const prototype=Object.getPrototypeOf(value);
52
+ return prototype===Object.prototype||prototype===null;
53
+ }
54
+
55
+ function isAbortSignal(value){
56
+ return Boolean(value)
57
+ &&typeof value==='object'
58
+ &&typeof value.aborted==='boolean'
59
+ &&typeof value.addEventListener==='function'
60
+ &&typeof value.removeEventListener==='function';
61
+ }
62
+
63
+ function normalizeOperationOptions(value={}){
64
+ if(!isPlainRecord(value)){
65
+ throw preferenceStoreError(
66
+ PREFERENCE_STORE_ERROR_CODES.operationOptionsInvalid,
67
+ 'preference-operation-options-invalid',
68
+ 'Preference operation options must be a plain object.',
69
+ TypeError
70
+ );
71
+ }
72
+ const keys=Reflect.ownKeys(value);
73
+ if(keys.some(function hasUnsupportedPreferenceOperationOption(key){
74
+ return key!=='signal';
75
+ })){
76
+ throw preferenceStoreError(
77
+ PREFERENCE_STORE_ERROR_CODES.operationOptionsInvalid,
78
+ 'preference-operation-options-invalid',
79
+ 'Preference operation options support only signal.',
80
+ TypeError
81
+ );
82
+ }
83
+ const signal=value.signal??null;
84
+ if(signal!==null&&!isAbortSignal(signal)){
85
+ throw preferenceStoreError(
86
+ PREFERENCE_STORE_ERROR_CODES.operationOptionsInvalid,
87
+ 'preference-operation-signal-invalid',
88
+ 'Preference operation signal must be an AbortSignal.',
89
+ TypeError
90
+ );
91
+ }
92
+ return Object.freeze({signal});
93
+ }
94
+
95
+ function setDataProperty(target,key,value){
96
+ Object.defineProperty(
97
+ target,
98
+ key,
99
+ {configurable:true,enumerable:true,value,writable:true}
100
+ );
101
+ }
102
+
103
+ function frozenPreferenceValues(values){
104
+ const copy={};
105
+ for(const [key,value] of Object.entries(values)) setDataProperty(copy,key,value);
106
+ return Object.freeze(copy);
107
+ }
108
+
109
+ function validateAdapter(adapter){
110
+ if(!adapter
111
+ ||typeof adapter.get!=='function'
112
+ ||typeof adapter.set!=='function'
113
+ ||typeof adapter.delete!=='function'){
114
+ throw preferenceStoreError(
115
+ PREFERENCE_STORE_ERROR_CODES.adapterInvalid,
116
+ 'preference-storage-adapter-invalid',
117
+ 'The preference storage adapter must provide get, set, and delete methods.',
118
+ TypeError
119
+ );
120
+ }
121
+ return adapter;
122
+ }
123
+
4
124
  function localAdapter(prefix){
5
125
  const storage=globalThis.localStorage;
6
126
  const scopedPrefix=resolveApplicationLocalStorageKey(prefix);
@@ -9,8 +129,14 @@ function localAdapter(prefix){
9
129
  const raw=storage?.getItem(`${scopedPrefix}:${key}`);
10
130
  return {found:raw!==null&&raw!==undefined,value:raw==null?null:JSON.parse(raw)};
11
131
  },
12
- async set(key,value){ storage?.setItem(`${scopedPrefix}:${key}`,JSON.stringify(value)); return {key,value}; },
13
- async delete(key){ storage?.removeItem(`${scopedPrefix}:${key}`); return {key,deleted:true}; }
132
+ async set(key,value){
133
+ storage?.setItem(`${scopedPrefix}:${key}`,JSON.stringify(value));
134
+ return {key,value};
135
+ },
136
+ async delete(key){
137
+ storage?.removeItem(`${scopedPrefix}:${key}`);
138
+ return {key,deleted:true};
139
+ }
14
140
  };
15
141
  }
16
142
 
@@ -40,69 +166,277 @@ function preferenceAdapter(){
40
166
  }
41
167
  }
42
168
  return {
43
- get:key=>call('get',[key]),
44
- set:(key,value)=>call('set',[key,value]),
45
- delete:key=>call('delete',[key])
169
+ async get(key){
170
+ return call('get',[key]);
171
+ },
172
+ async set(key,value){
173
+ return call('set',[key,value]);
174
+ },
175
+ async delete(key){
176
+ return call('delete',[key]);
177
+ }
46
178
  };
47
179
  }
48
180
 
49
181
  export default class PreferenceStore extends EventTarget{
182
+ #disposed=false;
183
+ #events;
184
+ #operationSequence=0;
185
+ #operationTail=Promise.resolve();
186
+ #pendingOperations=new Set();
187
+
50
188
  constructor({namespace='arcane',schema=[],adapter=null}={}){
51
189
  super();
52
190
  this.namespace=String(namespace||'arcane');
53
191
  this.schema=preferenceSchema(schema);
54
- this.adapter=adapter||preferenceAdapter();
192
+ this.adapter=validateAdapter(adapter||preferenceAdapter());
55
193
  this.values=this.defaults();
194
+ this.#events=createArcaneEventSource(
195
+ this,
196
+ {
197
+ source:'preference-store',
198
+ eventTypes:Object.freeze(Object.values(PREFERENCE_STORE_EVENT_TYPES))
199
+ }
200
+ );
56
201
  }
57
202
 
203
+ addEventListener(type,listener,options){return this.#events.addEventListener(type,listener,options);}
204
+ removeEventListener(type,listener,options){return this.#events.removeEventListener(type,listener,options);}
205
+ on(type,listener,options){return this.#events.on(type,listener,options);}
206
+ dispatchEvent(value){return this.#events.dispatchEvent(value);}
207
+
58
208
  defaults(){
59
- return Object.fromEntries(this.schema.map(item=>[item.key,item.defaultValue]));
209
+ const values={};
210
+ for(const definition of this.schema){
211
+ setDataProperty(values,definition.key,definition.defaultValue);
212
+ }
213
+ return frozenPreferenceValues(values);
60
214
  }
61
215
 
62
- storageKey(key){ return `${this.namespace}.${key}`; }
216
+ storageKey(key){return `${this.namespace}.${key}`;}
63
217
 
64
218
  definition(key){
65
- const definition=this.schema.find(item=>item.key===key);
66
- if(!definition) throw new RangeError(`Unknown preference: ${key}`);
219
+ const definition=this.schema.find(function findPreferenceDefinition(item){
220
+ return item.key===key;
221
+ });
222
+ if(!definition){
223
+ throw preferenceStoreError(
224
+ PREFERENCE_STORE_ERROR_CODES.keyUnknown,
225
+ 'preference-key-unknown',
226
+ `Unknown preference: ${key}`,
227
+ RangeError
228
+ );
229
+ }
67
230
  return definition;
68
231
  }
69
232
 
70
- async load(){
71
- const values=this.defaults();
72
- await Promise.all(this.schema.map(async definition=>{
73
- const result=await this.adapter.get(this.storageKey(definition.key));
74
- if(result?.found) values[definition.key]=definition.value(result.value);
75
- }));
76
- this.values=values;
77
- this.emit('load');
78
- return {...values};
233
+ async load(options={}){
234
+ const operation=normalizeOperationOptions(options);
235
+ const operationId=this.#nextOperationId('load');
236
+ const store=this;
237
+ return this.#enqueueOperation(
238
+ async function loadPreferences(){
239
+ const values={};
240
+ for(const definition of store.schema){
241
+ const result=await store.adapter.get(
242
+ store.storageKey(definition.key),
243
+ Object.freeze({operationId,signal:operation.signal})
244
+ );
245
+ store.#assertOperationActive(operation.signal);
246
+ setDataProperty(
247
+ values,
248
+ definition.key,
249
+ result?.found
250
+ ?definition.value(result.value)
251
+ :definition.defaultValue
252
+ );
253
+ }
254
+ store.values=frozenPreferenceValues(values);
255
+ store.#publish(PREFERENCE_STORE_EVENT_TYPES.load,{},operationId);
256
+ return frozenPreferenceValues(store.values);
257
+ },
258
+ operation.signal
259
+ );
79
260
  }
80
261
 
81
- async set(key,value){
262
+ async set(key,value,options={}){
263
+ const operation=normalizeOperationOptions(options);
82
264
  const definition=this.definition(key);
83
265
  const normalized=definition.value(value);
84
- await this.adapter.set(this.storageKey(key),normalized);
85
- this.values={...this.values,[key]:normalized};
86
- this.emit('change',{key,value:normalized});
87
- return normalized;
266
+ const operationId=this.#nextOperationId('set');
267
+ const store=this;
268
+ return this.#enqueueOperation(
269
+ async function setPreference(){
270
+ await store.adapter.set(
271
+ store.storageKey(key),
272
+ normalized,
273
+ Object.freeze({operationId,signal:operation.signal})
274
+ );
275
+ store.#assertOperationActive(operation.signal);
276
+ store.values=frozenPreferenceValues({...store.values,[key]:normalized});
277
+ store.#publish(
278
+ PREFERENCE_STORE_EVENT_TYPES.change,
279
+ {key,value:normalized},
280
+ operationId
281
+ );
282
+ return normalized;
283
+ },
284
+ operation.signal
285
+ );
88
286
  }
89
287
 
90
- async setAll(values={}){
288
+ async setAll(values={},options={}){
289
+ const operation=normalizeOperationOptions(options);
290
+ if(!isPlainRecord(values)){
291
+ throw preferenceStoreError(
292
+ PREFERENCE_STORE_ERROR_CODES.valuesInvalid,
293
+ 'preference-values-invalid',
294
+ 'Preference values must be a plain object.',
295
+ TypeError
296
+ );
297
+ }
91
298
  for(const definition of this.schema){
92
- if(Object.prototype.hasOwnProperty.call(values,definition.key)) await this.set(definition.key,values[definition.key]);
299
+ if(Object.prototype.hasOwnProperty.call(values,definition.key)){
300
+ await this.set(definition.key,values[definition.key],operation);
301
+ }
93
302
  }
94
- return {...this.values};
303
+ this.#assertOperationActive(operation.signal);
304
+ return frozenPreferenceValues(this.values);
95
305
  }
96
306
 
97
- async reset(){
98
- await Promise.all(this.schema.map(definition=>this.adapter.delete(this.storageKey(definition.key))));
99
- this.values=this.defaults();
100
- this.emit('reset');
101
- return {...this.values};
307
+ async reset(options={}){
308
+ const operation=normalizeOperationOptions(options);
309
+ const operationId=this.#nextOperationId('reset');
310
+ const store=this;
311
+ return this.#enqueueOperation(
312
+ async function resetPreferences(){
313
+ for(const definition of store.schema){
314
+ await store.adapter.delete(
315
+ store.storageKey(definition.key),
316
+ Object.freeze({operationId,signal:operation.signal})
317
+ );
318
+ store.#assertOperationActive(operation.signal);
319
+ }
320
+ store.values=store.defaults();
321
+ store.#publish(PREFERENCE_STORE_EVENT_TYPES.reset,{},operationId);
322
+ return frozenPreferenceValues(store.values);
323
+ },
324
+ operation.signal
325
+ );
102
326
  }
103
327
 
104
328
  emit(type,detail={}){
105
- this.dispatchEvent(new CustomEvent(`preference-${type}`,{detail:{values:{...this.values},...detail}}));
329
+ this.#assertOpen();
330
+ if(!isPlainRecord(detail)){
331
+ throw preferenceStoreError(
332
+ PREFERENCE_STORE_ERROR_CODES.eventDetailInvalid,
333
+ 'preference-event-detail-invalid',
334
+ 'Preference event detail must be a plain object.',
335
+ TypeError
336
+ );
337
+ }
338
+ const eventType=PREFERENCE_STORE_EVENT_TYPES[type]??type;
339
+ this.#publish(eventType,detail,this.#nextOperationId('emit'));
340
+ }
341
+
342
+ dispose(){
343
+ if(this.#disposed) return false;
344
+ this.#disposed=true;
345
+ const error=disposedError();
346
+ for(const cancel of [...this.#pendingOperations]) cancel(error);
347
+ return this.#events.dispose();
348
+ }
349
+
350
+ destroy(){return this.dispose();}
351
+
352
+ #assertOpen(){
353
+ if(this.#disposed) throw disposedError();
354
+ }
355
+
356
+ #assertOperationActive(signal){
357
+ this.#assertOpen();
358
+ if(signal?.aborted) throw operationAbortedError(signal.reason);
359
+ }
360
+
361
+ #nextOperationId(action){
362
+ this.#assertOpen();
363
+ this.#operationSequence+=1;
364
+ return `${this.#events.instanceId}:${action}:${this.#operationSequence.toString(36)}`;
365
+ }
366
+
367
+ #publish(type,detail,operationId){
368
+ const values=frozenPreferenceValues(this.values);
369
+ const compatibilityDetail=Object.freeze({
370
+ ...detail,
371
+ namespace:this.namespace,
372
+ values
373
+ });
374
+ const publicDetail=Object.freeze({
375
+ namespace:this.namespace,
376
+ values,
377
+ ...(typeof detail.key==='string'
378
+ ?{preferenceId:detail.key,value:detail.value}
379
+ :{})
380
+ });
381
+ this.#events.dispatch(
382
+ type,
383
+ compatibilityDetail,
384
+ {operationId,publicDetail}
385
+ );
386
+ }
387
+
388
+ #enqueueOperation(operation,signal){
389
+ this.#assertOperationActive(signal);
390
+ const store=this;
391
+ let abortHandler=null;
392
+ let rejectResult;
393
+ let resolveResult;
394
+ let settled=false;
395
+ const result=new Promise(function capturePreferenceOperationSettlement(resolve,reject){
396
+ resolveResult=resolve;
397
+ rejectResult=reject;
398
+ });
399
+ function cleanupPreferenceOperation(){
400
+ signal?.removeEventListener('abort',abortHandler);
401
+ store.#pendingOperations.delete(cancelPreferenceOperation);
402
+ }
403
+ function settlePreferenceOperation(handler,value){
404
+ if(settled) return false;
405
+ settled=true;
406
+ cleanupPreferenceOperation();
407
+ handler(value);
408
+ return true;
409
+ }
410
+ function cancelPreferenceOperation(error){
411
+ return settlePreferenceOperation(rejectResult,error);
412
+ }
413
+ abortHandler=function abortPreferenceOperation(){
414
+ cancelPreferenceOperation(operationAbortedError(signal.reason));
415
+ };
416
+ store.#pendingOperations.add(cancelPreferenceOperation);
417
+ signal?.addEventListener('abort',abortHandler,{once:true});
418
+ if(signal?.aborted) abortHandler();
419
+
420
+ async function runPreferenceOperation(){
421
+ if(settled) return;
422
+ try{
423
+ store.#assertOperationActive(signal);
424
+ const value=await operation();
425
+ store.#assertOperationActive(signal);
426
+ settlePreferenceOperation(resolveResult,value);
427
+ }catch(error){
428
+ settlePreferenceOperation(rejectResult,error);
429
+ }
430
+ }
431
+ const queued=this.#operationTail.then(
432
+ runPreferenceOperation,
433
+ runPreferenceOperation
434
+ );
435
+ this.#operationTail=queued.then(
436
+ function completePreferenceOperationLane(){},
437
+ function recoverPreferenceOperationLane(){}
438
+ );
439
+ return result;
106
440
  }
107
441
  }
108
442