@hoox-sh/hoox-shared 1.5.0 → 1.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 (64) hide show
  1. package/dist/agent-config-fields.d.ts +5 -0
  2. package/dist/agent-config-fields.d.ts.map +1 -1
  3. package/dist/analytics.d.ts.map +1 -1
  4. package/dist/analytics.js +8 -3
  5. package/dist/config.d.ts +10 -2
  6. package/dist/config.d.ts.map +1 -1
  7. package/dist/config.js +256 -24
  8. package/dist/errors.d.ts +1 -0
  9. package/dist/errors.d.ts.map +1 -1
  10. package/dist/exchange-client.d.ts +0 -19
  11. package/dist/exchange-client.d.ts.map +1 -1
  12. package/dist/exchange-client.js +0 -66
  13. package/dist/exchanges/base-exchange-client.d.ts.map +1 -1
  14. package/dist/exchanges/base-exchange-client.js +4 -3
  15. package/dist/exchanges/index.js +4 -3
  16. package/dist/index.d.ts +2 -3
  17. package/dist/index.d.ts.map +1 -1
  18. package/dist/index.js +293 -604
  19. package/dist/middleware/auth.d.ts +9 -0
  20. package/dist/middleware/auth.d.ts.map +1 -1
  21. package/dist/middleware/index.js +3 -2
  22. package/dist/middleware/logger.d.ts +2 -0
  23. package/dist/middleware/logger.d.ts.map +1 -1
  24. package/dist/middleware/rate-limit.d.ts +7 -0
  25. package/dist/middleware/rate-limit.d.ts.map +1 -1
  26. package/dist/middleware/rate-limit.js +3 -2
  27. package/dist/middleware/validate.d.ts +2 -0
  28. package/dist/middleware/validate.d.ts.map +1 -1
  29. package/dist/path-utils.d.ts.map +1 -1
  30. package/dist/path-utils.js +13 -3
  31. package/dist/queue-handler.d.ts.map +1 -1
  32. package/dist/queue-handler.js +19 -8
  33. package/dist/router.d.ts +5 -0
  34. package/dist/router.d.ts.map +1 -1
  35. package/dist/schemas/index.js +40 -23
  36. package/dist/schemas/registry.d.ts.map +1 -1
  37. package/dist/schemas/registry.js +4 -1
  38. package/dist/schemas/validators.d.ts.map +1 -1
  39. package/dist/schemas/validators.js +36 -22
  40. package/dist/service-bindings.d.ts +4 -0
  41. package/dist/service-bindings.d.ts.map +1 -1
  42. package/dist/session.d.ts +10 -3
  43. package/dist/session.d.ts.map +1 -1
  44. package/dist/session.js +109 -33
  45. package/dist/sse.d.ts.map +1 -1
  46. package/dist/sse.js +24 -6
  47. package/dist/stores/config-store.d.ts +2 -50
  48. package/dist/stores/config-store.d.ts.map +1 -1
  49. package/dist/stores/config-store.js +145 -134
  50. package/dist/stores/service-store.d.ts +2 -192
  51. package/dist/stores/service-store.d.ts.map +1 -1
  52. package/dist/stores/service-store.js +24 -6
  53. package/dist/stores/ui-store.d.ts +2 -48
  54. package/dist/stores/ui-store.d.ts.map +1 -1
  55. package/dist/tenant.d.ts +1 -0
  56. package/dist/tenant.d.ts.map +1 -1
  57. package/dist/types.d.ts +6 -1
  58. package/dist/types.d.ts.map +1 -1
  59. package/dist/types.js +19 -0
  60. package/dist/wizard/engine.d.ts.map +1 -1
  61. package/dist/wizard/engine.js +13 -7
  62. package/dist/wizard/index.js +13 -7
  63. package/dist/wizard/presets.js +3 -3
  64. package/package.json +1 -1
package/dist/session.js CHANGED
@@ -8,10 +8,20 @@ import {
8
8
  chmodSync
9
9
  } from "fs";
10
10
  import { homedir } from "os";
11
- import { dirname, join, resolve } from "path";
11
+ import { dirname, join, resolve, sep } from "path";
12
12
  function createHooxPath(path) {
13
13
  return path;
14
14
  }
15
+ function isInsideDir(child, parent) {
16
+ const resolvedChild = resolve(child);
17
+ const resolvedParent = resolve(parent);
18
+ const cmpChild = process.platform === "win32" ? resolvedChild.toLowerCase() : resolvedChild;
19
+ const cmpParent = process.platform === "win32" ? resolvedParent.toLowerCase() : resolvedParent;
20
+ if (cmpChild === cmpParent)
21
+ return true;
22
+ const prefix = cmpParent.endsWith(sep) ? cmpParent : cmpParent + sep;
23
+ return cmpChild.startsWith(prefix);
24
+ }
15
25
  function getHooxHome() {
16
26
  try {
17
27
  const override = process.env.HOOX_HOME?.trim();
@@ -175,7 +185,7 @@ function resolveHooxPath(relativePath) {
175
185
  const fullPath = join(hooxHome, normalizedPath);
176
186
  const resolvedPath = resolve(fullPath);
177
187
  const resolvedHome = resolve(hooxHome);
178
- if (!resolvedPath.startsWith(resolvedHome)) {
188
+ if (!isInsideDir(resolvedPath, resolvedHome)) {
179
189
  throw new Error(`Resolved path "${resolvedPath}" is outside Hoox home directory`);
180
190
  }
181
191
  return createHooxPath(resolvedPath);
@@ -185,7 +195,7 @@ function isWithinHooxHome(path) {
185
195
  const hooxHome = getHooxHome();
186
196
  const resolvedPath = resolve(path);
187
197
  const resolvedHome = resolve(hooxHome);
188
- return resolvedPath.startsWith(resolvedHome);
198
+ return isInsideDir(resolvedPath, resolvedHome);
189
199
  } catch {
190
200
  return false;
191
201
  }
@@ -220,17 +230,99 @@ function getHooxStatePath() {
220
230
  return resolveHooxPath("data/state.json");
221
231
  }
222
232
 
223
- // src/session.ts
233
+ // src/types.ts
224
234
  import { z } from "zod";
225
- var SessionStateFileSchema = z.object({
226
- activeView: z.string().optional(),
227
- sidebarExpanded: z.boolean().optional(),
228
- windowSize: z.object({
229
- cols: z.number().int().positive(),
230
- rows: z.number().int().positive()
235
+ var TradeActionSchema = z.enum([
236
+ "LONG",
237
+ "SHORT",
238
+ "CLOSE_LONG",
239
+ "CLOSE_SHORT"
240
+ ]);
241
+ var MAX_WEBHOOK_LEVERAGE = 125;
242
+ var MAX_WEBHOOK_QUANTITY = 1e6;
243
+ var WebhookPayloadSchema = z.object({
244
+ exchange: z.string().min(1),
245
+ action: TradeActionSchema,
246
+ symbol: z.string().min(1).max(20),
247
+ quantity: z.number().positive().finite().max(MAX_WEBHOOK_QUANTITY),
248
+ price: z.number().positive().finite().optional(),
249
+ orderType: z.string().optional(),
250
+ leverage: z.number().int().positive().max(MAX_WEBHOOK_LEVERAGE).optional(),
251
+ test: z.boolean().optional(),
252
+ tenantId: z.string().min(1).max(64).optional()
253
+ }).strict();
254
+ var TradeQueueMessageSchema = z.object({
255
+ requestId: z.string().min(1).max(128),
256
+ exchange: z.string().min(1).max(64),
257
+ action: TradeActionSchema,
258
+ symbol: z.string().min(1).max(32),
259
+ quantity: z.number().positive().finite().max(MAX_WEBHOOK_QUANTITY),
260
+ price: z.number().positive().finite().optional(),
261
+ leverage: z.number().int().positive().max(MAX_WEBHOOK_LEVERAGE).optional(),
262
+ test: z.boolean().optional(),
263
+ idempotencyKey: z.string().min(1).max(512).optional(),
264
+ tenantId: z.string().min(1).max(64).optional(),
265
+ queuedAt: z.string().min(1).max(64)
266
+ }).strict();
267
+ var TradeSignalSchema = z.object({
268
+ id: z.number().int().positive().optional(),
269
+ source: z.string().min(1),
270
+ symbol: z.string().min(1),
271
+ action: TradeActionSchema,
272
+ price: z.number().positive().finite().optional(),
273
+ quantity: z.number().positive().finite(),
274
+ leverage: z.number().int().positive().optional(),
275
+ status: z.enum(["pending", "executed", "failed", "skipped"]).optional(),
276
+ createdAt: z.string().optional(),
277
+ executedAt: z.string().optional(),
278
+ error: z.string().optional()
279
+ }).strict();
280
+ var PositionSchema = z.object({
281
+ id: z.string(),
282
+ symbol: z.string().min(1),
283
+ side: TradeActionSchema,
284
+ quantity: z.number().positive(),
285
+ entry_price: z.number().positive(),
286
+ current_price: z.number().positive(),
287
+ unrealized_pnl: z.number(),
288
+ timestamp: z.number().int().positive()
289
+ }).strict();
290
+ var BalanceSchema = z.object({
291
+ asset: z.string().min(1),
292
+ free: z.number().min(0),
293
+ locked: z.number().min(0),
294
+ timestamp: z.number().int().positive()
295
+ }).strict();
296
+ var VIEW_IDS = [
297
+ "dashboard",
298
+ "workers",
299
+ "worker-detail",
300
+ "trade-monitor",
301
+ "logs-viewer",
302
+ "service-manager",
303
+ "config-editor",
304
+ "setup-wizard",
305
+ "settings",
306
+ "queue-depth",
307
+ "kv-viewer",
308
+ "secrets-viewer",
309
+ "db-query",
310
+ "ai-chat",
311
+ "edge-topology",
312
+ "worker-settings"
313
+ ];
314
+
315
+ // src/session.ts
316
+ import { z as z2 } from "zod";
317
+ var SessionStateFileSchema = z2.object({
318
+ activeView: z2.string().optional(),
319
+ sidebarExpanded: z2.boolean().optional(),
320
+ windowSize: z2.object({
321
+ cols: z2.number().int().positive(),
322
+ rows: z2.number().int().positive()
231
323
  }).optional(),
232
- lastData: z.number().nonnegative().optional(),
233
- savedAt: z.string().optional()
324
+ lastData: z2.number().nonnegative().optional(),
325
+ savedAt: z2.string().optional()
234
326
  }).strict();
235
327
  var TUI_STATE_DIR = ".tui-state";
236
328
  function getSessionFilePath() {
@@ -267,7 +359,7 @@ async function restoreSession() {
267
359
  const file = Bun.file(getSessionFilePath());
268
360
  const exists = await file.exists();
269
361
  if (!exists)
270
- return { ...DEFAULT_SESSION };
362
+ return { ...DEFAULT_SESSION, fromDisk: false };
271
363
  const raw = await file.text();
272
364
  const result = SessionStateFileSchema.safeParse(JSON.parse(raw));
273
365
  const parsed = result.success ? result.data : {};
@@ -276,30 +368,14 @@ async function restoreSession() {
276
368
  sidebarExpanded: typeof parsed.sidebarExpanded === "boolean" ? parsed.sidebarExpanded : DEFAULT_SESSION.sidebarExpanded,
277
369
  windowSize: parsed.windowSize ?? DEFAULT_SESSION.windowSize,
278
370
  lastData: typeof parsed.lastData === "number" ? parsed.lastData : DEFAULT_SESSION.lastData,
279
- savedAt: parsed.savedAt ?? DEFAULT_SESSION.savedAt
371
+ savedAt: parsed.savedAt ?? DEFAULT_SESSION.savedAt,
372
+ fromDisk: true
280
373
  };
281
374
  } catch {
282
- return { ...DEFAULT_SESSION };
375
+ return { ...DEFAULT_SESSION, fromDisk: false };
283
376
  }
284
377
  }
285
- var VALID_VIEW_IDS = new Set([
286
- "dashboard",
287
- "workers",
288
- "worker-detail",
289
- "trade-monitor",
290
- "logs-viewer",
291
- "service-manager",
292
- "config-editor",
293
- "setup-wizard",
294
- "settings",
295
- "queue-depth",
296
- "kv-viewer",
297
- "secrets-viewer",
298
- "db-query",
299
- "ai-chat",
300
- "edge-topology",
301
- "worker-settings"
302
- ]);
378
+ var VALID_VIEW_IDS = new Set(VIEW_IDS);
303
379
  function validateViewId(id) {
304
380
  return typeof id === "string" && VALID_VIEW_IDS.has(id);
305
381
  }
package/dist/sse.d.ts.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"sse.d.ts","sourceRoot":"","sources":["../src/sse.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH;;;;;;;;;GASG;AAEH,OAAO,EAIL,KAAK,oBAAoB,EACzB,KAAK,wBAAwB,EAC9B,MAAM,sBAAsB,CAAC;AAS9B,MAAM,MAAM,WAAW,CAAC,CAAC,IAAI,CAAC,KAAK,EAAE,CAAC,KAAK,IAAI,CAAC;AAChD,MAAM,MAAM,iBAAiB,GAAG,CAC9B,MAAM,EAAE,WAAW,GAAG,cAAc,GAAG,cAAc,KAClD,IAAI,CAAC;AAEV,UAAU,eAAe;IACvB,KAAK,EAAE,MAAM,IAAI,CAAC;CACnB;AAED,MAAM,WAAW,mBAAmB;IAClC,SAAS,CAAC,EAAE,wBAAwB,CAAC;IACrC,YAAY,CAAC,EAAE,oBAAoB,CAAC;CACrC;AAID;;;;;;;;;;;GAWG;AACH,wBAAgB,YAAY,CAAC,CAAC,EAC5B,IAAI,EAAE,MAAM,EACZ,QAAQ,EAAE,WAAW,CAAC,CAAC,CAAC,EACxB,QAAQ,CAAC,EAAE,iBAAiB,EAC5B,OAAO,CAAC,EAAE,mBAAmB,GAC5B,eAAe,CAsFjB"}
1
+ {"version":3,"file":"sse.d.ts","sourceRoot":"","sources":["../src/sse.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH;;;;;;;;;GASG;AAEH,OAAO,EAIL,KAAK,oBAAoB,EACzB,KAAK,wBAAwB,EAC9B,MAAM,sBAAsB,CAAC;AAS9B,MAAM,MAAM,WAAW,CAAC,CAAC,IAAI,CAAC,KAAK,EAAE,CAAC,KAAK,IAAI,CAAC;AAChD,MAAM,MAAM,iBAAiB,GAAG,CAC9B,MAAM,EAAE,WAAW,GAAG,cAAc,GAAG,cAAc,KAClD,IAAI,CAAC;AAEV,UAAU,eAAe;IACvB,KAAK,EAAE,MAAM,IAAI,CAAC;CACnB;AAED,MAAM,WAAW,mBAAmB;IAClC,SAAS,CAAC,EAAE,wBAAwB,CAAC;IACrC,YAAY,CAAC,EAAE,oBAAoB,CAAC;CACrC;AAID;;;;;;;;;;;GAWG;AACH,wBAAgB,YAAY,CAAC,CAAC,EAC5B,IAAI,EAAE,MAAM,EACZ,QAAQ,EAAE,WAAW,CAAC,CAAC,CAAC,EACxB,QAAQ,CAAC,EAAE,iBAAiB,EAC5B,OAAO,CAAC,EAAE,mBAAmB,GAC5B,eAAe,CAwGjB"}
package/dist/sse.js CHANGED
@@ -81,6 +81,7 @@ var init_operator_transport = __esm(() => {
81
81
  // src/sse.ts
82
82
  function subscribeSSE(path, callback, onStatus, options) {
83
83
  let aborted = false;
84
+ const ac = new AbortController;
84
85
  const profile = options?.transport ?? (options?.transportEnv ? resolveOperatorTransportProfile(options.transportEnv) : resolveOperatorTransportProfile());
85
86
  const run = async () => {
86
87
  let attempt = 0;
@@ -91,7 +92,8 @@ function subscribeSSE(path, callback, onStatus, options) {
91
92
  headers: {
92
93
  Accept: "text/event-stream",
93
94
  ...buildOperatorAuthHeaders(profile)
94
- }
95
+ },
96
+ signal: ac.signal
95
97
  });
96
98
  if (!response.ok || !response.body) {
97
99
  throw new Error(`SSE connection failed: HTTP ${response.status}`);
@@ -103,17 +105,21 @@ function subscribeSSE(path, callback, onStatus, options) {
103
105
  let buffer = "";
104
106
  while (!aborted) {
105
107
  const { done, value } = await reader.read();
106
- if (done)
107
- break;
108
+ if (done) {
109
+ throw new Error("SSE stream ended");
110
+ }
108
111
  buffer += decoder.decode(value, { stream: true });
109
112
  const lines = buffer.split(`
110
113
  `);
111
114
  buffer = lines.pop() || "";
112
115
  for (const line of lines) {
113
116
  const trimmed = line.trim();
114
- if (trimmed.startsWith("data: ")) {
117
+ if (trimmed.startsWith("data:")) {
118
+ const jsonText = trimmed.slice(5).replace(/^\s/, "");
119
+ if (!jsonText)
120
+ continue;
115
121
  try {
116
- const parsed = JSON.parse(trimmed.slice(6));
122
+ const parsed = JSON.parse(jsonText);
117
123
  callback(parsed);
118
124
  } catch {}
119
125
  }
@@ -125,7 +131,18 @@ function subscribeSSE(path, callback, onStatus, options) {
125
131
  onStatus?.("reconnecting");
126
132
  const delay = Math.min(RECONNECT_BASE_MS * Math.pow(2, attempt), RECONNECT_MAX_MS);
127
133
  attempt++;
128
- await new Promise((resolve) => setTimeout(resolve, delay));
134
+ await new Promise((resolve) => {
135
+ const timer = setTimeout(resolve, delay);
136
+ const onAbort = () => {
137
+ clearTimeout(timer);
138
+ resolve();
139
+ };
140
+ if (ac.signal.aborted) {
141
+ onAbort();
142
+ return;
143
+ }
144
+ ac.signal.addEventListener("abort", onAbort, { once: true });
145
+ });
129
146
  }
130
147
  }
131
148
  if (!aborted) {
@@ -136,6 +153,7 @@ function subscribeSSE(path, callback, onStatus, options) {
136
153
  return {
137
154
  abort: () => {
138
155
  aborted = true;
156
+ ac.abort();
139
157
  }
140
158
  };
141
159
  }
@@ -38,56 +38,8 @@ export declare const useConfigStore: import("zustand").UseBoundStore<Omit<Omit<i
38
38
  getOptions: () => Partial<import("zustand/middleware").PersistOptions<ConfigState & ConfigActions, unknown, unknown>>;
39
39
  };
40
40
  }, "setState"> & {
41
- setState(nextStateOrUpdater: (ConfigState & ConfigActions) | Partial<ConfigState & ConfigActions> | ((state: {
42
- theme: "dark" | "light";
43
- refreshIntervalMs: number;
44
- defaultView: ViewId;
45
- activeExchanges: string[];
46
- keyboardShortcuts: {
47
- [x: string]: string;
48
- };
49
- logFilters: {
50
- levels: import("..").LogLevel[];
51
- workers: string[];
52
- searchText: string;
53
- };
54
- notifications: {
55
- alerts: boolean;
56
- trades: boolean;
57
- debug: boolean;
58
- system: boolean;
59
- };
60
- soundEnabled: boolean;
61
- updateConfig: (partial: Partial<ConfigState>) => void;
62
- resetDefaults: () => void;
63
- setShortcut: (action: string, key: string) => void;
64
- toggleNotification: (channel: keyof NotificationPreferences) => void;
65
- }) => void), shouldReplace?: false): unknown;
66
- setState(nextStateOrUpdater: (ConfigState & ConfigActions) | ((state: {
67
- theme: "dark" | "light";
68
- refreshIntervalMs: number;
69
- defaultView: ViewId;
70
- activeExchanges: string[];
71
- keyboardShortcuts: {
72
- [x: string]: string;
73
- };
74
- logFilters: {
75
- levels: import("..").LogLevel[];
76
- workers: string[];
77
- searchText: string;
78
- };
79
- notifications: {
80
- alerts: boolean;
81
- trades: boolean;
82
- debug: boolean;
83
- system: boolean;
84
- };
85
- soundEnabled: boolean;
86
- updateConfig: (partial: Partial<ConfigState>) => void;
87
- resetDefaults: () => void;
88
- setShortcut: (action: string, key: string) => void;
89
- toggleNotification: (channel: keyof NotificationPreferences) => void;
90
- }) => void), shouldReplace: true): unknown;
41
+ setState(nextStateOrUpdater: (ConfigState & ConfigActions) | Partial<ConfigState & ConfigActions> | ((state: import("immer").WritableNonArrayDraft<ConfigState & ConfigActions>) => void), shouldReplace?: false): unknown;
42
+ setState(nextStateOrUpdater: (ConfigState & ConfigActions) | ((state: import("immer").WritableNonArrayDraft<ConfigState & ConfigActions>) => void), shouldReplace: true): unknown;
91
43
  }>;
92
44
  export {};
93
45
  //# sourceMappingURL=config-store.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"config-store.d.ts","sourceRoot":"","sources":["../../src/stores/config-store.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAmBH,OAAO,KAAK,EAAE,MAAM,EAAE,SAAS,EAAE,uBAAuB,EAAE,MAAM,UAAU,CAAC;AAM3E,qFAAqF;AACrF,wBAAgB,qBAAqB,IAAI,MAAM,CAE9C;AA0ID,MAAM,WAAW,WAAW;IAC1B,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC;IACxB,iBAAiB,EAAE,MAAM,CAAC;IAC1B,WAAW,EAAE,MAAM,CAAC;IACpB,eAAe,EAAE,MAAM,EAAE,CAAC;IAC1B,iBAAiB,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC1C,UAAU,EAAE,SAAS,CAAC;IACtB,aAAa,EAAE,uBAAuB,CAAC;IACvC,YAAY,EAAE,OAAO,CAAC;CACvB;AAID,UAAU,aAAa;IACrB,+DAA+D;IAC/D,YAAY,EAAE,CAAC,OAAO,EAAE,OAAO,CAAC,WAAW,CAAC,KAAK,IAAI,CAAC;IACtD,8CAA8C;IAC9C,aAAa,EAAE,MAAM,IAAI,CAAC;IAC1B,yCAAyC;IACzC,WAAW,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,KAAK,IAAI,CAAC;IACnD,8CAA8C;IAC9C,kBAAkB,EAAE,CAAC,OAAO,EAAE,MAAM,uBAAuB,KAAK,IAAI,CAAC;CACtE;AAiBD,eAAO,MAAM,cAAc;;;;;;;;;;;;;;eAtClB,MAAM,GAAG,OAAO;2BACJ,MAAM;qBACZ,MAAM;;;;;;;;;;;;;;;;sBAKL,OAAO;sBAOP,CAAC,OAAO,EAAE,OAAO,CAAC,WAAW,CAAC,KAAK,IAAI;uBAEtC,MAAM,IAAI;qBAEZ,CAAC,MAAM,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,KAAK,IAAI;4BAE9B,CAAC,OAAO,EAAE,MAAM,uBAAuB,KAAK,IAAI;;;eApB7D,MAAM,GAAG,OAAO;2BACJ,MAAM;qBACZ,MAAM;;;;;;;;;;;;;;;;sBAKL,OAAO;sBAOP,CAAC,OAAO,EAAE,OAAO,CAAC,WAAW,CAAC,KAAK,IAAI;uBAEtC,MAAM,IAAI;qBAEZ,CAAC,MAAM,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,KAAK,IAAI;4BAE9B,CAAC,OAAO,EAAE,MAAM,uBAAuB,KAAK,IAAI;;EA+ErE,CAAC"}
1
+ {"version":3,"file":"config-store.d.ts","sourceRoot":"","sources":["../../src/stores/config-store.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAmBH,OAAO,KAAK,EAAE,MAAM,EAAE,SAAS,EAAE,uBAAuB,EAAE,MAAM,UAAU,CAAC;AAM3E,qFAAqF;AACrF,wBAAgB,qBAAqB,IAAI,MAAM,CAE9C;AA0ID,MAAM,WAAW,WAAW;IAC1B,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC;IACxB,iBAAiB,EAAE,MAAM,CAAC;IAC1B,WAAW,EAAE,MAAM,CAAC;IACpB,eAAe,EAAE,MAAM,EAAE,CAAC;IAC1B,iBAAiB,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC1C,UAAU,EAAE,SAAS,CAAC;IACtB,aAAa,EAAE,uBAAuB,CAAC;IACvC,YAAY,EAAE,OAAO,CAAC;CACvB;AAID,UAAU,aAAa;IACrB,+DAA+D;IAC/D,YAAY,EAAE,CAAC,OAAO,EAAE,OAAO,CAAC,WAAW,CAAC,KAAK,IAAI,CAAC;IACtD,8CAA8C;IAC9C,aAAa,EAAE,MAAM,IAAI,CAAC;IAC1B,yCAAyC;IACzC,WAAW,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,KAAK,IAAI,CAAC;IACnD,8CAA8C;IAC9C,kBAAkB,EAAE,CAAC,OAAO,EAAE,MAAM,uBAAuB,KAAK,IAAI,CAAC;CACtE;AAiBD,eAAO,MAAM,cAAc;;;;;;;;;;;;;;;EA6D1B,CAAC"}