@kronos-ts/axon-server 0.4.0 → 0.6.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 (106) hide show
  1. package/dist/axon-server-event-store.d.ts +0 -16
  2. package/dist/axon-server-event-store.d.ts.map +1 -1
  3. package/dist/axon-server-event-store.js +73 -45
  4. package/dist/axon-server-event-store.js.map +1 -1
  5. package/dist/axon-server-snapshotting-event-store.d.ts +30 -0
  6. package/dist/axon-server-snapshotting-event-store.d.ts.map +1 -0
  7. package/dist/axon-server-snapshotting-event-store.js +154 -0
  8. package/dist/axon-server-snapshotting-event-store.js.map +1 -0
  9. package/dist/axon-server.d.ts +46 -65
  10. package/dist/axon-server.d.ts.map +1 -1
  11. package/dist/axon-server.js +490 -317
  12. package/dist/axon-server.js.map +1 -1
  13. package/dist/bounded-read.d.ts +19 -0
  14. package/dist/bounded-read.d.ts.map +1 -0
  15. package/dist/bounded-read.js +39 -0
  16. package/dist/bounded-read.js.map +1 -0
  17. package/dist/connection-manager.d.ts +2 -2
  18. package/dist/connection-manager.d.ts.map +1 -1
  19. package/dist/connection.d.ts +36 -21
  20. package/dist/connection.d.ts.map +1 -1
  21. package/dist/connection.js +84 -45
  22. package/dist/connection.js.map +1 -1
  23. package/dist/context-view.d.ts +2 -2
  24. package/dist/context-view.d.ts.map +1 -1
  25. package/dist/control-plane.d.ts +14 -24
  26. package/dist/control-plane.d.ts.map +1 -1
  27. package/dist/control-plane.js +6 -37
  28. package/dist/control-plane.js.map +1 -1
  29. package/dist/event-processor-info.d.ts +7 -25
  30. package/dist/event-processor-info.d.ts.map +1 -1
  31. package/dist/event-processor-info.js +16 -20
  32. package/dist/event-processor-info.js.map +1 -1
  33. package/dist/flow-controlled-sender.d.ts +2 -2
  34. package/dist/flow-controlled-sender.d.ts.map +1 -1
  35. package/dist/flow-controlled-sender.js +37 -17
  36. package/dist/flow-controlled-sender.js.map +1 -1
  37. package/dist/generated/command.d.ts +20 -20
  38. package/dist/generated/command.d.ts.map +1 -1
  39. package/dist/generated/common.d.ts +20 -20
  40. package/dist/generated/common.d.ts.map +1 -1
  41. package/dist/generated/control.d.ts +36 -40
  42. package/dist/generated/control.d.ts.map +1 -1
  43. package/dist/generated/dcb.d.ts +88 -94
  44. package/dist/generated/dcb.d.ts.map +1 -1
  45. package/dist/generated/event.d.ts +81 -84
  46. package/dist/generated/event.d.ts.map +1 -1
  47. package/dist/generated/google/protobuf/empty.d.ts +3 -4
  48. package/dist/generated/google/protobuf/empty.d.ts.map +1 -1
  49. package/dist/generated/query.d.ts +40 -40
  50. package/dist/generated/query.d.ts.map +1 -1
  51. package/dist/index.d.ts +2 -2
  52. package/dist/index.d.ts.map +1 -1
  53. package/dist/index.js +1 -1
  54. package/dist/index.js.map +1 -1
  55. package/dist/message-size.d.ts +2 -2
  56. package/dist/message-size.d.ts.map +1 -1
  57. package/dist/outbound-stream.d.ts +7 -11
  58. package/dist/outbound-stream.d.ts.map +1 -1
  59. package/dist/outbound-stream.js +65 -16
  60. package/dist/outbound-stream.js.map +1 -1
  61. package/dist/platform-service.d.ts +14 -5
  62. package/dist/platform-service.d.ts.map +1 -1
  63. package/dist/platform-service.js +70 -10
  64. package/dist/platform-service.js.map +1 -1
  65. package/dist/resilience.d.ts +62 -0
  66. package/dist/resilience.d.ts.map +1 -0
  67. package/dist/resilience.js +103 -0
  68. package/dist/resilience.js.map +1 -0
  69. package/dist/shutdown-latch.d.ts +5 -4
  70. package/dist/shutdown-latch.d.ts.map +1 -1
  71. package/dist/shutdown-latch.js +20 -1
  72. package/dist/shutdown-latch.js.map +1 -1
  73. package/dist/stream-recovery.d.ts +9 -0
  74. package/dist/stream-recovery.d.ts.map +1 -0
  75. package/dist/stream-recovery.js +70 -0
  76. package/dist/stream-recovery.js.map +1 -0
  77. package/package.json +3 -3
  78. package/src/axon-server-event-store.ts +77 -47
  79. package/src/axon-server-snapshotting-event-store.ts +194 -0
  80. package/src/axon-server.ts +472 -374
  81. package/src/bounded-read.ts +43 -0
  82. package/src/connection-manager.ts +1 -1
  83. package/src/connection.ts +93 -59
  84. package/src/context-view.ts +1 -1
  85. package/src/control-plane.ts +22 -66
  86. package/src/event-processor-info.ts +23 -44
  87. package/src/flow-controlled-sender.ts +34 -15
  88. package/src/generated/command.ts +10 -10
  89. package/src/generated/common.ts +10 -10
  90. package/src/generated/control.ts +20 -20
  91. package/src/generated/dcb.ts +47 -47
  92. package/src/generated/event.ts +42 -42
  93. package/src/generated/google/protobuf/empty.ts +2 -2
  94. package/src/generated/query.ts +20 -20
  95. package/src/index.ts +1 -2
  96. package/src/message-size.ts +1 -1
  97. package/src/outbound-stream.ts +58 -28
  98. package/src/platform-service.ts +77 -13
  99. package/src/resilience.ts +149 -0
  100. package/src/shutdown-latch.ts +16 -3
  101. package/src/stream-recovery.ts +72 -0
  102. package/dist/axon-server-snapshot-store.d.ts +0 -12
  103. package/dist/axon-server-snapshot-store.d.ts.map +0 -1
  104. package/dist/axon-server-snapshot-store.js +0 -82
  105. package/dist/axon-server-snapshot-store.js.map +0 -1
  106. package/src/axon-server-snapshot-store.ts +0 -110
@@ -1,60 +1,36 @@
1
- /**
2
- * The Axon Server command and query buses.
3
- *
4
- * Axon Server is a SMART HUB: outbound dispatch always goes to the server, and
5
- * the server decides which node handles it — there is no client-side
6
- * prefer-local fork here, which is the whole difference from the dumb-pipe
7
- * broker in `@kronos-ts/rabbitmq`.
8
- *
9
- * Both buses are plain functions over the shared connection and YOUR local bus:
10
- *
11
- * ```ts
12
- * const commandBus = interceptingCommandBus(
13
- * axonServerCommandBus(axon, simpleCommandBus(unitOfWork)), lineage)
14
- * const queryBus = interceptingQueryBus(
15
- * axonServerQueryBus(axon, simpleQueryBus(unitOfWork)), lineage)
16
- * ```
17
- *
18
- * Axon-specific protocol invariants are preserved byte-for-byte:
19
- *
20
- * - CLIENT_SUPPORTS_STREAMING capability advertised on every dispatched
21
- * query via `defaultQueryInstructions(...)`;
22
- * - AxonIQ-Context + AxonIQ-Access-Token gRPC metadata headers built by
23
- * `contextView(...)` and attached to every outbound stream/RPC;
24
- * - permits-AFTER-subscriptions stream ordering preserved on the initial
25
- * handshake AND on reconnect (see `ensureStreamStarted` /
26
- * `reestablishStreamBody`).
27
- */
28
- import { type ResilienceConfig } from "@kronos-ts/core";
29
- import type { CommandBus, QueryBus } from "@kronos-ts/core";
1
+ import { type MessagingLimits } from "@kronos-ts/core";
2
+ import { type ResilienceConfig } from "./resilience.js";
3
+ import type { CommandBus, QueryBus, SubscriptionCapableQueryBus, UnitOfWork } from "@kronos-ts/core";
30
4
  import type { AxonServerBusSource } from "./connection.js";
31
5
  /**
32
6
  * Flow control configuration for a bus channel.
33
7
  */
34
- export interface FlowControlConfig {
8
+ export type FlowControlConfig = {
35
9
  /** Initial permits granted to Axon Server. Default: 5000 (aligned with Java). */
36
10
  permits?: number;
37
11
  /** Threshold at which to request more permits. Default: 2500 (aligned with Java). */
38
12
  refillThreshold?: number;
39
- }
13
+ };
40
14
  /**
41
15
  * Processing instructions attached to outbound messages.
42
16
  * Controls routing, priority, and timeout behavior on Axon Server.
43
17
  */
44
- export interface ProcessingInstructions {
18
+ export type ProcessingInstructions = {
45
19
  /** Routing key for consistent hashing (e.g., aggregate ID). */
46
20
  routingKey?: string;
47
21
  /** Priority (higher = processed first). Default: 0 */
48
22
  priority?: number;
49
23
  /** Timeout in ms. Axon Server cancels the command/query if not handled in time. */
50
24
  timeoutMs?: number;
51
- }
25
+ };
52
26
  /**
53
27
  * Tuning for {@link axonServerCommandBus}. Every field has a working default;
54
- * the two arguments that carry meaning — the connection and your local bus —
28
+ * the two arguments that carry meaning — the connection and your next bus —
55
29
  * are positional, and this record is the trailing remainder.
56
30
  */
57
- export interface AxonServerCommandBusOptions {
31
+ export type AxonServerCommandBusOptions = {
32
+ /** Client-side request deadline. Default: 30000ms. */
33
+ timeoutMs?: number;
58
34
  /** Axon Server context for this bus's stream. Default: the connection's. */
59
35
  context?: string;
60
36
  /** Flow control for the command stream. */
@@ -67,11 +43,13 @@ export interface AxonServerCommandBusOptions {
67
43
  loadFactor?: number;
68
44
  /** Retry policy for stream re-establishment. Default: the connection's. */
69
45
  resilience?: Partial<ResilienceConfig>;
70
- }
46
+ /** Bounded admission; excess nested work receives an overload error. */
47
+ limits?: MessagingLimits;
48
+ };
71
49
  /**
72
50
  * Tuning for {@link axonServerQueryBus}. See {@link AxonServerCommandBusOptions}.
73
51
  */
74
- export interface AxonServerQueryBusOptions {
52
+ export type AxonServerQueryBusOptions = {
75
53
  /** Axon Server context for this bus's stream. Default: the connection's. */
76
54
  context?: string;
77
55
  /** Flow control for the query stream. */
@@ -87,41 +65,43 @@ export interface AxonServerQueryBusOptions {
87
65
  */
88
66
  shortcutQueriesToLocalHandlers?: boolean;
89
67
  /**
90
- * Default timeout for query dispatch in ms. Default: 3600000 (1 hour).
68
+ * Default timeout for query dispatch in ms. Default: 30000ms.
91
69
  * Aligned with Java's processing instruction timeout.
92
70
  */
93
71
  timeoutMs?: number;
94
72
  /** Retry policy for stream re-establishment. Default: the connection's. */
95
73
  resilience?: Partial<ResilienceConfig>;
96
- }
74
+ /** Bounded admission; excess nested work receives an overload error. */
75
+ limits?: MessagingLimits;
76
+ };
97
77
  /**
98
- * A command bus backed by Axon Server, over YOUR local bus.
78
+ * A command bus backed by Axon Server, over YOUR next bus.
99
79
  *
100
80
  * - **Outbound dispatch**: ALWAYS through Axon Server, via the unary Dispatch
101
81
  * RPC. Axon Server routes the command to the appropriate node (which may be
102
- * this one). There is deliberately no client-side prefer-local fork: the hub
82
+ * this one). There is deliberately no client-side prefer-next fork: the hub
103
83
  * is the router, and short-circuiting it would silently defeat load factors,
104
84
  * priorities and routing keys.
105
- * - **Inbound**: a command the server routes here is dispatched into `local` —
85
+ * - **Inbound**: a command the server routes here is dispatched into `next` —
106
86
  * not into a privately-held handler map. That is what makes the unit-of-work
107
- * policy you chose for `local` (say `postgresUnitOfWork(pg, unitOfWork)`)
87
+ * policy you chose for `next` (say `postgresUnitOfWork(unitOfWork, pg)`)
108
88
  * apply to server-routed work exactly as it applies to work this process
109
89
  * originated. It is also why this function takes no `unitOfWork` argument:
110
- * `local` carries that policy now.
111
- * - **subscribe**: registers the handler on `local` AND announces the name to
90
+ * `next` carries that policy now.
91
+ * - **subscribe**: registers the handler on `next` AND announces the name to
112
92
  * Axon Server, so other nodes can route to us.
113
93
  *
114
- * ## Correlation lineage and the interceptor layer
94
+ * ## correlation and the interceptor layer
115
95
  *
116
- * The returned bus stamps no lineage of its own. A host that wants it wraps the
96
+ * The returned bus stamps no correlation of its own. A host that wants it wraps the
117
97
  * OUTERMOST bus:
118
98
  *
119
99
  * ```ts
120
- * interceptingCommandBus(axonServerCommandBus(conn, local), lineage)
100
+ * interceptingCommandBus(axonServerCommandBus(next, conn), correlation)
121
101
  * ```
122
102
  *
123
103
  * so whatever a host adds runs BEFORE the message is serialized onto the wire.
124
- * Lineage itself is usually already on `message.metadata` by then — `ctx.send`
104
+ * Correlation itself is usually already on `message.metadata` by then — `ctx.send`
125
105
  * stamps the unit of work's correlation data before any bus sees the message.
126
106
  *
127
107
  * This is precisely how the Java client does it. AF4's `AxonServerCommandBus`
@@ -129,37 +109,38 @@ export interface AxonServerQueryBusOptions {
129
109
  * `doDispatch(dispatchInterceptors.intercept(commandMessage), cb)` — one call
130
110
  * site, at the top, ahead of any routing. AF5 keeps the property via decorator
131
111
  * order: `DISTRIBUTED_COMMAND_BUS_ORDER = InterceptingCommandBus.DECORATION_ORDER - 50`
132
- * stacks `InterceptingCommandBus → DistributedCommandBus → SimpleCommandBus`.
112
+ * stacks `InterceptingCommandBus → DistributedCommandBus → LocalCommandBus`.
133
113
  *
134
- * If `local` is itself an intercepting bus, a server-routed command sees
135
- * `lineage` twice. That is harmless: both of its fields are `??` seeds, so the
114
+ * If `next` is itself an intercepting bus, a server-routed command sees
115
+ * `correlation` twice. That is harmless: both of its fields are `??` seeds, so the
136
116
  * second application finds them set and changes nothing.
137
117
  */
138
- export declare function axonServerCommandBus(conn: AxonServerBusSource, local: CommandBus, options?: AxonServerCommandBusOptions): CommandBus;
118
+ export declare function axonServerCommandBus<U extends UnitOfWork = UnitOfWork>(next: CommandBus<U>, conn: AxonServerBusSource, options?: AxonServerCommandBusOptions): CommandBus<U>;
139
119
  /**
140
- * A query bus backed by Axon Server, over YOUR local bus.
120
+ * A query bus backed by Axon Server, over YOUR next bus.
141
121
  *
142
122
  * Same architecture as {@link axonServerCommandBus}: outbound dispatch goes
143
- * through Axon Server, and a query the server routes here runs through `local`,
123
+ * through Axon Server, and a query the server routes here runs through `next`,
144
124
  * so your unit-of-work policy applies to server-routed reads too. `subscribe`
145
- * registers on `local` and announces the name to the server.
125
+ * registers on `next` and announces the name to the server.
146
126
  *
147
127
  * The one asymmetry with commands is `shortcutQueriesToLocalHandlers` — Java
148
128
  * has it for queries and not for commands, and so do we. When it is on and this
149
- * node subscribed the name, `query()` goes straight to `local` and the caller's
150
- * unit of work is passed through, so the local branch nests exactly as the
129
+ * node subscribed the name, `query()` goes straight to `next` and the caller's
130
+ * unit of work is passed through, so the next branch nests exactly as the
151
131
  * in-process bus does.
152
132
  *
153
- * Lineage, if wanted, is `interceptingQueryBus(bus, lineage)` at the host,
133
+ * Correlation, if wanted, is `interceptingQueryBus(bus, correlation)` at the host,
154
134
  * matching AF4's `AxonServerQueryBus`, which calls
155
135
  * `dispatchInterceptors.intercept(...)` at the top of `query`, `streamingQuery`,
156
136
  * `scatterGather` and `subscriptionQuery`. Because the wrap is outside, the
157
- * shortcut branch gets identical lineage to the remote branch.
137
+ * shortcut branch gets identical correlation to the remote branch.
158
138
  *
159
- * KNOWN GAP: `subscriptionQuery` / `subscribeToUpdates` build their proto
160
- * straight from `message.metadata`, and `interceptingQueryBus` (in
161
- * `@kronos-ts/core`) forwards those two calls to the delegate without
162
- * running the dispatch chain. Closing that needs a core change.
139
+ * Subscription queries run the dispatch chain: `interceptingQueryBus` wraps
140
+ * `subscriptionQuery` / `subscribeToUpdates` with the same intercept the
141
+ * primary `query` gets, so the proto built from `message.metadata` already
142
+ * carries whatever the host's intercept stamped (pinned in core by
143
+ * `interception/__tests__/subscription-interception.test.ts`).
163
144
  */
164
- export declare function axonServerQueryBus(conn: AxonServerBusSource, local: QueryBus, options?: AxonServerQueryBusOptions): QueryBus;
145
+ export declare function axonServerQueryBus<U extends UnitOfWork = UnitOfWork>(next: QueryBus<U>, conn: AxonServerBusSource, options?: AxonServerQueryBusOptions): SubscriptionCapableQueryBus<U>;
165
146
  //# sourceMappingURL=axon-server.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"axon-server.d.ts","sourceRoot":"","sources":["../src/axon-server.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AACH,OAAO,EAML,KAAK,gBAAgB,EACtB,MAAM,iBAAiB,CAAA;AACxB,OAAO,KAAK,EACV,UAAU,EAEV,QAAQ,EAOT,MAAM,iBAAiB,CAAA;AAOxB,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,iBAAiB,CAAA;AAgB1D;;GAEG;AACH,MAAM,WAAW,iBAAiB;IAChC,iFAAiF;IACjF,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,qFAAqF;IACrF,eAAe,CAAC,EAAE,MAAM,CAAA;CACzB;AAED;;;GAGG;AACH,MAAM,WAAW,sBAAsB;IACrC,+DAA+D;IAC/D,UAAU,CAAC,EAAE,MAAM,CAAA;IACnB,sDAAsD;IACtD,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,mFAAmF;IACnF,SAAS,CAAC,EAAE,MAAM,CAAA;CACnB;AAED;;;;GAIG;AACH,MAAM,WAAW,2BAA2B;IAC1C,4EAA4E;IAC5E,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,2CAA2C;IAC3C,WAAW,CAAC,EAAE,iBAAiB,CAAA;IAC/B;;;;OAIG;IACH,UAAU,CAAC,EAAE,MAAM,CAAA;IACnB,2EAA2E;IAC3E,UAAU,CAAC,EAAE,OAAO,CAAC,gBAAgB,CAAC,CAAA;CACvC;AAED;;GAEG;AACH,MAAM,WAAW,yBAAyB;IACxC,4EAA4E;IAC5E,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,yCAAyC;IACzC,WAAW,CAAC,EAAE,iBAAiB,CAAA;IAC/B;;;;;;;;OAQG;IACH,8BAA8B,CAAC,EAAE,OAAO,CAAA;IACxC;;;OAGG;IACH,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,2EAA2E;IAC3E,UAAU,CAAC,EAAE,OAAO,CAAC,gBAAgB,CAAC,CAAA;CACvC;AAyED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAwCG;AACH,wBAAgB,oBAAoB,CAClC,IAAI,EAAE,mBAAmB,EACzB,KAAK,EAAE,UAAU,EACjB,OAAO,GAAE,2BAAgC,GACxC,UAAU,CAuOZ;AAMD;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AACH,wBAAgB,kBAAkB,CAChC,IAAI,EAAE,mBAAmB,EACzB,KAAK,EAAE,QAAQ,EACf,OAAO,GAAE,yBAA8B,GACtC,QAAQ,CAojBV"}
1
+ {"version":3,"file":"axon-server.d.ts","sourceRoot":"","sources":["../src/axon-server.ts"],"names":[],"mappings":"AACA,OAAO,EAA0D,KAAK,eAAe,EAAE,MAAM,iBAAiB,CAAA;AAkC9G,OAAO,EAAE,KAAK,gBAAgB,EAAE,MAAM,iBAAiB,CAAA;AACvD,OAAO,KAAK,EACV,UAAU,EAEV,QAAQ,EACR,2BAA2B,EAI3B,UAAU,EAEX,MAAM,iBAAiB,CAAA;AAMxB,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,iBAAiB,CAAA;AAiB1D;;GAEG;AACH,MAAM,MAAM,iBAAiB,GAAG;IAC9B,iFAAiF;IACjF,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,qFAAqF;IACrF,eAAe,CAAC,EAAE,MAAM,CAAA;CACzB,CAAA;AAED;;;GAGG;AACH,MAAM,MAAM,sBAAsB,GAAG;IACnC,+DAA+D;IAC/D,UAAU,CAAC,EAAE,MAAM,CAAA;IACnB,sDAAsD;IACtD,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,mFAAmF;IACnF,SAAS,CAAC,EAAE,MAAM,CAAA;CACnB,CAAA;AAED;;;;GAIG;AACH,MAAM,MAAM,2BAA2B,GAAG;IACxC,sDAAsD;IACtD,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,4EAA4E;IAC5E,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,2CAA2C;IAC3C,WAAW,CAAC,EAAE,iBAAiB,CAAA;IAC/B;;;;OAIG;IACH,UAAU,CAAC,EAAE,MAAM,CAAA;IACnB,2EAA2E;IAC3E,UAAU,CAAC,EAAE,OAAO,CAAC,gBAAgB,CAAC,CAAA;IACtC,wEAAwE;IACxE,MAAM,CAAC,EAAE,eAAe,CAAA;CAEzB,CAAA;AAED;;GAEG;AACH,MAAM,MAAM,yBAAyB,GAAG;IACtC,4EAA4E;IAC5E,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,yCAAyC;IACzC,WAAW,CAAC,EAAE,iBAAiB,CAAA;IAC/B;;;;;;;;OAQG;IACH,8BAA8B,CAAC,EAAE,OAAO,CAAA;IACxC;;;OAGG;IACH,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,2EAA2E;IAC3E,UAAU,CAAC,EAAE,OAAO,CAAC,gBAAgB,CAAC,CAAA;IACtC,wEAAwE;IACxE,MAAM,CAAC,EAAE,eAAe,CAAA;CAEzB,CAAA;AAyED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAwCG;AACH,wBAAgB,oBAAoB,CAAC,CAAC,SAAS,UAAU,GAAG,UAAU,EACpE,IAAI,EAAE,UAAU,CAAC,CAAC,CAAC,EACnB,IAAI,EAAE,mBAAmB,EACzB,OAAO,GAAE,2BAAgC,GACxC,UAAU,CAAC,CAAC,CAAC,CAuPf;AAMD;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AACH,wBAAgB,kBAAkB,CAAC,CAAC,SAAS,UAAU,GAAG,UAAU,EAClE,IAAI,EAAE,QAAQ,CAAC,CAAC,CAAC,EACjB,IAAI,EAAE,mBAAmB,EACzB,OAAO,GAAE,yBAA8B,GACtC,2BAA2B,CAAC,CAAC,CAAC,CA4nBhC"}