@desplega.ai/qa-use 2.14.1 → 2.15.1
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/README.md +23 -0
- package/dist/lib/api/index.d.ts +5 -1
- package/dist/lib/api/index.d.ts.map +1 -1
- package/dist/lib/api/index.js +112 -5
- package/dist/lib/api/index.js.map +1 -1
- package/dist/lib/api/sse.d.ts +22 -2
- package/dist/lib/api/sse.d.ts.map +1 -1
- package/dist/lib/api/sse.js +77 -5
- package/dist/lib/api/sse.js.map +1 -1
- package/dist/lib/env/index.d.ts +13 -0
- package/dist/lib/env/index.d.ts.map +1 -1
- package/dist/lib/env/index.js +35 -0
- package/dist/lib/env/index.js.map +1 -1
- package/dist/lib/env/localhost.d.ts +22 -0
- package/dist/lib/env/localhost.d.ts.map +1 -0
- package/dist/lib/env/localhost.js +49 -0
- package/dist/lib/env/localhost.js.map +1 -0
- package/dist/lib/env/paths.d.ts +27 -0
- package/dist/lib/env/paths.d.ts.map +1 -0
- package/dist/lib/env/paths.js +42 -0
- package/dist/lib/env/paths.js.map +1 -0
- package/dist/lib/env/sessions.d.ts +55 -0
- package/dist/lib/env/sessions.d.ts.map +1 -0
- package/dist/lib/env/sessions.js +128 -0
- package/dist/lib/env/sessions.js.map +1 -0
- package/dist/lib/tunnel/errors.d.ts +61 -0
- package/dist/lib/tunnel/errors.d.ts.map +1 -0
- package/dist/lib/tunnel/errors.js +152 -0
- package/dist/lib/tunnel/errors.js.map +1 -0
- package/dist/lib/tunnel/index.d.ts.map +1 -1
- package/dist/lib/tunnel/index.js +26 -11
- package/dist/lib/tunnel/index.js.map +1 -1
- package/dist/lib/tunnel/registry.d.ts +182 -0
- package/dist/lib/tunnel/registry.d.ts.map +1 -0
- package/dist/lib/tunnel/registry.js +561 -0
- package/dist/lib/tunnel/registry.js.map +1 -0
- package/dist/package.json +1 -1
- package/dist/src/cli/commands/browser/_detached.d.ts +27 -0
- package/dist/src/cli/commands/browser/_detached.d.ts.map +1 -0
- package/dist/src/cli/commands/browser/_detached.js +422 -0
- package/dist/src/cli/commands/browser/_detached.js.map +1 -0
- package/dist/src/cli/commands/browser/close.d.ts +7 -0
- package/dist/src/cli/commands/browser/close.d.ts.map +1 -1
- package/dist/src/cli/commands/browser/close.js +101 -5
- package/dist/src/cli/commands/browser/close.js.map +1 -1
- package/dist/src/cli/commands/browser/create.d.ts +7 -0
- package/dist/src/cli/commands/browser/create.d.ts.map +1 -1
- package/dist/src/cli/commands/browser/create.js +233 -25
- package/dist/src/cli/commands/browser/create.js.map +1 -1
- package/dist/src/cli/commands/browser/index.d.ts.map +1 -1
- package/dist/src/cli/commands/browser/index.js +3 -0
- package/dist/src/cli/commands/browser/index.js.map +1 -1
- package/dist/src/cli/commands/browser/run.d.ts.map +1 -1
- package/dist/src/cli/commands/browser/run.js +13 -6
- package/dist/src/cli/commands/browser/run.js.map +1 -1
- package/dist/src/cli/commands/browser/status.d.ts +4 -0
- package/dist/src/cli/commands/browser/status.d.ts.map +1 -1
- package/dist/src/cli/commands/browser/status.js +85 -3
- package/dist/src/cli/commands/browser/status.js.map +1 -1
- package/dist/src/cli/commands/doctor.d.ts +45 -0
- package/dist/src/cli/commands/doctor.d.ts.map +1 -0
- package/dist/src/cli/commands/doctor.js +267 -0
- package/dist/src/cli/commands/doctor.js.map +1 -0
- package/dist/src/cli/commands/test/run.d.ts.map +1 -1
- package/dist/src/cli/commands/test/run.js +33 -19
- package/dist/src/cli/commands/test/run.js.map +1 -1
- package/dist/src/cli/commands/tunnel/close.d.ts +18 -0
- package/dist/src/cli/commands/tunnel/close.d.ts.map +1 -0
- package/dist/src/cli/commands/tunnel/close.js +154 -0
- package/dist/src/cli/commands/tunnel/close.js.map +1 -0
- package/dist/src/cli/commands/tunnel/index.d.ts +6 -0
- package/dist/src/cli/commands/tunnel/index.d.ts.map +1 -0
- package/dist/src/cli/commands/tunnel/index.js +17 -0
- package/dist/src/cli/commands/tunnel/index.js.map +1 -0
- package/dist/src/cli/commands/tunnel/ls.d.ts +10 -0
- package/dist/src/cli/commands/tunnel/ls.d.ts.map +1 -0
- package/dist/src/cli/commands/tunnel/ls.js +89 -0
- package/dist/src/cli/commands/tunnel/ls.js.map +1 -0
- package/dist/src/cli/commands/tunnel/start.d.ts +15 -0
- package/dist/src/cli/commands/tunnel/start.d.ts.map +1 -0
- package/dist/src/cli/commands/tunnel/start.js +65 -0
- package/dist/src/cli/commands/tunnel/start.js.map +1 -0
- package/dist/src/cli/commands/tunnel/status.d.ts +8 -0
- package/dist/src/cli/commands/tunnel/status.d.ts.map +1 -0
- package/dist/src/cli/commands/tunnel/status.js +58 -0
- package/dist/src/cli/commands/tunnel/status.js.map +1 -0
- package/dist/src/cli/generated/docs-content.d.ts +1 -1
- package/dist/src/cli/generated/docs-content.d.ts.map +1 -1
- package/dist/src/cli/generated/docs-content.js +157 -100
- package/dist/src/cli/generated/docs-content.js.map +1 -1
- package/dist/src/cli/index.js +8 -0
- package/dist/src/cli/index.js.map +1 -1
- package/dist/src/cli/lib/browser.d.ts +25 -9
- package/dist/src/cli/lib/browser.d.ts.map +1 -1
- package/dist/src/cli/lib/browser.js +73 -42
- package/dist/src/cli/lib/browser.js.map +1 -1
- package/dist/src/cli/lib/cli-entry.d.ts +40 -0
- package/dist/src/cli/lib/cli-entry.d.ts.map +1 -0
- package/dist/src/cli/lib/cli-entry.js +65 -0
- package/dist/src/cli/lib/cli-entry.js.map +1 -0
- package/dist/src/cli/lib/runner.d.ts +6 -0
- package/dist/src/cli/lib/runner.d.ts.map +1 -1
- package/dist/src/cli/lib/runner.js +2 -2
- package/dist/src/cli/lib/runner.js.map +1 -1
- package/dist/src/cli/lib/startup-sweep.d.ts +45 -0
- package/dist/src/cli/lib/startup-sweep.d.ts.map +1 -0
- package/dist/src/cli/lib/startup-sweep.js +246 -0
- package/dist/src/cli/lib/startup-sweep.js.map +1 -0
- package/dist/src/cli/lib/tunnel-banner.d.ts +33 -0
- package/dist/src/cli/lib/tunnel-banner.d.ts.map +1 -0
- package/dist/src/cli/lib/tunnel-banner.js +55 -0
- package/dist/src/cli/lib/tunnel-banner.js.map +1 -0
- package/dist/src/cli/lib/tunnel-error-hint.d.ts +20 -0
- package/dist/src/cli/lib/tunnel-error-hint.d.ts.map +1 -0
- package/dist/src/cli/lib/tunnel-error-hint.js +48 -0
- package/dist/src/cli/lib/tunnel-error-hint.js.map +1 -0
- package/dist/src/cli/lib/tunnel-option.d.ts +27 -0
- package/dist/src/cli/lib/tunnel-option.d.ts.map +1 -0
- package/dist/src/cli/lib/tunnel-option.js +77 -0
- package/dist/src/cli/lib/tunnel-option.js.map +1 -0
- package/dist/src/cli/lib/tunnel-resolve.d.ts +42 -0
- package/dist/src/cli/lib/tunnel-resolve.d.ts.map +1 -0
- package/dist/src/cli/lib/tunnel-resolve.js +72 -0
- package/dist/src/cli/lib/tunnel-resolve.js.map +1 -0
- package/lib/api/index.ts +136 -6
- package/lib/api/sse.test.ts +530 -0
- package/lib/api/sse.ts +105 -5
- package/lib/env/index.ts +51 -0
- package/lib/env/localhost.test.ts +63 -0
- package/lib/env/localhost.ts +51 -0
- package/lib/env/paths.ts +46 -0
- package/lib/env/sessions.test.ts +109 -0
- package/lib/env/sessions.ts +155 -0
- package/lib/tunnel/errors.test.ts +105 -0
- package/lib/tunnel/errors.ts +169 -0
- package/lib/tunnel/index.ts +26 -11
- package/lib/tunnel/registry.test.ts +420 -0
- package/lib/tunnel/registry.ts +646 -0
- package/package.json +1 -1
package/dist/lib/tunnel/index.js
CHANGED
|
@@ -3,6 +3,7 @@ import https from 'node:https';
|
|
|
3
3
|
import { URL } from 'node:url';
|
|
4
4
|
import localtunnel from '@desplega.ai/localtunnel';
|
|
5
5
|
import { getEnv } from '../env/index.js';
|
|
6
|
+
import { classifyTunnelFailure, TunnelError } from './errors.js';
|
|
6
7
|
export class TunnelManager {
|
|
7
8
|
session = null;
|
|
8
9
|
defaultRegion = 'auto';
|
|
@@ -42,22 +43,36 @@ export class TunnelManager {
|
|
|
42
43
|
if (!subdomain && options.apiKey !== undefined && options.sessionIndex !== undefined) {
|
|
43
44
|
// Use deterministic subdomain based on API key and session index
|
|
44
45
|
subdomain = TunnelManager.generateDeterministicSubdomain(options.apiKey, options.sessionIndex);
|
|
45
|
-
console.
|
|
46
|
+
console.error(`Using deterministic subdomain: ${subdomain}`);
|
|
46
47
|
}
|
|
47
48
|
else if (!subdomain) {
|
|
48
49
|
// Fallback to timestamp-based random subdomain
|
|
49
50
|
subdomain = `qa-use-${Date.now().toString().slice(-6)}`;
|
|
50
|
-
console.
|
|
51
|
+
console.error(`Using random subdomain: ${subdomain}`);
|
|
51
52
|
}
|
|
52
|
-
console.
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
53
|
+
console.error(`Starting tunnel on port ${port} with host ${host} in region ${region}`);
|
|
54
|
+
let tunnel;
|
|
55
|
+
try {
|
|
56
|
+
tunnel = await localtunnel({
|
|
57
|
+
port,
|
|
58
|
+
host,
|
|
59
|
+
subdomain,
|
|
60
|
+
local_host: options.localHost || 'localhost',
|
|
61
|
+
auth: true,
|
|
62
|
+
});
|
|
63
|
+
}
|
|
64
|
+
catch (err) {
|
|
65
|
+
// Classify provider errors into structured TunnelError subclasses so
|
|
66
|
+
// the CLI can render a triage-hint message. Zero retries here —
|
|
67
|
+
// surface the failure immediately.
|
|
68
|
+
const classified = err instanceof TunnelError
|
|
69
|
+
? err
|
|
70
|
+
: classifyTunnelFailure(err, {
|
|
71
|
+
target: `${options.localHost || 'localhost'}:${port}`,
|
|
72
|
+
});
|
|
73
|
+
throw classified;
|
|
74
|
+
}
|
|
75
|
+
console.error(`Tunnel started at ${tunnel.url}`);
|
|
61
76
|
this.session = {
|
|
62
77
|
tunnel,
|
|
63
78
|
publicUrl: tunnel.url,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../lib/tunnel/index.ts"],"names":[],"mappings":"AAAA,OAAO,MAAM,MAAM,aAAa,CAAC;AACjC,OAAO,KAAK,MAAM,YAAY,CAAC;AAC/B,OAAO,EAAE,GAAG,EAAE,MAAM,UAAU,CAAC;AAC/B,OAAO,WAAW,MAAM,0BAA0B,CAAC;AACnD,OAAO,EAAE,MAAM,EAAE,MAAM,iBAAiB,CAAC;
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../lib/tunnel/index.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,182 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* TunnelRegistry — a shared, refcount-managed layer over `TunnelManager`.
|
|
3
|
+
*
|
|
4
|
+
* Goals:
|
|
5
|
+
* - Two CLI commands targeting the same localhost base URL share one
|
|
6
|
+
* remote tunnel (one public URL, one provider connection).
|
|
7
|
+
* - State is visible and editable across sibling processes via
|
|
8
|
+
* `~/.qa-use/tunnels/<hash>.json`, so a SECOND process targeting the
|
|
9
|
+
* same localhost picks up the FIRST process's public URL rather than
|
|
10
|
+
* spinning up its own tunnel.
|
|
11
|
+
* - Last-releaser (in the OWNER process) keeps the tunnel alive for
|
|
12
|
+
* `GRACE_MS` (30 s default) so rapid-fire invocations do not thrash
|
|
13
|
+
* the provider.
|
|
14
|
+
*
|
|
15
|
+
* Cross-process coordination model:
|
|
16
|
+
* - The process that first acquires a given target becomes the OWNER
|
|
17
|
+
* and runs the in-process `TunnelManager`. Its PID is recorded in
|
|
18
|
+
* the registry file.
|
|
19
|
+
* - Later acquirers in OTHER processes read the file, see an alive
|
|
20
|
+
* owner PID, increment refcount under a lockfile, and return an
|
|
21
|
+
* "attach" handle (`isCrossProcessAttach: true`) with the owner's
|
|
22
|
+
* `publicUrl`. They do NOT construct a `TunnelManager`.
|
|
23
|
+
* - Read-modify-write of the record is guarded by a lockfile
|
|
24
|
+
* (`<hash>.lock`, `O_EXCL | O_CREAT`) with bounded retry.
|
|
25
|
+
*
|
|
26
|
+
* TTL grace limitation:
|
|
27
|
+
* - The grace window is bounded by the OWNER process's lifetime. Since
|
|
28
|
+
* `TunnelManager` is a per-process localtunnel client, the remote
|
|
29
|
+
* tunnel dies when the owner exits. For long-lived owners
|
|
30
|
+
* (`tunnel start --hold`, a running `test run`, a detached
|
|
31
|
+
* `browser create` from Phase 4) grace works as designed: a new
|
|
32
|
+
* acquirer within `GRACE_MS` cancels tear-down. For short-lived
|
|
33
|
+
* commands that release-and-exit immediately, grace collapses to
|
|
34
|
+
* zero (the owner process is gone, so there is no tunnel to keep
|
|
35
|
+
* alive anyway).
|
|
36
|
+
*
|
|
37
|
+
* Non-goals (this phase):
|
|
38
|
+
* - Daemonised tunnel hosts. Phase 4 adds detach so short-lived
|
|
39
|
+
* commands can leave a long-lived owner behind.
|
|
40
|
+
* - Retries on provider failure. Zero retries, consistent with Phase 2.
|
|
41
|
+
*/
|
|
42
|
+
import { TunnelManager, type TunnelOptions } from './index.js';
|
|
43
|
+
/**
|
|
44
|
+
* How long (ms) to keep a tunnel alive after its refcount hits zero.
|
|
45
|
+
* A new `acquire()` within this window reuses the existing tunnel.
|
|
46
|
+
* Overridable via `QA_USE_TUNNEL_GRACE_MS` env var (primarily a
|
|
47
|
+
* test-friendly knob; production callers should stick with the default).
|
|
48
|
+
*/
|
|
49
|
+
export declare const GRACE_MS = 30000;
|
|
50
|
+
/**
|
|
51
|
+
* Max concurrent tunnels per API key. Mirrors the sessionIndex clamp at
|
|
52
|
+
* `lib/tunnel/index.ts:41` so we surface a clear error instead of silently
|
|
53
|
+
* colliding on subdomains.
|
|
54
|
+
*/
|
|
55
|
+
export declare const MAX_CONCURRENT_TUNNELS = 10;
|
|
56
|
+
/** On-disk schema for a registry entry. */
|
|
57
|
+
export interface TunnelRecord {
|
|
58
|
+
id: string;
|
|
59
|
+
target: string;
|
|
60
|
+
publicUrl: string;
|
|
61
|
+
pid: number;
|
|
62
|
+
refcount: number;
|
|
63
|
+
ttlExpiresAt: number | null;
|
|
64
|
+
startedAt: number;
|
|
65
|
+
}
|
|
66
|
+
/**
|
|
67
|
+
* Handle returned by `acquire()` / kept in memory by consumers.
|
|
68
|
+
*
|
|
69
|
+
* Consumers must call `registry.release(handle)` exactly once per
|
|
70
|
+
* `acquire()` call.
|
|
71
|
+
*/
|
|
72
|
+
export interface TunnelHandle extends TunnelRecord {
|
|
73
|
+
/**
|
|
74
|
+
* True when this handle was acquired from a foreign process's tunnel
|
|
75
|
+
* (the registry file's `pid` !== `process.pid`). The caller MUST NOT
|
|
76
|
+
* attempt to retrieve a `TunnelManager` via `getLiveManager(target)` —
|
|
77
|
+
* there isn't one in this process. Use `handle.publicUrl` directly.
|
|
78
|
+
*/
|
|
79
|
+
isCrossProcessAttach: boolean;
|
|
80
|
+
/**
|
|
81
|
+
* Internal marker used to guard double-release. Not persisted.
|
|
82
|
+
*/
|
|
83
|
+
_released?: boolean;
|
|
84
|
+
}
|
|
85
|
+
/**
|
|
86
|
+
* Canonical target key — used both as the map key and to derive the
|
|
87
|
+
* filename hash. We lowercase the hostname and drop any path/query so
|
|
88
|
+
* `http://Localhost:3000/foo` and `http://localhost:3000/` dedupe.
|
|
89
|
+
*/
|
|
90
|
+
export declare function canonicalTarget(target: string): string;
|
|
91
|
+
/** Filename hash for a target. First 10 hex chars of sha256. */
|
|
92
|
+
export declare function targetHash(target: string): string;
|
|
93
|
+
/**
|
|
94
|
+
* Hook used by tests to inject a fake `TunnelManager` without booting a
|
|
95
|
+
* real tunnel. When unset (the default) the registry constructs a real
|
|
96
|
+
* `TunnelManager`.
|
|
97
|
+
*/
|
|
98
|
+
export type TunnelManagerFactory = () => TunnelManager;
|
|
99
|
+
export interface TunnelRegistryOptions {
|
|
100
|
+
/** Override factory (tests). */
|
|
101
|
+
managerFactory?: TunnelManagerFactory;
|
|
102
|
+
/** Override grace window (tests). */
|
|
103
|
+
graceMs?: number;
|
|
104
|
+
/** Override concurrency cap (tests). */
|
|
105
|
+
maxConcurrent?: number;
|
|
106
|
+
/** Options threaded into `TunnelManager.startTunnel(...)`. */
|
|
107
|
+
tunnelOptions?: TunnelOptions;
|
|
108
|
+
}
|
|
109
|
+
/**
|
|
110
|
+
* Acquire / release / list API for tunnels.
|
|
111
|
+
*
|
|
112
|
+
* A singleton is exported as `tunnelRegistry` below for convenience;
|
|
113
|
+
* callers that need isolation (tests) construct their own instance.
|
|
114
|
+
*/
|
|
115
|
+
export declare class TunnelRegistry {
|
|
116
|
+
private readonly live;
|
|
117
|
+
private readonly graceMs;
|
|
118
|
+
private readonly maxConcurrent;
|
|
119
|
+
private readonly managerFactory;
|
|
120
|
+
constructor(opts?: TunnelRegistryOptions);
|
|
121
|
+
/**
|
|
122
|
+
* Start a tunnel for `target` (or reuse an existing one — in-process
|
|
123
|
+
* OR in a sibling process), returning a handle. Caller must pair each
|
|
124
|
+
* acquire with exactly one `release(handle)`.
|
|
125
|
+
*/
|
|
126
|
+
acquire(target: string, opts?: TunnelOptions): Promise<TunnelHandle>;
|
|
127
|
+
/**
|
|
128
|
+
* Release a handle. Decrements refcount (under lock). When the
|
|
129
|
+
* refcount hits zero AND we are the owner, schedule a tear-down
|
|
130
|
+
* `graceMs` later. A subsequent `acquire()` within the grace window
|
|
131
|
+
* cancels the tear-down.
|
|
132
|
+
*
|
|
133
|
+
* Grace window is bounded by owner process lifetime — short-lived
|
|
134
|
+
* commands exit before grace expires and will tear down immediately.
|
|
135
|
+
*/
|
|
136
|
+
release(handle: TunnelHandle): Promise<void>;
|
|
137
|
+
/**
|
|
138
|
+
* Force teardown of a tunnel regardless of refcount. Used by
|
|
139
|
+
* `qa-use tunnel close`. Safe to call when no such tunnel exists.
|
|
140
|
+
*
|
|
141
|
+
* If the owner is this process, tears down the in-memory manager.
|
|
142
|
+
* Otherwise just removes the registry file (and leaves the orphan
|
|
143
|
+
* remote tunnel to die with its owner).
|
|
144
|
+
*/
|
|
145
|
+
forceClose(target: string): Promise<void>;
|
|
146
|
+
/**
|
|
147
|
+
* Look up a single entry by canonical target. Scans the on-disk
|
|
148
|
+
* registry; returns `null` if no record exists or the owning pid is
|
|
149
|
+
* dead.
|
|
150
|
+
*/
|
|
151
|
+
get(target: string): TunnelRecord | null;
|
|
152
|
+
/**
|
|
153
|
+
* List all live entries. Reconciles against owning PID; stale entries
|
|
154
|
+
* are removed as a side-effect.
|
|
155
|
+
*/
|
|
156
|
+
list(): TunnelRecord[];
|
|
157
|
+
/**
|
|
158
|
+
* Returns the live `TunnelManager` instance for `target` IF this process
|
|
159
|
+
* currently owns it. Used by callers that need health-check / WS-URL
|
|
160
|
+
* helpers on the underlying manager. Returns `null` for targets owned
|
|
161
|
+
* by a different process (file visible via `list()` / `get()` but not
|
|
162
|
+
* live in-memory here).
|
|
163
|
+
*/
|
|
164
|
+
getLiveManager(target: string): TunnelManager | null;
|
|
165
|
+
/**
|
|
166
|
+
* Look up by filename hash (e.g. output of `tunnel ls`).
|
|
167
|
+
*/
|
|
168
|
+
getByHash(hash: string): TunnelRecord | null;
|
|
169
|
+
private writeRecord;
|
|
170
|
+
/**
|
|
171
|
+
* Timer callback: re-check under lock whether we should tear down. A
|
|
172
|
+
* concurrent acquire may have bumped refcount back above zero.
|
|
173
|
+
*/
|
|
174
|
+
private maybeTeardown;
|
|
175
|
+
/**
|
|
176
|
+
* Unconditional tear-down. Callers must hold the per-target lock.
|
|
177
|
+
*/
|
|
178
|
+
private teardown;
|
|
179
|
+
}
|
|
180
|
+
/** Module-level singleton for CLI use. */
|
|
181
|
+
export declare const tunnelRegistry: TunnelRegistry;
|
|
182
|
+
//# sourceMappingURL=registry.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"registry.d.ts","sourceRoot":"","sources":["../../../lib/tunnel/registry.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAwCG;AASH,OAAO,EAAE,aAAa,EAAE,KAAK,aAAa,EAAE,MAAM,YAAY,CAAC;AAE/D;;;;;GAKG;AACH,eAAO,MAAM,QAAQ,QAAS,CAAC;AAU/B;;;;GAIG;AACH,eAAO,MAAM,sBAAsB,KAAK,CAAC;AAEzC,2CAA2C;AAC3C,MAAM,WAAW,YAAY;IAC3B,EAAE,EAAE,MAAM,CAAC;IACX,MAAM,EAAE,MAAM,CAAC;IACf,SAAS,EAAE,MAAM,CAAC;IAClB,GAAG,EAAE,MAAM,CAAC;IACZ,QAAQ,EAAE,MAAM,CAAC;IACjB,YAAY,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,SAAS,EAAE,MAAM,CAAC;CACnB;AAED;;;;;GAKG;AACH,MAAM,WAAW,YAAa,SAAQ,YAAY;IAChD;;;;;OAKG;IACH,oBAAoB,EAAE,OAAO,CAAC;IAC9B;;OAEG;IACH,SAAS,CAAC,EAAE,OAAO,CAAC;CACrB;AAED;;;;GAIG;AACH,wBAAgB,eAAe,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAOtD;AAED,gEAAgE;AAChE,wBAAgB,UAAU,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAEjD;AA+GD;;;;GAIG;AACH,MAAM,MAAM,oBAAoB,GAAG,MAAM,aAAa,CAAC;AAEvD,MAAM,WAAW,qBAAqB;IACpC,gCAAgC;IAChC,cAAc,CAAC,EAAE,oBAAoB,CAAC;IACtC,qCAAqC;IACrC,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,wCAAwC;IACxC,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,8DAA8D;IAC9D,aAAa,CAAC,EAAE,aAAa,CAAC;CAC/B;AAED;;;;;GAKG;AACH,qBAAa,cAAc;IACzB,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAgC;IACrD,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAS;IACjC,OAAO,CAAC,QAAQ,CAAC,aAAa,CAAS;IACvC,OAAO,CAAC,QAAQ,CAAC,cAAc,CAAuB;gBAE1C,IAAI,GAAE,qBAA0B;IAM5C;;;;OAIG;IACG,OAAO,CAAC,MAAM,EAAE,MAAM,EAAE,IAAI,GAAE,aAAkB,GAAG,OAAO,CAAC,YAAY,CAAC;IAsH9E;;;;;;;;OAQG;IACG,OAAO,CAAC,MAAM,EAAE,YAAY,GAAG,OAAO,CAAC,IAAI,CAAC;IAsDlD;;;;;;;OAOG;IACG,UAAU,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAS/C;;;;OAIG;IACH,GAAG,CAAC,MAAM,EAAE,MAAM,GAAG,YAAY,GAAG,IAAI;IAaxC;;;OAGG;IACH,IAAI,IAAI,YAAY,EAAE;IA2BtB;;;;;;OAMG;IACH,cAAc,CAAC,MAAM,EAAE,MAAM,GAAG,aAAa,GAAG,IAAI;IAMpD;;OAEG;IACH,SAAS,CAAC,IAAI,EAAE,MAAM,GAAG,YAAY,GAAG,IAAI;IAe5C,OAAO,CAAC,WAAW;IAKnB;;;OAGG;YACW,aAAa;IA0D3B;;OAEG;YACW,QAAQ;CAoBvB;AAED,0CAA0C;AAC1C,eAAO,MAAM,cAAc,gBAAuB,CAAC"}
|