@visual-layer/core 1.0.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.
- package/dist/artifact-store/index.d.ts +70 -0
- package/dist/artifact-store/index.d.ts.map +1 -0
- package/dist/artifact-store/index.js +289 -0
- package/dist/artifact-store/index.js.map +1 -0
- package/dist/browser-adapter.d.ts +1362 -0
- package/dist/browser-adapter.d.ts.map +1 -0
- package/dist/browser-adapter.js +264 -0
- package/dist/browser-adapter.js.map +1 -0
- package/dist/confidence.d.ts +8 -0
- package/dist/confidence.d.ts.map +1 -0
- package/dist/confidence.js +28 -0
- package/dist/confidence.js.map +1 -0
- package/dist/errors.d.ts +41 -0
- package/dist/errors.d.ts.map +1 -0
- package/dist/errors.js +33 -0
- package/dist/errors.js.map +1 -0
- package/dist/geometry/bbox.d.ts +30 -0
- package/dist/geometry/bbox.d.ts.map +1 -0
- package/dist/geometry/bbox.js +77 -0
- package/dist/geometry/bbox.js.map +1 -0
- package/dist/geometry/coordinates.d.ts +26 -0
- package/dist/geometry/coordinates.d.ts.map +1 -0
- package/dist/geometry/coordinates.js +25 -0
- package/dist/geometry/coordinates.js.map +1 -0
- package/dist/geometry/index.d.ts +3 -0
- package/dist/geometry/index.d.ts.map +1 -0
- package/dist/geometry/index.js +3 -0
- package/dist/geometry/index.js.map +1 -0
- package/dist/ids.d.ts +7 -0
- package/dist/ids.d.ts.map +1 -0
- package/dist/ids.js +21 -0
- package/dist/ids.js.map +1 -0
- package/dist/index.d.ts +17 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +17 -0
- package/dist/index.js.map +1 -0
- package/dist/provenance.d.ts +7 -0
- package/dist/provenance.d.ts.map +1 -0
- package/dist/provenance.js +9 -0
- package/dist/provenance.js.map +1 -0
- package/dist/redaction/index.d.ts +28 -0
- package/dist/redaction/index.d.ts.map +1 -0
- package/dist/redaction/index.js +97 -0
- package/dist/redaction/index.js.map +1 -0
- package/dist/schema/index.d.ts +383 -0
- package/dist/schema/index.d.ts.map +1 -0
- package/dist/schema/index.js +96 -0
- package/dist/schema/index.js.map +1 -0
- package/dist/text/index.d.ts +18 -0
- package/dist/text/index.d.ts.map +1 -0
- package/dist/text/index.js +60 -0
- package/dist/text/index.js.map +1 -0
- package/dist/trace/index.d.ts +64 -0
- package/dist/trace/index.d.ts.map +1 -0
- package/dist/trace/index.js +63 -0
- package/dist/trace/index.js.map +1 -0
- package/dist/warnings.d.ts +7 -0
- package/dist/warnings.d.ts.map +1 -0
- package/dist/warnings.js +10 -0
- package/dist/warnings.js.map +1 -0
- package/package.json +33 -0
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
export type ArtifactKind = 'graph' | 'screenshot' | 'figma-render' | 'trace' | 'comparison' | 'crop' | 'eval';
|
|
2
|
+
export interface ArtifactMeta {
|
|
3
|
+
artifactId: string;
|
|
4
|
+
kind: ArtifactKind;
|
|
5
|
+
filename: string;
|
|
6
|
+
mimeType: string;
|
|
7
|
+
sha256?: string;
|
|
8
|
+
byteSize: number;
|
|
9
|
+
createdAt: string;
|
|
10
|
+
runId: string;
|
|
11
|
+
}
|
|
12
|
+
export interface ArtifactStoreOptions {
|
|
13
|
+
root?: string;
|
|
14
|
+
/** Warn when a single artifact exceeds this many bytes. */
|
|
15
|
+
warnBytes?: number;
|
|
16
|
+
/** Hard cap; write throws when exceeded. */
|
|
17
|
+
maxBytes?: number;
|
|
18
|
+
}
|
|
19
|
+
export declare class ArtifactWriteFailedError extends Error {
|
|
20
|
+
readonly operation: string;
|
|
21
|
+
readonly artifactType: ArtifactKind;
|
|
22
|
+
readonly root: string;
|
|
23
|
+
readonly code: "artifact_write_failed";
|
|
24
|
+
constructor(message: string, operation: string, artifactType: ArtifactKind, root: string);
|
|
25
|
+
}
|
|
26
|
+
export declare class ArtifactForbiddenError extends Error {
|
|
27
|
+
readonly code: "artifact_forbidden";
|
|
28
|
+
constructor(message: string);
|
|
29
|
+
}
|
|
30
|
+
export declare class ArtifactStore {
|
|
31
|
+
readonly root: string;
|
|
32
|
+
readonly warnBytes: number;
|
|
33
|
+
readonly maxBytes: number;
|
|
34
|
+
constructor(opts?: ArtifactStoreOptions);
|
|
35
|
+
/** Create (or reuse) a run directory and return its id. */
|
|
36
|
+
ensureRun(runId?: string): Promise<string>;
|
|
37
|
+
runDir(runId: string): string;
|
|
38
|
+
/**
|
|
39
|
+
* Write an artifact. JSON-shaped content is redacted fail-closed before write.
|
|
40
|
+
* Returns metadata (no bytes are returned to the caller).
|
|
41
|
+
*/
|
|
42
|
+
write(runId: string, artifactId: string, kind: ArtifactKind, content: string | Uint8Array, opts?: {
|
|
43
|
+
mimeType?: string;
|
|
44
|
+
filename?: string;
|
|
45
|
+
redactable?: boolean;
|
|
46
|
+
sha256?: string;
|
|
47
|
+
}): Promise<ArtifactMeta>;
|
|
48
|
+
/** Read artifact bytes. Caller is responsible for size. */
|
|
49
|
+
read(runId: string, artifactId: string, filename: string): Promise<Buffer>;
|
|
50
|
+
/** Read an artifact's parsed metadata from the index. */
|
|
51
|
+
index(runId: string): Promise<ArtifactMeta[]>;
|
|
52
|
+
/** Resolve a safe path for an artifact; rejects traversal / absolute / symlink escape. */
|
|
53
|
+
artifactPath(runId: string, artifactId: string, filename: string): string;
|
|
54
|
+
/**
|
|
55
|
+
* Lookup metadata by artifactId only (no filename). Returns first match.
|
|
56
|
+
* Used by get_artifact tool.
|
|
57
|
+
*/
|
|
58
|
+
lookup(runId: string, artifactId: string): Promise<ArtifactMeta | null>;
|
|
59
|
+
/** Best-effort cleanup of runs older than ttlMs or when store exceeds sizeCapBytes. */
|
|
60
|
+
cleanup(opts?: {
|
|
61
|
+
ttlMs?: number;
|
|
62
|
+
sizeCapBytes?: number;
|
|
63
|
+
nowMs?: number;
|
|
64
|
+
}): Promise<{
|
|
65
|
+
removed: string[];
|
|
66
|
+
}>;
|
|
67
|
+
private appendIndex;
|
|
68
|
+
private assertSafeId;
|
|
69
|
+
}
|
|
70
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/artifact-store/index.ts"],"names":[],"mappings":"AAgBA,MAAM,MAAM,YAAY,GACpB,OAAO,GACP,YAAY,GACZ,cAAc,GACd,OAAO,GACP,YAAY,GACZ,MAAM,GACN,MAAM,CAAC;AAEX,MAAM,WAAW,YAAY;IAC3B,UAAU,EAAE,MAAM,CAAC;IACnB,IAAI,EAAE,YAAY,CAAC;IACnB,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,EAAE,MAAM,CAAC;IAClB,KAAK,EAAE,MAAM,CAAC;CACf;AAED,MAAM,WAAW,oBAAoB;IACnC,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,2DAA2D;IAC3D,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,4CAA4C;IAC5C,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAED,qBAAa,wBAAyB,SAAQ,KAAK;IAI/C,QAAQ,CAAC,SAAS,EAAE,MAAM;IAC1B,QAAQ,CAAC,YAAY,EAAE,YAAY;IACnC,QAAQ,CAAC,IAAI,EAAE,MAAM;IALvB,QAAQ,CAAC,IAAI,EAAG,uBAAuB,CAAU;gBAE/C,OAAO,EAAE,MAAM,EACN,SAAS,EAAE,MAAM,EACjB,YAAY,EAAE,YAAY,EAC1B,IAAI,EAAE,MAAM;CAKxB;AAED,qBAAa,sBAAuB,SAAQ,KAAK;IAC/C,QAAQ,CAAC,IAAI,EAAG,oBAAoB,CAAU;gBAClC,OAAO,EAAE,MAAM;CAI5B;AASD,qBAAa,aAAa;IACxB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;gBAEd,IAAI,GAAE,oBAAyB;IAM3C,2DAA2D;IACrD,SAAS,CAAC,KAAK,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;IAMhD,MAAM,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM;IAS7B;;;OAGG;IACG,KAAK,CACT,KAAK,EAAE,MAAM,EACb,UAAU,EAAE,MAAM,EAClB,IAAI,EAAE,YAAY,EAClB,OAAO,EAAE,MAAM,GAAG,UAAU,EAC5B,IAAI,GAAE;QAAE,QAAQ,CAAC,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;QAAC,UAAU,CAAC,EAAE,OAAO,CAAC;QAAC,MAAM,CAAC,EAAE,MAAM,CAAA;KAAO,GACzF,OAAO,CAAC,YAAY,CAAC;IA4ExB,2DAA2D;IACrD,IAAI,CAAC,KAAK,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;IAKhF,yDAAyD;IACnD,KAAK,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,YAAY,EAAE,CAAC;IAUnD,0FAA0F;IAC1F,YAAY,CAAC,KAAK,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,MAAM;IAczE;;;OAGG;IACG,MAAM,CAAC,KAAK,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,YAAY,GAAG,IAAI,CAAC;IAK7E,uFAAuF;IACjF,OAAO,CAAC,IAAI,GAAE;QAAE,KAAK,CAAC,EAAE,MAAM,CAAC;QAAC,YAAY,CAAC,EAAE,MAAM,CAAC;QAAC,KAAK,CAAC,EAAE,MAAM,CAAA;KAAO,GAAG,OAAO,CAAC;QAAE,OAAO,EAAE,MAAM,EAAE,CAAA;KAAE,CAAC;YAoCrG,WAAW;IAUzB,OAAO,CAAC,YAAY;CAKrB"}
|
|
@@ -0,0 +1,289 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Run-scoped artifact store. All graph / screenshot / trace / comparison /
|
|
3
|
+
* crop / eval outputs live under `<root>/<runId>/`.
|
|
4
|
+
*
|
|
5
|
+
* Guarantees (§18.2):
|
|
6
|
+
* - atomic writes (temp file + rename)
|
|
7
|
+
* - typed metadata in per-run index
|
|
8
|
+
* - safe lookup by artifactId (no path traversal / absolute / symlink escape)
|
|
9
|
+
* - size caps + redaction applied to JSON artifacts
|
|
10
|
+
* - cleanup policy (TTL + store size)
|
|
11
|
+
*/
|
|
12
|
+
import { promises as fs } from 'node:fs';
|
|
13
|
+
import path from 'node:path';
|
|
14
|
+
import { randomBytes } from 'node:crypto';
|
|
15
|
+
import { redactJsonFailClosed, redactString, RedactionError } from '../redaction/index.js';
|
|
16
|
+
export class ArtifactWriteFailedError extends Error {
|
|
17
|
+
operation;
|
|
18
|
+
artifactType;
|
|
19
|
+
root;
|
|
20
|
+
code = 'artifact_write_failed';
|
|
21
|
+
constructor(message, operation, artifactType, root) {
|
|
22
|
+
super(message);
|
|
23
|
+
this.operation = operation;
|
|
24
|
+
this.artifactType = artifactType;
|
|
25
|
+
this.root = root;
|
|
26
|
+
this.name = 'ArtifactWriteFailedError';
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
export class ArtifactForbiddenError extends Error {
|
|
30
|
+
code = 'artifact_forbidden';
|
|
31
|
+
constructor(message) {
|
|
32
|
+
super(message);
|
|
33
|
+
this.name = 'ArtifactForbiddenError';
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
const SAFE_ID_RE = /^[a-zA-Z0-9._-]+$/;
|
|
37
|
+
const DEFAULTS = {
|
|
38
|
+
warnBytes: 20 * 1024 * 1024, // 20 MiB
|
|
39
|
+
maxBytes: 100 * 1024 * 1024, // 100 MiB per artifact
|
|
40
|
+
};
|
|
41
|
+
export class ArtifactStore {
|
|
42
|
+
root;
|
|
43
|
+
warnBytes;
|
|
44
|
+
maxBytes;
|
|
45
|
+
constructor(opts = {}) {
|
|
46
|
+
this.root = path.resolve(opts.root ?? '.visual-layer/artifacts');
|
|
47
|
+
this.warnBytes = opts.warnBytes ?? DEFAULTS.warnBytes;
|
|
48
|
+
this.maxBytes = opts.maxBytes ?? DEFAULTS.maxBytes;
|
|
49
|
+
}
|
|
50
|
+
/** Create (or reuse) a run directory and return its id. */
|
|
51
|
+
async ensureRun(runId) {
|
|
52
|
+
const id = runId ?? makeRunId();
|
|
53
|
+
await fs.mkdir(this.runDir(id), { recursive: true });
|
|
54
|
+
return id;
|
|
55
|
+
}
|
|
56
|
+
runDir(runId) {
|
|
57
|
+
this.assertSafeId(runId);
|
|
58
|
+
const dir = path.resolve(this.root, runId);
|
|
59
|
+
if (dir !== this.root && !dir.startsWith(this.root + path.sep)) {
|
|
60
|
+
throw new ArtifactForbiddenError(`run dir escapes root: ${runId}`);
|
|
61
|
+
}
|
|
62
|
+
return dir;
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* Write an artifact. JSON-shaped content is redacted fail-closed before write.
|
|
66
|
+
* Returns metadata (no bytes are returned to the caller).
|
|
67
|
+
*/
|
|
68
|
+
async write(runId, artifactId, kind, content, opts = {}) {
|
|
69
|
+
this.assertSafeId(runId);
|
|
70
|
+
this.assertSafeId(artifactId);
|
|
71
|
+
const redactable = opts.redactable ?? true;
|
|
72
|
+
let bytes;
|
|
73
|
+
if (typeof content === 'string') {
|
|
74
|
+
if (redactable && looksJson(content)) {
|
|
75
|
+
try {
|
|
76
|
+
const parsed = JSON.parse(content);
|
|
77
|
+
const redacted = redactJsonFailClosed(parsed);
|
|
78
|
+
bytes = Buffer.from(JSON.stringify(redacted), 'utf8');
|
|
79
|
+
}
|
|
80
|
+
catch (e) {
|
|
81
|
+
if (e instanceof RedactionError) {
|
|
82
|
+
throw new ArtifactWriteFailedError('redaction failed; sensitive content not persisted', 'write', kind, this.root);
|
|
83
|
+
}
|
|
84
|
+
// looked like JSON but failed to parse: redact at the string level
|
|
85
|
+
// (fail-closed §18.6) rather than persisting raw bytes that may hide a secret
|
|
86
|
+
bytes = Buffer.from(redactString(content).redacted, 'utf8');
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
else {
|
|
90
|
+
// non-JSON string: written as-is (internal callers pass JSON; raw strings
|
|
91
|
+
// are the caller's responsibility — screenshot bytes go through the Uint8Array path)
|
|
92
|
+
bytes = Buffer.from(content, 'utf8');
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
else {
|
|
96
|
+
bytes = content;
|
|
97
|
+
}
|
|
98
|
+
if (bytes.byteLength > this.maxBytes) {
|
|
99
|
+
throw new ArtifactWriteFailedError(`artifact ${artifactId} (${bytes.byteLength}B) exceeds cap ${this.maxBytes}B`, 'write', kind, this.root);
|
|
100
|
+
}
|
|
101
|
+
const filename = opts.filename ?? defaultFilename(artifactId, kind, opts.mimeType);
|
|
102
|
+
const target = this.artifactPath(runId, artifactId, filename);
|
|
103
|
+
await fs.mkdir(path.dirname(target), { recursive: true });
|
|
104
|
+
// atomic: temp file in same dir, then rename
|
|
105
|
+
const tmp = `${target}.tmp-${randomBytes(4).toString('hex')}`;
|
|
106
|
+
try {
|
|
107
|
+
await fs.writeFile(tmp, bytes);
|
|
108
|
+
await fs.rename(tmp, target);
|
|
109
|
+
}
|
|
110
|
+
catch (e) {
|
|
111
|
+
await fs.unlink(tmp).catch(() => undefined);
|
|
112
|
+
throw new ArtifactWriteFailedError(`failed to write ${artifactId}: ${e instanceof Error ? e.message : String(e)}`, 'write', kind, this.root);
|
|
113
|
+
}
|
|
114
|
+
const meta = {
|
|
115
|
+
artifactId,
|
|
116
|
+
kind,
|
|
117
|
+
filename,
|
|
118
|
+
mimeType: opts.mimeType ?? defaultMime(kind),
|
|
119
|
+
sha256: opts.sha256,
|
|
120
|
+
byteSize: bytes.byteLength,
|
|
121
|
+
createdAt: new Date().toISOString(),
|
|
122
|
+
runId,
|
|
123
|
+
};
|
|
124
|
+
await this.appendIndex(runId, meta);
|
|
125
|
+
return meta;
|
|
126
|
+
}
|
|
127
|
+
/** Read artifact bytes. Caller is responsible for size. */
|
|
128
|
+
async read(runId, artifactId, filename) {
|
|
129
|
+
const p = this.artifactPath(runId, artifactId, filename);
|
|
130
|
+
return fs.readFile(p);
|
|
131
|
+
}
|
|
132
|
+
/** Read an artifact's parsed metadata from the index. */
|
|
133
|
+
async index(runId) {
|
|
134
|
+
const idx = path.join(this.runDir(runId), 'index.json');
|
|
135
|
+
try {
|
|
136
|
+
const raw = await fs.readFile(idx, 'utf8');
|
|
137
|
+
return JSON.parse(raw);
|
|
138
|
+
}
|
|
139
|
+
catch {
|
|
140
|
+
return [];
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
/** Resolve a safe path for an artifact; rejects traversal / absolute / symlink escape. */
|
|
144
|
+
artifactPath(runId, artifactId, filename) {
|
|
145
|
+
this.assertSafeId(runId);
|
|
146
|
+
this.assertSafeId(artifactId);
|
|
147
|
+
if (!SAFE_ID_RE.test(filename)) {
|
|
148
|
+
throw new ArtifactForbiddenError(`unsafe filename: ${filename}`);
|
|
149
|
+
}
|
|
150
|
+
const dir = path.join(this.runDir(runId), artifactId);
|
|
151
|
+
const resolved = path.resolve(dir, filename);
|
|
152
|
+
if (resolved !== dir && !resolved.startsWith(dir + path.sep)) {
|
|
153
|
+
throw new ArtifactForbiddenError(`path escape blocked: ${filename}`);
|
|
154
|
+
}
|
|
155
|
+
return resolved;
|
|
156
|
+
}
|
|
157
|
+
/**
|
|
158
|
+
* Lookup metadata by artifactId only (no filename). Returns first match.
|
|
159
|
+
* Used by get_artifact tool.
|
|
160
|
+
*/
|
|
161
|
+
async lookup(runId, artifactId) {
|
|
162
|
+
const idx = await this.index(runId);
|
|
163
|
+
return idx.find((m) => m.artifactId === artifactId) ?? null;
|
|
164
|
+
}
|
|
165
|
+
/** Best-effort cleanup of runs older than ttlMs or when store exceeds sizeCapBytes. */
|
|
166
|
+
async cleanup(opts = {}) {
|
|
167
|
+
const ttlMs = opts.ttlMs ?? 7 * 24 * 60 * 60 * 1000;
|
|
168
|
+
const sizeCapBytes = opts.sizeCapBytes ?? 1024 * 1024 * 1024; // 1 GiB
|
|
169
|
+
const now = opts.nowMs ?? Date.now();
|
|
170
|
+
const removed = [];
|
|
171
|
+
let entries = [];
|
|
172
|
+
try {
|
|
173
|
+
const dirs = await fs.readdir(this.root, { withFileTypes: true });
|
|
174
|
+
for (const d of dirs) {
|
|
175
|
+
if (!d.isDirectory())
|
|
176
|
+
continue;
|
|
177
|
+
try {
|
|
178
|
+
const st = await fs.stat(path.join(this.root, d.name));
|
|
179
|
+
entries.push({ runId: d.name, mtime: st.mtimeMs });
|
|
180
|
+
}
|
|
181
|
+
catch {
|
|
182
|
+
// skip unreadable
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
catch {
|
|
187
|
+
return { removed };
|
|
188
|
+
}
|
|
189
|
+
entries.sort((a, b) => a.mtime - b.mtime);
|
|
190
|
+
let totalSize = 0;
|
|
191
|
+
for (const e of entries)
|
|
192
|
+
totalSize += await runSize(this.root, e.runId).catch(() => 0);
|
|
193
|
+
for (const e of entries) {
|
|
194
|
+
const expired = now - e.mtime > ttlMs;
|
|
195
|
+
const overCap = totalSize > sizeCapBytes;
|
|
196
|
+
if (expired || overCap) {
|
|
197
|
+
await fs.rm(path.join(this.root, e.runId), { recursive: true, force: true }).catch(() => undefined);
|
|
198
|
+
totalSize -= await runSize(this.root, e.runId).catch(() => 0);
|
|
199
|
+
removed.push(e.runId);
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
return { removed };
|
|
203
|
+
}
|
|
204
|
+
async appendIndex(runId, meta) {
|
|
205
|
+
const idx = path.join(this.runDir(runId), 'index.json');
|
|
206
|
+
const existing = await this.index(runId);
|
|
207
|
+
existing.push(meta);
|
|
208
|
+
// unique tmp name avoids clobbering a concurrent append in the same run
|
|
209
|
+
const tmp = `${idx}.tmp-${randomBytes(4).toString('hex')}`;
|
|
210
|
+
await fs.writeFile(tmp, JSON.stringify(existing, null, 2), 'utf8');
|
|
211
|
+
await fs.rename(tmp, idx);
|
|
212
|
+
}
|
|
213
|
+
assertSafeId(id) {
|
|
214
|
+
if (!SAFE_ID_RE.test(id) || /^\.+$/.test(id)) {
|
|
215
|
+
throw new ArtifactForbiddenError(`unsafe id: ${id}`);
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
function makeRunId() {
|
|
220
|
+
const ts = Date.now().toString(36);
|
|
221
|
+
const rand = randomBytes(4).toString('hex');
|
|
222
|
+
return `run_${ts}_${rand}`;
|
|
223
|
+
}
|
|
224
|
+
function defaultFilename(artifactId, kind, mime) {
|
|
225
|
+
switch (kind) {
|
|
226
|
+
case 'graph':
|
|
227
|
+
case 'trace':
|
|
228
|
+
case 'comparison':
|
|
229
|
+
case 'eval':
|
|
230
|
+
return `${kind}.json`;
|
|
231
|
+
case 'screenshot':
|
|
232
|
+
case 'figma-render':
|
|
233
|
+
case 'crop':
|
|
234
|
+
return mime === 'image/jpeg' ? `${kind}.jpg` : `${kind}.png`;
|
|
235
|
+
default:
|
|
236
|
+
return artifactId;
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
function defaultMime(kind) {
|
|
240
|
+
switch (kind) {
|
|
241
|
+
case 'graph':
|
|
242
|
+
case 'trace':
|
|
243
|
+
case 'comparison':
|
|
244
|
+
case 'eval':
|
|
245
|
+
return 'application/json';
|
|
246
|
+
case 'screenshot':
|
|
247
|
+
case 'figma-render':
|
|
248
|
+
case 'crop':
|
|
249
|
+
return 'image/png';
|
|
250
|
+
default:
|
|
251
|
+
return 'application/octet-stream';
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
function looksJson(s) {
|
|
255
|
+
const t = s.trimStart();
|
|
256
|
+
return t.startsWith('{') || t.startsWith('[');
|
|
257
|
+
}
|
|
258
|
+
async function runSize(root, runId) {
|
|
259
|
+
const dir = path.join(root, runId);
|
|
260
|
+
let total = 0;
|
|
261
|
+
const stack = [dir];
|
|
262
|
+
while (stack.length > 0) {
|
|
263
|
+
const cur = stack.pop();
|
|
264
|
+
let dirents;
|
|
265
|
+
try {
|
|
266
|
+
dirents = await fs.readdir(cur, { withFileTypes: true });
|
|
267
|
+
}
|
|
268
|
+
catch {
|
|
269
|
+
continue;
|
|
270
|
+
}
|
|
271
|
+
for (const d of dirents) {
|
|
272
|
+
const full = path.join(cur, d.name);
|
|
273
|
+
if (d.isDirectory()) {
|
|
274
|
+
stack.push(full);
|
|
275
|
+
}
|
|
276
|
+
else {
|
|
277
|
+
try {
|
|
278
|
+
const st = await fs.stat(full);
|
|
279
|
+
total += st.size;
|
|
280
|
+
}
|
|
281
|
+
catch {
|
|
282
|
+
// ignore
|
|
283
|
+
}
|
|
284
|
+
}
|
|
285
|
+
}
|
|
286
|
+
}
|
|
287
|
+
return total;
|
|
288
|
+
}
|
|
289
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/artifact-store/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AACH,OAAO,EAAE,QAAQ,IAAI,EAAE,EAAE,MAAM,SAAS,CAAC;AACzC,OAAO,IAAI,MAAM,WAAW,CAAC;AAC7B,OAAO,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAC1C,OAAO,EAAE,oBAAoB,EAAE,YAAY,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AA8B3F,MAAM,OAAO,wBAAyB,SAAQ,KAAK;IAItC;IACA;IACA;IALF,IAAI,GAAG,uBAAgC,CAAC;IACjD,YACE,OAAe,EACN,SAAiB,EACjB,YAA0B,EAC1B,IAAY;QAErB,KAAK,CAAC,OAAO,CAAC,CAAC;QAJN,cAAS,GAAT,SAAS,CAAQ;QACjB,iBAAY,GAAZ,YAAY,CAAc;QAC1B,SAAI,GAAJ,IAAI,CAAQ;QAGrB,IAAI,CAAC,IAAI,GAAG,0BAA0B,CAAC;IACzC,CAAC;CACF;AAED,MAAM,OAAO,sBAAuB,SAAQ,KAAK;IACtC,IAAI,GAAG,oBAA6B,CAAC;IAC9C,YAAY,OAAe;QACzB,KAAK,CAAC,OAAO,CAAC,CAAC;QACf,IAAI,CAAC,IAAI,GAAG,wBAAwB,CAAC;IACvC,CAAC;CACF;AAED,MAAM,UAAU,GAAG,mBAAmB,CAAC;AAEvC,MAAM,QAAQ,GAAG;IACf,SAAS,EAAE,EAAE,GAAG,IAAI,GAAG,IAAI,EAAE,SAAS;IACtC,QAAQ,EAAE,GAAG,GAAG,IAAI,GAAG,IAAI,EAAE,uBAAuB;CAC5C,CAAC;AAEX,MAAM,OAAO,aAAa;IACf,IAAI,CAAS;IACb,SAAS,CAAS;IAClB,QAAQ,CAAS;IAE1B,YAAY,OAA6B,EAAE;QACzC,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,IAAI,IAAI,yBAAyB,CAAC,CAAC;QACjE,IAAI,CAAC,SAAS,GAAG,IAAI,CAAC,SAAS,IAAI,QAAQ,CAAC,SAAS,CAAC;QACtD,IAAI,CAAC,QAAQ,GAAG,IAAI,CAAC,QAAQ,IAAI,QAAQ,CAAC,QAAQ,CAAC;IACrD,CAAC;IAED,2DAA2D;IAC3D,KAAK,CAAC,SAAS,CAAC,KAAc;QAC5B,MAAM,EAAE,GAAG,KAAK,IAAI,SAAS,EAAE,CAAC;QAChC,MAAM,EAAE,CAAC,KAAK,CAAC,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;QACrD,OAAO,EAAE,CAAC;IACZ,CAAC;IAED,MAAM,CAAC,KAAa;QAClB,IAAI,CAAC,YAAY,CAAC,KAAK,CAAC,CAAC;QACzB,MAAM,GAAG,GAAG,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC;QAC3C,IAAI,GAAG,KAAK,IAAI,CAAC,IAAI,IAAI,CAAC,GAAG,CAAC,UAAU,CAAC,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC;YAC/D,MAAM,IAAI,sBAAsB,CAAC,yBAAyB,KAAK,EAAE,CAAC,CAAC;QACrE,CAAC;QACD,OAAO,GAAG,CAAC;IACb,CAAC;IAED;;;OAGG;IACH,KAAK,CAAC,KAAK,CACT,KAAa,EACb,UAAkB,EAClB,IAAkB,EAClB,OAA4B,EAC5B,OAAwF,EAAE;QAE1F,IAAI,CAAC,YAAY,CAAC,KAAK,CAAC,CAAC;QACzB,IAAI,CAAC,YAAY,CAAC,UAAU,CAAC,CAAC;QAC9B,MAAM,UAAU,GAAG,IAAI,CAAC,UAAU,IAAI,IAAI,CAAC;QAE3C,IAAI,KAAiB,CAAC;QACtB,IAAI,OAAO,OAAO,KAAK,QAAQ,EAAE,CAAC;YAChC,IAAI,UAAU,IAAI,SAAS,CAAC,OAAO,CAAC,EAAE,CAAC;gBACrC,IAAI,CAAC;oBACH,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,OAAO,CAAY,CAAC;oBAC9C,MAAM,QAAQ,GAAG,oBAAoB,CAAC,MAAM,CAAC,CAAC;oBAC9C,KAAK,GAAG,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,SAAS,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAC,CAAC;gBACxD,CAAC;gBAAC,OAAO,CAAC,EAAE,CAAC;oBACX,IAAI,CAAC,YAAY,cAAc,EAAE,CAAC;wBAChC,MAAM,IAAI,wBAAwB,CAChC,mDAAmD,EACnD,OAAO,EACP,IAAI,EACJ,IAAI,CAAC,IAAI,CACV,CAAC;oBACJ,CAAC;oBACD,mEAAmE;oBACnE,8EAA8E;oBAC9E,KAAK,GAAG,MAAM,CAAC,IAAI,CAAC,YAAY,CAAC,OAAO,CAAC,CAAC,QAAQ,EAAE,MAAM,CAAC,CAAC;gBAC9D,CAAC;YACH,CAAC;iBAAM,CAAC;gBACN,0EAA0E;gBAC1E,qFAAqF;gBACrF,KAAK,GAAG,MAAM,CAAC,IAAI,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC;YACvC,CAAC;QACH,CAAC;aAAM,CAAC;YACN,KAAK,GAAG,OAAO,CAAC;QAClB,CAAC;QAED,IAAI,KAAK,CAAC,UAAU,GAAG,IAAI,CAAC,QAAQ,EAAE,CAAC;YACrC,MAAM,IAAI,wBAAwB,CAChC,YAAY,UAAU,KAAK,KAAK,CAAC,UAAU,kBAAkB,IAAI,CAAC,QAAQ,GAAG,EAC7E,OAAO,EACP,IAAI,EACJ,IAAI,CAAC,IAAI,CACV,CAAC;QACJ,CAAC;QAED,MAAM,QAAQ,GAAG,IAAI,CAAC,QAAQ,IAAI,eAAe,CAAC,UAAU,EAAE,IAAI,EAAE,IAAI,CAAC,QAAQ,CAAC,CAAC;QACnF,MAAM,MAAM,GAAG,IAAI,CAAC,YAAY,CAAC,KAAK,EAAE,UAAU,EAAE,QAAQ,CAAC,CAAC;QAC9D,MAAM,EAAE,CAAC,KAAK,CAAC,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;QAE1D,6CAA6C;QAC7C,MAAM,GAAG,GAAG,GAAG,MAAM,QAAQ,WAAW,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,EAAE,CAAC;QAC9D,IAAI,CAAC;YACH,MAAM,EAAE,CAAC,SAAS,CAAC,GAAG,EAAE,KAAK,CAAC,CAAC;YAC/B,MAAM,EAAE,CAAC,MAAM,CAAC,GAAG,EAAE,MAAM,CAAC,CAAC;QAC/B,CAAC;QAAC,OAAO,CAAC,EAAE,CAAC;YACX,MAAM,EAAE,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,SAAS,CAAC,CAAC;YAC5C,MAAM,IAAI,wBAAwB,CAChC,mBAAmB,UAAU,KAAK,CAAC,YAAY,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAC9E,OAAO,EACP,IAAI,EACJ,IAAI,CAAC,IAAI,CACV,CAAC;QACJ,CAAC;QAED,MAAM,IAAI,GAAiB;YACzB,UAAU;YACV,IAAI;YACJ,QAAQ;YACR,QAAQ,EAAE,IAAI,CAAC,QAAQ,IAAI,WAAW,CAAC,IAAI,CAAC;YAC5C,MAAM,EAAE,IAAI,CAAC,MAAM;YACnB,QAAQ,EAAE,KAAK,CAAC,UAAU;YAC1B,SAAS,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;YACnC,KAAK;SACN,CAAC;QACF,MAAM,IAAI,CAAC,WAAW,CAAC,KAAK,EAAE,IAAI,CAAC,CAAC;QACpC,OAAO,IAAI,CAAC;IACd,CAAC;IAED,2DAA2D;IAC3D,KAAK,CAAC,IAAI,CAAC,KAAa,EAAE,UAAkB,EAAE,QAAgB;QAC5D,MAAM,CAAC,GAAG,IAAI,CAAC,YAAY,CAAC,KAAK,EAAE,UAAU,EAAE,QAAQ,CAAC,CAAC;QACzD,OAAO,EAAE,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC;IACxB,CAAC;IAED,yDAAyD;IACzD,KAAK,CAAC,KAAK,CAAC,KAAa;QACvB,MAAM,GAAG,GAAG,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE,YAAY,CAAC,CAAC;QACxD,IAAI,CAAC;YACH,MAAM,GAAG,GAAG,MAAM,EAAE,CAAC,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC,CAAC;YAC3C,OAAO,IAAI,CAAC,KAAK,CAAC,GAAG,CAAmB,CAAC;QAC3C,CAAC;QAAC,MAAM,CAAC;YACP,OAAO,EAAE,CAAC;QACZ,CAAC;IACH,CAAC;IAED,0FAA0F;IAC1F,YAAY,CAAC,KAAa,EAAE,UAAkB,EAAE,QAAgB;QAC9D,IAAI,CAAC,YAAY,CAAC,KAAK,CAAC,CAAC;QACzB,IAAI,CAAC,YAAY,CAAC,UAAU,CAAC,CAAC;QAC9B,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,QAAQ,CAAC,EAAE,CAAC;YAC/B,MAAM,IAAI,sBAAsB,CAAC,oBAAoB,QAAQ,EAAE,CAAC,CAAC;QACnE,CAAC;QACD,MAAM,GAAG,GAAG,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE,UAAU,CAAC,CAAC;QACtD,MAAM,QAAQ,GAAG,IAAI,CAAC,OAAO,CAAC,GAAG,EAAE,QAAQ,CAAC,CAAC;QAC7C,IAAI,QAAQ,KAAK,GAAG,IAAI,CAAC,QAAQ,CAAC,UAAU,CAAC,GAAG,GAAG,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC;YAC7D,MAAM,IAAI,sBAAsB,CAAC,wBAAwB,QAAQ,EAAE,CAAC,CAAC;QACvE,CAAC;QACD,OAAO,QAAQ,CAAC;IAClB,CAAC;IAED;;;OAGG;IACH,KAAK,CAAC,MAAM,CAAC,KAAa,EAAE,UAAkB;QAC5C,MAAM,GAAG,GAAG,MAAM,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC;QACpC,OAAO,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,UAAU,KAAK,UAAU,CAAC,IAAI,IAAI,CAAC;IAC9D,CAAC;IAED,uFAAuF;IACvF,KAAK,CAAC,OAAO,CAAC,OAAkE,EAAE;QAChF,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,IAAI,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,IAAI,CAAC;QACpD,MAAM,YAAY,GAAG,IAAI,CAAC,YAAY,IAAI,IAAI,GAAG,IAAI,GAAG,IAAI,CAAC,CAAC,QAAQ;QACtE,MAAM,GAAG,GAAG,IAAI,CAAC,KAAK,IAAI,IAAI,CAAC,GAAG,EAAE,CAAC;QACrC,MAAM,OAAO,GAAa,EAAE,CAAC;QAC7B,IAAI,OAAO,GAAuC,EAAE,CAAC;QACrD,IAAI,CAAC;YACH,MAAM,IAAI,GAAG,MAAM,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC,IAAI,EAAE,EAAE,aAAa,EAAE,IAAI,EAAE,CAAC,CAAC;YAClE,KAAK,MAAM,CAAC,IAAI,IAAI,EAAE,CAAC;gBACrB,IAAI,CAAC,CAAC,CAAC,WAAW,EAAE;oBAAE,SAAS;gBAC/B,IAAI,CAAC;oBACH,MAAM,EAAE,GAAG,MAAM,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC;oBACvD,OAAO,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,CAAC,CAAC,IAAI,EAAE,KAAK,EAAE,EAAE,CAAC,OAAO,EAAE,CAAC,CAAC;gBACrD,CAAC;gBAAC,MAAM,CAAC;oBACP,kBAAkB;gBACpB,CAAC;YACH,CAAC;QACH,CAAC;QAAC,MAAM,CAAC;YACP,OAAO,EAAE,OAAO,EAAE,CAAC;QACrB,CAAC;QACD,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,KAAK,GAAG,CAAC,CAAC,KAAK,CAAC,CAAC;QAC1C,IAAI,SAAS,GAAG,CAAC,CAAC;QAClB,KAAK,MAAM,CAAC,IAAI,OAAO;YAAE,SAAS,IAAI,MAAM,OAAO,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC,CAAC;QAEvF,KAAK,MAAM,CAAC,IAAI,OAAO,EAAE,CAAC;YACxB,MAAM,OAAO,GAAG,GAAG,GAAG,CAAC,CAAC,KAAK,GAAG,KAAK,CAAC;YACtC,MAAM,OAAO,GAAG,SAAS,GAAG,YAAY,CAAC;YACzC,IAAI,OAAO,IAAI,OAAO,EAAE,CAAC;gBACvB,MAAM,EAAE,CAAC,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC,CAAC,KAAK,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,SAAS,CAAC,CAAC;gBACpG,SAAS,IAAI,MAAM,OAAO,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC,CAAC;gBAC9D,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC;YACxB,CAAC;QACH,CAAC;QACD,OAAO,EAAE,OAAO,EAAE,CAAC;IACrB,CAAC;IAEO,KAAK,CAAC,WAAW,CAAC,KAAa,EAAE,IAAkB;QACzD,MAAM,GAAG,GAAG,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE,YAAY,CAAC,CAAC;QACxD,MAAM,QAAQ,GAAG,MAAM,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC;QACzC,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QACpB,wEAAwE;QACxE,MAAM,GAAG,GAAG,GAAG,GAAG,QAAQ,WAAW,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,EAAE,CAAC;QAC3D,MAAM,EAAE,CAAC,SAAS,CAAC,GAAG,EAAE,IAAI,CAAC,SAAS,CAAC,QAAQ,EAAE,IAAI,EAAE,CAAC,CAAC,EAAE,MAAM,CAAC,CAAC;QACnE,MAAM,EAAE,CAAC,MAAM,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC;IAC5B,CAAC;IAEO,YAAY,CAAC,EAAU;QAC7B,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,EAAE,CAAC,IAAI,OAAO,CAAC,IAAI,CAAC,EAAE,CAAC,EAAE,CAAC;YAC7C,MAAM,IAAI,sBAAsB,CAAC,cAAc,EAAE,EAAE,CAAC,CAAC;QACvD,CAAC;IACH,CAAC;CACF;AAED,SAAS,SAAS;IAChB,MAAM,EAAE,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC;IACnC,MAAM,IAAI,GAAG,WAAW,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC;IAC5C,OAAO,OAAO,EAAE,IAAI,IAAI,EAAE,CAAC;AAC7B,CAAC;AAED,SAAS,eAAe,CAAC,UAAkB,EAAE,IAAkB,EAAE,IAAa;IAC5E,QAAQ,IAAI,EAAE,CAAC;QACb,KAAK,OAAO,CAAC;QACb,KAAK,OAAO,CAAC;QACb,KAAK,YAAY,CAAC;QAClB,KAAK,MAAM;YACT,OAAO,GAAG,IAAI,OAAO,CAAC;QACxB,KAAK,YAAY,CAAC;QAClB,KAAK,cAAc,CAAC;QACpB,KAAK,MAAM;YACT,OAAO,IAAI,KAAK,YAAY,CAAC,CAAC,CAAC,GAAG,IAAI,MAAM,CAAC,CAAC,CAAC,GAAG,IAAI,MAAM,CAAC;QAC/D;YACE,OAAO,UAAU,CAAC;IACtB,CAAC;AACH,CAAC;AAED,SAAS,WAAW,CAAC,IAAkB;IACrC,QAAQ,IAAI,EAAE,CAAC;QACb,KAAK,OAAO,CAAC;QACb,KAAK,OAAO,CAAC;QACb,KAAK,YAAY,CAAC;QAClB,KAAK,MAAM;YACT,OAAO,kBAAkB,CAAC;QAC5B,KAAK,YAAY,CAAC;QAClB,KAAK,cAAc,CAAC;QACpB,KAAK,MAAM;YACT,OAAO,WAAW,CAAC;QACrB;YACE,OAAO,0BAA0B,CAAC;IACtC,CAAC;AACH,CAAC;AAED,SAAS,SAAS,CAAC,CAAS;IAC1B,MAAM,CAAC,GAAG,CAAC,CAAC,SAAS,EAAE,CAAC;IACxB,OAAO,CAAC,CAAC,UAAU,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC;AAChD,CAAC;AAED,KAAK,UAAU,OAAO,CAAC,IAAY,EAAE,KAAa;IAChD,MAAM,GAAG,GAAG,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC;IACnC,IAAI,KAAK,GAAG,CAAC,CAAC;IACd,MAAM,KAAK,GAAG,CAAC,GAAG,CAAC,CAAC;IACpB,OAAO,KAAK,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QACxB,MAAM,GAAG,GAAG,KAAK,CAAC,GAAG,EAAG,CAAC;QACzB,IAAI,OAAmC,CAAC;QACxC,IAAI,CAAC;YACH,OAAO,GAAG,MAAM,EAAE,CAAC,OAAO,CAAC,GAAG,EAAE,EAAE,aAAa,EAAE,IAAI,EAAE,CAAC,CAAC;QAC3D,CAAC;QAAC,MAAM,CAAC;YACP,SAAS;QACX,CAAC;QACD,KAAK,MAAM,CAAC,IAAI,OAAO,EAAE,CAAC;YACxB,MAAM,IAAI,GAAG,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC;YACpC,IAAI,CAAC,CAAC,WAAW,EAAE,EAAE,CAAC;gBACpB,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;YACnB,CAAC;iBAAM,CAAC;gBACN,IAAI,CAAC;oBACH,MAAM,EAAE,GAAG,MAAM,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;oBAC/B,KAAK,IAAI,EAAE,CAAC,IAAI,CAAC;gBACnB,CAAC;gBAAC,MAAM,CAAC;oBACP,SAAS;gBACX,CAAC;YACH,CAAC;QACH,CAAC;IACH,CAAC;IACD,OAAO,KAAK,CAAC;AACf,CAAC"}
|