@opengeni/interaction 0.2.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/dist/index.js ADDED
@@ -0,0 +1,571 @@
1
+ // src/index.ts
2
+ import {
3
+ BrowserActionCommand,
4
+ BrowserActionReceipt,
5
+ BrowserObservation,
6
+ BrowserTarget,
7
+ ComputerActionCommand,
8
+ ComputerActionReceipt,
9
+ ComputerObservation,
10
+ ComputerTarget
11
+ } from "@opengeni/contracts";
12
+
13
+ // src/controller-core.ts
14
+ import { createHash } from "crypto";
15
+ var InteractionControllerError = class extends Error {
16
+ constructor(code, message, retryable = false) {
17
+ super(message);
18
+ this.code = code;
19
+ this.retryable = retryable;
20
+ this.name = "InteractionControllerError";
21
+ }
22
+ };
23
+ var InteractionDefiniteDriverError = class extends Error {
24
+ constructor(code, message, retryable = false) {
25
+ super(message);
26
+ this.code = code;
27
+ this.retryable = retryable;
28
+ this.name = "InteractionDefiniteDriverError";
29
+ }
30
+ };
31
+ var terminalStates = /* @__PURE__ */ new Set([
32
+ "completed",
33
+ "failed",
34
+ "outcome_unknown"
35
+ ]);
36
+ var InteractionControllerCore = class {
37
+ driver;
38
+ adapter;
39
+ authority;
40
+ maxJournalEntries;
41
+ now;
42
+ onJournalRecord;
43
+ journal = /* @__PURE__ */ new Map();
44
+ targetTails = /* @__PURE__ */ new Map();
45
+ constructor(options) {
46
+ this.driver = options.driver;
47
+ this.adapter = options.adapter;
48
+ this.authority = options.authority;
49
+ this.maxJournalEntries = options.maxJournalEntries ?? 1e4;
50
+ this.now = options.now ?? (() => /* @__PURE__ */ new Date());
51
+ this.onJournalRecord = options.onJournalRecord;
52
+ if (!Number.isSafeInteger(this.maxJournalEntries) || this.maxJournalEntries < 1) {
53
+ throw new Error("maxJournalEntries must be a positive safe integer");
54
+ }
55
+ for (const record of options.initialJournal ?? []) this.restoreJournalRecord(record);
56
+ }
57
+ async observe(targetId) {
58
+ const target = await this.requireCurrentTarget(targetId);
59
+ const observed = this.adapter.parseObservation(await this.driver.observe(target.id));
60
+ this.adapter.assertObservationAuthority(observed, target.id);
61
+ return observed;
62
+ }
63
+ run(commandInput) {
64
+ const command = this.adapter.parseCommand(commandInput);
65
+ this.adapter.assertCommandAuthority(command);
66
+ const commandDigest = digestJson(command);
67
+ const existing = this.journal.get(command.operationId);
68
+ if (existing) {
69
+ if (existing.commandDigest !== commandDigest) {
70
+ throw new InteractionControllerError(
71
+ "operation_conflict",
72
+ `operation id is already bound to a different ${this.adapter.resourceLabel} command`
73
+ );
74
+ }
75
+ return existing.completion;
76
+ }
77
+ this.makeJournalSpace();
78
+ const prepared = this.makeReceipt(command, "prepared", null, null, null, null);
79
+ const entry = {
80
+ operationId: command.operationId,
81
+ commandDigest,
82
+ receipt: prepared,
83
+ completion: Promise.resolve(prepared),
84
+ preparationPersisted: this.publish(command.operationId, commandDigest, prepared).then(
85
+ () => true,
86
+ () => false
87
+ )
88
+ };
89
+ this.journal.set(command.operationId, entry);
90
+ const previous = this.targetTails.get(command.targetId) ?? Promise.resolve();
91
+ entry.completion = previous.then(async () => await this.execute(entry, command));
92
+ const tail = entry.completion.then(
93
+ () => void 0,
94
+ () => void 0
95
+ );
96
+ this.targetTails.set(command.targetId, tail);
97
+ void tail.finally(() => {
98
+ if (this.targetTails.get(command.targetId) === tail)
99
+ this.targetTails.delete(command.targetId);
100
+ });
101
+ return entry.completion;
102
+ }
103
+ receipt(operationId) {
104
+ return this.journal.get(operationId)?.receipt ?? null;
105
+ }
106
+ journalSnapshot() {
107
+ return [...this.journal.values()].map(({ operationId, commandDigest, receipt }) => ({
108
+ operationId,
109
+ commandDigest,
110
+ receipt
111
+ }));
112
+ }
113
+ /** Wait until every command already admitted to a target queue settles.
114
+ * Callers must fence new dispatch through `authority` before awaiting this. */
115
+ async waitForIdle() {
116
+ while (this.targetTails.size > 0) await Promise.all([...this.targetTails.values()]);
117
+ }
118
+ async execute(entry, command) {
119
+ if (!await entry.preparationPersisted) {
120
+ return await this.failBeforeDispatch(
121
+ entry,
122
+ command,
123
+ `${this.adapter.resourceLabel} operation journal rejected the command before dispatch`
124
+ );
125
+ }
126
+ try {
127
+ await this.authority?.authorizeDispatch(command);
128
+ const target = await this.requireCurrentTarget(command.targetId);
129
+ this.adapter.assertExpectedGenerations(command, target);
130
+ await this.driver.validate?.(command, target);
131
+ } catch (error) {
132
+ return await this.settle(
133
+ entry,
134
+ this.makeReceipt(
135
+ command,
136
+ "failed",
137
+ null,
138
+ this.timestamp(),
139
+ null,
140
+ safePredispatchError(error, this.adapter.resourceLabel)
141
+ )
142
+ );
143
+ }
144
+ const dispatchedAt = this.timestamp();
145
+ const dispatched = this.makeReceipt(command, "dispatched", dispatchedAt, null, null, null);
146
+ try {
147
+ await this.publish(entry.operationId, entry.commandDigest, dispatched);
148
+ entry.receipt = dispatched;
149
+ } catch {
150
+ return await this.failBeforeDispatch(
151
+ entry,
152
+ command,
153
+ `${this.adapter.resourceLabel} operation journal became unavailable before dispatch`
154
+ );
155
+ }
156
+ try {
157
+ const observation = this.adapter.parseObservation(await this.driver.dispatch(command));
158
+ this.adapter.assertObservationAuthority(observation, command.targetId);
159
+ const completed = this.makeReceipt(
160
+ command,
161
+ "completed",
162
+ dispatchedAt,
163
+ this.timestamp(),
164
+ observation,
165
+ null
166
+ );
167
+ try {
168
+ await this.publish(entry.operationId, entry.commandDigest, completed);
169
+ entry.receipt = completed;
170
+ return completed;
171
+ } catch {
172
+ return await this.settle(
173
+ entry,
174
+ this.makeReceipt(command, "outcome_unknown", dispatchedAt, this.timestamp(), null, {
175
+ code: "controller_lost",
176
+ message: `${this.adapter.resourceLabel} command completed but its durable outcome could not be recorded`,
177
+ retryable: false
178
+ })
179
+ );
180
+ }
181
+ } catch (error) {
182
+ if (error instanceof InteractionDefiniteDriverError) {
183
+ return await this.settle(
184
+ entry,
185
+ this.makeReceipt(command, "failed", dispatchedAt, this.timestamp(), null, {
186
+ code: error.code,
187
+ message: error.message,
188
+ retryable: error.retryable
189
+ })
190
+ );
191
+ }
192
+ return await this.settle(
193
+ entry,
194
+ this.makeReceipt(command, "outcome_unknown", dispatchedAt, this.timestamp(), null, {
195
+ code: "controller_lost",
196
+ message: `${this.adapter.resourceLabel} command outcome is unknown after dispatch`,
197
+ retryable: false
198
+ })
199
+ );
200
+ }
201
+ }
202
+ async requireCurrentTarget(targetId) {
203
+ const target = await this.driver.target(targetId);
204
+ if (!target) {
205
+ throw new InteractionControllerError(
206
+ "target_not_found",
207
+ `${this.adapter.resourceLabel} target does not exist`
208
+ );
209
+ }
210
+ const parsed = this.adapter.parseTarget(target);
211
+ this.adapter.assertTargetAuthority(parsed);
212
+ return parsed;
213
+ }
214
+ makeReceipt(command, state, dispatchedAt, settledAt, observation, error) {
215
+ return this.adapter.makeReceipt({
216
+ command,
217
+ state,
218
+ dispatchedAt,
219
+ settledAt,
220
+ observation,
221
+ error
222
+ });
223
+ }
224
+ async settle(entry, receipt) {
225
+ entry.receipt = receipt;
226
+ try {
227
+ await this.publish(entry.operationId, entry.commandDigest, receipt);
228
+ } catch {
229
+ }
230
+ return receipt;
231
+ }
232
+ async failBeforeDispatch(entry, command, message) {
233
+ return await this.settle(
234
+ entry,
235
+ this.makeReceipt(command, "failed", null, this.timestamp(), null, {
236
+ code: "driver_failed",
237
+ message,
238
+ retryable: true
239
+ })
240
+ );
241
+ }
242
+ async publish(operationId, commandDigest, receipt) {
243
+ await this.onJournalRecord?.({ operationId, commandDigest, receipt });
244
+ }
245
+ timestamp() {
246
+ return this.now().toISOString();
247
+ }
248
+ makeJournalSpace() {
249
+ while (this.journal.size >= this.maxJournalEntries) {
250
+ const terminal = [...this.journal.entries()].find(
251
+ ([, entry]) => terminalStates.has(entry.receipt.state)
252
+ );
253
+ if (!terminal) {
254
+ throw new InteractionControllerError(
255
+ "journal_full",
256
+ `${this.adapter.resourceLabel} operation journal has no safely evictable terminal entry`,
257
+ true
258
+ );
259
+ }
260
+ this.journal.delete(terminal[0]);
261
+ }
262
+ }
263
+ restoreJournalRecord(record) {
264
+ if (this.journal.has(record.operationId)) {
265
+ throw new Error(`duplicate restored operation id: ${record.operationId}`);
266
+ }
267
+ const parsed = this.adapter.parseReceipt(record.receipt);
268
+ if (parsed.operationId !== record.operationId) {
269
+ throw new Error(`restored operation ${record.operationId} has another receipt id`);
270
+ }
271
+ const receipt = this.adapter.recoverReceipt(parsed, this.timestamp());
272
+ const entry = {
273
+ operationId: record.operationId,
274
+ commandDigest: record.commandDigest,
275
+ receipt,
276
+ completion: Promise.resolve(receipt),
277
+ preparationPersisted: Promise.resolve(true)
278
+ };
279
+ this.journal.set(record.operationId, entry);
280
+ }
281
+ };
282
+ function recoverInteractionReceipt(receipt, settledAt, resourceLabel, parse) {
283
+ if (terminalStates.has(receipt.state)) return receipt;
284
+ return parse({
285
+ ...receipt,
286
+ state: receipt.state === "dispatched" ? "outcome_unknown" : "failed",
287
+ settledAt,
288
+ observation: null,
289
+ error: receipt.state === "dispatched" ? {
290
+ code: "controller_lost",
291
+ message: `${resourceLabel} controller restarted after command dispatch`,
292
+ retryable: false
293
+ } : {
294
+ code: "controller_lost",
295
+ message: `${resourceLabel} controller restarted before command dispatch`,
296
+ retryable: true
297
+ }
298
+ });
299
+ }
300
+ function safePredispatchError(error, resourceLabel) {
301
+ if (error instanceof InteractionControllerError && error.code !== "journal_full") {
302
+ return {
303
+ code: error.code,
304
+ message: error.message,
305
+ retryable: error.retryable
306
+ };
307
+ }
308
+ return {
309
+ code: "driver_failed",
310
+ message: `${resourceLabel} command failed before dispatch`,
311
+ retryable: false
312
+ };
313
+ }
314
+ function digestJson(value) {
315
+ return createHash("sha256").update(canonicalJson(value), "utf8").digest("hex");
316
+ }
317
+ function canonicalJson(value) {
318
+ return JSON.stringify(canonicalJsonValue(value));
319
+ }
320
+ function canonicalJsonValue(value) {
321
+ if (Array.isArray(value)) return value.map(canonicalJsonValue);
322
+ if (value !== null && typeof value === "object") {
323
+ return Object.fromEntries(
324
+ Object.entries(value).sort(([left], [right]) => left.localeCompare(right)).map(([key, entry]) => [key, canonicalJsonValue(entry)])
325
+ );
326
+ }
327
+ return value;
328
+ }
329
+
330
+ // src/index.ts
331
+ var BrowserInteractionController = class {
332
+ core;
333
+ constructor(options) {
334
+ const { browserSessionId, controllerGeneration } = options;
335
+ this.core = new InteractionControllerCore({
336
+ driver: options.driver,
337
+ ...options.authority ? { authority: options.authority } : {},
338
+ ...options.maxJournalEntries !== void 0 ? { maxJournalEntries: options.maxJournalEntries } : {},
339
+ ...options.now ? { now: options.now } : {},
340
+ ...options.initialJournal ? { initialJournal: options.initialJournal } : {},
341
+ ...options.onJournalRecord ? { onJournalRecord: options.onJournalRecord } : {},
342
+ adapter: {
343
+ resourceLabel: "browser",
344
+ parseCommand: (value) => BrowserActionCommand.parse(value),
345
+ parseTarget: (value) => BrowserTarget.parse(value),
346
+ parseObservation: (value) => BrowserObservation.parse(value),
347
+ parseReceipt: (value) => BrowserActionReceipt.parse(value),
348
+ assertCommandAuthority(command) {
349
+ if (command.browserSessionId !== browserSessionId) {
350
+ throw new InteractionControllerError(
351
+ "resource_not_found",
352
+ "browser command targets another browser session"
353
+ );
354
+ }
355
+ if (command.controllerGeneration !== controllerGeneration) {
356
+ throw new InteractionControllerError(
357
+ "controller_stale",
358
+ "browser command targets a stale controller generation"
359
+ );
360
+ }
361
+ },
362
+ assertTargetAuthority(target) {
363
+ if (target.browserSessionId !== browserSessionId || target.controllerGeneration !== controllerGeneration) {
364
+ throw new InteractionControllerError(
365
+ "controller_stale",
366
+ "browser target belongs to a stale controller generation"
367
+ );
368
+ }
369
+ },
370
+ assertExpectedGenerations(command, target) {
371
+ if (command.expectedTargetGeneration !== target.targetGeneration) {
372
+ throw new InteractionControllerError(
373
+ "target_stale",
374
+ "browser target changed before the command could dispatch"
375
+ );
376
+ }
377
+ if (command.expectedDocumentGeneration !== target.documentGeneration) {
378
+ throw new InteractionControllerError(
379
+ "document_stale",
380
+ "browser document changed before the command could dispatch"
381
+ );
382
+ }
383
+ },
384
+ assertObservationAuthority(observation, targetId) {
385
+ if (observation.browserSessionId !== browserSessionId || observation.target.id !== targetId || observation.target.browserSessionId !== browserSessionId || observation.target.controllerGeneration !== controllerGeneration) {
386
+ throw new InteractionControllerError(
387
+ "driver_failed",
388
+ "browser driver returned an observation outside controller authority"
389
+ );
390
+ }
391
+ },
392
+ makeReceipt(input) {
393
+ return BrowserActionReceipt.parse({
394
+ protocolVersion: 1,
395
+ operationId: input.command.operationId,
396
+ browserSessionId,
397
+ controllerGeneration,
398
+ targetId: input.command.targetId,
399
+ state: input.state,
400
+ dispatchedAt: input.dispatchedAt,
401
+ settledAt: input.settledAt,
402
+ observation: input.observation,
403
+ error: input.error
404
+ });
405
+ },
406
+ recoverReceipt(receipt, settledAt) {
407
+ if (receipt.browserSessionId !== browserSessionId || receipt.controllerGeneration !== controllerGeneration) {
408
+ throw new Error(
409
+ `restored operation ${receipt.operationId} is outside controller authority`
410
+ );
411
+ }
412
+ return recoverInteractionReceipt(
413
+ receipt,
414
+ settledAt,
415
+ "browser",
416
+ (value) => BrowserActionReceipt.parse(value)
417
+ );
418
+ }
419
+ }
420
+ });
421
+ }
422
+ observe(targetId) {
423
+ return this.core.observe(targetId);
424
+ }
425
+ run(command) {
426
+ return this.core.run(command);
427
+ }
428
+ receipt(operationId) {
429
+ return this.core.receipt(operationId);
430
+ }
431
+ journalSnapshot() {
432
+ return this.core.journalSnapshot();
433
+ }
434
+ waitForIdle() {
435
+ return this.core.waitForIdle();
436
+ }
437
+ };
438
+ function recoverBrowserOperationJournalRecord(record, settledAt) {
439
+ const receipt = BrowserActionReceipt.parse(record.receipt);
440
+ return {
441
+ ...record,
442
+ receipt: recoverInteractionReceipt(
443
+ receipt,
444
+ settledAt,
445
+ "browser",
446
+ (value) => BrowserActionReceipt.parse(value)
447
+ )
448
+ };
449
+ }
450
+ var ComputerInteractionController = class {
451
+ core;
452
+ constructor(options) {
453
+ const { computerSessionId, controllerGeneration } = options;
454
+ this.core = new InteractionControllerCore({
455
+ driver: options.driver,
456
+ ...options.authority ? { authority: options.authority } : {},
457
+ ...options.maxJournalEntries !== void 0 ? { maxJournalEntries: options.maxJournalEntries } : {},
458
+ ...options.now ? { now: options.now } : {},
459
+ ...options.initialJournal ? { initialJournal: options.initialJournal } : {},
460
+ ...options.onJournalRecord ? { onJournalRecord: options.onJournalRecord } : {},
461
+ adapter: {
462
+ resourceLabel: "computer",
463
+ parseCommand: (value) => ComputerActionCommand.parse(value),
464
+ parseTarget: (value) => ComputerTarget.parse(value),
465
+ parseObservation: (value) => ComputerObservation.parse(value),
466
+ parseReceipt: (value) => ComputerActionReceipt.parse(value),
467
+ assertCommandAuthority(command) {
468
+ if (command.computerSessionId !== computerSessionId) {
469
+ throw new InteractionControllerError(
470
+ "resource_not_found",
471
+ "computer command targets another computer session"
472
+ );
473
+ }
474
+ if (command.controllerGeneration !== controllerGeneration) {
475
+ throw new InteractionControllerError(
476
+ "controller_stale",
477
+ "computer command targets a stale controller generation"
478
+ );
479
+ }
480
+ },
481
+ assertTargetAuthority(target) {
482
+ if (target.computerSessionId !== computerSessionId || target.controllerGeneration !== controllerGeneration) {
483
+ throw new InteractionControllerError(
484
+ "controller_stale",
485
+ "computer target belongs to a stale controller generation"
486
+ );
487
+ }
488
+ },
489
+ assertExpectedGenerations(command, target) {
490
+ if (command.expectedTargetGeneration !== target.targetGeneration) {
491
+ throw new InteractionControllerError(
492
+ "target_stale",
493
+ "computer target changed before the command could dispatch"
494
+ );
495
+ }
496
+ },
497
+ assertObservationAuthority(observation, targetId) {
498
+ if (observation.computerSessionId !== computerSessionId || observation.target.id !== targetId || observation.target.computerSessionId !== computerSessionId || observation.target.controllerGeneration !== controllerGeneration) {
499
+ throw new InteractionControllerError(
500
+ "driver_failed",
501
+ "computer driver returned an observation outside controller authority"
502
+ );
503
+ }
504
+ },
505
+ makeReceipt(input) {
506
+ return ComputerActionReceipt.parse({
507
+ protocolVersion: 1,
508
+ operationId: input.command.operationId,
509
+ computerSessionId,
510
+ controllerGeneration,
511
+ targetId: input.command.targetId,
512
+ state: input.state,
513
+ dispatchedAt: input.dispatchedAt,
514
+ settledAt: input.settledAt,
515
+ observation: input.observation,
516
+ error: input.error
517
+ });
518
+ },
519
+ recoverReceipt(receipt, settledAt) {
520
+ if (receipt.computerSessionId !== computerSessionId || receipt.controllerGeneration !== controllerGeneration) {
521
+ throw new Error(
522
+ `restored operation ${receipt.operationId} is outside controller authority`
523
+ );
524
+ }
525
+ return recoverInteractionReceipt(
526
+ receipt,
527
+ settledAt,
528
+ "computer",
529
+ (value) => ComputerActionReceipt.parse(value)
530
+ );
531
+ }
532
+ }
533
+ });
534
+ }
535
+ observe(targetId) {
536
+ return this.core.observe(targetId);
537
+ }
538
+ run(command) {
539
+ return this.core.run(command);
540
+ }
541
+ receipt(operationId) {
542
+ return this.core.receipt(operationId);
543
+ }
544
+ journalSnapshot() {
545
+ return this.core.journalSnapshot();
546
+ }
547
+ waitForIdle() {
548
+ return this.core.waitForIdle();
549
+ }
550
+ };
551
+ function recoverComputerOperationJournalRecord(record, settledAt) {
552
+ const receipt = ComputerActionReceipt.parse(record.receipt);
553
+ return {
554
+ ...record,
555
+ receipt: recoverInteractionReceipt(
556
+ receipt,
557
+ settledAt,
558
+ "computer",
559
+ (value) => ComputerActionReceipt.parse(value)
560
+ )
561
+ };
562
+ }
563
+ export {
564
+ BrowserInteractionController,
565
+ ComputerInteractionController,
566
+ InteractionControllerError,
567
+ InteractionDefiniteDriverError,
568
+ recoverBrowserOperationJournalRecord,
569
+ recoverComputerOperationJournalRecord
570
+ };
571
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/index.ts","../src/controller-core.ts"],"sourcesContent":["import {\n BrowserActionCommand,\n BrowserActionReceipt,\n BrowserObservation,\n BrowserTarget,\n ComputerActionCommand,\n ComputerActionReceipt,\n ComputerObservation,\n ComputerTarget,\n type BrowserActionCommand as BrowserActionCommandValue,\n type BrowserActionReceipt as BrowserActionReceiptValue,\n type BrowserObservation as BrowserObservationValue,\n type BrowserTarget as BrowserTargetValue,\n type ComputerActionCommand as ComputerActionCommandValue,\n type ComputerActionReceipt as ComputerActionReceiptValue,\n type ComputerObservation as ComputerObservationValue,\n type ComputerTarget as ComputerTargetValue,\n} from \"@opengeni/contracts\";\nimport {\n InteractionControllerCore,\n InteractionControllerError,\n InteractionDefiniteDriverError,\n recoverInteractionReceipt,\n type InteractionControllerErrorCode,\n type InteractionOperationJournalRecord,\n} from \"./controller-core\";\n\nexport {\n InteractionControllerError,\n InteractionDefiniteDriverError,\n type InteractionControllerErrorCode,\n};\n\nexport type BrowserInteractionDriver = {\n target(targetId: string): Promise<BrowserTargetValue | null>;\n observe(targetId: string): Promise<BrowserObservationValue>;\n validate?(command: BrowserActionCommandValue, target: BrowserTargetValue): Promise<void> | void;\n dispatch(command: BrowserActionCommandValue): Promise<BrowserObservationValue>;\n};\n\nexport type BrowserInteractionAuthority = {\n authorizeDispatch(command: BrowserActionCommandValue): Promise<void> | void;\n};\n\nexport type BrowserOperationJournalRecord =\n InteractionOperationJournalRecord<BrowserActionReceiptValue>;\n\nexport type BrowserInteractionControllerOptions = {\n browserSessionId: string;\n controllerGeneration: string;\n driver: BrowserInteractionDriver;\n authority?: BrowserInteractionAuthority;\n maxJournalEntries?: number;\n now?: () => Date;\n initialJournal?: readonly BrowserOperationJournalRecord[];\n onJournalRecord?: (record: BrowserOperationJournalRecord) => Promise<void> | void;\n};\n\n/** Placement-resident BrowserSession mutation authority. */\nexport class BrowserInteractionController {\n private readonly core: InteractionControllerCore<\n BrowserActionCommandValue,\n BrowserTargetValue,\n BrowserObservationValue,\n BrowserActionReceiptValue\n >;\n\n constructor(options: BrowserInteractionControllerOptions) {\n const { browserSessionId, controllerGeneration } = options;\n this.core = new InteractionControllerCore({\n driver: options.driver,\n ...(options.authority ? { authority: options.authority } : {}),\n ...(options.maxJournalEntries !== undefined\n ? { maxJournalEntries: options.maxJournalEntries }\n : {}),\n ...(options.now ? { now: options.now } : {}),\n ...(options.initialJournal ? { initialJournal: options.initialJournal } : {}),\n ...(options.onJournalRecord ? { onJournalRecord: options.onJournalRecord } : {}),\n adapter: {\n resourceLabel: \"browser\",\n parseCommand: (value) => BrowserActionCommand.parse(value),\n parseTarget: (value) => BrowserTarget.parse(value),\n parseObservation: (value) => BrowserObservation.parse(value),\n parseReceipt: (value) => BrowserActionReceipt.parse(value),\n assertCommandAuthority(command) {\n if (command.browserSessionId !== browserSessionId) {\n throw new InteractionControllerError(\n \"resource_not_found\",\n \"browser command targets another browser session\",\n );\n }\n if (command.controllerGeneration !== controllerGeneration) {\n throw new InteractionControllerError(\n \"controller_stale\",\n \"browser command targets a stale controller generation\",\n );\n }\n },\n assertTargetAuthority(target) {\n if (\n target.browserSessionId !== browserSessionId ||\n target.controllerGeneration !== controllerGeneration\n ) {\n throw new InteractionControllerError(\n \"controller_stale\",\n \"browser target belongs to a stale controller generation\",\n );\n }\n },\n assertExpectedGenerations(command, target) {\n if (command.expectedTargetGeneration !== target.targetGeneration) {\n throw new InteractionControllerError(\n \"target_stale\",\n \"browser target changed before the command could dispatch\",\n );\n }\n if (command.expectedDocumentGeneration !== target.documentGeneration) {\n throw new InteractionControllerError(\n \"document_stale\",\n \"browser document changed before the command could dispatch\",\n );\n }\n },\n assertObservationAuthority(observation, targetId) {\n if (\n observation.browserSessionId !== browserSessionId ||\n observation.target.id !== targetId ||\n observation.target.browserSessionId !== browserSessionId ||\n observation.target.controllerGeneration !== controllerGeneration\n ) {\n throw new InteractionControllerError(\n \"driver_failed\",\n \"browser driver returned an observation outside controller authority\",\n );\n }\n },\n makeReceipt(input) {\n return BrowserActionReceipt.parse({\n protocolVersion: 1,\n operationId: input.command.operationId,\n browserSessionId,\n controllerGeneration,\n targetId: input.command.targetId,\n state: input.state,\n dispatchedAt: input.dispatchedAt,\n settledAt: input.settledAt,\n observation: input.observation,\n error: input.error,\n });\n },\n recoverReceipt(receipt, settledAt) {\n if (\n receipt.browserSessionId !== browserSessionId ||\n receipt.controllerGeneration !== controllerGeneration\n ) {\n throw new Error(\n `restored operation ${receipt.operationId} is outside controller authority`,\n );\n }\n return recoverInteractionReceipt(receipt, settledAt, \"browser\", (value) =>\n BrowserActionReceipt.parse(value),\n );\n },\n },\n });\n }\n\n observe(targetId: string): Promise<BrowserObservationValue> {\n return this.core.observe(targetId);\n }\n\n run(command: BrowserActionCommandValue): Promise<BrowserActionReceiptValue> {\n return this.core.run(command);\n }\n\n receipt(operationId: string): BrowserActionReceiptValue | null {\n return this.core.receipt(operationId);\n }\n\n journalSnapshot(): BrowserOperationJournalRecord[] {\n return this.core.journalSnapshot();\n }\n\n waitForIdle(): Promise<void> {\n return this.core.waitForIdle();\n }\n}\n\nexport function recoverBrowserOperationJournalRecord(\n record: BrowserOperationJournalRecord,\n settledAt: string,\n): BrowserOperationJournalRecord {\n const receipt = BrowserActionReceipt.parse(record.receipt);\n return {\n ...record,\n receipt: recoverInteractionReceipt(receipt, settledAt, \"browser\", (value) =>\n BrowserActionReceipt.parse(value),\n ),\n };\n}\n\nexport type ComputerInteractionDriver = {\n target(targetId: string): Promise<ComputerTargetValue | null>;\n observe(targetId: string): Promise<ComputerObservationValue>;\n validate?(command: ComputerActionCommandValue, target: ComputerTargetValue): Promise<void> | void;\n dispatch(command: ComputerActionCommandValue): Promise<ComputerObservationValue>;\n};\n\nexport type ComputerInteractionAuthority = {\n authorizeDispatch(command: ComputerActionCommandValue): Promise<void> | void;\n};\n\nexport type ComputerOperationJournalRecord =\n InteractionOperationJournalRecord<ComputerActionReceiptValue>;\n\nexport type ComputerInteractionControllerOptions = {\n computerSessionId: string;\n controllerGeneration: string;\n driver: ComputerInteractionDriver;\n authority?: ComputerInteractionAuthority;\n maxJournalEntries?: number;\n now?: () => Date;\n initialJournal?: readonly ComputerOperationJournalRecord[];\n onJournalRecord?: (record: ComputerOperationJournalRecord) => Promise<void> | void;\n};\n\n/** Placement-resident ComputerSession mutation authority. Linux AT-SPI/X11,\n * macOS AX/ScreenCaptureKit, and later UIA adapters share this exact core. */\nexport class ComputerInteractionController {\n private readonly core: InteractionControllerCore<\n ComputerActionCommandValue,\n ComputerTargetValue,\n ComputerObservationValue,\n ComputerActionReceiptValue\n >;\n\n constructor(options: ComputerInteractionControllerOptions) {\n const { computerSessionId, controllerGeneration } = options;\n this.core = new InteractionControllerCore({\n driver: options.driver,\n ...(options.authority ? { authority: options.authority } : {}),\n ...(options.maxJournalEntries !== undefined\n ? { maxJournalEntries: options.maxJournalEntries }\n : {}),\n ...(options.now ? { now: options.now } : {}),\n ...(options.initialJournal ? { initialJournal: options.initialJournal } : {}),\n ...(options.onJournalRecord ? { onJournalRecord: options.onJournalRecord } : {}),\n adapter: {\n resourceLabel: \"computer\",\n parseCommand: (value) => ComputerActionCommand.parse(value),\n parseTarget: (value) => ComputerTarget.parse(value),\n parseObservation: (value) => ComputerObservation.parse(value),\n parseReceipt: (value) => ComputerActionReceipt.parse(value),\n assertCommandAuthority(command) {\n if (command.computerSessionId !== computerSessionId) {\n throw new InteractionControllerError(\n \"resource_not_found\",\n \"computer command targets another computer session\",\n );\n }\n if (command.controllerGeneration !== controllerGeneration) {\n throw new InteractionControllerError(\n \"controller_stale\",\n \"computer command targets a stale controller generation\",\n );\n }\n },\n assertTargetAuthority(target) {\n if (\n target.computerSessionId !== computerSessionId ||\n target.controllerGeneration !== controllerGeneration\n ) {\n throw new InteractionControllerError(\n \"controller_stale\",\n \"computer target belongs to a stale controller generation\",\n );\n }\n },\n assertExpectedGenerations(command, target) {\n if (command.expectedTargetGeneration !== target.targetGeneration) {\n throw new InteractionControllerError(\n \"target_stale\",\n \"computer target changed before the command could dispatch\",\n );\n }\n },\n assertObservationAuthority(observation, targetId) {\n if (\n observation.computerSessionId !== computerSessionId ||\n observation.target.id !== targetId ||\n observation.target.computerSessionId !== computerSessionId ||\n observation.target.controllerGeneration !== controllerGeneration\n ) {\n throw new InteractionControllerError(\n \"driver_failed\",\n \"computer driver returned an observation outside controller authority\",\n );\n }\n },\n makeReceipt(input) {\n return ComputerActionReceipt.parse({\n protocolVersion: 1,\n operationId: input.command.operationId,\n computerSessionId,\n controllerGeneration,\n targetId: input.command.targetId,\n state: input.state,\n dispatchedAt: input.dispatchedAt,\n settledAt: input.settledAt,\n observation: input.observation,\n error: input.error,\n });\n },\n recoverReceipt(receipt, settledAt) {\n if (\n receipt.computerSessionId !== computerSessionId ||\n receipt.controllerGeneration !== controllerGeneration\n ) {\n throw new Error(\n `restored operation ${receipt.operationId} is outside controller authority`,\n );\n }\n return recoverInteractionReceipt(receipt, settledAt, \"computer\", (value) =>\n ComputerActionReceipt.parse(value),\n );\n },\n },\n });\n }\n\n observe(targetId: string): Promise<ComputerObservationValue> {\n return this.core.observe(targetId);\n }\n\n run(command: ComputerActionCommandValue): Promise<ComputerActionReceiptValue> {\n return this.core.run(command);\n }\n\n receipt(operationId: string): ComputerActionReceiptValue | null {\n return this.core.receipt(operationId);\n }\n\n journalSnapshot(): ComputerOperationJournalRecord[] {\n return this.core.journalSnapshot();\n }\n\n waitForIdle(): Promise<void> {\n return this.core.waitForIdle();\n }\n}\n\nexport function recoverComputerOperationJournalRecord(\n record: ComputerOperationJournalRecord,\n settledAt: string,\n): ComputerOperationJournalRecord {\n const receipt = ComputerActionReceipt.parse(record.receipt);\n return {\n ...record,\n receipt: recoverInteractionReceipt(receipt, settledAt, \"computer\", (value) =>\n ComputerActionReceipt.parse(value),\n ),\n };\n}\n","import { createHash } from \"node:crypto\";\nimport type { InteractionError, InteractionOperationState } from \"@opengeni/contracts\";\n\nexport type InteractionControllerErrorCode = InteractionError[\"code\"] | \"journal_full\";\n\n/** A safe, typed rejection known not to have dispatched a side effect. */\nexport class InteractionControllerError extends Error {\n constructor(\n readonly code: InteractionControllerErrorCode,\n message: string,\n readonly retryable = false,\n ) {\n super(message);\n this.name = \"InteractionControllerError\";\n }\n}\n\n/** Driver proof that a dispatched command definitively failed without an ambiguous outcome. */\nexport class InteractionDefiniteDriverError extends Error {\n constructor(\n readonly code: InteractionError[\"code\"],\n message: string,\n readonly retryable = false,\n ) {\n super(message);\n this.name = \"InteractionDefiniteDriverError\";\n }\n}\n\nexport type InteractionCoreCommand = {\n operationId: string;\n controllerGeneration: string;\n targetId: string;\n};\n\nexport type InteractionCoreTarget = {\n id: string;\n controllerGeneration: string;\n};\n\nexport type InteractionCoreObservation<TTarget extends InteractionCoreTarget> = {\n target: TTarget;\n};\n\nexport type InteractionCoreReceipt<TObservation> = {\n operationId: string;\n controllerGeneration: string;\n targetId: string;\n state: InteractionOperationState;\n dispatchedAt: string | null;\n settledAt: string | null;\n observation: TObservation | null;\n error: InteractionError | null;\n};\n\nexport type InteractionOperationJournalRecord<TReceipt> = {\n operationId: string;\n commandDigest: string;\n receipt: TReceipt;\n};\n\ntype InteractionDriver<\n TCommand extends InteractionCoreCommand,\n TTarget extends InteractionCoreTarget,\n TObservation extends InteractionCoreObservation<TTarget>,\n> = {\n target(targetId: string): Promise<TTarget | null>;\n observe(targetId: string): Promise<TObservation>;\n validate?(command: TCommand, target: TTarget): Promise<void> | void;\n dispatch(command: TCommand): Promise<TObservation>;\n};\n\ntype InteractionCoreAdapter<\n TCommand extends InteractionCoreCommand,\n TTarget extends InteractionCoreTarget,\n TObservation extends InteractionCoreObservation<TTarget>,\n TReceipt extends InteractionCoreReceipt<TObservation>,\n> = {\n resourceLabel: string;\n parseCommand(value: unknown): TCommand;\n parseTarget(value: unknown): TTarget;\n parseObservation(value: unknown): TObservation;\n parseReceipt(value: unknown): TReceipt;\n assertCommandAuthority(command: TCommand): void;\n assertTargetAuthority(target: TTarget): void;\n assertExpectedGenerations(command: TCommand, target: TTarget): void;\n assertObservationAuthority(observation: TObservation, targetId: string): void;\n makeReceipt(input: {\n command: TCommand;\n state: InteractionOperationState;\n dispatchedAt: string | null;\n settledAt: string | null;\n observation: TObservation | null;\n error: InteractionError | null;\n }): TReceipt;\n recoverReceipt(receipt: TReceipt, settledAt: string): TReceipt;\n};\n\ntype InteractionCoreAuthority<TCommand> = {\n authorizeDispatch(command: TCommand): Promise<void> | void;\n};\n\nexport type InteractionControllerCoreOptions<\n TCommand extends InteractionCoreCommand,\n TTarget extends InteractionCoreTarget,\n TObservation extends InteractionCoreObservation<TTarget>,\n TReceipt extends InteractionCoreReceipt<TObservation>,\n> = {\n driver: InteractionDriver<TCommand, TTarget, TObservation>;\n adapter: InteractionCoreAdapter<TCommand, TTarget, TObservation, TReceipt>;\n authority?: InteractionCoreAuthority<TCommand>;\n maxJournalEntries?: number;\n now?: () => Date;\n initialJournal?: readonly InteractionOperationJournalRecord<TReceipt>[];\n onJournalRecord?: (record: InteractionOperationJournalRecord<TReceipt>) => Promise<void> | void;\n};\n\ntype JournalEntry<TReceipt> = InteractionOperationJournalRecord<TReceipt> & {\n completion: Promise<TReceipt>;\n preparationPersisted: Promise<boolean>;\n};\n\nconst terminalStates = new Set<InteractionOperationState>([\n \"completed\",\n \"failed\",\n \"outcome_unknown\",\n]);\n\n/**\n * Resource-neutral placement mutation authority. Public Browser and Computer\n * controllers supply only their schemas and generation semantics; journaling,\n * idempotency, target-local serialization, and crash policy stay identical.\n */\nexport class InteractionControllerCore<\n TCommand extends InteractionCoreCommand,\n TTarget extends InteractionCoreTarget,\n TObservation extends InteractionCoreObservation<TTarget>,\n TReceipt extends InteractionCoreReceipt<TObservation>,\n> {\n private readonly driver: InteractionDriver<TCommand, TTarget, TObservation>;\n private readonly adapter: InteractionCoreAdapter<TCommand, TTarget, TObservation, TReceipt>;\n private readonly authority: InteractionCoreAuthority<TCommand> | undefined;\n private readonly maxJournalEntries: number;\n private readonly now: () => Date;\n private readonly onJournalRecord:\n | ((record: InteractionOperationJournalRecord<TReceipt>) => Promise<void> | void)\n | undefined;\n private readonly journal = new Map<string, JournalEntry<TReceipt>>();\n private readonly targetTails = new Map<string, Promise<void>>();\n\n constructor(\n options: InteractionControllerCoreOptions<TCommand, TTarget, TObservation, TReceipt>,\n ) {\n this.driver = options.driver;\n this.adapter = options.adapter;\n this.authority = options.authority;\n this.maxJournalEntries = options.maxJournalEntries ?? 10_000;\n this.now = options.now ?? (() => new Date());\n this.onJournalRecord = options.onJournalRecord;\n if (!Number.isSafeInteger(this.maxJournalEntries) || this.maxJournalEntries < 1) {\n throw new Error(\"maxJournalEntries must be a positive safe integer\");\n }\n for (const record of options.initialJournal ?? []) this.restoreJournalRecord(record);\n }\n\n async observe(targetId: string): Promise<TObservation> {\n const target = await this.requireCurrentTarget(targetId);\n const observed = this.adapter.parseObservation(await this.driver.observe(target.id));\n this.adapter.assertObservationAuthority(observed, target.id);\n return observed;\n }\n\n run(commandInput: TCommand): Promise<TReceipt> {\n const command = this.adapter.parseCommand(commandInput);\n this.adapter.assertCommandAuthority(command);\n const commandDigest = digestJson(command);\n const existing = this.journal.get(command.operationId);\n if (existing) {\n if (existing.commandDigest !== commandDigest) {\n throw new InteractionControllerError(\n \"operation_conflict\",\n `operation id is already bound to a different ${this.adapter.resourceLabel} command`,\n );\n }\n return existing.completion;\n }\n\n this.makeJournalSpace();\n const prepared = this.makeReceipt(command, \"prepared\", null, null, null, null);\n const entry: JournalEntry<TReceipt> = {\n operationId: command.operationId,\n commandDigest,\n receipt: prepared,\n completion: Promise.resolve(prepared),\n preparationPersisted: this.publish(command.operationId, commandDigest, prepared).then(\n () => true,\n () => false,\n ),\n };\n this.journal.set(command.operationId, entry);\n\n const previous = this.targetTails.get(command.targetId) ?? Promise.resolve();\n entry.completion = previous.then(async () => await this.execute(entry, command));\n const tail = entry.completion.then(\n () => undefined,\n () => undefined,\n );\n this.targetTails.set(command.targetId, tail);\n void tail.finally(() => {\n if (this.targetTails.get(command.targetId) === tail)\n this.targetTails.delete(command.targetId);\n });\n return entry.completion;\n }\n\n receipt(operationId: string): TReceipt | null {\n return this.journal.get(operationId)?.receipt ?? null;\n }\n\n journalSnapshot(): InteractionOperationJournalRecord<TReceipt>[] {\n return [...this.journal.values()].map(({ operationId, commandDigest, receipt }) => ({\n operationId,\n commandDigest,\n receipt,\n }));\n }\n\n /** Wait until every command already admitted to a target queue settles.\n * Callers must fence new dispatch through `authority` before awaiting this. */\n async waitForIdle(): Promise<void> {\n while (this.targetTails.size > 0) await Promise.all([...this.targetTails.values()]);\n }\n\n private async execute(entry: JournalEntry<TReceipt>, command: TCommand): Promise<TReceipt> {\n if (!(await entry.preparationPersisted)) {\n return await this.failBeforeDispatch(\n entry,\n command,\n `${this.adapter.resourceLabel} operation journal rejected the command before dispatch`,\n );\n }\n\n try {\n await this.authority?.authorizeDispatch(command);\n const target = await this.requireCurrentTarget(command.targetId);\n this.adapter.assertExpectedGenerations(command, target);\n await this.driver.validate?.(command, target);\n } catch (error) {\n return await this.settle(\n entry,\n this.makeReceipt(\n command,\n \"failed\",\n null,\n this.timestamp(),\n null,\n safePredispatchError(error, this.adapter.resourceLabel),\n ),\n );\n }\n\n const dispatchedAt = this.timestamp();\n const dispatched = this.makeReceipt(command, \"dispatched\", dispatchedAt, null, null, null);\n try {\n await this.publish(entry.operationId, entry.commandDigest, dispatched);\n entry.receipt = dispatched;\n } catch {\n return await this.failBeforeDispatch(\n entry,\n command,\n `${this.adapter.resourceLabel} operation journal became unavailable before dispatch`,\n );\n }\n\n try {\n const observation = this.adapter.parseObservation(await this.driver.dispatch(command));\n this.adapter.assertObservationAuthority(observation, command.targetId);\n const completed = this.makeReceipt(\n command,\n \"completed\",\n dispatchedAt,\n this.timestamp(),\n observation,\n null,\n );\n try {\n await this.publish(entry.operationId, entry.commandDigest, completed);\n entry.receipt = completed;\n return completed;\n } catch {\n return await this.settle(\n entry,\n this.makeReceipt(command, \"outcome_unknown\", dispatchedAt, this.timestamp(), null, {\n code: \"controller_lost\",\n message: `${this.adapter.resourceLabel} command completed but its durable outcome could not be recorded`,\n retryable: false,\n }),\n );\n }\n } catch (error) {\n if (error instanceof InteractionDefiniteDriverError) {\n return await this.settle(\n entry,\n this.makeReceipt(command, \"failed\", dispatchedAt, this.timestamp(), null, {\n code: error.code,\n message: error.message,\n retryable: error.retryable,\n }),\n );\n }\n return await this.settle(\n entry,\n this.makeReceipt(command, \"outcome_unknown\", dispatchedAt, this.timestamp(), null, {\n code: \"controller_lost\",\n message: `${this.adapter.resourceLabel} command outcome is unknown after dispatch`,\n retryable: false,\n }),\n );\n }\n }\n\n private async requireCurrentTarget(targetId: string): Promise<TTarget> {\n const target = await this.driver.target(targetId);\n if (!target) {\n throw new InteractionControllerError(\n \"target_not_found\",\n `${this.adapter.resourceLabel} target does not exist`,\n );\n }\n const parsed = this.adapter.parseTarget(target);\n this.adapter.assertTargetAuthority(parsed);\n return parsed;\n }\n\n private makeReceipt(\n command: TCommand,\n state: InteractionOperationState,\n dispatchedAt: string | null,\n settledAt: string | null,\n observation: TObservation | null,\n error: InteractionError | null,\n ): TReceipt {\n return this.adapter.makeReceipt({\n command,\n state,\n dispatchedAt,\n settledAt,\n observation,\n error,\n });\n }\n\n private async settle(entry: JournalEntry<TReceipt>, receipt: TReceipt): Promise<TReceipt> {\n entry.receipt = receipt;\n try {\n await this.publish(entry.operationId, entry.commandDigest, receipt);\n } catch {\n // Controller-lifetime terminal truth remains authoritative. A restored\n // dispatched receipt is always recovered as outcome_unknown, never replayed.\n }\n return receipt;\n }\n\n private async failBeforeDispatch(\n entry: JournalEntry<TReceipt>,\n command: TCommand,\n message: string,\n ): Promise<TReceipt> {\n return await this.settle(\n entry,\n this.makeReceipt(command, \"failed\", null, this.timestamp(), null, {\n code: \"driver_failed\",\n message,\n retryable: true,\n }),\n );\n }\n\n private async publish(\n operationId: string,\n commandDigest: string,\n receipt: TReceipt,\n ): Promise<void> {\n await this.onJournalRecord?.({ operationId, commandDigest, receipt });\n }\n\n private timestamp(): string {\n return this.now().toISOString();\n }\n\n private makeJournalSpace(): void {\n while (this.journal.size >= this.maxJournalEntries) {\n const terminal = [...this.journal.entries()].find(([, entry]) =>\n terminalStates.has(entry.receipt.state),\n );\n if (!terminal) {\n throw new InteractionControllerError(\n \"journal_full\",\n `${this.adapter.resourceLabel} operation journal has no safely evictable terminal entry`,\n true,\n );\n }\n this.journal.delete(terminal[0]);\n }\n }\n\n private restoreJournalRecord(record: InteractionOperationJournalRecord<TReceipt>): void {\n if (this.journal.has(record.operationId)) {\n throw new Error(`duplicate restored operation id: ${record.operationId}`);\n }\n const parsed = this.adapter.parseReceipt(record.receipt);\n if (parsed.operationId !== record.operationId) {\n throw new Error(`restored operation ${record.operationId} has another receipt id`);\n }\n const receipt = this.adapter.recoverReceipt(parsed, this.timestamp());\n const entry: JournalEntry<TReceipt> = {\n operationId: record.operationId,\n commandDigest: record.commandDigest,\n receipt,\n completion: Promise.resolve(receipt),\n preparationPersisted: Promise.resolve(true),\n };\n this.journal.set(record.operationId, entry);\n }\n}\n\nexport function recoverInteractionReceipt<TReceipt extends InteractionCoreReceipt<unknown>>(\n receipt: TReceipt,\n settledAt: string,\n resourceLabel: string,\n parse: (value: unknown) => TReceipt,\n): TReceipt {\n if (terminalStates.has(receipt.state)) return receipt;\n return parse({\n ...receipt,\n state: receipt.state === \"dispatched\" ? \"outcome_unknown\" : \"failed\",\n settledAt,\n observation: null,\n error:\n receipt.state === \"dispatched\"\n ? {\n code: \"controller_lost\",\n message: `${resourceLabel} controller restarted after command dispatch`,\n retryable: false,\n }\n : {\n code: \"controller_lost\",\n message: `${resourceLabel} controller restarted before command dispatch`,\n retryable: true,\n },\n });\n}\n\nfunction safePredispatchError(error: unknown, resourceLabel: string): InteractionError {\n if (error instanceof InteractionControllerError && error.code !== \"journal_full\") {\n return {\n code: error.code,\n message: error.message,\n retryable: error.retryable,\n };\n }\n return {\n code: \"driver_failed\",\n message: `${resourceLabel} command failed before dispatch`,\n retryable: false,\n };\n}\n\nfunction digestJson(value: unknown): string {\n return createHash(\"sha256\").update(canonicalJson(value), \"utf8\").digest(\"hex\");\n}\n\nfunction canonicalJson(value: unknown): string {\n return JSON.stringify(canonicalJsonValue(value));\n}\n\nfunction canonicalJsonValue(value: unknown): unknown {\n if (Array.isArray(value)) return value.map(canonicalJsonValue);\n if (value !== null && typeof value === \"object\") {\n return Object.fromEntries(\n Object.entries(value as Record<string, unknown>)\n .sort(([left], [right]) => left.localeCompare(right))\n .map(([key, entry]) => [key, canonicalJsonValue(entry)]),\n );\n }\n return value;\n}\n"],"mappings":";AAAA;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OASK;;;ACjBP,SAAS,kBAAkB;AAMpB,IAAM,6BAAN,cAAyC,MAAM;AAAA,EACpD,YACW,MACT,SACS,YAAY,OACrB;AACA,UAAM,OAAO;AAJJ;AAEA;AAGT,SAAK,OAAO;AAAA,EACd;AACF;AAGO,IAAM,iCAAN,cAA6C,MAAM;AAAA,EACxD,YACW,MACT,SACS,YAAY,OACrB;AACA,UAAM,OAAO;AAJJ;AAEA;AAGT,SAAK,OAAO;AAAA,EACd;AACF;AA+FA,IAAM,iBAAiB,oBAAI,IAA+B;AAAA,EACxD;AAAA,EACA;AAAA,EACA;AACF,CAAC;AAOM,IAAM,4BAAN,MAKL;AAAA,EACiB;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EAGA,UAAU,oBAAI,IAAoC;AAAA,EAClD,cAAc,oBAAI,IAA2B;AAAA,EAE9D,YACE,SACA;AACA,SAAK,SAAS,QAAQ;AACtB,SAAK,UAAU,QAAQ;AACvB,SAAK,YAAY,QAAQ;AACzB,SAAK,oBAAoB,QAAQ,qBAAqB;AACtD,SAAK,MAAM,QAAQ,QAAQ,MAAM,oBAAI,KAAK;AAC1C,SAAK,kBAAkB,QAAQ;AAC/B,QAAI,CAAC,OAAO,cAAc,KAAK,iBAAiB,KAAK,KAAK,oBAAoB,GAAG;AAC/E,YAAM,IAAI,MAAM,mDAAmD;AAAA,IACrE;AACA,eAAW,UAAU,QAAQ,kBAAkB,CAAC,EAAG,MAAK,qBAAqB,MAAM;AAAA,EACrF;AAAA,EAEA,MAAM,QAAQ,UAAyC;AACrD,UAAM,SAAS,MAAM,KAAK,qBAAqB,QAAQ;AACvD,UAAM,WAAW,KAAK,QAAQ,iBAAiB,MAAM,KAAK,OAAO,QAAQ,OAAO,EAAE,CAAC;AACnF,SAAK,QAAQ,2BAA2B,UAAU,OAAO,EAAE;AAC3D,WAAO;AAAA,EACT;AAAA,EAEA,IAAI,cAA2C;AAC7C,UAAM,UAAU,KAAK,QAAQ,aAAa,YAAY;AACtD,SAAK,QAAQ,uBAAuB,OAAO;AAC3C,UAAM,gBAAgB,WAAW,OAAO;AACxC,UAAM,WAAW,KAAK,QAAQ,IAAI,QAAQ,WAAW;AACrD,QAAI,UAAU;AACZ,UAAI,SAAS,kBAAkB,eAAe;AAC5C,cAAM,IAAI;AAAA,UACR;AAAA,UACA,gDAAgD,KAAK,QAAQ,aAAa;AAAA,QAC5E;AAAA,MACF;AACA,aAAO,SAAS;AAAA,IAClB;AAEA,SAAK,iBAAiB;AACtB,UAAM,WAAW,KAAK,YAAY,SAAS,YAAY,MAAM,MAAM,MAAM,IAAI;AAC7E,UAAM,QAAgC;AAAA,MACpC,aAAa,QAAQ;AAAA,MACrB;AAAA,MACA,SAAS;AAAA,MACT,YAAY,QAAQ,QAAQ,QAAQ;AAAA,MACpC,sBAAsB,KAAK,QAAQ,QAAQ,aAAa,eAAe,QAAQ,EAAE;AAAA,QAC/E,MAAM;AAAA,QACN,MAAM;AAAA,MACR;AAAA,IACF;AACA,SAAK,QAAQ,IAAI,QAAQ,aAAa,KAAK;AAE3C,UAAM,WAAW,KAAK,YAAY,IAAI,QAAQ,QAAQ,KAAK,QAAQ,QAAQ;AAC3E,UAAM,aAAa,SAAS,KAAK,YAAY,MAAM,KAAK,QAAQ,OAAO,OAAO,CAAC;AAC/E,UAAM,OAAO,MAAM,WAAW;AAAA,MAC5B,MAAM;AAAA,MACN,MAAM;AAAA,IACR;AACA,SAAK,YAAY,IAAI,QAAQ,UAAU,IAAI;AAC3C,SAAK,KAAK,QAAQ,MAAM;AACtB,UAAI,KAAK,YAAY,IAAI,QAAQ,QAAQ,MAAM;AAC7C,aAAK,YAAY,OAAO,QAAQ,QAAQ;AAAA,IAC5C,CAAC;AACD,WAAO,MAAM;AAAA,EACf;AAAA,EAEA,QAAQ,aAAsC;AAC5C,WAAO,KAAK,QAAQ,IAAI,WAAW,GAAG,WAAW;AAAA,EACnD;AAAA,EAEA,kBAAiE;AAC/D,WAAO,CAAC,GAAG,KAAK,QAAQ,OAAO,CAAC,EAAE,IAAI,CAAC,EAAE,aAAa,eAAe,QAAQ,OAAO;AAAA,MAClF;AAAA,MACA;AAAA,MACA;AAAA,IACF,EAAE;AAAA,EACJ;AAAA;AAAA;AAAA,EAIA,MAAM,cAA6B;AACjC,WAAO,KAAK,YAAY,OAAO,EAAG,OAAM,QAAQ,IAAI,CAAC,GAAG,KAAK,YAAY,OAAO,CAAC,CAAC;AAAA,EACpF;AAAA,EAEA,MAAc,QAAQ,OAA+B,SAAsC;AACzF,QAAI,CAAE,MAAM,MAAM,sBAAuB;AACvC,aAAO,MAAM,KAAK;AAAA,QAChB;AAAA,QACA;AAAA,QACA,GAAG,KAAK,QAAQ,aAAa;AAAA,MAC/B;AAAA,IACF;AAEA,QAAI;AACF,YAAM,KAAK,WAAW,kBAAkB,OAAO;AAC/C,YAAM,SAAS,MAAM,KAAK,qBAAqB,QAAQ,QAAQ;AAC/D,WAAK,QAAQ,0BAA0B,SAAS,MAAM;AACtD,YAAM,KAAK,OAAO,WAAW,SAAS,MAAM;AAAA,IAC9C,SAAS,OAAO;AACd,aAAO,MAAM,KAAK;AAAA,QAChB;AAAA,QACA,KAAK;AAAA,UACH;AAAA,UACA;AAAA,UACA;AAAA,UACA,KAAK,UAAU;AAAA,UACf;AAAA,UACA,qBAAqB,OAAO,KAAK,QAAQ,aAAa;AAAA,QACxD;AAAA,MACF;AAAA,IACF;AAEA,UAAM,eAAe,KAAK,UAAU;AACpC,UAAM,aAAa,KAAK,YAAY,SAAS,cAAc,cAAc,MAAM,MAAM,IAAI;AACzF,QAAI;AACF,YAAM,KAAK,QAAQ,MAAM,aAAa,MAAM,eAAe,UAAU;AACrE,YAAM,UAAU;AAAA,IAClB,QAAQ;AACN,aAAO,MAAM,KAAK;AAAA,QAChB;AAAA,QACA;AAAA,QACA,GAAG,KAAK,QAAQ,aAAa;AAAA,MAC/B;AAAA,IACF;AAEA,QAAI;AACF,YAAM,cAAc,KAAK,QAAQ,iBAAiB,MAAM,KAAK,OAAO,SAAS,OAAO,CAAC;AACrF,WAAK,QAAQ,2BAA2B,aAAa,QAAQ,QAAQ;AACrE,YAAM,YAAY,KAAK;AAAA,QACrB;AAAA,QACA;AAAA,QACA;AAAA,QACA,KAAK,UAAU;AAAA,QACf;AAAA,QACA;AAAA,MACF;AACA,UAAI;AACF,cAAM,KAAK,QAAQ,MAAM,aAAa,MAAM,eAAe,SAAS;AACpE,cAAM,UAAU;AAChB,eAAO;AAAA,MACT,QAAQ;AACN,eAAO,MAAM,KAAK;AAAA,UAChB;AAAA,UACA,KAAK,YAAY,SAAS,mBAAmB,cAAc,KAAK,UAAU,GAAG,MAAM;AAAA,YACjF,MAAM;AAAA,YACN,SAAS,GAAG,KAAK,QAAQ,aAAa;AAAA,YACtC,WAAW;AAAA,UACb,CAAC;AAAA,QACH;AAAA,MACF;AAAA,IACF,SAAS,OAAO;AACd,UAAI,iBAAiB,gCAAgC;AACnD,eAAO,MAAM,KAAK;AAAA,UAChB;AAAA,UACA,KAAK,YAAY,SAAS,UAAU,cAAc,KAAK,UAAU,GAAG,MAAM;AAAA,YACxE,MAAM,MAAM;AAAA,YACZ,SAAS,MAAM;AAAA,YACf,WAAW,MAAM;AAAA,UACnB,CAAC;AAAA,QACH;AAAA,MACF;AACA,aAAO,MAAM,KAAK;AAAA,QAChB;AAAA,QACA,KAAK,YAAY,SAAS,mBAAmB,cAAc,KAAK,UAAU,GAAG,MAAM;AAAA,UACjF,MAAM;AAAA,UACN,SAAS,GAAG,KAAK,QAAQ,aAAa;AAAA,UACtC,WAAW;AAAA,QACb,CAAC;AAAA,MACH;AAAA,IACF;AAAA,EACF;AAAA,EAEA,MAAc,qBAAqB,UAAoC;AACrE,UAAM,SAAS,MAAM,KAAK,OAAO,OAAO,QAAQ;AAChD,QAAI,CAAC,QAAQ;AACX,YAAM,IAAI;AAAA,QACR;AAAA,QACA,GAAG,KAAK,QAAQ,aAAa;AAAA,MAC/B;AAAA,IACF;AACA,UAAM,SAAS,KAAK,QAAQ,YAAY,MAAM;AAC9C,SAAK,QAAQ,sBAAsB,MAAM;AACzC,WAAO;AAAA,EACT;AAAA,EAEQ,YACN,SACA,OACA,cACA,WACA,aACA,OACU;AACV,WAAO,KAAK,QAAQ,YAAY;AAAA,MAC9B;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IACF,CAAC;AAAA,EACH;AAAA,EAEA,MAAc,OAAO,OAA+B,SAAsC;AACxF,UAAM,UAAU;AAChB,QAAI;AACF,YAAM,KAAK,QAAQ,MAAM,aAAa,MAAM,eAAe,OAAO;AAAA,IACpE,QAAQ;AAAA,IAGR;AACA,WAAO;AAAA,EACT;AAAA,EAEA,MAAc,mBACZ,OACA,SACA,SACmB;AACnB,WAAO,MAAM,KAAK;AAAA,MAChB;AAAA,MACA,KAAK,YAAY,SAAS,UAAU,MAAM,KAAK,UAAU,GAAG,MAAM;AAAA,QAChE,MAAM;AAAA,QACN;AAAA,QACA,WAAW;AAAA,MACb,CAAC;AAAA,IACH;AAAA,EACF;AAAA,EAEA,MAAc,QACZ,aACA,eACA,SACe;AACf,UAAM,KAAK,kBAAkB,EAAE,aAAa,eAAe,QAAQ,CAAC;AAAA,EACtE;AAAA,EAEQ,YAAoB;AAC1B,WAAO,KAAK,IAAI,EAAE,YAAY;AAAA,EAChC;AAAA,EAEQ,mBAAyB;AAC/B,WAAO,KAAK,QAAQ,QAAQ,KAAK,mBAAmB;AAClD,YAAM,WAAW,CAAC,GAAG,KAAK,QAAQ,QAAQ,CAAC,EAAE;AAAA,QAAK,CAAC,CAAC,EAAE,KAAK,MACzD,eAAe,IAAI,MAAM,QAAQ,KAAK;AAAA,MACxC;AACA,UAAI,CAAC,UAAU;AACb,cAAM,IAAI;AAAA,UACR;AAAA,UACA,GAAG,KAAK,QAAQ,aAAa;AAAA,UAC7B;AAAA,QACF;AAAA,MACF;AACA,WAAK,QAAQ,OAAO,SAAS,CAAC,CAAC;AAAA,IACjC;AAAA,EACF;AAAA,EAEQ,qBAAqB,QAA2D;AACtF,QAAI,KAAK,QAAQ,IAAI,OAAO,WAAW,GAAG;AACxC,YAAM,IAAI,MAAM,oCAAoC,OAAO,WAAW,EAAE;AAAA,IAC1E;AACA,UAAM,SAAS,KAAK,QAAQ,aAAa,OAAO,OAAO;AACvD,QAAI,OAAO,gBAAgB,OAAO,aAAa;AAC7C,YAAM,IAAI,MAAM,sBAAsB,OAAO,WAAW,yBAAyB;AAAA,IACnF;AACA,UAAM,UAAU,KAAK,QAAQ,eAAe,QAAQ,KAAK,UAAU,CAAC;AACpE,UAAM,QAAgC;AAAA,MACpC,aAAa,OAAO;AAAA,MACpB,eAAe,OAAO;AAAA,MACtB;AAAA,MACA,YAAY,QAAQ,QAAQ,OAAO;AAAA,MACnC,sBAAsB,QAAQ,QAAQ,IAAI;AAAA,IAC5C;AACA,SAAK,QAAQ,IAAI,OAAO,aAAa,KAAK;AAAA,EAC5C;AACF;AAEO,SAAS,0BACd,SACA,WACA,eACA,OACU;AACV,MAAI,eAAe,IAAI,QAAQ,KAAK,EAAG,QAAO;AAC9C,SAAO,MAAM;AAAA,IACX,GAAG;AAAA,IACH,OAAO,QAAQ,UAAU,eAAe,oBAAoB;AAAA,IAC5D;AAAA,IACA,aAAa;AAAA,IACb,OACE,QAAQ,UAAU,eACd;AAAA,MACE,MAAM;AAAA,MACN,SAAS,GAAG,aAAa;AAAA,MACzB,WAAW;AAAA,IACb,IACA;AAAA,MACE,MAAM;AAAA,MACN,SAAS,GAAG,aAAa;AAAA,MACzB,WAAW;AAAA,IACb;AAAA,EACR,CAAC;AACH;AAEA,SAAS,qBAAqB,OAAgB,eAAyC;AACrF,MAAI,iBAAiB,8BAA8B,MAAM,SAAS,gBAAgB;AAChF,WAAO;AAAA,MACL,MAAM,MAAM;AAAA,MACZ,SAAS,MAAM;AAAA,MACf,WAAW,MAAM;AAAA,IACnB;AAAA,EACF;AACA,SAAO;AAAA,IACL,MAAM;AAAA,IACN,SAAS,GAAG,aAAa;AAAA,IACzB,WAAW;AAAA,EACb;AACF;AAEA,SAAS,WAAW,OAAwB;AAC1C,SAAO,WAAW,QAAQ,EAAE,OAAO,cAAc,KAAK,GAAG,MAAM,EAAE,OAAO,KAAK;AAC/E;AAEA,SAAS,cAAc,OAAwB;AAC7C,SAAO,KAAK,UAAU,mBAAmB,KAAK,CAAC;AACjD;AAEA,SAAS,mBAAmB,OAAyB;AACnD,MAAI,MAAM,QAAQ,KAAK,EAAG,QAAO,MAAM,IAAI,kBAAkB;AAC7D,MAAI,UAAU,QAAQ,OAAO,UAAU,UAAU;AAC/C,WAAO,OAAO;AAAA,MACZ,OAAO,QAAQ,KAAgC,EAC5C,KAAK,CAAC,CAAC,IAAI,GAAG,CAAC,KAAK,MAAM,KAAK,cAAc,KAAK,CAAC,EACnD,IAAI,CAAC,CAAC,KAAK,KAAK,MAAM,CAAC,KAAK,mBAAmB,KAAK,CAAC,CAAC;AAAA,IAC3D;AAAA,EACF;AACA,SAAO;AACT;;;AD3aO,IAAM,+BAAN,MAAmC;AAAA,EACvB;AAAA,EAOjB,YAAY,SAA8C;AACxD,UAAM,EAAE,kBAAkB,qBAAqB,IAAI;AACnD,SAAK,OAAO,IAAI,0BAA0B;AAAA,MACxC,QAAQ,QAAQ;AAAA,MAChB,GAAI,QAAQ,YAAY,EAAE,WAAW,QAAQ,UAAU,IAAI,CAAC;AAAA,MAC5D,GAAI,QAAQ,sBAAsB,SAC9B,EAAE,mBAAmB,QAAQ,kBAAkB,IAC/C,CAAC;AAAA,MACL,GAAI,QAAQ,MAAM,EAAE,KAAK,QAAQ,IAAI,IAAI,CAAC;AAAA,MAC1C,GAAI,QAAQ,iBAAiB,EAAE,gBAAgB,QAAQ,eAAe,IAAI,CAAC;AAAA,MAC3E,GAAI,QAAQ,kBAAkB,EAAE,iBAAiB,QAAQ,gBAAgB,IAAI,CAAC;AAAA,MAC9E,SAAS;AAAA,QACP,eAAe;AAAA,QACf,cAAc,CAAC,UAAU,qBAAqB,MAAM,KAAK;AAAA,QACzD,aAAa,CAAC,UAAU,cAAc,MAAM,KAAK;AAAA,QACjD,kBAAkB,CAAC,UAAU,mBAAmB,MAAM,KAAK;AAAA,QAC3D,cAAc,CAAC,UAAU,qBAAqB,MAAM,KAAK;AAAA,QACzD,uBAAuB,SAAS;AAC9B,cAAI,QAAQ,qBAAqB,kBAAkB;AACjD,kBAAM,IAAI;AAAA,cACR;AAAA,cACA;AAAA,YACF;AAAA,UACF;AACA,cAAI,QAAQ,yBAAyB,sBAAsB;AACzD,kBAAM,IAAI;AAAA,cACR;AAAA,cACA;AAAA,YACF;AAAA,UACF;AAAA,QACF;AAAA,QACA,sBAAsB,QAAQ;AAC5B,cACE,OAAO,qBAAqB,oBAC5B,OAAO,yBAAyB,sBAChC;AACA,kBAAM,IAAI;AAAA,cACR;AAAA,cACA;AAAA,YACF;AAAA,UACF;AAAA,QACF;AAAA,QACA,0BAA0B,SAAS,QAAQ;AACzC,cAAI,QAAQ,6BAA6B,OAAO,kBAAkB;AAChE,kBAAM,IAAI;AAAA,cACR;AAAA,cACA;AAAA,YACF;AAAA,UACF;AACA,cAAI,QAAQ,+BAA+B,OAAO,oBAAoB;AACpE,kBAAM,IAAI;AAAA,cACR;AAAA,cACA;AAAA,YACF;AAAA,UACF;AAAA,QACF;AAAA,QACA,2BAA2B,aAAa,UAAU;AAChD,cACE,YAAY,qBAAqB,oBACjC,YAAY,OAAO,OAAO,YAC1B,YAAY,OAAO,qBAAqB,oBACxC,YAAY,OAAO,yBAAyB,sBAC5C;AACA,kBAAM,IAAI;AAAA,cACR;AAAA,cACA;AAAA,YACF;AAAA,UACF;AAAA,QACF;AAAA,QACA,YAAY,OAAO;AACjB,iBAAO,qBAAqB,MAAM;AAAA,YAChC,iBAAiB;AAAA,YACjB,aAAa,MAAM,QAAQ;AAAA,YAC3B;AAAA,YACA;AAAA,YACA,UAAU,MAAM,QAAQ;AAAA,YACxB,OAAO,MAAM;AAAA,YACb,cAAc,MAAM;AAAA,YACpB,WAAW,MAAM;AAAA,YACjB,aAAa,MAAM;AAAA,YACnB,OAAO,MAAM;AAAA,UACf,CAAC;AAAA,QACH;AAAA,QACA,eAAe,SAAS,WAAW;AACjC,cACE,QAAQ,qBAAqB,oBAC7B,QAAQ,yBAAyB,sBACjC;AACA,kBAAM,IAAI;AAAA,cACR,sBAAsB,QAAQ,WAAW;AAAA,YAC3C;AAAA,UACF;AACA,iBAAO;AAAA,YAA0B;AAAA,YAAS;AAAA,YAAW;AAAA,YAAW,CAAC,UAC/D,qBAAqB,MAAM,KAAK;AAAA,UAClC;AAAA,QACF;AAAA,MACF;AAAA,IACF,CAAC;AAAA,EACH;AAAA,EAEA,QAAQ,UAAoD;AAC1D,WAAO,KAAK,KAAK,QAAQ,QAAQ;AAAA,EACnC;AAAA,EAEA,IAAI,SAAwE;AAC1E,WAAO,KAAK,KAAK,IAAI,OAAO;AAAA,EAC9B;AAAA,EAEA,QAAQ,aAAuD;AAC7D,WAAO,KAAK,KAAK,QAAQ,WAAW;AAAA,EACtC;AAAA,EAEA,kBAAmD;AACjD,WAAO,KAAK,KAAK,gBAAgB;AAAA,EACnC;AAAA,EAEA,cAA6B;AAC3B,WAAO,KAAK,KAAK,YAAY;AAAA,EAC/B;AACF;AAEO,SAAS,qCACd,QACA,WAC+B;AAC/B,QAAM,UAAU,qBAAqB,MAAM,OAAO,OAAO;AACzD,SAAO;AAAA,IACL,GAAG;AAAA,IACH,SAAS;AAAA,MAA0B;AAAA,MAAS;AAAA,MAAW;AAAA,MAAW,CAAC,UACjE,qBAAqB,MAAM,KAAK;AAAA,IAClC;AAAA,EACF;AACF;AA6BO,IAAM,gCAAN,MAAoC;AAAA,EACxB;AAAA,EAOjB,YAAY,SAA+C;AACzD,UAAM,EAAE,mBAAmB,qBAAqB,IAAI;AACpD,SAAK,OAAO,IAAI,0BAA0B;AAAA,MACxC,QAAQ,QAAQ;AAAA,MAChB,GAAI,QAAQ,YAAY,EAAE,WAAW,QAAQ,UAAU,IAAI,CAAC;AAAA,MAC5D,GAAI,QAAQ,sBAAsB,SAC9B,EAAE,mBAAmB,QAAQ,kBAAkB,IAC/C,CAAC;AAAA,MACL,GAAI,QAAQ,MAAM,EAAE,KAAK,QAAQ,IAAI,IAAI,CAAC;AAAA,MAC1C,GAAI,QAAQ,iBAAiB,EAAE,gBAAgB,QAAQ,eAAe,IAAI,CAAC;AAAA,MAC3E,GAAI,QAAQ,kBAAkB,EAAE,iBAAiB,QAAQ,gBAAgB,IAAI,CAAC;AAAA,MAC9E,SAAS;AAAA,QACP,eAAe;AAAA,QACf,cAAc,CAAC,UAAU,sBAAsB,MAAM,KAAK;AAAA,QAC1D,aAAa,CAAC,UAAU,eAAe,MAAM,KAAK;AAAA,QAClD,kBAAkB,CAAC,UAAU,oBAAoB,MAAM,KAAK;AAAA,QAC5D,cAAc,CAAC,UAAU,sBAAsB,MAAM,KAAK;AAAA,QAC1D,uBAAuB,SAAS;AAC9B,cAAI,QAAQ,sBAAsB,mBAAmB;AACnD,kBAAM,IAAI;AAAA,cACR;AAAA,cACA;AAAA,YACF;AAAA,UACF;AACA,cAAI,QAAQ,yBAAyB,sBAAsB;AACzD,kBAAM,IAAI;AAAA,cACR;AAAA,cACA;AAAA,YACF;AAAA,UACF;AAAA,QACF;AAAA,QACA,sBAAsB,QAAQ;AAC5B,cACE,OAAO,sBAAsB,qBAC7B,OAAO,yBAAyB,sBAChC;AACA,kBAAM,IAAI;AAAA,cACR;AAAA,cACA;AAAA,YACF;AAAA,UACF;AAAA,QACF;AAAA,QACA,0BAA0B,SAAS,QAAQ;AACzC,cAAI,QAAQ,6BAA6B,OAAO,kBAAkB;AAChE,kBAAM,IAAI;AAAA,cACR;AAAA,cACA;AAAA,YACF;AAAA,UACF;AAAA,QACF;AAAA,QACA,2BAA2B,aAAa,UAAU;AAChD,cACE,YAAY,sBAAsB,qBAClC,YAAY,OAAO,OAAO,YAC1B,YAAY,OAAO,sBAAsB,qBACzC,YAAY,OAAO,yBAAyB,sBAC5C;AACA,kBAAM,IAAI;AAAA,cACR;AAAA,cACA;AAAA,YACF;AAAA,UACF;AAAA,QACF;AAAA,QACA,YAAY,OAAO;AACjB,iBAAO,sBAAsB,MAAM;AAAA,YACjC,iBAAiB;AAAA,YACjB,aAAa,MAAM,QAAQ;AAAA,YAC3B;AAAA,YACA;AAAA,YACA,UAAU,MAAM,QAAQ;AAAA,YACxB,OAAO,MAAM;AAAA,YACb,cAAc,MAAM;AAAA,YACpB,WAAW,MAAM;AAAA,YACjB,aAAa,MAAM;AAAA,YACnB,OAAO,MAAM;AAAA,UACf,CAAC;AAAA,QACH;AAAA,QACA,eAAe,SAAS,WAAW;AACjC,cACE,QAAQ,sBAAsB,qBAC9B,QAAQ,yBAAyB,sBACjC;AACA,kBAAM,IAAI;AAAA,cACR,sBAAsB,QAAQ,WAAW;AAAA,YAC3C;AAAA,UACF;AACA,iBAAO;AAAA,YAA0B;AAAA,YAAS;AAAA,YAAW;AAAA,YAAY,CAAC,UAChE,sBAAsB,MAAM,KAAK;AAAA,UACnC;AAAA,QACF;AAAA,MACF;AAAA,IACF,CAAC;AAAA,EACH;AAAA,EAEA,QAAQ,UAAqD;AAC3D,WAAO,KAAK,KAAK,QAAQ,QAAQ;AAAA,EACnC;AAAA,EAEA,IAAI,SAA0E;AAC5E,WAAO,KAAK,KAAK,IAAI,OAAO;AAAA,EAC9B;AAAA,EAEA,QAAQ,aAAwD;AAC9D,WAAO,KAAK,KAAK,QAAQ,WAAW;AAAA,EACtC;AAAA,EAEA,kBAAoD;AAClD,WAAO,KAAK,KAAK,gBAAgB;AAAA,EACnC;AAAA,EAEA,cAA6B;AAC3B,WAAO,KAAK,KAAK,YAAY;AAAA,EAC/B;AACF;AAEO,SAAS,sCACd,QACA,WACgC;AAChC,QAAM,UAAU,sBAAsB,MAAM,OAAO,OAAO;AAC1D,SAAO;AAAA,IACL,GAAG;AAAA,IACH,SAAS;AAAA,MAA0B;AAAA,MAAS;AAAA,MAAW;AAAA,MAAY,CAAC,UAClE,sBAAsB,MAAM,KAAK;AAAA,IACnC;AAAA,EACF;AACF;","names":[]}