@krantho/persistence-postgres 0.0.0-stage → 1.0.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.
Files changed (127) hide show
  1. package/LICENSE +21 -0
  2. package/dist/auth-adapter.d.ts +23 -0
  3. package/dist/auth-adapter.d.ts.map +1 -0
  4. package/dist/auth-adapter.js +159 -0
  5. package/dist/auth-adapter.js.map +1 -0
  6. package/dist/content-migration.d.ts +14 -0
  7. package/dist/content-migration.d.ts.map +1 -0
  8. package/dist/content-migration.js +64 -0
  9. package/dist/content-migration.js.map +1 -0
  10. package/dist/content-query.d.ts +23 -0
  11. package/dist/content-query.d.ts.map +1 -0
  12. package/dist/content-query.js +170 -0
  13. package/dist/content-query.js.map +1 -0
  14. package/dist/index.d.ts +17 -0
  15. package/dist/index.d.ts.map +1 -0
  16. package/dist/index.js +15 -0
  17. package/dist/index.js.map +1 -0
  18. package/dist/migration-runner.d.ts +29 -0
  19. package/dist/migration-runner.d.ts.map +1 -0
  20. package/dist/migration-runner.js +123 -0
  21. package/dist/migration-runner.js.map +1 -0
  22. package/dist/migrations/index.d.ts +4 -0
  23. package/dist/migrations/index.d.ts.map +1 -0
  24. package/dist/migrations/index.js +32 -0
  25. package/dist/migrations/index.js.map +1 -0
  26. package/dist/migrations/v001-initial-schema.d.ts +10 -0
  27. package/dist/migrations/v001-initial-schema.d.ts.map +1 -0
  28. package/dist/migrations/v001-initial-schema.js +94 -0
  29. package/dist/migrations/v001-initial-schema.js.map +1 -0
  30. package/dist/migrations/v002-auth-tables.d.ts +8 -0
  31. package/dist/migrations/v002-auth-tables.d.ts.map +1 -0
  32. package/dist/migrations/v002-auth-tables.js +37 -0
  33. package/dist/migrations/v002-auth-tables.js.map +1 -0
  34. package/dist/migrations/v003-user-permissions.d.ts +6 -0
  35. package/dist/migrations/v003-user-permissions.d.ts.map +1 -0
  36. package/dist/migrations/v003-user-permissions.js +18 -0
  37. package/dist/migrations/v003-user-permissions.js.map +1 -0
  38. package/dist/migrations/v004-media-hotspot.d.ts +14 -0
  39. package/dist/migrations/v004-media-hotspot.d.ts.map +1 -0
  40. package/dist/migrations/v004-media-hotspot.js +25 -0
  41. package/dist/migrations/v004-media-hotspot.js.map +1 -0
  42. package/dist/migrations/v005-content-locks.d.ts +6 -0
  43. package/dist/migrations/v005-content-locks.d.ts.map +1 -0
  44. package/dist/migrations/v005-content-locks.js +21 -0
  45. package/dist/migrations/v005-content-locks.js.map +1 -0
  46. package/dist/migrations/v006-webhook-deliveries.d.ts +6 -0
  47. package/dist/migrations/v006-webhook-deliveries.d.ts.map +1 -0
  48. package/dist/migrations/v006-webhook-deliveries.js +24 -0
  49. package/dist/migrations/v006-webhook-deliveries.js.map +1 -0
  50. package/dist/migrations/v007-media-folders.d.ts +6 -0
  51. package/dist/migrations/v007-media-folders.d.ts.map +1 -0
  52. package/dist/migrations/v007-media-folders.js +19 -0
  53. package/dist/migrations/v007-media-folders.js.map +1 -0
  54. package/dist/migrations/v008-site-settings.d.ts +6 -0
  55. package/dist/migrations/v008-site-settings.d.ts.map +1 -0
  56. package/dist/migrations/v008-site-settings.js +17 -0
  57. package/dist/migrations/v008-site-settings.js.map +1 -0
  58. package/dist/migrations/v009-seo-config.d.ts +12 -0
  59. package/dist/migrations/v009-seo-config.d.ts.map +1 -0
  60. package/dist/migrations/v009-seo-config.js +27 -0
  61. package/dist/migrations/v009-seo-config.js.map +1 -0
  62. package/dist/migrations/v010-content-live-version.d.ts +15 -0
  63. package/dist/migrations/v010-content-live-version.d.ts.map +1 -0
  64. package/dist/migrations/v010-content-live-version.js +40 -0
  65. package/dist/migrations/v010-content-live-version.js.map +1 -0
  66. package/dist/migrations/v011-media.d.ts +12 -0
  67. package/dist/migrations/v011-media.d.ts.map +1 -0
  68. package/dist/migrations/v011-media.js +43 -0
  69. package/dist/migrations/v011-media.js.map +1 -0
  70. package/dist/migrations/v012-page-cache.d.ts +12 -0
  71. package/dist/migrations/v012-page-cache.d.ts.map +1 -0
  72. package/dist/migrations/v012-page-cache.js +31 -0
  73. package/dist/migrations/v012-page-cache.js.map +1 -0
  74. package/dist/migrations/v013-content-contracts.d.ts +17 -0
  75. package/dist/migrations/v013-content-contracts.d.ts.map +1 -0
  76. package/dist/migrations/v013-content-contracts.js +41 -0
  77. package/dist/migrations/v013-content-contracts.js.map +1 -0
  78. package/dist/migrations/v014-content-manifest-commit.d.ts +7 -0
  79. package/dist/migrations/v014-content-manifest-commit.d.ts.map +1 -0
  80. package/dist/migrations/v014-content-manifest-commit.js +12 -0
  81. package/dist/migrations/v014-content-manifest-commit.js.map +1 -0
  82. package/dist/postgres-adapter.d.ts +71 -0
  83. package/dist/postgres-adapter.d.ts.map +1 -0
  84. package/dist/postgres-adapter.js +327 -0
  85. package/dist/postgres-adapter.js.map +1 -0
  86. package/dist/postgres-checkpoints.d.ts +20 -0
  87. package/dist/postgres-checkpoints.d.ts.map +1 -0
  88. package/dist/postgres-checkpoints.js +109 -0
  89. package/dist/postgres-checkpoints.js.map +1 -0
  90. package/dist/postgres-lock-adapter.d.ts +12 -0
  91. package/dist/postgres-lock-adapter.d.ts.map +1 -0
  92. package/dist/postgres-lock-adapter.js +62 -0
  93. package/dist/postgres-lock-adapter.js.map +1 -0
  94. package/dist/postgres-media-adapter.d.ts +28 -0
  95. package/dist/postgres-media-adapter.d.ts.map +1 -0
  96. package/dist/postgres-media-adapter.js +167 -0
  97. package/dist/postgres-media-adapter.js.map +1 -0
  98. package/dist/postgres-media-folder-adapter.d.ts +12 -0
  99. package/dist/postgres-media-folder-adapter.d.ts.map +1 -0
  100. package/dist/postgres-media-folder-adapter.js +60 -0
  101. package/dist/postgres-media-folder-adapter.js.map +1 -0
  102. package/dist/postgres-page-cache-store.d.ts +23 -0
  103. package/dist/postgres-page-cache-store.d.ts.map +1 -0
  104. package/dist/postgres-page-cache-store.js +80 -0
  105. package/dist/postgres-page-cache-store.js.map +1 -0
  106. package/dist/postgres-retention-adapter.d.ts +14 -0
  107. package/dist/postgres-retention-adapter.d.ts.map +1 -0
  108. package/dist/postgres-retention-adapter.js +61 -0
  109. package/dist/postgres-retention-adapter.js.map +1 -0
  110. package/dist/postgres-seo-config-adapter.d.ts +14 -0
  111. package/dist/postgres-seo-config-adapter.d.ts.map +1 -0
  112. package/dist/postgres-seo-config-adapter.js +59 -0
  113. package/dist/postgres-seo-config-adapter.js.map +1 -0
  114. package/dist/postgres-site-settings-adapter.d.ts +11 -0
  115. package/dist/postgres-site-settings-adapter.d.ts.map +1 -0
  116. package/dist/postgres-site-settings-adapter.js +30 -0
  117. package/dist/postgres-site-settings-adapter.js.map +1 -0
  118. package/dist/postgres-webhook-delivery-adapter.d.ts +27 -0
  119. package/dist/postgres-webhook-delivery-adapter.d.ts.map +1 -0
  120. package/dist/postgres-webhook-delivery-adapter.js +99 -0
  121. package/dist/postgres-webhook-delivery-adapter.js.map +1 -0
  122. package/dist/row-mapping.d.ts +40 -0
  123. package/dist/row-mapping.d.ts.map +1 -0
  124. package/dist/row-mapping.js +49 -0
  125. package/dist/row-mapping.js.map +1 -0
  126. package/package.json +39 -3
  127. package/README.md +0 -3
@@ -0,0 +1,123 @@
1
+ import { createHash } from 'node:crypto';
2
+ import { migrationFailedMessage, resolveCurrentVersion, validateChecksums, } from '@krantho/persistence';
3
+ /** Compute SHA-256 checksum of a migration's identity */
4
+ function computeChecksum(migration) {
5
+ const content = `v${migration.version}:${migration.name}`;
6
+ return createHash('sha256').update(content).digest('hex');
7
+ }
8
+ const CREATE_SCHEMA_MIGRATIONS = `
9
+ CREATE TABLE IF NOT EXISTS schema_migrations (
10
+ version INTEGER PRIMARY KEY,
11
+ name TEXT NOT NULL,
12
+ checksum TEXT NOT NULL,
13
+ applied_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
14
+ )`;
15
+ /**
16
+ * Advisory lock key that serializes migration runs across processes. A fixed
17
+ * value — the ASCII bytes of "krantho" — so every krantho process sharing a
18
+ * database contends for the same lock.
19
+ */
20
+ const MIGRATION_LOCK_KEY = '30224656064259183';
21
+ /** Read the applied-migration ledger, or null when it has not been created yet */
22
+ async function readLedger(sql) {
23
+ try {
24
+ const rows = await sql `
25
+ SELECT version, name, checksum, applied_at FROM schema_migrations ORDER BY version`;
26
+ return new Map(rows.map((m) => [m.version, m]));
27
+ }
28
+ catch (err) {
29
+ if (isUndefinedTable(err))
30
+ return null;
31
+ throw err;
32
+ }
33
+ }
34
+ /** Apply every pending migration. Must run inside the transaction holding the migration lock. */
35
+ async function applyPending(tx, migrations) {
36
+ await tx.unsafe(CREATE_SCHEMA_MIGRATIONS);
37
+ const ledger = (await readLedger(tx)) ?? new Map();
38
+ validateChecksums(migrations, ledger, computeChecksum);
39
+ const newlyApplied = [];
40
+ for (const migration of [...migrations].sort((a, b) => a.version - b.version)) {
41
+ if (ledger.has(migration.version))
42
+ continue;
43
+ const checksum = computeChecksum(migration);
44
+ const appliedAt = new Date().toISOString();
45
+ try {
46
+ await migration.apply(tx);
47
+ await tx.unsafe('INSERT INTO schema_migrations (version, name, checksum, applied_at) VALUES ($1, $2, $3, $4)', [migration.version, migration.name, checksum, appliedAt]);
48
+ }
49
+ catch (err) {
50
+ throw new Error(migrationFailedMessage(migration.version, migration.name, err));
51
+ }
52
+ newlyApplied.push({ version: migration.version, name: migration.name, checksum, appliedAt });
53
+ }
54
+ return {
55
+ applied: newlyApplied,
56
+ currentVersion: resolveCurrentVersion(ledger.keys(), newlyApplied),
57
+ };
58
+ }
59
+ /**
60
+ * Run pending migrations on a Postgres database.
61
+ *
62
+ * Self-bootstrapping: creates the schema_migrations table if it doesn't exist.
63
+ * All pending migrations run in one transaction. Halts on first failure, which
64
+ * rolls back the whole run.
65
+ *
66
+ * Deciding what is pending and applying it is a check-then-act, so it runs while
67
+ * holding a transaction-scoped advisory lock: the lock is taken before the ledger
68
+ * is read and released when the last migration commits. Serverless platforms
69
+ * cold-start several instances against the same database at once, and without
70
+ * the lock they all read an empty ledger and race to create the same tables. A
71
+ * losing instance waits on the lock and then re-reads the ledger inside it,
72
+ * finding the work already done.
73
+ */
74
+ export async function runMigrations(sql, migrations) {
75
+ // Fast path — an already-migrated database is the common case, and reading the
76
+ // ledger without the lock is safe because "every migration is applied" is a
77
+ // state no concurrent migration run can take away.
78
+ const ledger = await readLedger(sql);
79
+ if (ledger) {
80
+ validateChecksums(migrations, ledger, computeChecksum);
81
+ if (migrations.every((m) => ledger.has(m.version))) {
82
+ return { applied: [], currentVersion: resolveCurrentVersion(ledger.keys(), []) };
83
+ }
84
+ }
85
+ return sql.begin(async (tx) => {
86
+ await tx.unsafe(`SELECT pg_advisory_xact_lock(${MIGRATION_LOCK_KEY})`);
87
+ return applyPending(tx, migrations);
88
+ });
89
+ }
90
+ /** Get the current schema version from the database */
91
+ export async function getSchemaVersion(sql) {
92
+ try {
93
+ const rows = await sql `
94
+ SELECT MAX(version) as max_version FROM schema_migrations`;
95
+ return rows[0]?.max_version ?? 0;
96
+ }
97
+ catch (err) {
98
+ // 42P01 = "relation does not exist" — table not created yet
99
+ if (isUndefinedTable(err))
100
+ return 0;
101
+ throw err;
102
+ }
103
+ }
104
+ /** Get all applied migrations */
105
+ export async function getAppliedMigrations(sql) {
106
+ const ledger = await readLedger(sql);
107
+ if (!ledger)
108
+ return [];
109
+ return [...ledger.values()].map((r) => ({
110
+ version: r.version,
111
+ name: r.name,
112
+ checksum: r.checksum,
113
+ appliedAt: r.applied_at instanceof Date ? r.applied_at.toISOString() : String(r.applied_at),
114
+ }));
115
+ }
116
+ /** Check if a Postgres error is "relation does not exist" (42P01) */
117
+ function isUndefinedTable(err) {
118
+ if (typeof err === 'object' && err !== null && 'code' in err) {
119
+ return err.code === '42P01';
120
+ }
121
+ return false;
122
+ }
123
+ //# sourceMappingURL=migration-runner.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"migration-runner.js","sourceRoot":"","sources":["../src/migration-runner.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,4 @@
1
+ import type { PostgresMigration } from '../migration-runner.js';
2
+ /** All registered Postgres migrations, in version order */
3
+ export declare const postgresMigrations: readonly PostgresMigration[];
4
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/migrations/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,wBAAwB,CAAA;AAgB/D,2DAA2D;AAC3D,eAAO,MAAM,kBAAkB,EAAE,SAAS,iBAAiB,EAe1D,CAAA"}
@@ -0,0 +1,32 @@
1
+ import { v001InitialSchema } from './v001-initial-schema.js';
2
+ import { v002AuthTables } from './v002-auth-tables.js';
3
+ import { v003UserPermissions } from './v003-user-permissions.js';
4
+ import { v004MediaHotspot } from './v004-media-hotspot.js';
5
+ import { v005ContentLocks } from './v005-content-locks.js';
6
+ import { v006WebhookDeliveries } from './v006-webhook-deliveries.js';
7
+ import { v007MediaFolders } from './v007-media-folders.js';
8
+ import { v008SiteSettings } from './v008-site-settings.js';
9
+ import { v009SeoConfig } from './v009-seo-config.js';
10
+ import { v010ContentLiveVersion } from './v010-content-live-version.js';
11
+ import { v011Media } from './v011-media.js';
12
+ import { v012PageCache } from './v012-page-cache.js';
13
+ import { v013ContentContracts } from './v013-content-contracts.js';
14
+ import { v014ContentManifestCommit } from './v014-content-manifest-commit.js';
15
+ /** All registered Postgres migrations, in version order */
16
+ export const postgresMigrations = [
17
+ v001InitialSchema,
18
+ v002AuthTables,
19
+ v003UserPermissions,
20
+ v004MediaHotspot,
21
+ v005ContentLocks,
22
+ v006WebhookDeliveries,
23
+ v007MediaFolders,
24
+ v008SiteSettings,
25
+ v009SeoConfig,
26
+ v010ContentLiveVersion,
27
+ v011Media,
28
+ v012PageCache,
29
+ v013ContentContracts,
30
+ v014ContentManifestCommit,
31
+ ];
32
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/migrations/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,iBAAiB,EAAE,MAAM,0BAA0B,CAAA;AAC5D,OAAO,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAA;AACtD,OAAO,EAAE,mBAAmB,EAAE,MAAM,4BAA4B,CAAA;AAChE,OAAO,EAAE,gBAAgB,EAAE,MAAM,yBAAyB,CAAA;AAC1D,OAAO,EAAE,gBAAgB,EAAE,MAAM,yBAAyB,CAAA;AAC1D,OAAO,EAAE,qBAAqB,EAAE,MAAM,8BAA8B,CAAA;AACpE,OAAO,EAAE,gBAAgB,EAAE,MAAM,yBAAyB,CAAA;AAC1D,OAAO,EAAE,gBAAgB,EAAE,MAAM,yBAAyB,CAAA;AAC1D,OAAO,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAA;AACpD,OAAO,EAAE,sBAAsB,EAAE,MAAM,gCAAgC,CAAA;AACvE,OAAO,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAA;AAC3C,OAAO,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAA;AACpD,OAAO,EAAE,oBAAoB,EAAE,MAAM,6BAA6B,CAAA;AAClE,OAAO,EAAE,yBAAyB,EAAE,MAAM,mCAAmC,CAAA;AAE7E,2DAA2D;AAC3D,MAAM,CAAC,MAAM,kBAAkB,GAAiC;IAC9D,iBAAiB;IACjB,cAAc;IACd,mBAAmB;IACnB,gBAAgB;IAChB,gBAAgB;IAChB,qBAAqB;IACrB,gBAAgB;IAChB,gBAAgB;IAChB,aAAa;IACb,sBAAsB;IACtB,SAAS;IACT,aAAa;IACb,oBAAoB;IACpB,yBAAyB;CAC1B,CAAA"}
@@ -0,0 +1,10 @@
1
+ import type { PostgresMigration } from '../migration-runner.js';
2
+ /**
3
+ * V001: Initial schema — all core tables in their final form.
4
+ *
5
+ * Content uses the append-only versioning model (version, is_current, deleted_at).
6
+ * Collection schemas are append-only. Includes content manifest, migration
7
+ * conflicts, and checkpoint tables.
8
+ */
9
+ export declare const v001InitialSchema: PostgresMigration;
10
+ //# sourceMappingURL=v001-initial-schema.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"v001-initial-schema.d.ts","sourceRoot":"","sources":["../../src/migrations/v001-initial-schema.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,wBAAwB,CAAA;AAE/D;;;;;;GAMG;AACH,eAAO,MAAM,iBAAiB,EAAE,iBA0G/B,CAAA"}
@@ -0,0 +1,94 @@
1
+ /**
2
+ * V001: Initial schema — all core tables in their final form.
3
+ *
4
+ * Content uses the append-only versioning model (version, is_current, deleted_at).
5
+ * Collection schemas are append-only. Includes content manifest, migration
6
+ * conflicts, and checkpoint tables.
7
+ */
8
+ export const v001InitialSchema = {
9
+ version: 1,
10
+ name: 'initial_schema',
11
+ apply: async (sql) => {
12
+ // --- Content (append-only) ---
13
+ await sql.unsafe(`
14
+ CREATE TABLE content (
15
+ id TEXT PRIMARY KEY,
16
+ collection TEXT NOT NULL,
17
+ slug TEXT NOT NULL,
18
+ locale TEXT NOT NULL DEFAULT 'en',
19
+ version INTEGER NOT NULL,
20
+ is_current BOOLEAN NOT NULL DEFAULT TRUE,
21
+ status TEXT NOT NULL DEFAULT 'draft',
22
+ fields JSONB NOT NULL,
23
+ body TEXT NOT NULL,
24
+ html TEXT NOT NULL DEFAULT '',
25
+ sections JSONB NOT NULL DEFAULT '{}'::jsonb,
26
+ source TEXT NOT NULL DEFAULT 'api',
27
+ file_path TEXT,
28
+ changed_by TEXT,
29
+ deleted_at TIMESTAMPTZ,
30
+ created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
31
+ UNIQUE(collection, slug, locale, version)
32
+ )
33
+ `);
34
+ await sql.unsafe('CREATE INDEX idx_content_current ON content(collection, slug, locale) WHERE is_current = TRUE');
35
+ await sql.unsafe('CREATE INDEX idx_content_collection_status ON content(collection, status) WHERE is_current = TRUE');
36
+ await sql.unsafe('CREATE INDEX idx_content_slug ON content(slug) WHERE is_current = TRUE');
37
+ // --- Collection schemas (append-only) ---
38
+ await sql.unsafe(`
39
+ CREATE TABLE collection_schemas (
40
+ row_id TEXT PRIMARY KEY,
41
+ collection TEXT NOT NULL,
42
+ version INTEGER NOT NULL,
43
+ is_current BOOLEAN NOT NULL DEFAULT TRUE,
44
+ fields JSONB NOT NULL,
45
+ changed_by TEXT,
46
+ deleted_at TIMESTAMPTZ,
47
+ created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
48
+ UNIQUE(collection, version)
49
+ )
50
+ `);
51
+ await sql.unsafe('CREATE INDEX idx_schemas_current ON collection_schemas(collection) WHERE is_current = TRUE');
52
+ // --- Content manifest ---
53
+ await sql.unsafe(`
54
+ CREATE TABLE content_manifest (
55
+ id SERIAL PRIMARY KEY,
56
+ repo_version INTEGER NOT NULL,
57
+ imported_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
58
+ file_checksums JSONB NOT NULL
59
+ )
60
+ `);
61
+ await sql.unsafe(`
62
+ CREATE TABLE content_migration_conflicts (
63
+ id SERIAL PRIMARY KEY,
64
+ migration_id INTEGER NOT NULL,
65
+ collection TEXT NOT NULL,
66
+ slug TEXT NOT NULL,
67
+ repo_checksum TEXT NOT NULL,
68
+ db_checksum TEXT NOT NULL,
69
+ resolved BOOLEAN DEFAULT FALSE,
70
+ resolved_at TIMESTAMPTZ,
71
+ resolution TEXT
72
+ )
73
+ `);
74
+ await sql.unsafe('CREATE INDEX idx_content_conflicts_unresolved ON content_migration_conflicts(resolved) WHERE resolved = FALSE');
75
+ // --- Checkpoints ---
76
+ await sql.unsafe(`
77
+ CREATE TABLE checkpoints (
78
+ id SERIAL PRIMARY KEY,
79
+ version INTEGER NOT NULL UNIQUE,
80
+ name TEXT,
81
+ trigger TEXT NOT NULL,
82
+ created_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
83
+ )
84
+ `);
85
+ await sql.unsafe(`
86
+ CREATE TABLE checkpoint_counter (
87
+ id INTEGER PRIMARY KEY CHECK (id = 1),
88
+ next INTEGER NOT NULL DEFAULT 1
89
+ )
90
+ `);
91
+ await sql.unsafe('INSERT INTO checkpoint_counter (id, next) VALUES (1, 1)');
92
+ },
93
+ };
94
+ //# sourceMappingURL=v001-initial-schema.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"v001-initial-schema.js","sourceRoot":"","sources":["../../src/migrations/v001-initial-schema.ts"],"names":[],"mappings":"AAEA;;;;;;GAMG;AACH,MAAM,CAAC,MAAM,iBAAiB,GAAsB;IAClD,OAAO,EAAE,CAAC;IACV,IAAI,EAAE,gBAAgB;IACtB,KAAK,EAAE,KAAK,EAAE,GAAG,EAAE,EAAE;QACnB,gCAAgC;QAEhC,MAAM,GAAG,CAAC,MAAM,CAAC;;;;;;;;;;;;;;;;;;;;KAoBhB,CAAC,CAAA;QAEF,MAAM,GAAG,CAAC,MAAM,CACd,+FAA+F,CAChG,CAAA;QACD,MAAM,GAAG,CAAC,MAAM,CACd,mGAAmG,CACpG,CAAA;QACD,MAAM,GAAG,CAAC,MAAM,CAAC,wEAAwE,CAAC,CAAA;QAE1F,2CAA2C;QAE3C,MAAM,GAAG,CAAC,MAAM,CAAC;;;;;;;;;;;;KAYhB,CAAC,CAAA;QAEF,MAAM,GAAG,CAAC,MAAM,CACd,4FAA4F,CAC7F,CAAA;QAED,2BAA2B;QAE3B,MAAM,GAAG,CAAC,MAAM,CAAC;;;;;;;KAOhB,CAAC,CAAA;QAEF,MAAM,GAAG,CAAC,MAAM,CAAC;;;;;;;;;;;;KAYhB,CAAC,CAAA;QAEF,MAAM,GAAG,CAAC,MAAM,CACd,+GAA+G,CAChH,CAAA;QAED,sBAAsB;QAEtB,MAAM,GAAG,CAAC,MAAM,CAAC;;;;;;;;KAQhB,CAAC,CAAA;QAEF,MAAM,GAAG,CAAC,MAAM,CAAC;;;;;KAKhB,CAAC,CAAA;QAEF,MAAM,GAAG,CAAC,MAAM,CAAC,yDAAyD,CAAC,CAAA;IAC7E,CAAC;CACF,CAAA"}
@@ -0,0 +1,8 @@
1
+ import type { PostgresMigration } from '../migration-runner.js';
2
+ /**
3
+ * V002: Auth tables — users and refresh tokens.
4
+ *
5
+ * Postgres uses UUID defaults, TEXT[] for roles, BOOLEAN, TIMESTAMPTZ.
6
+ */
7
+ export declare const v002AuthTables: PostgresMigration;
8
+ //# sourceMappingURL=v002-auth-tables.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"v002-auth-tables.d.ts","sourceRoot":"","sources":["../../src/migrations/v002-auth-tables.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,wBAAwB,CAAA;AAE/D;;;;GAIG;AACH,eAAO,MAAM,cAAc,EAAE,iBAgC5B,CAAA"}
@@ -0,0 +1,37 @@
1
+ /**
2
+ * V002: Auth tables — users and refresh tokens.
3
+ *
4
+ * Postgres uses UUID defaults, TEXT[] for roles, BOOLEAN, TIMESTAMPTZ.
5
+ */
6
+ export const v002AuthTables = {
7
+ version: 2,
8
+ name: 'auth_tables',
9
+ apply: async (sql) => {
10
+ await sql.unsafe(`
11
+ CREATE TABLE users (
12
+ id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
13
+ email TEXT UNIQUE,
14
+ name TEXT,
15
+ roles TEXT[] NOT NULL DEFAULT '{viewer}',
16
+ oidc_subject TEXT,
17
+ oidc_issuer TEXT,
18
+ is_active BOOLEAN NOT NULL DEFAULT true,
19
+ created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
20
+ updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
21
+ UNIQUE(oidc_issuer, oidc_subject)
22
+ )
23
+ `);
24
+ await sql.unsafe(`
25
+ CREATE TABLE refresh_tokens (
26
+ id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
27
+ user_id UUID NOT NULL REFERENCES users(id) ON DELETE CASCADE,
28
+ token_hash TEXT NOT NULL UNIQUE,
29
+ expires_at TIMESTAMPTZ NOT NULL,
30
+ created_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
31
+ )
32
+ `);
33
+ await sql.unsafe('CREATE INDEX idx_refresh_user ON refresh_tokens(user_id)');
34
+ await sql.unsafe('CREATE INDEX idx_refresh_expires ON refresh_tokens(expires_at)');
35
+ },
36
+ };
37
+ //# sourceMappingURL=v002-auth-tables.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"v002-auth-tables.js","sourceRoot":"","sources":["../../src/migrations/v002-auth-tables.ts"],"names":[],"mappings":"AAEA;;;;GAIG;AACH,MAAM,CAAC,MAAM,cAAc,GAAsB;IAC/C,OAAO,EAAE,CAAC;IACV,IAAI,EAAE,aAAa;IACnB,KAAK,EAAE,KAAK,EAAE,GAAG,EAAE,EAAE;QACnB,MAAM,GAAG,CAAC,MAAM,CAAC;;;;;;;;;;;;;KAahB,CAAC,CAAA;QAEF,MAAM,GAAG,CAAC,MAAM,CAAC;;;;;;;;KAQhB,CAAC,CAAA;QAEF,MAAM,GAAG,CAAC,MAAM,CAAC,0DAA0D,CAAC,CAAA;QAC5E,MAAM,GAAG,CAAC,MAAM,CAAC,gEAAgE,CAAC,CAAA;IACpF,CAAC;CACF,CAAA"}
@@ -0,0 +1,6 @@
1
+ import type { PostgresMigration } from '../migration-runner.js';
2
+ /**
3
+ * V003: Per-collection permission overrides.
4
+ */
5
+ export declare const v003UserPermissions: PostgresMigration;
6
+ //# sourceMappingURL=v003-user-permissions.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"v003-user-permissions.d.ts","sourceRoot":"","sources":["../../src/migrations/v003-user-permissions.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,wBAAwB,CAAA;AAE/D;;GAEG;AACH,eAAO,MAAM,mBAAmB,EAAE,iBAajC,CAAA"}
@@ -0,0 +1,18 @@
1
+ /**
2
+ * V003: Per-collection permission overrides.
3
+ */
4
+ export const v003UserPermissions = {
5
+ version: 3,
6
+ name: 'user_permissions',
7
+ apply: async (sql) => {
8
+ await sql.unsafe(`
9
+ CREATE TABLE user_permissions (
10
+ user_id UUID NOT NULL REFERENCES users(id) ON DELETE CASCADE,
11
+ collection TEXT NOT NULL,
12
+ role TEXT NOT NULL,
13
+ PRIMARY KEY (user_id, collection)
14
+ )
15
+ `);
16
+ },
17
+ };
18
+ //# sourceMappingURL=v003-user-permissions.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"v003-user-permissions.js","sourceRoot":"","sources":["../../src/migrations/v003-user-permissions.ts"],"names":[],"mappings":"AAEA;;GAEG;AACH,MAAM,CAAC,MAAM,mBAAmB,GAAsB;IACpD,OAAO,EAAE,CAAC;IACV,IAAI,EAAE,kBAAkB;IACxB,KAAK,EAAE,KAAK,EAAE,GAAG,EAAE,EAAE;QACnB,MAAM,GAAG,CAAC,MAAM,CAAC;;;;;;;KAOhB,CAAC,CAAA;IACJ,CAAC;CACF,CAAA"}
@@ -0,0 +1,14 @@
1
+ import type { PostgresMigration } from '../migration-runner.js';
2
+ /**
3
+ * V004: Add hotspot column to media table.
4
+ *
5
+ * Stores a JSON-encoded hotspot (center + ellipse) for adaptive
6
+ * aspect-ratio cropping. NULL means no hotspot defined.
7
+ *
8
+ * It ran before the `media` table was part of the migrated schema, so it is a
9
+ * no-op when the table is missing. It stays because applied migrations form
10
+ * the numbered ledger (the checksum covers only `version:name`); v011 creates
11
+ * `media` with the hotspot column.
12
+ */
13
+ export declare const v004MediaHotspot: PostgresMigration;
14
+ //# sourceMappingURL=v004-media-hotspot.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"v004-media-hotspot.d.ts","sourceRoot":"","sources":["../../src/migrations/v004-media-hotspot.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,wBAAwB,CAAA;AAE/D;;;;;;;;;;GAUG;AACH,eAAO,MAAM,gBAAgB,EAAE,iBAe9B,CAAA"}
@@ -0,0 +1,25 @@
1
+ /**
2
+ * V004: Add hotspot column to media table.
3
+ *
4
+ * Stores a JSON-encoded hotspot (center + ellipse) for adaptive
5
+ * aspect-ratio cropping. NULL means no hotspot defined.
6
+ *
7
+ * It ran before the `media` table was part of the migrated schema, so it is a
8
+ * no-op when the table is missing. It stays because applied migrations form
9
+ * the numbered ledger (the checksum covers only `version:name`); v011 creates
10
+ * `media` with the hotspot column.
11
+ */
12
+ export const v004MediaHotspot = {
13
+ version: 4,
14
+ name: 'media_hotspot',
15
+ apply: async (sql) => {
16
+ const tables = await sql.unsafe(`SELECT table_name FROM information_schema.tables WHERE table_name = 'media' AND table_schema = current_schema()`);
17
+ if (tables.length === 0)
18
+ return;
19
+ const cols = await sql.unsafe(`SELECT column_name FROM information_schema.columns WHERE table_name = 'media' AND column_name = 'hotspot'`);
20
+ if (cols.length > 0)
21
+ return;
22
+ await sql.unsafe(`ALTER TABLE media ADD COLUMN hotspot JSONB DEFAULT NULL`);
23
+ },
24
+ };
25
+ //# sourceMappingURL=v004-media-hotspot.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"v004-media-hotspot.js","sourceRoot":"","sources":["../../src/migrations/v004-media-hotspot.ts"],"names":[],"mappings":"AAEA;;;;;;;;;;GAUG;AACH,MAAM,CAAC,MAAM,gBAAgB,GAAsB;IACjD,OAAO,EAAE,CAAC;IACV,IAAI,EAAE,eAAe;IACrB,KAAK,EAAE,KAAK,EAAE,GAAG,EAAE,EAAE;QACnB,MAAM,MAAM,GAAG,MAAM,GAAG,CAAC,MAAM,CAC7B,iHAAiH,CAClH,CAAA;QACD,IAAI,MAAM,CAAC,MAAM,KAAK,CAAC;YAAE,OAAM;QAE/B,MAAM,IAAI,GAAG,MAAM,GAAG,CAAC,MAAM,CAC3B,2GAA2G,CAC5G,CAAA;QACD,IAAI,IAAI,CAAC,MAAM,GAAG,CAAC;YAAE,OAAM;QAC3B,MAAM,GAAG,CAAC,MAAM,CAAC,yDAAyD,CAAC,CAAA;IAC7E,CAAC;CACF,CAAA"}
@@ -0,0 +1,6 @@
1
+ import type { PostgresMigration } from '../migration-runner.js';
2
+ /**
3
+ * V005: Advisory content locks.
4
+ */
5
+ export declare const v005ContentLocks: PostgresMigration;
6
+ //# sourceMappingURL=v005-content-locks.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"v005-content-locks.d.ts","sourceRoot":"","sources":["../../src/migrations/v005-content-locks.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,wBAAwB,CAAA;AAE/D;;GAEG;AACH,eAAO,MAAM,gBAAgB,EAAE,iBAgB9B,CAAA"}
@@ -0,0 +1,21 @@
1
+ /**
2
+ * V005: Advisory content locks.
3
+ */
4
+ export const v005ContentLocks = {
5
+ version: 5,
6
+ name: 'content_locks',
7
+ apply: async (sql) => {
8
+ await sql.unsafe(`
9
+ CREATE TABLE content_locks (
10
+ collection TEXT NOT NULL,
11
+ slug TEXT NOT NULL,
12
+ locale TEXT NOT NULL DEFAULT 'en',
13
+ locked_by TEXT NOT NULL,
14
+ locked_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
15
+ expires_at TIMESTAMPTZ NOT NULL,
16
+ PRIMARY KEY (collection, slug, locale)
17
+ )
18
+ `);
19
+ },
20
+ };
21
+ //# sourceMappingURL=v005-content-locks.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"v005-content-locks.js","sourceRoot":"","sources":["../../src/migrations/v005-content-locks.ts"],"names":[],"mappings":"AAEA;;GAEG;AACH,MAAM,CAAC,MAAM,gBAAgB,GAAsB;IACjD,OAAO,EAAE,CAAC;IACV,IAAI,EAAE,eAAe;IACrB,KAAK,EAAE,KAAK,EAAE,GAAG,EAAE,EAAE;QACnB,MAAM,GAAG,CAAC,MAAM,CAAC;;;;;;;;;;KAUhB,CAAC,CAAA;IACJ,CAAC;CACF,CAAA"}
@@ -0,0 +1,6 @@
1
+ import type { PostgresMigration } from '../migration-runner.js';
2
+ /**
3
+ * V006: Webhook delivery log with retry support.
4
+ */
5
+ export declare const v006WebhookDeliveries: PostgresMigration;
6
+ //# sourceMappingURL=v006-webhook-deliveries.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"v006-webhook-deliveries.d.ts","sourceRoot":"","sources":["../../src/migrations/v006-webhook-deliveries.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,wBAAwB,CAAA;AAE/D;;GAEG;AACH,eAAO,MAAM,qBAAqB,EAAE,iBAqBnC,CAAA"}
@@ -0,0 +1,24 @@
1
+ /**
2
+ * V006: Webhook delivery log with retry support.
3
+ */
4
+ export const v006WebhookDeliveries = {
5
+ version: 6,
6
+ name: 'webhook_deliveries',
7
+ apply: async (sql) => {
8
+ await sql.unsafe(`
9
+ CREATE TABLE webhook_deliveries (
10
+ id SERIAL PRIMARY KEY,
11
+ webhook_url TEXT NOT NULL,
12
+ event TEXT NOT NULL,
13
+ payload JSONB NOT NULL,
14
+ status INTEGER,
15
+ attempts INTEGER NOT NULL DEFAULT 0,
16
+ next_retry_at TIMESTAMPTZ,
17
+ created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
18
+ delivered_at TIMESTAMPTZ
19
+ )
20
+ `);
21
+ await sql.unsafe('CREATE INDEX idx_webhook_pending ON webhook_deliveries(next_retry_at) WHERE delivered_at IS NULL AND attempts < 5');
22
+ },
23
+ };
24
+ //# sourceMappingURL=v006-webhook-deliveries.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"v006-webhook-deliveries.js","sourceRoot":"","sources":["../../src/migrations/v006-webhook-deliveries.ts"],"names":[],"mappings":"AAEA;;GAEG;AACH,MAAM,CAAC,MAAM,qBAAqB,GAAsB;IACtD,OAAO,EAAE,CAAC;IACV,IAAI,EAAE,oBAAoB;IAC1B,KAAK,EAAE,KAAK,EAAE,GAAG,EAAE,EAAE;QACnB,MAAM,GAAG,CAAC,MAAM,CAAC;;;;;;;;;;;;KAYhB,CAAC,CAAA;QACF,MAAM,GAAG,CAAC,MAAM,CACd,mHAAmH,CACpH,CAAA;IACH,CAAC;CACF,CAAA"}
@@ -0,0 +1,6 @@
1
+ import type { PostgresMigration } from '../migration-runner.js';
2
+ /**
3
+ * V007: Media folders — hierarchical folder structure for media organization.
4
+ */
5
+ export declare const v007MediaFolders: PostgresMigration;
6
+ //# sourceMappingURL=v007-media-folders.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"v007-media-folders.d.ts","sourceRoot":"","sources":["../../src/migrations/v007-media-folders.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,wBAAwB,CAAA;AAE/D;;GAEG;AACH,eAAO,MAAM,gBAAgB,EAAE,iBAc9B,CAAA"}
@@ -0,0 +1,19 @@
1
+ /**
2
+ * V007: Media folders — hierarchical folder structure for media organization.
3
+ */
4
+ export const v007MediaFolders = {
5
+ version: 7,
6
+ name: 'media_folders',
7
+ apply: async (sql) => {
8
+ await sql.unsafe(`
9
+ CREATE TABLE media_folders (
10
+ id TEXT PRIMARY KEY,
11
+ name TEXT NOT NULL,
12
+ parent_id TEXT REFERENCES media_folders(id),
13
+ created_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
14
+ )
15
+ `);
16
+ await sql.unsafe('CREATE INDEX idx_media_folders_parent ON media_folders(parent_id)');
17
+ },
18
+ };
19
+ //# sourceMappingURL=v007-media-folders.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"v007-media-folders.js","sourceRoot":"","sources":["../../src/migrations/v007-media-folders.ts"],"names":[],"mappings":"AAEA;;GAEG;AACH,MAAM,CAAC,MAAM,gBAAgB,GAAsB;IACjD,OAAO,EAAE,CAAC;IACV,IAAI,EAAE,eAAe;IACrB,KAAK,EAAE,KAAK,EAAE,GAAG,EAAE,EAAE;QACnB,MAAM,GAAG,CAAC,MAAM,CAAC;;;;;;;KAOhB,CAAC,CAAA;QACF,MAAM,GAAG,CAAC,MAAM,CAAC,mEAAmE,CAAC,CAAA;IACvF,CAAC;CACF,CAAA"}
@@ -0,0 +1,6 @@
1
+ import type { PostgresMigration } from '../migration-runner.js';
2
+ /**
3
+ * V008: Site settings — runtime-configurable key-value settings.
4
+ */
5
+ export declare const v008SiteSettings: PostgresMigration;
6
+ //# sourceMappingURL=v008-site-settings.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"v008-site-settings.d.ts","sourceRoot":"","sources":["../../src/migrations/v008-site-settings.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,wBAAwB,CAAA;AAE/D;;GAEG;AACH,eAAO,MAAM,gBAAgB,EAAE,iBAY9B,CAAA"}
@@ -0,0 +1,17 @@
1
+ /**
2
+ * V008: Site settings — runtime-configurable key-value settings.
3
+ */
4
+ export const v008SiteSettings = {
5
+ version: 8,
6
+ name: 'site_settings',
7
+ apply: async (sql) => {
8
+ await sql.unsafe(`
9
+ CREATE TABLE site_settings (
10
+ key TEXT PRIMARY KEY,
11
+ value TEXT NOT NULL,
12
+ updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
13
+ )
14
+ `);
15
+ },
16
+ };
17
+ //# sourceMappingURL=v008-site-settings.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"v008-site-settings.js","sourceRoot":"","sources":["../../src/migrations/v008-site-settings.ts"],"names":[],"mappings":"AAEA;;GAEG;AACH,MAAM,CAAC,MAAM,gBAAgB,GAAsB;IACjD,OAAO,EAAE,CAAC;IACV,IAAI,EAAE,eAAe;IACrB,KAAK,EAAE,KAAK,EAAE,GAAG,EAAE,EAAE;QACnB,MAAM,GAAG,CAAC,MAAM,CAAC;;;;;;KAMhB,CAAC,CAAA;IACJ,CAAC;CACF,CAAA"}
@@ -0,0 +1,12 @@
1
+ import type { PostgresMigration } from '../migration-runner.js';
2
+ /**
3
+ * V009: SEO configuration — structured entity graph per site, collection,
4
+ * document, or route.
5
+ *
6
+ * Stores a single `config` JSONB column holding a `SeoConfigData` object
7
+ * with an ordered entity array and optional field-mapping overrides.
8
+ * A GIN index on the column enables containment queries for site-wide
9
+ * lookups (e.g. "find every doc that uses an Article entity").
10
+ */
11
+ export declare const v009SeoConfig: PostgresMigration;
12
+ //# sourceMappingURL=v009-seo-config.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"v009-seo-config.d.ts","sourceRoot":"","sources":["../../src/migrations/v009-seo-config.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,wBAAwB,CAAA;AAE/D;;;;;;;;GAQG;AACH,eAAO,MAAM,aAAa,EAAE,iBAkB3B,CAAA"}
@@ -0,0 +1,27 @@
1
+ /**
2
+ * V009: SEO configuration — structured entity graph per site, collection,
3
+ * document, or route.
4
+ *
5
+ * Stores a single `config` JSONB column holding a `SeoConfigData` object
6
+ * with an ordered entity array and optional field-mapping overrides.
7
+ * A GIN index on the column enables containment queries for site-wide
8
+ * lookups (e.g. "find every doc that uses an Article entity").
9
+ */
10
+ export const v009SeoConfig = {
11
+ version: 9,
12
+ name: 'seo_config',
13
+ apply: async (sql) => {
14
+ await sql.unsafe(`
15
+ CREATE TABLE seo_config (
16
+ id TEXT PRIMARY KEY,
17
+ scope TEXT NOT NULL CHECK (scope IN ('site', 'collection', 'document', 'route')),
18
+ config JSONB NOT NULL DEFAULT '{"entities":[]}'::jsonb,
19
+ created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
20
+ updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
21
+ )
22
+ `);
23
+ await sql.unsafe('CREATE INDEX idx_seo_config_scope ON seo_config(scope)');
24
+ await sql.unsafe('CREATE INDEX idx_seo_config_gin ON seo_config USING GIN (config jsonb_path_ops)');
25
+ },
26
+ };
27
+ //# sourceMappingURL=v009-seo-config.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"v009-seo-config.js","sourceRoot":"","sources":["../../src/migrations/v009-seo-config.ts"],"names":[],"mappings":"AAEA;;;;;;;;GAQG;AACH,MAAM,CAAC,MAAM,aAAa,GAAsB;IAC9C,OAAO,EAAE,CAAC;IACV,IAAI,EAAE,YAAY;IAClB,KAAK,EAAE,KAAK,EAAE,GAAG,EAAE,EAAE;QACnB,MAAM,GAAG,CAAC,MAAM,CAAC;;;;;;;;KAQhB,CAAC,CAAA;QACF,MAAM,GAAG,CAAC,MAAM,CAAC,wDAAwD,CAAC,CAAA;QAC1E,MAAM,GAAG,CAAC,MAAM,CACd,iFAAiF,CAClF,CAAA;IACH,CAAC;CACF,CAAA"}