swagger-parser-mcp-server 2.0.4 → 2.3.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/README.md +131 -100
- package/dist/application/snapshot/createSnapshotRuntime.d.ts +2 -0
- package/dist/application/snapshot/createSnapshotRuntime.d.ts.map +1 -0
- package/dist/application/snapshot/createSnapshotRuntime.js +2 -0
- package/dist/application/snapshot/createSnapshotRuntime.js.map +1 -0
- package/dist/application/snapshot/snapshotCaptureService.d.ts +90 -0
- package/dist/application/snapshot/snapshotCaptureService.d.ts.map +1 -0
- package/dist/application/snapshot/snapshotCaptureService.js +394 -0
- package/dist/application/snapshot/snapshotCaptureService.js.map +1 -0
- package/dist/application/snapshot/snapshotRepository.d.ts +77 -0
- package/dist/application/snapshot/snapshotRepository.d.ts.map +1 -0
- package/dist/application/snapshot/snapshotRepository.js +2 -0
- package/dist/application/snapshot/snapshotRepository.js.map +1 -0
- package/dist/domain/canonical/canonicalSnapshot.d.ts +61 -0
- package/dist/domain/canonical/canonicalSnapshot.d.ts.map +1 -0
- package/dist/domain/canonical/canonicalSnapshot.js +300 -0
- package/dist/domain/canonical/canonicalSnapshot.js.map +1 -0
- package/dist/domain/contracts/runtimeEnvironmentContract.d.ts +21 -0
- package/dist/domain/contracts/runtimeEnvironmentContract.d.ts.map +1 -0
- package/dist/domain/contracts/runtimeEnvironmentContract.js +50 -0
- package/dist/domain/contracts/runtimeEnvironmentContract.js.map +1 -0
- package/dist/domain/contracts/snapshotDiffContract.d.ts +270 -0
- package/dist/domain/contracts/snapshotDiffContract.d.ts.map +1 -0
- package/dist/domain/contracts/snapshotDiffContract.js +99 -0
- package/dist/domain/contracts/snapshotDiffContract.js.map +1 -0
- package/dist/domain/diff/endpointDiffClassifier.d.ts +78 -0
- package/dist/domain/diff/endpointDiffClassifier.d.ts.map +1 -0
- package/dist/domain/diff/endpointDiffClassifier.js +317 -0
- package/dist/domain/diff/endpointDiffClassifier.js.map +1 -0
- package/dist/http.d.ts +3 -0
- package/dist/http.d.ts.map +1 -0
- package/dist/http.js +52 -0
- package/dist/http.js.map +1 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +88 -266
- package/dist/index.js.map +1 -1
- package/dist/infrastructure/postgres/migrationRunner.d.ts +14 -0
- package/dist/infrastructure/postgres/migrationRunner.d.ts.map +1 -0
- package/dist/infrastructure/postgres/migrationRunner.js +161 -0
- package/dist/infrastructure/postgres/migrationRunner.js.map +1 -0
- package/dist/infrastructure/postgres/migrations/001_snapshot_schema.sql +29 -0
- package/dist/infrastructure/postgres/migrations/002_snapshot_change_history.sql +32 -0
- package/dist/infrastructure/postgres/postgresSnapshotRepository.d.ts +25 -0
- package/dist/infrastructure/postgres/postgresSnapshotRepository.d.ts.map +1 -0
- package/dist/infrastructure/postgres/postgresSnapshotRepository.js +323 -0
- package/dist/infrastructure/postgres/postgresSnapshotRepository.js.map +1 -0
- package/dist/infrastructure/postgres/runMigrations.d.ts +3 -0
- package/dist/infrastructure/postgres/runMigrations.d.ts.map +1 -0
- package/dist/infrastructure/postgres/runMigrations.js +33 -0
- package/dist/infrastructure/postgres/runMigrations.js.map +1 -0
- package/dist/infrastructure/runtime/createSnapshotRuntime.d.ts +17 -0
- package/dist/infrastructure/runtime/createSnapshotRuntime.d.ts.map +1 -0
- package/dist/infrastructure/runtime/createSnapshotRuntime.js +38 -0
- package/dist/infrastructure/runtime/createSnapshotRuntime.js.map +1 -0
- package/dist/schemas.d.ts +284 -3
- package/dist/schemas.d.ts.map +1 -1
- package/dist/schemas.js +110 -1
- package/dist/schemas.js.map +1 -1
- package/dist/tests/canonicalSnapshot.test.d.ts +2 -0
- package/dist/tests/canonicalSnapshot.test.d.ts.map +1 -0
- package/dist/tests/canonicalSnapshot.test.js +425 -0
- package/dist/tests/canonicalSnapshot.test.js.map +1 -0
- package/dist/tests/endpointDiffClassifier.test.d.ts +2 -0
- package/dist/tests/endpointDiffClassifier.test.d.ts.map +1 -0
- package/dist/tests/endpointDiffClassifier.test.js +633 -0
- package/dist/tests/endpointDiffClassifier.test.js.map +1 -0
- package/dist/tests/httpSnapshotTransport.test.d.ts +2 -0
- package/dist/tests/httpSnapshotTransport.test.d.ts.map +1 -0
- package/dist/tests/httpSnapshotTransport.test.js +356 -0
- package/dist/tests/httpSnapshotTransport.test.js.map +1 -0
- package/dist/tests/indexLifecycle.test.d.ts +2 -0
- package/dist/tests/indexLifecycle.test.d.ts.map +1 -0
- package/dist/tests/indexLifecycle.test.js +23 -0
- package/dist/tests/indexLifecycle.test.js.map +1 -0
- package/dist/tests/mcpSnapshotTools.test.d.ts +2 -0
- package/dist/tests/mcpSnapshotTools.test.d.ts.map +1 -0
- package/dist/tests/mcpSnapshotTools.test.js +316 -0
- package/dist/tests/mcpSnapshotTools.test.js.map +1 -0
- package/dist/tests/postgresMigrationSmoke.test.d.ts +2 -0
- package/dist/tests/postgresMigrationSmoke.test.d.ts.map +1 -0
- package/dist/tests/postgresMigrationSmoke.test.js +187 -0
- package/dist/tests/postgresMigrationSmoke.test.js.map +1 -0
- package/dist/tests/realPostgresTestSchema.d.ts +10 -0
- package/dist/tests/realPostgresTestSchema.d.ts.map +1 -0
- package/dist/tests/realPostgresTestSchema.js +73 -0
- package/dist/tests/realPostgresTestSchema.js.map +1 -0
- package/dist/tests/snapshotCapturePipeline.test.d.ts +2 -0
- package/dist/tests/snapshotCapturePipeline.test.d.ts.map +1 -0
- package/dist/tests/snapshotCapturePipeline.test.js +475 -0
- package/dist/tests/snapshotCapturePipeline.test.js.map +1 -0
- package/dist/tests/snapshotDiffContract.test.d.ts +2 -0
- package/dist/tests/snapshotDiffContract.test.d.ts.map +1 -0
- package/dist/tests/snapshotDiffContract.test.js +156 -0
- package/dist/tests/snapshotDiffContract.test.js.map +1 -0
- package/dist/tests/snapshotPersistence.real.test.d.ts +2 -0
- package/dist/tests/snapshotPersistence.real.test.d.ts.map +1 -0
- package/dist/tests/snapshotPersistence.real.test.js +310 -0
- package/dist/tests/snapshotPersistence.real.test.js.map +1 -0
- package/dist/tests/webServerRuntime.test.d.ts +2 -0
- package/dist/tests/webServerRuntime.test.d.ts.map +1 -0
- package/dist/tests/webServerRuntime.test.js +123 -0
- package/dist/tests/webServerRuntime.test.js.map +1 -0
- package/dist/transport/createSnapshotToolRuntime.d.ts +7 -0
- package/dist/transport/createSnapshotToolRuntime.d.ts.map +1 -0
- package/dist/transport/createSnapshotToolRuntime.js +40 -0
- package/dist/transport/createSnapshotToolRuntime.js.map +1 -0
- package/dist/transport/httpSnapshotServer.d.ts +11 -0
- package/dist/transport/httpSnapshotServer.d.ts.map +1 -0
- package/dist/transport/httpSnapshotServer.js +216 -0
- package/dist/transport/httpSnapshotServer.js.map +1 -0
- package/dist/transport/mcpToolRouter.d.ts +81 -0
- package/dist/transport/mcpToolRouter.d.ts.map +1 -0
- package/dist/transport/mcpToolRouter.js +416 -0
- package/dist/transport/mcpToolRouter.js.map +1 -0
- package/dist/transport/webServerRuntime.d.ts +17 -0
- package/dist/transport/webServerRuntime.d.ts.map +1 -0
- package/dist/transport/webServerRuntime.js +73 -0
- package/dist/transport/webServerRuntime.js.map +1 -0
- package/dist/utils/swaggerCache.d.ts +4 -0
- package/dist/utils/swaggerCache.d.ts.map +1 -1
- package/dist/utils/swaggerCache.js +8 -0
- package/dist/utils/swaggerCache.js.map +1 -1
- package/dist/utils/types.d.ts +2 -1
- package/dist/utils/types.d.ts.map +1 -1
- package/dist/utils/types.js +2 -0
- package/dist/utils/types.js.map +1 -1
- package/dist/web/dashboard.css +411 -0
- package/dist/web/dashboard.html +141 -0
- package/dist/web/dashboard.js +540 -0
- package/package.json +27 -17
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
CREATE TABLE IF NOT EXISTS snapshot_transitions (
|
|
2
|
+
id BIGSERIAL PRIMARY KEY,
|
|
3
|
+
source_id BIGINT NOT NULL REFERENCES sources(id) ON DELETE CASCADE,
|
|
4
|
+
baseline_snapshot_id BIGINT NOT NULL REFERENCES snapshots(id) ON DELETE CASCADE,
|
|
5
|
+
target_snapshot_id BIGINT NOT NULL UNIQUE REFERENCES snapshots(id) ON DELETE CASCADE,
|
|
6
|
+
captured_at TIMESTAMPTZ NOT NULL,
|
|
7
|
+
counts JSONB NOT NULL,
|
|
8
|
+
warnings JSONB NOT NULL
|
|
9
|
+
);
|
|
10
|
+
|
|
11
|
+
CREATE INDEX IF NOT EXISTS idx_snapshot_transitions_source_captured_desc
|
|
12
|
+
ON snapshot_transitions (source_id, captured_at DESC, id DESC);
|
|
13
|
+
|
|
14
|
+
CREATE TABLE IF NOT EXISTS endpoint_change_history (
|
|
15
|
+
id BIGSERIAL PRIMARY KEY,
|
|
16
|
+
transition_id BIGINT NOT NULL REFERENCES snapshot_transitions(id) ON DELETE CASCADE,
|
|
17
|
+
source_id BIGINT NOT NULL REFERENCES sources(id) ON DELETE CASCADE,
|
|
18
|
+
path TEXT NOT NULL,
|
|
19
|
+
method TEXT NOT NULL,
|
|
20
|
+
classification TEXT NOT NULL,
|
|
21
|
+
change_reason TEXT NOT NULL,
|
|
22
|
+
baseline_snapshot_id BIGINT NOT NULL REFERENCES snapshots(id) ON DELETE CASCADE,
|
|
23
|
+
target_snapshot_id BIGINT NOT NULL REFERENCES snapshots(id) ON DELETE CASCADE,
|
|
24
|
+
changed_at TIMESTAMPTZ NOT NULL,
|
|
25
|
+
UNIQUE (transition_id, path, method)
|
|
26
|
+
);
|
|
27
|
+
|
|
28
|
+
CREATE INDEX IF NOT EXISTS idx_endpoint_change_history_source_changed_desc
|
|
29
|
+
ON endpoint_change_history (source_id, changed_at DESC, id DESC);
|
|
30
|
+
|
|
31
|
+
CREATE INDEX IF NOT EXISTS idx_endpoint_change_history_source_path_method_changed_desc
|
|
32
|
+
ON endpoint_change_history (source_id, path, method, changed_at DESC, id DESC);
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import type { Pool, PoolClient } from 'pg';
|
|
2
|
+
import { EndpointChangeHistoryRecord, ListEndpointChangeHistoryInput, SaveSnapshotInput, SaveSnapshotResult, SnapshotProjectRecord, SnapshotRecord, SnapshotRepository, SnapshotSourceIdentityRecord, SnapshotSourceRecord } from '../../application/snapshot/snapshotRepository.js';
|
|
3
|
+
import { MigrationRunOptions } from './migrationRunner.js';
|
|
4
|
+
type Queryable = Pick<Pool, 'query'> | Pick<Pool, 'query' | 'connect'> | Pick<PoolClient, 'query'>;
|
|
5
|
+
interface PostgresSnapshotRepositoryOptions {
|
|
6
|
+
migrationRunOptions?: MigrationRunOptions;
|
|
7
|
+
}
|
|
8
|
+
export declare class PostgresSnapshotRepository implements SnapshotRepository {
|
|
9
|
+
private readonly db;
|
|
10
|
+
private readonly options;
|
|
11
|
+
constructor(db: Queryable, options?: PostgresSnapshotRepositoryOptions);
|
|
12
|
+
initializeSchema(): Promise<void>;
|
|
13
|
+
ensureProject(projectKey: string): Promise<SnapshotProjectRecord>;
|
|
14
|
+
ensureSource(projectId: string, swaggerUrl: string): Promise<SnapshotSourceRecord>;
|
|
15
|
+
getSourceIdentityById(sourceId: string): Promise<SnapshotSourceIdentityRecord | null>;
|
|
16
|
+
getLatestSnapshot(sourceId: string): Promise<SnapshotRecord | null>;
|
|
17
|
+
private acquireTransactionSession;
|
|
18
|
+
private insertSnapshotTransition;
|
|
19
|
+
saveSnapshot(input: SaveSnapshotInput): Promise<SaveSnapshotResult>;
|
|
20
|
+
getSnapshotById(snapshotId: string): Promise<SnapshotRecord | null>;
|
|
21
|
+
listSnapshotsBySource(sourceId: string, limit?: number): Promise<SnapshotRecord[]>;
|
|
22
|
+
listEndpointChangeHistory(input: ListEndpointChangeHistoryInput): Promise<EndpointChangeHistoryRecord[]>;
|
|
23
|
+
}
|
|
24
|
+
export {};
|
|
25
|
+
//# sourceMappingURL=postgresSnapshotRepository.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"postgresSnapshotRepository.d.ts","sourceRoot":"","sources":["../../../src/infrastructure/postgres/postgresSnapshotRepository.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAE,UAAU,EAAE,MAAM,IAAI,CAAC;AAC3C,OAAO,EACL,2BAA2B,EAC3B,8BAA8B,EAE9B,iBAAiB,EACjB,kBAAkB,EAClB,qBAAqB,EACrB,cAAc,EACd,kBAAkB,EAClB,4BAA4B,EAC5B,oBAAoB,EACrB,MAAM,kDAAkD,CAAC;AAE1D,OAAO,EAAE,mBAAmB,EAAyB,MAAM,sBAAsB,CAAC;AAElF,KAAK,SAAS,GAAG,IAAI,CAAC,IAAI,EAAE,OAAO,CAAC,GAAG,IAAI,CAAC,IAAI,EAAE,OAAO,GAAG,SAAS,CAAC,GAAG,IAAI,CAAC,UAAU,EAAE,OAAO,CAAC,CAAC;AAGnG,UAAU,iCAAiC;IACzC,mBAAmB,CAAC,EAAE,mBAAmB,CAAC;CAC3C;AAyKD,qBAAa,0BAA2B,YAAW,kBAAkB;IAEjE,OAAO,CAAC,QAAQ,CAAC,EAAE;IACnB,OAAO,CAAC,QAAQ,CAAC,OAAO;gBADP,EAAE,EAAE,SAAS,EACb,OAAO,GAAE,iCAAsC;IAG5D,gBAAgB,IAAI,OAAO,CAAC,IAAI,CAAC;IAIjC,aAAa,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,qBAAqB,CAAC;IAejE,YAAY,CAAC,SAAS,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,oBAAoB,CAAC;IAelF,qBAAqB,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,4BAA4B,GAAG,IAAI,CAAC;IAuBrF,iBAAiB,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,cAAc,GAAG,IAAI,CAAC;YAmB3D,yBAAyB;YAQzB,wBAAwB;IAuEhC,YAAY,CAAC,KAAK,EAAE,iBAAiB,GAAG,OAAO,CAAC,kBAAkB,CAAC;IAmEnE,eAAe,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,cAAc,GAAG,IAAI,CAAC;IAkBnE,qBAAqB,CAAC,QAAQ,EAAE,MAAM,EAAE,KAAK,SAAK,GAAG,OAAO,CAAC,cAAc,EAAE,CAAC;IAgB9E,yBAAyB,CAAC,KAAK,EAAE,8BAA8B,GAAG,OAAO,CAAC,2BAA2B,EAAE,CAAC;CA+B/G"}
|
|
@@ -0,0 +1,323 @@
|
|
|
1
|
+
import { runPostgresMigrations } from './migrationRunner.js';
|
|
2
|
+
function toIsoTimestamp(value) {
|
|
3
|
+
if (value instanceof Date) {
|
|
4
|
+
return value.toISOString();
|
|
5
|
+
}
|
|
6
|
+
return new Date(value).toISOString();
|
|
7
|
+
}
|
|
8
|
+
function isRecord(value) {
|
|
9
|
+
return value !== null && typeof value === 'object' && !Array.isArray(value);
|
|
10
|
+
}
|
|
11
|
+
function requireString(value, fieldName) {
|
|
12
|
+
if (typeof value !== 'string' || value.length === 0) {
|
|
13
|
+
throw new Error(`Invalid repository row: ${fieldName} must be a non-empty string.`);
|
|
14
|
+
}
|
|
15
|
+
return value;
|
|
16
|
+
}
|
|
17
|
+
function requireId(value, fieldName) {
|
|
18
|
+
if (typeof value !== 'string' && typeof value !== 'number') {
|
|
19
|
+
throw new Error(`Invalid repository row: ${fieldName} must be string or number.`);
|
|
20
|
+
}
|
|
21
|
+
return String(value);
|
|
22
|
+
}
|
|
23
|
+
function requireTimestamp(value, fieldName) {
|
|
24
|
+
if (typeof value !== 'string' && !(value instanceof Date)) {
|
|
25
|
+
throw new Error(`Invalid repository row: ${fieldName} must be a timestamp.`);
|
|
26
|
+
}
|
|
27
|
+
return toIsoTimestamp(value);
|
|
28
|
+
}
|
|
29
|
+
function requireSingleRow(rows, context) {
|
|
30
|
+
if (rows.length === 0) {
|
|
31
|
+
throw new Error(`Repository query returned no rows for ${context}.`);
|
|
32
|
+
}
|
|
33
|
+
return rows[0];
|
|
34
|
+
}
|
|
35
|
+
function parseCanonicalSnapshot(raw) {
|
|
36
|
+
let parsed = raw;
|
|
37
|
+
if (typeof raw === 'string') {
|
|
38
|
+
try {
|
|
39
|
+
parsed = JSON.parse(raw);
|
|
40
|
+
}
|
|
41
|
+
catch {
|
|
42
|
+
throw new Error('Invalid repository row: canonical_snapshot is not valid JSON.');
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
if (!isRecord(parsed)) {
|
|
46
|
+
throw new Error('Invalid repository row: canonical_snapshot must be an object.');
|
|
47
|
+
}
|
|
48
|
+
if (typeof parsed.sourceUrl !== 'string' || typeof parsed.documentFingerprint !== 'string') {
|
|
49
|
+
throw new Error('Invalid repository row: canonical_snapshot is missing sourceUrl/documentFingerprint.');
|
|
50
|
+
}
|
|
51
|
+
if (!Array.isArray(parsed.endpoints)) {
|
|
52
|
+
throw new Error('Invalid repository row: canonical_snapshot.endpoints must be an array.');
|
|
53
|
+
}
|
|
54
|
+
if (!isRecord(parsed.versionSignal)) {
|
|
55
|
+
throw new Error('Invalid repository row: canonical_snapshot.versionSignal must be an object.');
|
|
56
|
+
}
|
|
57
|
+
return parsed;
|
|
58
|
+
}
|
|
59
|
+
function mapProjectRow(row) {
|
|
60
|
+
return {
|
|
61
|
+
id: requireId(row.id, 'projects.id'),
|
|
62
|
+
projectKey: requireString(row.project_key, 'projects.project_key'),
|
|
63
|
+
createdAt: requireTimestamp(row.created_at, 'projects.created_at'),
|
|
64
|
+
};
|
|
65
|
+
}
|
|
66
|
+
function mapSourceRow(row) {
|
|
67
|
+
return {
|
|
68
|
+
id: requireId(row.id, 'sources.id'),
|
|
69
|
+
projectId: requireId(row.project_id, 'sources.project_id'),
|
|
70
|
+
swaggerUrl: requireString(row.swagger_url, 'sources.swagger_url'),
|
|
71
|
+
createdAt: requireTimestamp(row.created_at, 'sources.created_at'),
|
|
72
|
+
};
|
|
73
|
+
}
|
|
74
|
+
function mapSnapshotRow(row) {
|
|
75
|
+
return {
|
|
76
|
+
id: requireId(row.id, 'snapshots.id'),
|
|
77
|
+
sourceId: requireId(row.source_id, 'snapshots.source_id'),
|
|
78
|
+
specHash: requireString(row.spec_hash, 'snapshots.spec_hash'),
|
|
79
|
+
documentFingerprint: requireString(row.document_fingerprint, 'snapshots.document_fingerprint'),
|
|
80
|
+
canonicalSnapshot: parseCanonicalSnapshot(row.canonical_snapshot),
|
|
81
|
+
capturedAt: requireTimestamp(row.captured_at, 'snapshots.captured_at'),
|
|
82
|
+
};
|
|
83
|
+
}
|
|
84
|
+
function mapSourceIdentityRow(row) {
|
|
85
|
+
return {
|
|
86
|
+
sourceId: requireId(row.source_id, 'sources.id'),
|
|
87
|
+
projectId: requireId(row.project_id, 'sources.project_id'),
|
|
88
|
+
projectKey: requireString(row.project_key, 'projects.project_key'),
|
|
89
|
+
swaggerUrl: requireString(row.swagger_url, 'sources.swagger_url'),
|
|
90
|
+
};
|
|
91
|
+
}
|
|
92
|
+
function mapEndpointChangeHistoryRow(row) {
|
|
93
|
+
return {
|
|
94
|
+
baselineSnapshotId: requireId(row.baseline_snapshot_id, 'endpoint_change_history.baseline_snapshot_id'),
|
|
95
|
+
targetSnapshotId: requireId(row.target_snapshot_id, 'endpoint_change_history.target_snapshot_id'),
|
|
96
|
+
path: requireString(row.path, 'endpoint_change_history.path'),
|
|
97
|
+
method: requireString(row.method, 'endpoint_change_history.method'),
|
|
98
|
+
classification: requireString(row.classification, 'endpoint_change_history.classification'),
|
|
99
|
+
changeReason: requireString(row.change_reason, 'endpoint_change_history.change_reason'),
|
|
100
|
+
changedAt: requireTimestamp(row.changed_at, 'endpoint_change_history.changed_at'),
|
|
101
|
+
};
|
|
102
|
+
}
|
|
103
|
+
export class PostgresSnapshotRepository {
|
|
104
|
+
db;
|
|
105
|
+
options;
|
|
106
|
+
constructor(db, options = {}) {
|
|
107
|
+
this.db = db;
|
|
108
|
+
this.options = options;
|
|
109
|
+
}
|
|
110
|
+
async initializeSchema() {
|
|
111
|
+
await runPostgresMigrations(this.db, this.options.migrationRunOptions);
|
|
112
|
+
}
|
|
113
|
+
async ensureProject(projectKey) {
|
|
114
|
+
const result = await this.db.query(`
|
|
115
|
+
INSERT INTO projects (project_key)
|
|
116
|
+
VALUES ($1)
|
|
117
|
+
ON CONFLICT (project_key)
|
|
118
|
+
DO UPDATE SET project_key = EXCLUDED.project_key
|
|
119
|
+
RETURNING id, project_key, created_at;
|
|
120
|
+
`, [projectKey]);
|
|
121
|
+
return mapProjectRow(requireSingleRow(result.rows, 'ensure project'));
|
|
122
|
+
}
|
|
123
|
+
async ensureSource(projectId, swaggerUrl) {
|
|
124
|
+
const result = await this.db.query(`
|
|
125
|
+
INSERT INTO sources (project_id, swagger_url)
|
|
126
|
+
VALUES ($1, $2)
|
|
127
|
+
ON CONFLICT (project_id, swagger_url)
|
|
128
|
+
DO UPDATE SET swagger_url = EXCLUDED.swagger_url
|
|
129
|
+
RETURNING id, project_id, swagger_url, created_at;
|
|
130
|
+
`, [projectId, swaggerUrl]);
|
|
131
|
+
return mapSourceRow(requireSingleRow(result.rows, 'ensure source'));
|
|
132
|
+
}
|
|
133
|
+
async getSourceIdentityById(sourceId) {
|
|
134
|
+
const result = await this.db.query(`
|
|
135
|
+
SELECT
|
|
136
|
+
s.id AS source_id,
|
|
137
|
+
s.project_id,
|
|
138
|
+
p.project_key,
|
|
139
|
+
s.swagger_url
|
|
140
|
+
FROM sources s
|
|
141
|
+
INNER JOIN projects p ON p.id = s.project_id
|
|
142
|
+
WHERE s.id = $1
|
|
143
|
+
LIMIT 1;
|
|
144
|
+
`, [sourceId]);
|
|
145
|
+
if (result.rows.length === 0) {
|
|
146
|
+
return null;
|
|
147
|
+
}
|
|
148
|
+
return mapSourceIdentityRow(result.rows[0]);
|
|
149
|
+
}
|
|
150
|
+
async getLatestSnapshot(sourceId) {
|
|
151
|
+
const result = await this.db.query(`
|
|
152
|
+
SELECT id, source_id, spec_hash, document_fingerprint, canonical_snapshot, captured_at
|
|
153
|
+
FROM snapshots
|
|
154
|
+
WHERE source_id = $1
|
|
155
|
+
ORDER BY captured_at DESC, id DESC
|
|
156
|
+
LIMIT 1;
|
|
157
|
+
`, [sourceId]);
|
|
158
|
+
if (result.rows.length === 0) {
|
|
159
|
+
return null;
|
|
160
|
+
}
|
|
161
|
+
return mapSnapshotRow(result.rows[0]);
|
|
162
|
+
}
|
|
163
|
+
async acquireTransactionSession() {
|
|
164
|
+
if ('connect' in this.db && typeof this.db.connect === 'function') {
|
|
165
|
+
return this.db.connect();
|
|
166
|
+
}
|
|
167
|
+
return this.db;
|
|
168
|
+
}
|
|
169
|
+
async insertSnapshotTransition(session, sourceId, snapshot, transition) {
|
|
170
|
+
const transitionResult = await session.query(`
|
|
171
|
+
INSERT INTO snapshot_transitions (
|
|
172
|
+
source_id,
|
|
173
|
+
baseline_snapshot_id,
|
|
174
|
+
target_snapshot_id,
|
|
175
|
+
captured_at,
|
|
176
|
+
counts,
|
|
177
|
+
warnings
|
|
178
|
+
)
|
|
179
|
+
VALUES ($1, $2, $3, $4, $5, $6)
|
|
180
|
+
ON CONFLICT (target_snapshot_id) DO NOTHING
|
|
181
|
+
RETURNING id;
|
|
182
|
+
`, [
|
|
183
|
+
sourceId,
|
|
184
|
+
transition.baselineSnapshotId,
|
|
185
|
+
snapshot.id,
|
|
186
|
+
snapshot.capturedAt,
|
|
187
|
+
JSON.stringify(transition.counts),
|
|
188
|
+
JSON.stringify(transition.warnings),
|
|
189
|
+
]);
|
|
190
|
+
if (transitionResult.rows.length === 0) {
|
|
191
|
+
return;
|
|
192
|
+
}
|
|
193
|
+
const transitionId = requireId(requireSingleRow(transitionResult.rows, 'insert snapshot transition').id, 'snapshot_transitions.id');
|
|
194
|
+
for (const event of transition.events) {
|
|
195
|
+
await session.query(`
|
|
196
|
+
INSERT INTO endpoint_change_history (
|
|
197
|
+
transition_id,
|
|
198
|
+
source_id,
|
|
199
|
+
path,
|
|
200
|
+
method,
|
|
201
|
+
classification,
|
|
202
|
+
change_reason,
|
|
203
|
+
baseline_snapshot_id,
|
|
204
|
+
target_snapshot_id,
|
|
205
|
+
changed_at
|
|
206
|
+
)
|
|
207
|
+
VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9)
|
|
208
|
+
ON CONFLICT (transition_id, path, method) DO NOTHING;
|
|
209
|
+
`, [
|
|
210
|
+
transitionId,
|
|
211
|
+
sourceId,
|
|
212
|
+
event.path,
|
|
213
|
+
event.method,
|
|
214
|
+
event.classification,
|
|
215
|
+
event.changeReason,
|
|
216
|
+
transition.baselineSnapshotId,
|
|
217
|
+
snapshot.id,
|
|
218
|
+
snapshot.capturedAt,
|
|
219
|
+
]);
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
async saveSnapshot(input) {
|
|
223
|
+
const session = await this.acquireTransactionSession();
|
|
224
|
+
try {
|
|
225
|
+
await session.query('BEGIN');
|
|
226
|
+
const result = await session.query(`
|
|
227
|
+
WITH inserted AS (
|
|
228
|
+
INSERT INTO snapshots (source_id, spec_hash, document_fingerprint, canonical_snapshot)
|
|
229
|
+
VALUES ($1, $2, $3, $4)
|
|
230
|
+
ON CONFLICT (source_id, spec_hash) DO NOTHING
|
|
231
|
+
RETURNING id, source_id, spec_hash, document_fingerprint, canonical_snapshot, captured_at
|
|
232
|
+
),
|
|
233
|
+
selected AS (
|
|
234
|
+
SELECT TRUE AS created, id, source_id, spec_hash, document_fingerprint, canonical_snapshot, captured_at
|
|
235
|
+
FROM inserted
|
|
236
|
+
UNION ALL
|
|
237
|
+
SELECT FALSE AS created, s.id, s.source_id, s.spec_hash, s.document_fingerprint, s.canonical_snapshot, s.captured_at
|
|
238
|
+
FROM snapshots s
|
|
239
|
+
WHERE s.source_id = $1
|
|
240
|
+
AND s.spec_hash = $2
|
|
241
|
+
AND NOT EXISTS (SELECT 1 FROM inserted)
|
|
242
|
+
)
|
|
243
|
+
SELECT created, id, source_id, spec_hash, document_fingerprint, canonical_snapshot, captured_at
|
|
244
|
+
FROM selected
|
|
245
|
+
LIMIT 1;
|
|
246
|
+
`, [input.sourceId, input.specHash, input.documentFingerprint, JSON.stringify(input.canonicalSnapshot)]);
|
|
247
|
+
const row = requireSingleRow(result.rows, 'save snapshot');
|
|
248
|
+
const snapshot = mapSnapshotRow(row);
|
|
249
|
+
const created = row.created === true;
|
|
250
|
+
if (created && input.transition) {
|
|
251
|
+
await this.insertSnapshotTransition(session, input.sourceId, snapshot, input.transition);
|
|
252
|
+
}
|
|
253
|
+
await session.query('COMMIT');
|
|
254
|
+
return {
|
|
255
|
+
snapshot,
|
|
256
|
+
created,
|
|
257
|
+
};
|
|
258
|
+
}
|
|
259
|
+
catch (error) {
|
|
260
|
+
await session.query('ROLLBACK').catch(() => undefined);
|
|
261
|
+
const message = error instanceof Error ? error.message : 'Unknown repository error.';
|
|
262
|
+
if (message.includes('no unique or exclusion constraint')) {
|
|
263
|
+
throw new Error('Missing snapshots unique constraint on (source_id, spec_hash). Run postgres migrations before capture.');
|
|
264
|
+
}
|
|
265
|
+
if (message.includes('relation "snapshots" does not exist') ||
|
|
266
|
+
message.includes('relation "snapshot_transitions" does not exist') ||
|
|
267
|
+
message.includes('relation "endpoint_change_history" does not exist')) {
|
|
268
|
+
throw new Error('Snapshot history tables are missing. Run postgres migrations before capture.');
|
|
269
|
+
}
|
|
270
|
+
throw error;
|
|
271
|
+
}
|
|
272
|
+
finally {
|
|
273
|
+
session.release?.();
|
|
274
|
+
}
|
|
275
|
+
}
|
|
276
|
+
async getSnapshotById(snapshotId) {
|
|
277
|
+
const result = await this.db.query(`
|
|
278
|
+
SELECT id, source_id, spec_hash, document_fingerprint, canonical_snapshot, captured_at
|
|
279
|
+
FROM snapshots
|
|
280
|
+
WHERE id = $1
|
|
281
|
+
LIMIT 1;
|
|
282
|
+
`, [snapshotId]);
|
|
283
|
+
if (result.rows.length === 0) {
|
|
284
|
+
return null;
|
|
285
|
+
}
|
|
286
|
+
return mapSnapshotRow(result.rows[0]);
|
|
287
|
+
}
|
|
288
|
+
async listSnapshotsBySource(sourceId, limit = 50) {
|
|
289
|
+
const normalizedLimit = Math.max(1, Math.min(limit, 200));
|
|
290
|
+
const result = await this.db.query(`
|
|
291
|
+
SELECT id, source_id, spec_hash, document_fingerprint, canonical_snapshot, captured_at
|
|
292
|
+
FROM snapshots
|
|
293
|
+
WHERE source_id = $1
|
|
294
|
+
ORDER BY captured_at DESC, id DESC
|
|
295
|
+
LIMIT $2;
|
|
296
|
+
`, [sourceId, normalizedLimit]);
|
|
297
|
+
return result.rows.map(mapSnapshotRow);
|
|
298
|
+
}
|
|
299
|
+
async listEndpointChangeHistory(input) {
|
|
300
|
+
const normalizedLimit = Math.max(1, Math.min(input.limit ?? 50, 200));
|
|
301
|
+
const queryParams = [input.sourceId];
|
|
302
|
+
const filters = ['source_id = $1'];
|
|
303
|
+
let parameterIndex = 2;
|
|
304
|
+
if (input.path && input.method) {
|
|
305
|
+
filters.push(`path = $${parameterIndex}`);
|
|
306
|
+
queryParams.push(input.path);
|
|
307
|
+
parameterIndex += 1;
|
|
308
|
+
filters.push(`method = $${parameterIndex}`);
|
|
309
|
+
queryParams.push(input.method);
|
|
310
|
+
parameterIndex += 1;
|
|
311
|
+
}
|
|
312
|
+
queryParams.push(normalizedLimit);
|
|
313
|
+
const result = await this.db.query(`
|
|
314
|
+
SELECT baseline_snapshot_id, target_snapshot_id, path, method, classification, change_reason, changed_at
|
|
315
|
+
FROM endpoint_change_history
|
|
316
|
+
WHERE ${filters.join(' AND ')}
|
|
317
|
+
ORDER BY changed_at DESC, id DESC
|
|
318
|
+
LIMIT $${parameterIndex};
|
|
319
|
+
`, queryParams);
|
|
320
|
+
return result.rows.map(mapEndpointChangeHistoryRow);
|
|
321
|
+
}
|
|
322
|
+
}
|
|
323
|
+
//# sourceMappingURL=postgresSnapshotRepository.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"postgresSnapshotRepository.js","sourceRoot":"","sources":["../../../src/infrastructure/postgres/postgresSnapshotRepository.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"runMigrations.d.ts","sourceRoot":"","sources":["../../../src/infrastructure/postgres/runMigrations.ts"],"names":[],"mappings":"AAYA,iBAAe,MAAM,IAAI,OAAO,CAAC,IAAI,CAAC,CAYrC;AAaD,OAAO,EAAE,MAAM,IAAI,wBAAwB,EAAE,CAAC"}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { Pool } from 'pg';
|
|
2
|
+
import { pathToFileURL } from 'node:url';
|
|
3
|
+
import { runPostgresMigrations } from './migrationRunner.js';
|
|
4
|
+
function readDatabaseUrlFromEnvironment(env) {
|
|
5
|
+
const databaseUrl = env.DATABASE_URL?.trim();
|
|
6
|
+
if (!databaseUrl) {
|
|
7
|
+
throw new Error('DATABASE_URL is required to run postgres migrations.');
|
|
8
|
+
}
|
|
9
|
+
return databaseUrl;
|
|
10
|
+
}
|
|
11
|
+
async function runCli() {
|
|
12
|
+
const databaseUrl = readDatabaseUrlFromEnvironment(process.env);
|
|
13
|
+
const pool = new Pool({
|
|
14
|
+
connectionString: databaseUrl,
|
|
15
|
+
});
|
|
16
|
+
try {
|
|
17
|
+
const summary = await runPostgresMigrations(pool);
|
|
18
|
+
console.log(JSON.stringify(summary, null, 2));
|
|
19
|
+
}
|
|
20
|
+
finally {
|
|
21
|
+
await pool.end();
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
const isDirectExecution = typeof process.argv[1] === 'string' && pathToFileURL(process.argv[1]).href === import.meta.url;
|
|
25
|
+
if (isDirectExecution) {
|
|
26
|
+
runCli().catch(error => {
|
|
27
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
28
|
+
console.error(`Failed to run migrations: ${message}`);
|
|
29
|
+
process.exit(1);
|
|
30
|
+
});
|
|
31
|
+
}
|
|
32
|
+
export { runCli as runPostgresMigrationsCli };
|
|
33
|
+
//# sourceMappingURL=runMigrations.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"runMigrations.js","sourceRoot":"","sources":["../../../src/infrastructure/postgres/runMigrations.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,IAAI,CAAC;AAC1B,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AACzC,OAAO,EAAE,qBAAqB,EAAE,MAAM,sBAAsB,CAAC;AAE7D,SAAS,8BAA8B,CAAC,GAAsB;IAC5D,MAAM,WAAW,GAAG,GAAG,CAAC,YAAY,EAAE,IAAI,EAAE,CAAC;IAC7C,IAAI,CAAC,WAAW,EAAE,CAAC;QACjB,MAAM,IAAI,KAAK,CAAC,sDAAsD,CAAC,CAAC;IAC1E,CAAC;IACD,OAAO,WAAW,CAAC;AACrB,CAAC;AAED,KAAK,UAAU,MAAM;IACnB,MAAM,WAAW,GAAG,8BAA8B,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;IAChE,MAAM,IAAI,GAAG,IAAI,IAAI,CAAC;QACpB,gBAAgB,EAAE,WAAW;KAC9B,CAAC,CAAC;IAEH,IAAI,CAAC;QACH,MAAM,OAAO,GAAG,MAAM,qBAAqB,CAAC,IAAI,CAAC,CAAC;QAClD,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,SAAS,CAAC,OAAO,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC;IAChD,CAAC;YAAS,CAAC;QACT,MAAM,IAAI,CAAC,GAAG,EAAE,CAAC;IACnB,CAAC;AACH,CAAC;AAED,MAAM,iBAAiB,GACrB,OAAO,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,KAAK,QAAQ,IAAI,aAAa,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,KAAK,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC;AAEjG,IAAI,iBAAiB,EAAE,CAAC;IACtB,MAAM,EAAE,CAAC,KAAK,CAAC,KAAK,CAAC,EAAE;QACrB,MAAM,OAAO,GAAG,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;QACvE,OAAO,CAAC,KAAK,CAAC,6BAA6B,OAAO,EAAE,CAAC,CAAC;QACtD,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC,CAAC,CAAC;AACL,CAAC;AAED,OAAO,EAAE,MAAM,IAAI,wBAAwB,EAAE,CAAC"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { Pool } from 'pg';
|
|
2
|
+
import { SnapshotCaptureService, SnapshotDocumentLoader } from '../../application/snapshot/snapshotCaptureService.js';
|
|
3
|
+
import { SnapshotRepository } from '../../application/snapshot/snapshotRepository.js';
|
|
4
|
+
import { RuntimeEnvironment } from '../../domain/contracts/runtimeEnvironmentContract.js';
|
|
5
|
+
export interface SnapshotRuntime {
|
|
6
|
+
environment: RuntimeEnvironment;
|
|
7
|
+
service: SnapshotCaptureService;
|
|
8
|
+
dispose(): Promise<void>;
|
|
9
|
+
}
|
|
10
|
+
export interface SnapshotRuntimeDependencies {
|
|
11
|
+
pool: Pick<Pool, 'end'>;
|
|
12
|
+
repository: SnapshotRepository;
|
|
13
|
+
loader: SnapshotDocumentLoader;
|
|
14
|
+
}
|
|
15
|
+
export type SnapshotRuntimeDependencyFactory = (environment: RuntimeEnvironment) => Promise<SnapshotRuntimeDependencies> | SnapshotRuntimeDependencies;
|
|
16
|
+
export declare function createSnapshotRuntime(env: NodeJS.ProcessEnv, dependencyFactory?: SnapshotRuntimeDependencyFactory): Promise<SnapshotRuntime>;
|
|
17
|
+
//# sourceMappingURL=createSnapshotRuntime.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"createSnapshotRuntime.d.ts","sourceRoot":"","sources":["../../../src/infrastructure/runtime/createSnapshotRuntime.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,IAAI,CAAC;AAC1B,OAAO,EAAE,sBAAsB,EAAE,sBAAsB,EAAE,MAAM,sDAAsD,CAAC;AACtH,OAAO,EAAE,kBAAkB,EAAE,MAAM,kDAAkD,CAAC;AACtF,OAAO,EAAE,kBAAkB,EAAuB,MAAM,sDAAsD,CAAC;AAI/G,MAAM,WAAW,eAAe;IAC9B,WAAW,EAAE,kBAAkB,CAAC;IAChC,OAAO,EAAE,sBAAsB,CAAC;IAChC,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;CAC1B;AAED,MAAM,WAAW,2BAA2B;IAC1C,IAAI,EAAE,IAAI,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC;IACxB,UAAU,EAAE,kBAAkB,CAAC;IAC/B,MAAM,EAAE,sBAAsB,CAAC;CAChC;AAED,MAAM,MAAM,gCAAgC,GAAG,CAC7C,WAAW,EAAE,kBAAkB,KAC5B,OAAO,CAAC,2BAA2B,CAAC,GAAG,2BAA2B,CAAC;AAcxE,wBAAsB,qBAAqB,CACzC,GAAG,EAAE,MAAM,CAAC,UAAU,EACtB,iBAAiB,GAAE,gCAA4D,GAC9E,OAAO,CAAC,eAAe,CAAC,CAsB1B"}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { Pool } from 'pg';
|
|
2
|
+
import { SnapshotCaptureService } from '../../application/snapshot/snapshotCaptureService.js';
|
|
3
|
+
import { validateEnvironment } from '../../domain/contracts/runtimeEnvironmentContract.js';
|
|
4
|
+
import { PostgresSnapshotRepository } from '../postgres/postgresSnapshotRepository.js';
|
|
5
|
+
import { SwaggerCache } from '../../utils/swaggerCache.js';
|
|
6
|
+
function createDefaultDependencies(environment) {
|
|
7
|
+
const pool = new Pool({
|
|
8
|
+
connectionString: environment.DATABASE_URL,
|
|
9
|
+
});
|
|
10
|
+
return {
|
|
11
|
+
pool,
|
|
12
|
+
repository: new PostgresSnapshotRepository(pool),
|
|
13
|
+
loader: new SwaggerCache(),
|
|
14
|
+
};
|
|
15
|
+
}
|
|
16
|
+
export async function createSnapshotRuntime(env, dependencyFactory = createDefaultDependencies) {
|
|
17
|
+
const environment = validateEnvironment(env);
|
|
18
|
+
let dependencies = null;
|
|
19
|
+
try {
|
|
20
|
+
dependencies = await dependencyFactory(environment);
|
|
21
|
+
const service = new SnapshotCaptureService(dependencies.repository, dependencies.loader);
|
|
22
|
+
await service.bootstrap(environment);
|
|
23
|
+
return {
|
|
24
|
+
environment,
|
|
25
|
+
service,
|
|
26
|
+
async dispose() {
|
|
27
|
+
await dependencies.pool.end();
|
|
28
|
+
},
|
|
29
|
+
};
|
|
30
|
+
}
|
|
31
|
+
catch (error) {
|
|
32
|
+
if (dependencies) {
|
|
33
|
+
await dependencies.pool.end().catch(() => undefined);
|
|
34
|
+
}
|
|
35
|
+
throw error;
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
//# sourceMappingURL=createSnapshotRuntime.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"createSnapshotRuntime.js","sourceRoot":"","sources":["../../../src/infrastructure/runtime/createSnapshotRuntime.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,IAAI,CAAC;AAC1B,OAAO,EAAE,sBAAsB,EAA0B,MAAM,sDAAsD,CAAC;AAEtH,OAAO,EAAsB,mBAAmB,EAAE,MAAM,sDAAsD,CAAC;AAC/G,OAAO,EAAE,0BAA0B,EAAE,MAAM,2CAA2C,CAAC;AACvF,OAAO,EAAE,YAAY,EAAE,MAAM,6BAA6B,CAAC;AAkB3D,SAAS,yBAAyB,CAAC,WAA+B;IAChE,MAAM,IAAI,GAAG,IAAI,IAAI,CAAC;QACpB,gBAAgB,EAAE,WAAW,CAAC,YAAY;KAC3C,CAAC,CAAC;IAEH,OAAO;QACL,IAAI;QACJ,UAAU,EAAE,IAAI,0BAA0B,CAAC,IAAI,CAAC;QAChD,MAAM,EAAE,IAAI,YAAY,EAAE;KAC3B,CAAC;AACJ,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,qBAAqB,CACzC,GAAsB,EACtB,oBAAsD,yBAAyB;IAE/E,MAAM,WAAW,GAAG,mBAAmB,CAAC,GAAG,CAAC,CAAC;IAC7C,IAAI,YAAY,GAAuC,IAAI,CAAC;IAE5D,IAAI,CAAC;QACH,YAAY,GAAG,MAAM,iBAAiB,CAAC,WAAW,CAAC,CAAC;QACpD,MAAM,OAAO,GAAG,IAAI,sBAAsB,CAAC,YAAY,CAAC,UAAU,EAAE,YAAY,CAAC,MAAM,CAAC,CAAC;QACzF,MAAM,OAAO,CAAC,SAAS,CAAC,WAAW,CAAC,CAAC;QAErC,OAAO;YACL,WAAW;YACX,OAAO;YACP,KAAK,CAAC,OAAO;gBACX,MAAM,YAAa,CAAC,IAAI,CAAC,GAAG,EAAE,CAAC;YACjC,CAAC;SACF,CAAC;IACJ,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,IAAI,YAAY,EAAE,CAAC;YACjB,MAAM,YAAY,CAAC,IAAI,CAAC,GAAG,EAAE,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,SAAS,CAAC,CAAC;QACvD,CAAC;QACD,MAAM,KAAK,CAAC;IACd,CAAC;AACH,CAAC"}
|