emdash 0.2.0 → 0.4.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/{adapters-N6BF7RCD.d.mts → adapters-C2BzVy0p.d.mts} +1 -1
- package/dist/{adapters-N6BF7RCD.d.mts.map → adapters-C2BzVy0p.d.mts.map} +1 -1
- package/dist/{apply-wmVEOSbR.mjs → apply-Cma_PiF6.mjs} +38 -23
- package/dist/apply-Cma_PiF6.mjs.map +1 -0
- package/dist/astro/index.d.mts +25 -11
- package/dist/astro/index.d.mts.map +1 -1
- package/dist/astro/index.mjs +38 -25
- package/dist/astro/index.mjs.map +1 -1
- package/dist/astro/middleware/auth.d.mts +5 -5
- package/dist/astro/middleware/auth.mjs +2 -2
- package/dist/astro/middleware/redirect.d.mts.map +1 -1
- package/dist/astro/middleware/redirect.mjs +20 -8
- package/dist/astro/middleware/redirect.mjs.map +1 -1
- package/dist/astro/middleware/request-context.mjs +12 -2
- package/dist/astro/middleware/request-context.mjs.map +1 -1
- package/dist/astro/middleware/setup.mjs +1 -1
- package/dist/astro/middleware.d.mts.map +1 -1
- package/dist/astro/middleware.mjs +52 -45
- package/dist/astro/middleware.mjs.map +1 -1
- package/dist/astro/types.d.mts +9 -9
- package/dist/astro/types.d.mts.map +1 -1
- package/dist/{byline-1WQPlISL.mjs → byline-WuOq9MFJ.mjs} +5 -4
- package/dist/byline-WuOq9MFJ.mjs.map +1 -0
- package/dist/{bylines-BYdTYmia.mjs → bylines-C_Wsnz4L.mjs} +38 -6
- package/dist/bylines-C_Wsnz4L.mjs.map +1 -0
- package/dist/cache-E3Dts-yT.mjs +56 -0
- package/dist/cache-E3Dts-yT.mjs.map +1 -0
- package/dist/cli/index.mjs +13 -13
- package/dist/cli/index.mjs.map +1 -1
- package/dist/client/cf-access.d.mts +1 -1
- package/dist/client/index.d.mts +1 -1
- package/dist/client/index.mjs +1 -1
- package/dist/{config-Cq8H0SfX.mjs → config-DkxPrM9l.mjs} +1 -1
- package/dist/{config-Cq8H0SfX.mjs.map → config-DkxPrM9l.mjs.map} +1 -1
- package/dist/{content-BmXndhdi.mjs → content-BsBoyj8G.mjs} +20 -3
- package/dist/content-BsBoyj8G.mjs.map +1 -0
- package/dist/db/index.d.mts +3 -3
- package/dist/db/index.mjs +2 -2
- package/dist/db/libsql.d.mts +1 -1
- package/dist/db/postgres.d.mts +1 -1
- package/dist/db/sqlite.d.mts +1 -1
- package/dist/{default-WYlzADZL.mjs → default-PUx9RK6u.mjs} +1 -1
- package/dist/{default-WYlzADZL.mjs.map → default-PUx9RK6u.mjs.map} +1 -1
- package/dist/{dialect-helpers-B9uSp2GJ.mjs → dialect-helpers-DhTzaUxP.mjs} +4 -1
- package/dist/dialect-helpers-DhTzaUxP.mjs.map +1 -0
- package/dist/{error-DrxtnGPg.mjs → error-HBeQbVhV.mjs} +1 -1
- package/dist/{error-DrxtnGPg.mjs.map → error-HBeQbVhV.mjs.map} +1 -1
- package/dist/{index-UHEVQMus.d.mts → index-CRg3PWfZ.d.mts} +59 -33
- package/dist/index-CRg3PWfZ.d.mts.map +1 -0
- package/dist/index.d.mts +11 -11
- package/dist/index.mjs +20 -20
- package/dist/{load-Veizk2cT.mjs → load-BhSSm-TS.mjs} +1 -1
- package/dist/{load-Veizk2cT.mjs.map → load-BhSSm-TS.mjs.map} +1 -1
- package/dist/{loader-CHb2v0jm.mjs → loader-BYzwzORf.mjs} +4 -2
- package/dist/loader-BYzwzORf.mjs.map +1 -0
- package/dist/{manifest-schema-CuMio1A9.mjs → manifest-schema-BsXINkQD.mjs} +1 -1
- package/dist/{manifest-schema-CuMio1A9.mjs.map → manifest-schema-BsXINkQD.mjs.map} +1 -1
- package/dist/media/index.d.mts +1 -1
- package/dist/media/index.mjs +1 -1
- package/dist/media/local-runtime.d.mts +7 -7
- package/dist/{mode-CYeM2rPt.mjs → mode-CyPLdO3C.mjs} +1 -1
- package/dist/{mode-CYeM2rPt.mjs.map → mode-CyPLdO3C.mjs.map} +1 -1
- package/dist/page/index.d.mts +1 -1
- package/dist/patterns-CrCYkMBb.mjs +93 -0
- package/dist/patterns-CrCYkMBb.mjs.map +1 -0
- package/dist/{placeholder-bOx1xCTY.d.mts → placeholder-BBCtpTES.d.mts} +1 -1
- package/dist/{placeholder-bOx1xCTY.d.mts.map → placeholder-BBCtpTES.d.mts.map} +1 -1
- package/dist/{placeholder-aiCD8aSZ.mjs → placeholder-DntBEQo7.mjs} +1 -1
- package/dist/{placeholder-aiCD8aSZ.mjs.map → placeholder-DntBEQo7.mjs.map} +1 -1
- package/dist/plugins/adapt-sandbox-entry.d.mts +5 -5
- package/dist/plugins/adapt-sandbox-entry.mjs +1 -1
- package/dist/{query-5Hcv_5ER.mjs → query-B6Vu0d2i.mjs} +35 -16
- package/dist/{query-5Hcv_5ER.mjs.map → query-B6Vu0d2i.mjs.map} +1 -1
- package/dist/{redirect-DIfIni3r.mjs → redirect-7lGhLBNZ.mjs} +10 -93
- package/dist/redirect-7lGhLBNZ.mjs.map +1 -0
- package/dist/{registry-1EvbAfsC.mjs → registry-BgnP3ysR.mjs} +27 -37
- package/dist/registry-BgnP3ysR.mjs.map +1 -0
- package/dist/{runner-BoN0-FPi.mjs → runner-Cd-_WyDo.mjs} +18 -6
- package/dist/runner-Cd-_WyDo.mjs.map +1 -0
- package/dist/{runner-DTqkzOzc.d.mts → runner-DYv3rX8P.d.mts} +10 -3
- package/dist/runner-DYv3rX8P.d.mts.map +1 -0
- package/dist/runtime.d.mts +6 -6
- package/dist/runtime.mjs +2 -2
- package/dist/{search-BsYMed12.mjs → search-B5p9D36n.mjs} +108 -57
- package/dist/search-B5p9D36n.mjs.map +1 -0
- package/dist/seed/index.d.mts +2 -2
- package/dist/seed/index.mjs +10 -10
- package/dist/seo/index.d.mts +1 -1
- package/dist/storage/local.d.mts +1 -1
- package/dist/storage/local.mjs +1 -1
- package/dist/storage/s3.d.mts +11 -3
- package/dist/storage/s3.d.mts.map +1 -1
- package/dist/storage/s3.mjs +76 -15
- package/dist/storage/s3.mjs.map +1 -1
- package/dist/{tokens-DrB-W6Q-.mjs → tokens-DKHiCYCB.mjs} +1 -1
- package/dist/{tokens-DrB-W6Q-.mjs.map → tokens-DKHiCYCB.mjs.map} +1 -1
- package/dist/transaction-Cn2rjY78.mjs +28 -0
- package/dist/transaction-Cn2rjY78.mjs.map +1 -0
- package/dist/{transport-Bl8cTdYt.mjs → transport-BtcQ-Z7T.mjs} +1 -1
- package/dist/{transport-Bl8cTdYt.mjs.map → transport-BtcQ-Z7T.mjs.map} +1 -1
- package/dist/{transport-COOs9GSE.d.mts → transport-CKQA_G44.d.mts} +1 -1
- package/dist/{transport-COOs9GSE.d.mts.map → transport-CKQA_G44.d.mts.map} +1 -1
- package/dist/{types-7-UjSEyB.d.mts → types-B6BzlZxx.d.mts} +1 -1
- package/dist/{types-7-UjSEyB.d.mts.map → types-B6BzlZxx.d.mts.map} +1 -1
- package/dist/{types-6dqxBqsH.d.mts → types-BYWYxLcp.d.mts} +109 -5
- package/dist/types-BYWYxLcp.d.mts.map +1 -0
- package/dist/{types-CIsTnQvJ.d.mts → types-BmkQR1En.d.mts} +1 -1
- package/dist/{types-CIsTnQvJ.d.mts.map → types-BmkQR1En.d.mts.map} +1 -1
- package/dist/{types-BljtYPSd.d.mts → types-DNZpaCBk.d.mts} +14 -6
- package/dist/types-DNZpaCBk.d.mts.map +1 -0
- package/dist/{types-Bec-r_3_.mjs → types-Dz9_WMS6.mjs} +1 -1
- package/dist/types-Dz9_WMS6.mjs.map +1 -0
- package/dist/{types-CcreFIIH.d.mts → types-gLYVCXCQ.d.mts} +1 -1
- package/dist/{types-CcreFIIH.d.mts.map → types-gLYVCXCQ.d.mts.map} +1 -1
- package/dist/{types-DuNbGKjF.mjs → types-xxCWI3j0.mjs} +1 -1
- package/dist/{types-DuNbGKjF.mjs.map → types-xxCWI3j0.mjs.map} +1 -1
- package/dist/{validate-B7KP7VLM.d.mts → validate-CcNRWH6I.d.mts} +4 -4
- package/dist/{validate-B7KP7VLM.d.mts.map → validate-CcNRWH6I.d.mts.map} +1 -1
- package/dist/{validate-CXnRKfJK.mjs → validate-DuZDIxfy.mjs} +2 -2
- package/dist/{validate-CXnRKfJK.mjs.map → validate-DuZDIxfy.mjs.map} +1 -1
- package/dist/{validate-CqRJb_xU.mjs → validate-VPnKoIzW.mjs} +11 -11
- package/dist/{validate-CqRJb_xU.mjs.map → validate-VPnKoIzW.mjs.map} +1 -1
- package/dist/version-DlTDRdpv.mjs +7 -0
- package/dist/version-DlTDRdpv.mjs.map +1 -0
- package/package.json +7 -5
- package/src/api/handlers/content.ts +36 -25
- package/src/api/handlers/menus.ts +19 -16
- package/src/api/handlers/redirects.ts +95 -3
- package/src/api/schemas/redirects.ts +1 -0
- package/src/astro/integration/index.ts +2 -3
- package/src/astro/integration/runtime.ts +8 -14
- package/src/astro/integration/vite-config.ts +14 -4
- package/src/astro/middleware/redirect.ts +30 -15
- package/src/astro/middleware.ts +11 -19
- package/src/astro/routes/admin.astro +2 -2
- package/src/astro/routes/api/admin/bylines/[id]/index.ts +3 -0
- package/src/astro/routes/api/admin/bylines/index.ts +2 -0
- package/src/astro/routes/api/comments/[collection]/[contentId]/index.ts +2 -0
- package/src/astro/routes/api/import/wordpress/rewrite-urls.ts +2 -0
- package/src/astro/routes/api/manifest.ts +3 -1
- package/src/astro/routes/api/redirects/[id].ts +3 -0
- package/src/astro/routes/api/redirects/index.ts +2 -0
- package/src/astro/routes/api/schema/collections/[slug]/index.ts +2 -0
- package/src/astro/routes/api/schema/collections/index.ts +1 -0
- package/src/astro/storage/adapters.ts +19 -5
- package/src/astro/storage/types.ts +12 -4
- package/src/astro/types.ts +1 -0
- package/src/bylines/index.ts +50 -2
- package/src/cleanup.ts +3 -3
- package/src/cli/commands/bundle-utils.ts +5 -5
- package/src/database/dialect-helpers.ts +3 -0
- package/src/database/migrations/011_sections.ts +2 -2
- package/src/database/migrations/runner.ts +23 -2
- package/src/database/repositories/byline.ts +2 -1
- package/src/database/repositories/content.ts +5 -0
- package/src/database/repositories/redirect.ts +13 -0
- package/src/database/validate.ts +10 -10
- package/src/emdash-runtime.ts +23 -9
- package/src/index.ts +3 -0
- package/src/loader.ts +2 -0
- package/src/mcp/server.ts +40 -67
- package/src/menus/index.ts +4 -0
- package/src/plugins/context.ts +28 -4
- package/src/plugins/cron.ts +29 -4
- package/src/plugins/hooks.ts +22 -10
- package/src/plugins/index.ts +1 -0
- package/src/plugins/manager.ts +6 -2
- package/src/plugins/marketplace.ts +33 -3
- package/src/plugins/routes.ts +3 -3
- package/src/plugins/types.ts +7 -0
- package/src/query.ts +37 -14
- package/src/redirects/cache.ts +68 -0
- package/src/redirects/loops.ts +318 -0
- package/src/schema/registry.ts +3 -0
- package/src/search/fts-manager.ts +24 -11
- package/src/search/query.ts +8 -9
- package/src/seed/apply.ts +49 -28
- package/src/storage/s3.ts +94 -25
- package/src/storage/types.ts +13 -5
- package/src/utils/slugify.ts +11 -0
- package/src/version.ts +12 -0
- package/src/visual-editing/toolbar.ts +11 -1
- package/dist/apply-wmVEOSbR.mjs.map +0 -1
- package/dist/byline-1WQPlISL.mjs.map +0 -1
- package/dist/bylines-BYdTYmia.mjs.map +0 -1
- package/dist/content-BmXndhdi.mjs.map +0 -1
- package/dist/dialect-helpers-B9uSp2GJ.mjs.map +0 -1
- package/dist/index-UHEVQMus.d.mts.map +0 -1
- package/dist/loader-CHb2v0jm.mjs.map +0 -1
- package/dist/redirect-DIfIni3r.mjs.map +0 -1
- package/dist/registry-1EvbAfsC.mjs.map +0 -1
- package/dist/runner-BoN0-FPi.mjs.map +0 -1
- package/dist/runner-DTqkzOzc.d.mts.map +0 -1
- package/dist/search-BsYMed12.mjs.map +0 -1
- package/dist/types-6dqxBqsH.d.mts.map +0 -1
- package/dist/types-Bec-r_3_.mjs.map +0 -1
- package/dist/types-BljtYPSd.d.mts.map +0 -1
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"content-BmXndhdi.mjs","names":[],"sources":["../src/utils/slugify.ts","../src/database/repositories/revision.ts","../src/database/repositories/content.ts"],"sourcesContent":["// Regex patterns for slug normalization\nconst DIACRITICS_PATTERN = /[\\u0300-\\u036f]/g;\nconst WHITESPACE_UNDERSCORE_PATTERN = /[\\s_]+/g;\nconst NON_ALPHANUMERIC_HYPHEN_PATTERN = /[^a-z0-9-]/g;\nconst MULTIPLE_HYPHENS_PATTERN = /-+/g;\nconst LEADING_TRAILING_HYPHEN_PATTERN = /^-|-$/g;\nconst TRAILING_HYPHEN_PATTERN = /-$/;\n\n/**\n * Convert a string to a URL-friendly slug.\n *\n * Handles unicode by normalizing to NFD and stripping diacritics,\n * so \"café\" becomes \"cafe\", \"naïve\" becomes \"naive\", etc.\n */\nexport function slugify(text: string, maxLength: number = 80): string {\n\treturn (\n\t\ttext\n\t\t\t.toLowerCase()\n\t\t\t.normalize(\"NFD\")\n\t\t\t.replace(DIACRITICS_PATTERN, \"\")\n\t\t\t.replace(WHITESPACE_UNDERSCORE_PATTERN, \"-\")\n\t\t\t.replace(NON_ALPHANUMERIC_HYPHEN_PATTERN, \"\")\n\t\t\t.replace(MULTIPLE_HYPHENS_PATTERN, \"-\")\n\t\t\t.replace(LEADING_TRAILING_HYPHEN_PATTERN, \"\")\n\t\t\t.slice(0, maxLength)\n\t\t\t// Clean trailing hyphen from truncation\n\t\t\t.replace(TRAILING_HYPHEN_PATTERN, \"\")\n\t);\n}\n","import type { Kysely } from \"kysely\";\nimport { monotonicFactory } from \"ulidx\";\n\nimport type { Database, RevisionTable } from \"../types.js\";\n\nconst monotonic = monotonicFactory();\n\nexport interface Revision {\n\tid: string;\n\tcollection: string;\n\tentryId: string;\n\tdata: Record<string, unknown>;\n\tauthorId: string | null;\n\tcreatedAt: string;\n}\n\nexport interface CreateRevisionInput {\n\tcollection: string;\n\tentryId: string;\n\tdata: Record<string, unknown>;\n\tauthorId?: string;\n}\n\n/**\n * Revision repository for version history\n *\n * Each revision stores a JSON snapshot of the content at a point in time.\n * Used when collection has `supports: [\"revisions\"]` enabled.\n */\nexport class RevisionRepository {\n\tconstructor(private db: Kysely<Database>) {}\n\n\t/**\n\t * Create a new revision\n\t */\n\tasync create(input: CreateRevisionInput): Promise<Revision> {\n\t\tconst id = monotonic();\n\n\t\tconst row: Omit<RevisionTable, \"created_at\"> = {\n\t\t\tid,\n\t\t\tcollection: input.collection,\n\t\t\tentry_id: input.entryId,\n\t\t\tdata: JSON.stringify(input.data),\n\t\t\tauthor_id: input.authorId ?? null,\n\t\t};\n\n\t\tawait this.db.insertInto(\"revisions\").values(row).execute();\n\n\t\tconst revision = await this.findById(id);\n\t\tif (!revision) {\n\t\t\tthrow new Error(\"Failed to create revision\");\n\t\t}\n\t\treturn revision;\n\t}\n\n\t/**\n\t * Find revision by ID\n\t */\n\tasync findById(id: string): Promise<Revision | null> {\n\t\tconst row = await this.db\n\t\t\t.selectFrom(\"revisions\")\n\t\t\t.selectAll()\n\t\t\t.where(\"id\", \"=\", id)\n\t\t\t.executeTakeFirst();\n\n\t\treturn row ? this.rowToRevision(row) : null;\n\t}\n\n\t/**\n\t * Get all revisions for an entry (newest first)\n\t *\n\t * Orders by monotonic ULID (descending). The monotonic factory\n\t * guarantees strictly increasing IDs even within the same millisecond.\n\t */\n\tasync findByEntry(\n\t\tcollection: string,\n\t\tentryId: string,\n\t\toptions: { limit?: number } = {},\n\t): Promise<Revision[]> {\n\t\tlet query = this.db\n\t\t\t.selectFrom(\"revisions\")\n\t\t\t.selectAll()\n\t\t\t.where(\"collection\", \"=\", collection)\n\t\t\t.where(\"entry_id\", \"=\", entryId)\n\t\t\t.orderBy(\"id\", \"desc\");\n\n\t\tif (options.limit) {\n\t\t\tquery = query.limit(options.limit);\n\t\t}\n\n\t\tconst rows = await query.execute();\n\t\treturn rows.map((row) => this.rowToRevision(row));\n\t}\n\n\t/**\n\t * Get the most recent revision for an entry\n\t */\n\tasync findLatest(collection: string, entryId: string): Promise<Revision | null> {\n\t\tconst row = await this.db\n\t\t\t.selectFrom(\"revisions\")\n\t\t\t.selectAll()\n\t\t\t.where(\"collection\", \"=\", collection)\n\t\t\t.where(\"entry_id\", \"=\", entryId)\n\t\t\t.orderBy(\"id\", \"desc\")\n\t\t\t.limit(1)\n\t\t\t.executeTakeFirst();\n\n\t\treturn row ? this.rowToRevision(row) : null;\n\t}\n\n\t/**\n\t * Count revisions for an entry\n\t */\n\tasync countByEntry(collection: string, entryId: string): Promise<number> {\n\t\tconst result = await this.db\n\t\t\t.selectFrom(\"revisions\")\n\t\t\t.select((eb) => eb.fn.count(\"id\").as(\"count\"))\n\t\t\t.where(\"collection\", \"=\", collection)\n\t\t\t.where(\"entry_id\", \"=\", entryId)\n\t\t\t.executeTakeFirst();\n\n\t\treturn Number(result?.count || 0);\n\t}\n\n\t/**\n\t * Delete all revisions for an entry (use when entry is deleted)\n\t */\n\tasync deleteByEntry(collection: string, entryId: string): Promise<number> {\n\t\tconst result = await this.db\n\t\t\t.deleteFrom(\"revisions\")\n\t\t\t.where(\"collection\", \"=\", collection)\n\t\t\t.where(\"entry_id\", \"=\", entryId)\n\t\t\t.executeTakeFirst();\n\n\t\treturn Number(result.numDeletedRows ?? 0);\n\t}\n\n\t/**\n\t * Delete old revisions, keeping the most recent N\n\t */\n\tasync pruneOldRevisions(collection: string, entryId: string, keepCount: number): Promise<number> {\n\t\t// Get IDs of revisions to keep\n\t\tconst keep = await this.db\n\t\t\t.selectFrom(\"revisions\")\n\t\t\t.select(\"id\")\n\t\t\t.where(\"collection\", \"=\", collection)\n\t\t\t.where(\"entry_id\", \"=\", entryId)\n\t\t\t.orderBy(\"created_at\", \"desc\")\n\t\t\t.orderBy(\"id\", \"desc\") // ULID tiebreaker\n\t\t\t.limit(keepCount)\n\t\t\t.execute();\n\n\t\tconst keepIds = keep.map((r) => r.id);\n\n\t\tif (keepIds.length === 0) return 0;\n\n\t\t// Delete everything else for this entry\n\t\tconst result = await this.db\n\t\t\t.deleteFrom(\"revisions\")\n\t\t\t.where(\"collection\", \"=\", collection)\n\t\t\t.where(\"entry_id\", \"=\", entryId)\n\t\t\t.where(\"id\", \"not in\", keepIds)\n\t\t\t.executeTakeFirst();\n\n\t\treturn Number(result.numDeletedRows ?? 0);\n\t}\n\n\t/**\n\t * Update revision data in place\n\t * Used for autosave to avoid creating many small revisions.\n\t */\n\tasync updateData(id: string, data: Record<string, unknown>): Promise<void> {\n\t\tawait this.db\n\t\t\t.updateTable(\"revisions\")\n\t\t\t.set({ data: JSON.stringify(data) })\n\t\t\t.where(\"id\", \"=\", id)\n\t\t\t.execute();\n\t}\n\n\t/**\n\t * Convert database row to Revision object\n\t */\n\tprivate rowToRevision(row: {\n\t\tid: string;\n\t\tcollection: string;\n\t\tentry_id: string;\n\t\tdata: string;\n\t\tauthor_id: string | null;\n\t\tcreated_at: string;\n\t}): Revision {\n\t\treturn {\n\t\t\tid: row.id,\n\t\t\tcollection: row.collection,\n\t\t\tentryId: row.entry_id,\n\t\t\tdata: JSON.parse(row.data),\n\t\t\tauthorId: row.author_id,\n\t\t\tcreatedAt: row.created_at,\n\t\t};\n\t}\n}\n","import { sql, type Kysely } from \"kysely\";\nimport { ulid } from \"ulidx\";\n\nimport { slugify } from \"../../utils/slugify.js\";\nimport type { Database } from \"../types.js\";\nimport { RevisionRepository } from \"./revision.js\";\nimport type {\n\tCreateContentInput,\n\tUpdateContentInput,\n\tFindManyOptions,\n\tFindManyResult,\n\tContentItem,\n} from \"./types.js\";\nimport { EmDashValidationError, encodeCursor, decodeCursor } from \"./types.js\";\n\n// Regex pattern for ULID validation\nconst ULID_PATTERN = /^[0-9A-Z]{26}$/;\n\n/**\n * System columns that exist in every ec_* table\n */\nconst SYSTEM_COLUMNS = new Set([\n\t\"id\",\n\t\"slug\",\n\t\"status\",\n\t\"author_id\",\n\t\"primary_byline_id\",\n\t\"created_at\",\n\t\"updated_at\",\n\t\"published_at\",\n\t\"scheduled_at\",\n\t\"deleted_at\",\n\t\"version\",\n\t\"live_revision_id\",\n\t\"draft_revision_id\",\n\t\"locale\",\n\t\"translation_group\",\n]);\n\n/**\n * Get the table name for a collection type\n */\nfunction getTableName(type: string): string {\n\treturn `ec_${type}`;\n}\n\n/**\n * Serialize a value for database storage\n * Objects/arrays are JSON-stringified\n * Booleans are converted to 0/1 for SQLite\n */\nfunction serializeValue(value: unknown): unknown {\n\tif (value === null || value === undefined) {\n\t\treturn null;\n\t}\n\tif (typeof value === \"boolean\") {\n\t\treturn value ? 1 : 0;\n\t}\n\tif (typeof value === \"object\") {\n\t\treturn JSON.stringify(value);\n\t}\n\treturn value;\n}\n\n/**\n * Deserialize a value from database storage\n * Attempts to parse JSON strings that look like objects/arrays\n */\nfunction deserializeValue(value: unknown): unknown {\n\tif (typeof value === \"string\") {\n\t\t// Try to parse if it looks like JSON\n\t\tif (value.startsWith(\"{\") || value.startsWith(\"[\")) {\n\t\t\ttry {\n\t\t\t\treturn JSON.parse(value);\n\t\t\t} catch {\n\t\t\t\treturn value;\n\t\t\t}\n\t\t}\n\t}\n\treturn value;\n}\n\n/** Pattern for escaping special regex characters */\nconst REGEX_ESCAPE_PATTERN = /[.*+?^${}()|[\\]\\\\]/g;\n\n/**\n * Escape special regex characters in a string for use in `new RegExp()`\n */\nfunction escapeRegExp(s: string): string {\n\treturn s.replace(REGEX_ESCAPE_PATTERN, \"\\\\$&\");\n}\n\n/**\n * Repository for content CRUD operations\n *\n * Content is stored in per-collection tables (ec_posts, ec_pages, etc.)\n * Each field becomes a real column in the table.\n */\nexport class ContentRepository {\n\tconstructor(private db: Kysely<Database>) {}\n\n\t/**\n\t * Create a new content item\n\t */\n\tasync create(input: CreateContentInput): Promise<ContentItem> {\n\t\tconst id = ulid();\n\t\tconst now = new Date().toISOString();\n\n\t\tconst {\n\t\t\ttype,\n\t\t\tslug,\n\t\t\tdata,\n\t\t\tstatus = \"draft\",\n\t\t\tauthorId,\n\t\t\tprimaryBylineId,\n\t\t\tlocale,\n\t\t\ttranslationOf,\n\t\t\tpublishedAt,\n\t\t\tcreatedAt,\n\t\t} = input;\n\n\t\t// Validate required fields\n\t\tif (!type) {\n\t\t\tthrow new EmDashValidationError(\"Content type is required\");\n\t\t}\n\n\t\tconst tableName = getTableName(type);\n\n\t\t// Resolve translation_group: if translationOf is set, look up the source item's group\n\t\tlet translationGroup: string = id; // default: self-reference\n\t\tif (translationOf) {\n\t\t\tconst source = await this.findById(type, translationOf);\n\t\t\tif (!source) {\n\t\t\t\tthrow new EmDashValidationError(\"Translation source content not found\");\n\t\t\t}\n\t\t\ttranslationGroup = source.translationGroup || source.id;\n\t\t}\n\n\t\t// Build column names and values\n\t\tconst columns: string[] = [\n\t\t\t\"id\",\n\t\t\t\"slug\",\n\t\t\t\"status\",\n\t\t\t\"author_id\",\n\t\t\t\"primary_byline_id\",\n\t\t\t\"created_at\",\n\t\t\t\"updated_at\",\n\t\t\t\"published_at\",\n\t\t\t\"version\",\n\t\t\t\"locale\",\n\t\t\t\"translation_group\",\n\t\t];\n\t\tconst values: unknown[] = [\n\t\t\tid,\n\t\t\tslug || null,\n\t\t\tstatus,\n\t\t\tauthorId || null,\n\t\t\tprimaryBylineId ?? null,\n\t\t\tcreatedAt || now,\n\t\t\tnow,\n\t\t\tpublishedAt || null,\n\t\t\t1,\n\t\t\tlocale || \"en\",\n\t\t\ttranslationGroup,\n\t\t];\n\n\t\t// Add data fields as columns (skip system columns to prevent injection via data)\n\t\tif (data && typeof data === \"object\") {\n\t\t\tfor (const [key, value] of Object.entries(data)) {\n\t\t\t\tif (!SYSTEM_COLUMNS.has(key)) {\n\t\t\t\t\tcolumns.push(key);\n\t\t\t\t\tvalues.push(serializeValue(value));\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\t// Build dynamic INSERT using raw SQL\n\t\tconst columnRefs = columns.map((c) => sql.ref(c));\n\t\tconst valuePlaceholders = values.map((v) => (v === null ? sql`NULL` : sql`${v}`));\n\n\t\tawait sql`\n\t\t\tINSERT INTO ${sql.ref(tableName)} (${sql.join(columnRefs, sql`, `)})\n\t\t\tVALUES (${sql.join(valuePlaceholders, sql`, `)})\n\t\t`.execute(this.db);\n\n\t\t// Fetch and return the created item\n\t\tconst item = await this.findById(type, id);\n\t\tif (!item) {\n\t\t\tthrow new Error(\"Failed to create content\");\n\t\t}\n\t\treturn item;\n\t}\n\n\t/**\n\t * Generate a unique slug for a content item within a collection.\n\t *\n\t * Checks the collection table for existing slugs that match `baseSlug`\n\t * (optionally scoped to a locale) and appends a numeric suffix (`-1`,\n\t * `-2`, etc.) on collision to guarantee uniqueness.\n\t *\n\t * Returns `null` if `baseSlug` is empty after slugification.\n\t */\n\tasync generateUniqueSlug(type: string, text: string, locale?: string): Promise<string | null> {\n\t\tconst baseSlug = slugify(text);\n\t\tif (!baseSlug) return null;\n\n\t\tconst tableName = getTableName(type);\n\n\t\t// Check if the base slug is available\n\t\tconst existing = locale\n\t\t\t? await sql<{ slug: string }>`\n\t\t\t\t\tSELECT slug FROM ${sql.ref(tableName)}\n\t\t\t\t\tWHERE slug = ${baseSlug}\n\t\t\t\t\tAND locale = ${locale}\n\t\t\t\t\tLIMIT 1\n\t\t\t\t`.execute(this.db)\n\t\t\t: await sql<{ slug: string }>`\n\t\t\t\t\tSELECT slug FROM ${sql.ref(tableName)}\n\t\t\t\t\tWHERE slug = ${baseSlug}\n\t\t\t\t\tLIMIT 1\n\t\t\t\t`.execute(this.db);\n\n\t\tif (existing.rows.length === 0) {\n\t\t\treturn baseSlug;\n\t\t}\n\n\t\t// Find all slugs matching the pattern `baseSlug` or `baseSlug-N`\n\t\tconst pattern = `${baseSlug}-%`;\n\t\tconst candidates = locale\n\t\t\t? await sql<{ slug: string }>`\n\t\t\t\t\tSELECT slug FROM ${sql.ref(tableName)}\n\t\t\t\t\tWHERE (slug = ${baseSlug} OR slug LIKE ${pattern})\n\t\t\t\t\tAND locale = ${locale}\n\t\t\t\t`.execute(this.db)\n\t\t\t: await sql<{ slug: string }>`\n\t\t\t\t\tSELECT slug FROM ${sql.ref(tableName)}\n\t\t\t\t\tWHERE slug = ${baseSlug} OR slug LIKE ${pattern}\n\t\t\t\t`.execute(this.db);\n\n\t\t// Find the highest numeric suffix in use\n\t\tlet maxSuffix = 0;\n\t\tconst suffixPattern = new RegExp(`^${escapeRegExp(baseSlug)}-(\\\\d+)$`);\n\t\tfor (const row of candidates.rows) {\n\t\t\tconst match = suffixPattern.exec(row.slug);\n\t\t\tif (match) {\n\t\t\t\tconst n = parseInt(match[1], 10);\n\t\t\t\tif (n > maxSuffix) maxSuffix = n;\n\t\t\t}\n\t\t}\n\n\t\treturn `${baseSlug}-${maxSuffix + 1}`;\n\t}\n\n\t/**\n\t * Duplicate a content item\n\t * Creates a new draft copy with \"(Copy)\" appended to the title.\n\t * A slug is auto-generated from the new title by the handler layer.\n\t */\n\tasync duplicate(type: string, id: string, authorId?: string): Promise<ContentItem> {\n\t\t// Fetch the original item\n\t\tconst original = await this.findById(type, id);\n\t\tif (!original) {\n\t\t\tthrow new EmDashValidationError(\"Content item not found\");\n\t\t}\n\n\t\t// Prepare the new data\n\t\tconst newData = { ...original.data };\n\n\t\t// Append \"(Copy)\" to title if present\n\t\tif (typeof newData.title === \"string\") {\n\t\t\tnewData.title = `${newData.title} (Copy)`;\n\t\t} else if (typeof newData.name === \"string\") {\n\t\t\tnewData.name = `${newData.name} (Copy)`;\n\t\t}\n\n\t\t// Auto-generate a unique slug from the new title/name\n\t\tconst slugSource =\n\t\t\ttypeof newData.title === \"string\"\n\t\t\t\t? newData.title\n\t\t\t\t: typeof newData.name === \"string\"\n\t\t\t\t\t? newData.name\n\t\t\t\t\t: null;\n\n\t\tconst slug = slugSource\n\t\t\t? await this.generateUniqueSlug(type, slugSource, original.locale ?? undefined)\n\t\t\t: null;\n\n\t\t// Create the duplicate as a draft — use override authorId if provided (caller owns the copy)\n\t\treturn this.create({\n\t\t\ttype,\n\t\t\tslug,\n\t\t\tdata: newData,\n\t\t\tstatus: \"draft\",\n\t\t\tauthorId: authorId || original.authorId || undefined,\n\t\t});\n\t}\n\n\t/**\n\t * Find content by ID\n\t */\n\tasync findById(type: string, id: string): Promise<ContentItem | null> {\n\t\tconst tableName = getTableName(type);\n\n\t\tconst result = await sql<Record<string, unknown>>`\n\t\t\tSELECT * FROM ${sql.ref(tableName)}\n\t\t\tWHERE id = ${id}\n\t\t\tAND deleted_at IS NULL\n\t\t`.execute(this.db);\n\n\t\tconst row = result.rows[0];\n\t\tif (!row) {\n\t\t\treturn null;\n\t\t}\n\n\t\treturn this.mapRow(type, row);\n\t}\n\n\t/**\n\t * Find content by id, including trashed (soft-deleted) items.\n\t * Used by restore endpoint for ownership checks.\n\t */\n\tasync findByIdIncludingTrashed(type: string, id: string): Promise<ContentItem | null> {\n\t\tconst tableName = getTableName(type);\n\n\t\tconst result = await sql<Record<string, unknown>>`\n\t\t\tSELECT * FROM ${sql.ref(tableName)}\n\t\t\tWHERE id = ${id}\n\t\t`.execute(this.db);\n\n\t\tconst row = result.rows[0];\n\t\tif (!row) {\n\t\t\treturn null;\n\t\t}\n\n\t\treturn this.mapRow(type, row);\n\t}\n\n\t/**\n\t * Find content by ID or slug. Tries ID first if it looks like a ULID,\n\t * otherwise tries slug. Falls back to the other if the first lookup misses.\n\t */\n\tasync findByIdOrSlug(\n\t\ttype: string,\n\t\tidentifier: string,\n\t\tlocale?: string,\n\t): Promise<ContentItem | null> {\n\t\treturn this._findByIdOrSlug(type, identifier, false, locale);\n\t}\n\n\t/**\n\t * Find content by ID or slug, including trashed (soft-deleted) items.\n\t * Used by restore/permanent-delete endpoints.\n\t */\n\tasync findByIdOrSlugIncludingTrashed(\n\t\ttype: string,\n\t\tidentifier: string,\n\t\tlocale?: string,\n\t): Promise<ContentItem | null> {\n\t\treturn this._findByIdOrSlug(type, identifier, true, locale);\n\t}\n\n\tprivate async _findByIdOrSlug(\n\t\ttype: string,\n\t\tidentifier: string,\n\t\tincludeTrashed: boolean,\n\t\tlocale?: string,\n\t): Promise<ContentItem | null> {\n\t\t// ULIDs are 26 uppercase alphanumeric chars\n\t\tconst looksLikeUlid = ULID_PATTERN.test(identifier);\n\n\t\tconst findById = includeTrashed\n\t\t\t? (t: string, id: string) => this.findByIdIncludingTrashed(t, id)\n\t\t\t: (t: string, id: string) => this.findById(t, id);\n\t\tconst findBySlug = includeTrashed\n\t\t\t? (t: string, s: string) => this.findBySlugIncludingTrashed(t, s, locale)\n\t\t\t: (t: string, s: string) => this.findBySlug(t, s, locale);\n\n\t\tif (looksLikeUlid) {\n\t\t\t// Try ID first, fall back to slug\n\t\t\tconst byId = await findById(type, identifier);\n\t\t\tif (byId) return byId;\n\t\t\treturn findBySlug(type, identifier);\n\t\t}\n\t\t// Try slug first, fall back to ID\n\t\tconst bySlug = await findBySlug(type, identifier);\n\t\tif (bySlug) return bySlug;\n\t\treturn findById(type, identifier);\n\t}\n\n\t/**\n\t * Find content by slug\n\t */\n\tasync findBySlug(type: string, slug: string, locale?: string): Promise<ContentItem | null> {\n\t\tconst tableName = getTableName(type);\n\n\t\tconst result = locale\n\t\t\t? await sql<Record<string, unknown>>`\n\t\t\t\t\tSELECT * FROM ${sql.ref(tableName)}\n\t\t\t\t\tWHERE slug = ${slug}\n\t\t\t\t\tAND locale = ${locale}\n\t\t\t\t\tAND deleted_at IS NULL\n\t\t\t\t`.execute(this.db)\n\t\t\t: await sql<Record<string, unknown>>`\n\t\t\t\t\tSELECT * FROM ${sql.ref(tableName)}\n\t\t\t\t\tWHERE slug = ${slug}\n\t\t\t\t\tAND deleted_at IS NULL\n\t\t\t\t\tORDER BY locale ASC\n\t\t\t\t\tLIMIT 1\n\t\t\t\t`.execute(this.db);\n\n\t\tconst row = result.rows[0];\n\t\tif (!row) {\n\t\t\treturn null;\n\t\t}\n\n\t\treturn this.mapRow(type, row);\n\t}\n\n\t/**\n\t * Find content by slug, including trashed (soft-deleted) items.\n\t * Used by restore/permanent-delete endpoints.\n\t */\n\tasync findBySlugIncludingTrashed(\n\t\ttype: string,\n\t\tslug: string,\n\t\tlocale?: string,\n\t): Promise<ContentItem | null> {\n\t\tconst tableName = getTableName(type);\n\n\t\tconst result = locale\n\t\t\t? await sql<Record<string, unknown>>`\n\t\t\t\t\tSELECT * FROM ${sql.ref(tableName)}\n\t\t\t\t\tWHERE slug = ${slug}\n\t\t\t\t\tAND locale = ${locale}\n\t\t\t\t`.execute(this.db)\n\t\t\t: await sql<Record<string, unknown>>`\n\t\t\t\t\tSELECT * FROM ${sql.ref(tableName)}\n\t\t\t\t\tWHERE slug = ${slug}\n\t\t\t\t\tORDER BY locale ASC\n\t\t\t\t\tLIMIT 1\n\t\t\t\t`.execute(this.db);\n\n\t\tconst row = result.rows[0];\n\t\tif (!row) {\n\t\t\treturn null;\n\t\t}\n\n\t\treturn this.mapRow(type, row);\n\t}\n\n\t/**\n\t * Find many content items with filtering and pagination\n\t */\n\tasync findMany(\n\t\ttype: string,\n\t\toptions: FindManyOptions = {},\n\t): Promise<FindManyResult<ContentItem>> {\n\t\tconst tableName = getTableName(type);\n\t\tconst limit = Math.min(options.limit || 50, 100);\n\n\t\t// Determine ordering\n\t\tconst orderField = options.orderBy?.field || \"createdAt\";\n\t\tconst orderDirection = options.orderBy?.direction || \"desc\";\n\t\tconst dbField = this.mapOrderField(orderField);\n\n\t\t// Validate order direction to prevent injection\n\t\tconst safeOrderDirection = orderDirection.toLowerCase() === \"asc\" ? \"ASC\" : \"DESC\";\n\n\t\t// Build query with parameterized values (no string interpolation)\n\t\t// Note: Dynamic content tables have deleted_at column, cast needed for Kysely\n\t\tlet query = this.db\n\t\t\t.selectFrom(tableName as keyof Database)\n\t\t\t.selectAll()\n\t\t\t.where(\"deleted_at\" as never, \"is\", null);\n\n\t\t// Apply filters with parameterized queries\n\t\tif (options.where?.status) {\n\t\t\tquery = query.where(\"status\", \"=\", options.where.status);\n\t\t}\n\n\t\tif (options.where?.authorId) {\n\t\t\tquery = query.where(\"author_id\", \"=\", options.where.authorId);\n\t\t}\n\n\t\tif (options.where?.locale) {\n\t\t\tquery = query.where(\"locale\" as any, \"=\", options.where.locale);\n\t\t}\n\n\t\t// Handle cursor pagination\n\t\tif (options.cursor) {\n\t\t\tconst decoded = decodeCursor(options.cursor);\n\t\t\tif (decoded) {\n\t\t\t\tconst { orderValue, id: cursorId } = decoded;\n\n\t\t\t\tif (safeOrderDirection === \"DESC\") {\n\t\t\t\t\tquery = query.where((eb) =>\n\t\t\t\t\t\teb.or([\n\t\t\t\t\t\t\teb(dbField as any, \"<\", orderValue),\n\t\t\t\t\t\t\teb.and([eb(dbField as any, \"=\", orderValue), eb(\"id\", \"<\", cursorId)]),\n\t\t\t\t\t\t]),\n\t\t\t\t\t);\n\t\t\t\t} else {\n\t\t\t\t\tquery = query.where((eb) =>\n\t\t\t\t\t\teb.or([\n\t\t\t\t\t\t\teb(dbField as any, \">\", orderValue),\n\t\t\t\t\t\t\teb.and([eb(dbField as any, \"=\", orderValue), eb(\"id\", \">\", cursorId)]),\n\t\t\t\t\t\t]),\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\t// Apply ordering and limit\n\t\tquery = query\n\t\t\t.orderBy(dbField as any, safeOrderDirection === \"ASC\" ? \"asc\" : \"desc\")\n\t\t\t.orderBy(\"id\", safeOrderDirection === \"ASC\" ? \"asc\" : \"desc\")\n\t\t\t.limit(limit + 1);\n\n\t\tconst rows = await query.execute();\n\t\tconst hasMore = rows.length > limit;\n\t\tconst items = rows.slice(0, limit);\n\n\t\tconst mappedResult: FindManyResult<ContentItem> = {\n\t\t\titems: items.map((row) => this.mapRow(type, row as Record<string, unknown>)),\n\t\t};\n\n\t\tif (hasMore && items.length > 0) {\n\t\t\tconst lastRow = items.at(-1) as Record<string, unknown>;\n\t\t\tconst lastOrderValue = lastRow[dbField];\n\t\t\tconst orderStr =\n\t\t\t\ttypeof lastOrderValue === \"string\" || typeof lastOrderValue === \"number\"\n\t\t\t\t\t? String(lastOrderValue)\n\t\t\t\t\t: \"\";\n\t\t\tmappedResult.nextCursor = encodeCursor(orderStr, String(lastRow.id));\n\t\t}\n\n\t\treturn mappedResult;\n\t}\n\n\t/**\n\t * Update content\n\t */\n\tasync update(type: string, id: string, input: UpdateContentInput): Promise<ContentItem> {\n\t\tconst tableName = getTableName(type);\n\t\tconst now = new Date().toISOString();\n\n\t\t// Build update object with parameterized values\n\t\tconst updates: Record<string, unknown> = {\n\t\t\tupdated_at: now,\n\t\t\tversion: sql`version + 1`,\n\t\t};\n\n\t\tif (input.status !== undefined) {\n\t\t\tupdates.status = input.status;\n\t\t}\n\n\t\tif (input.slug !== undefined) {\n\t\t\tupdates.slug = input.slug;\n\t\t}\n\n\t\tif (input.publishedAt !== undefined) {\n\t\t\tupdates.published_at = input.publishedAt;\n\t\t}\n\n\t\tif (input.scheduledAt !== undefined) {\n\t\t\tupdates.scheduled_at = input.scheduledAt;\n\t\t}\n\n\t\tif (input.authorId !== undefined) {\n\t\t\tupdates.author_id = input.authorId;\n\t\t}\n\n\t\tif (input.primaryBylineId !== undefined) {\n\t\t\tupdates.primary_byline_id = input.primaryBylineId;\n\t\t}\n\n\t\t// Update data fields (skip system columns to prevent injection via data)\n\t\tif (input.data !== undefined && typeof input.data === \"object\") {\n\t\t\tfor (const [key, value] of Object.entries(input.data)) {\n\t\t\t\tif (!SYSTEM_COLUMNS.has(key)) {\n\t\t\t\t\tupdates[key] = serializeValue(value);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tawait this.db\n\t\t\t.updateTable(tableName as keyof Database)\n\t\t\t.set(updates)\n\t\t\t.where(\"id\", \"=\", id)\n\t\t\t.where(\"deleted_at\" as never, \"is\", null)\n\t\t\t.execute();\n\n\t\tconst updated = await this.findById(type, id);\n\t\tif (!updated) {\n\t\t\tthrow new Error(\"Content not found\");\n\t\t}\n\n\t\treturn updated;\n\t}\n\n\t/**\n\t * Delete content (soft delete - moves to trash)\n\t */\n\tasync delete(type: string, id: string): Promise<boolean> {\n\t\tconst tableName = getTableName(type);\n\t\tconst now = new Date().toISOString();\n\n\t\tconst result = await sql`\n\t\t\tUPDATE ${sql.ref(tableName)}\n\t\t\tSET deleted_at = ${now}\n\t\t\tWHERE id = ${id}\n\t\t\tAND deleted_at IS NULL\n\t\t`.execute(this.db);\n\n\t\treturn (result.numAffectedRows ?? 0n) > 0n;\n\t}\n\n\t/**\n\t * Restore content from trash\n\t */\n\tasync restore(type: string, id: string): Promise<boolean> {\n\t\tconst tableName = getTableName(type);\n\n\t\tconst result = await sql`\n\t\t\tUPDATE ${sql.ref(tableName)}\n\t\t\tSET deleted_at = NULL\n\t\t\tWHERE id = ${id}\n\t\t\tAND deleted_at IS NOT NULL\n\t\t`.execute(this.db);\n\n\t\treturn (result.numAffectedRows ?? 0n) > 0n;\n\t}\n\n\t/**\n\t * Permanently delete content (cannot be undone)\n\t */\n\tasync permanentDelete(type: string, id: string): Promise<boolean> {\n\t\tconst tableName = getTableName(type);\n\n\t\tconst result = await sql`\n\t\t\tDELETE FROM ${sql.ref(tableName)}\n\t\t\tWHERE id = ${id}\n\t\t`.execute(this.db);\n\n\t\treturn (result.numAffectedRows ?? 0n) > 0n;\n\t}\n\n\t/**\n\t * Find trashed content items\n\t */\n\tasync findTrashed(\n\t\ttype: string,\n\t\toptions: Omit<FindManyOptions, \"where\"> = {},\n\t): Promise<FindManyResult<ContentItem & { deletedAt: string }>> {\n\t\tconst tableName = getTableName(type);\n\t\tconst limit = Math.min(options.limit || 50, 100);\n\n\t\t// Determine ordering - default to most recently deleted\n\t\tconst orderField = options.orderBy?.field || \"deletedAt\";\n\t\tconst orderDirection = options.orderBy?.direction || \"desc\";\n\t\tconst dbField = this.mapOrderField(orderField);\n\n\t\tconst safeOrderDirection = orderDirection.toLowerCase() === \"asc\" ? \"ASC\" : \"DESC\";\n\n\t\tlet query = this.db\n\t\t\t.selectFrom(tableName as keyof Database)\n\t\t\t.selectAll()\n\t\t\t.where(\"deleted_at\" as never, \"is not\", null);\n\n\t\t// Handle cursor pagination\n\t\tif (options.cursor) {\n\t\t\tconst decoded = decodeCursor(options.cursor);\n\t\t\tif (decoded) {\n\t\t\t\tconst { orderValue, id: cursorId } = decoded;\n\n\t\t\t\tif (safeOrderDirection === \"DESC\") {\n\t\t\t\t\tquery = query.where((eb) =>\n\t\t\t\t\t\teb.or([\n\t\t\t\t\t\t\teb(dbField as any, \"<\", orderValue),\n\t\t\t\t\t\t\teb.and([eb(dbField as any, \"=\", orderValue), eb(\"id\", \"<\", cursorId)]),\n\t\t\t\t\t\t]),\n\t\t\t\t\t);\n\t\t\t\t} else {\n\t\t\t\t\tquery = query.where((eb) =>\n\t\t\t\t\t\teb.or([\n\t\t\t\t\t\t\teb(dbField as any, \">\", orderValue),\n\t\t\t\t\t\t\teb.and([eb(dbField as any, \"=\", orderValue), eb(\"id\", \">\", cursorId)]),\n\t\t\t\t\t\t]),\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tquery = query\n\t\t\t.orderBy(dbField as any, safeOrderDirection === \"ASC\" ? \"asc\" : \"desc\")\n\t\t\t.orderBy(\"id\", safeOrderDirection === \"ASC\" ? \"asc\" : \"desc\")\n\t\t\t.limit(limit + 1);\n\n\t\tconst rows = await query.execute();\n\t\tconst hasMore = rows.length > limit;\n\t\tconst items = rows.slice(0, limit);\n\n\t\tconst mappedResult: FindManyResult<ContentItem & { deletedAt: string }> = {\n\t\t\titems: items.map((row) => {\n\t\t\t\tconst record = row as Record<string, unknown>;\n\t\t\t\treturn {\n\t\t\t\t\t...this.mapRow(type, record),\n\t\t\t\t\tdeletedAt: typeof record.deleted_at === \"string\" ? record.deleted_at : \"\",\n\t\t\t\t};\n\t\t\t}),\n\t\t};\n\n\t\tif (hasMore && items.length > 0) {\n\t\t\tconst lastRow = items.at(-1) as Record<string, unknown>;\n\t\t\tconst lastOrderValue = lastRow[dbField];\n\t\t\tconst orderStr =\n\t\t\t\ttypeof lastOrderValue === \"string\" || typeof lastOrderValue === \"number\"\n\t\t\t\t\t? String(lastOrderValue)\n\t\t\t\t\t: \"\";\n\t\t\tmappedResult.nextCursor = encodeCursor(orderStr, String(lastRow.id));\n\t\t}\n\n\t\treturn mappedResult;\n\t}\n\n\t/**\n\t * Count trashed content items\n\t */\n\tasync countTrashed(type: string): Promise<number> {\n\t\tconst tableName = getTableName(type);\n\n\t\tconst result = await this.db\n\t\t\t.selectFrom(tableName as keyof Database)\n\t\t\t.select((eb) => eb.fn.count(\"id\").as(\"count\"))\n\t\t\t.where(\"deleted_at\" as never, \"is not\", null)\n\t\t\t.executeTakeFirst();\n\n\t\treturn Number(result?.count || 0);\n\t}\n\n\t/**\n\t * Count content items\n\t */\n\tasync count(\n\t\ttype: string,\n\t\twhere?: { status?: string; authorId?: string; locale?: string },\n\t): Promise<number> {\n\t\tconst tableName = getTableName(type);\n\n\t\tlet query = this.db\n\t\t\t.selectFrom(tableName as keyof Database)\n\t\t\t.select((eb) => eb.fn.count(\"id\").as(\"count\"))\n\t\t\t.where(\"deleted_at\" as never, \"is\", null);\n\n\t\tif (where?.status) {\n\t\t\tquery = query.where(\"status\", \"=\", where.status);\n\t\t}\n\n\t\tif (where?.authorId) {\n\t\t\tquery = query.where(\"author_id\", \"=\", where.authorId);\n\t\t}\n\n\t\tif (where?.locale) {\n\t\t\tquery = query.where(\"locale\" as any, \"=\", where.locale);\n\t\t}\n\n\t\tconst result = await query.executeTakeFirst();\n\t\treturn Number(result?.count || 0);\n\t}\n\n\t// get overall statistics (total, published, draft) for a content type in a single query\n\tasync getStats(type: string): Promise<{ total: number; published: number; draft: number }> {\n\t\tconst tableName = getTableName(type);\n\n\t\tconst result = await this.db\n\t\t\t.selectFrom(tableName as keyof Database)\n\t\t\t.select((eb) => [\n\t\t\t\teb.fn.count(\"id\").as(\"total\"),\n\t\t\t\teb.fn.sum(eb.case().when(\"status\", \"=\", \"published\").then(1).else(0).end()).as(\"published\"),\n\t\t\t\teb.fn.sum(eb.case().when(\"status\", \"=\", \"draft\").then(1).else(0).end()).as(\"draft\"),\n\t\t\t])\n\t\t\t.where(\"deleted_at\" as never, \"is\", null)\n\t\t\t.executeTakeFirst();\n\n\t\treturn {\n\t\t\ttotal: Number(result?.total || 0),\n\t\t\tpublished: Number(result?.published || 0),\n\t\t\tdraft: Number(result?.draft || 0),\n\t\t};\n\t}\n\n\t/**\n\t * Schedule content for future publishing\n\t *\n\t * Sets status to 'scheduled' and stores the scheduled publish time.\n\t * The content will be auto-published when the scheduled time is reached.\n\t */\n\tasync schedule(type: string, id: string, scheduledAt: string): Promise<ContentItem> {\n\t\tconst tableName = getTableName(type);\n\t\tconst now = new Date().toISOString();\n\n\t\t// Validate scheduledAt is in the future\n\t\tconst scheduledDate = new Date(scheduledAt);\n\t\tif (isNaN(scheduledDate.getTime())) {\n\t\t\tthrow new EmDashValidationError(\"Invalid scheduled date\");\n\t\t}\n\t\tif (scheduledDate <= new Date()) {\n\t\t\tthrow new EmDashValidationError(\"Scheduled date must be in the future\");\n\t\t}\n\n\t\tconst existing = await this.findById(type, id);\n\t\tif (!existing) {\n\t\t\tthrow new EmDashValidationError(\"Content item not found\");\n\t\t}\n\n\t\t// Published posts keep their status — the schedule applies to the\n\t\t// pending draft, not the currently-live revision. Unpublished posts\n\t\t// transition to 'scheduled' so they aren't visible before the time.\n\t\tconst newStatus = existing.status === \"published\" ? \"published\" : \"scheduled\";\n\n\t\tawait sql`\n\t\t\tUPDATE ${sql.ref(tableName)}\n\t\t\tSET status = ${newStatus},\n\t\t\t\tscheduled_at = ${scheduledAt},\n\t\t\t\tupdated_at = ${now}\n\t\t\tWHERE id = ${id}\n\t\t\tAND deleted_at IS NULL\n\t\t`.execute(this.db);\n\n\t\tconst updated = await this.findById(type, id);\n\t\tif (!updated) {\n\t\t\tthrow new Error(\"Content not found\");\n\t\t}\n\n\t\treturn updated;\n\t}\n\n\t/**\n\t * Unschedule content\n\t *\n\t * Clears the scheduled time. Published posts stay published;\n\t * draft/scheduled posts revert to 'draft'.\n\t */\n\tasync unschedule(type: string, id: string): Promise<ContentItem> {\n\t\tconst tableName = getTableName(type);\n\t\tconst now = new Date().toISOString();\n\n\t\tconst existing = await this.findById(type, id);\n\t\tif (!existing) {\n\t\t\tthrow new EmDashValidationError(\"Content item not found\");\n\t\t}\n\n\t\t// Published posts keep their status — just clear the pending schedule.\n\t\t// Draft/scheduled posts revert to 'draft'.\n\t\tconst newStatus = existing.status === \"published\" ? \"published\" : \"draft\";\n\n\t\tawait sql`\n\t\t\tUPDATE ${sql.ref(tableName)}\n\t\t\tSET status = ${newStatus},\n\t\t\t\tscheduled_at = NULL,\n\t\t\t\tupdated_at = ${now}\n\t\t\tWHERE id = ${id}\n\t\t\tAND scheduled_at IS NOT NULL\n\t\t\tAND deleted_at IS NULL\n\t\t`.execute(this.db);\n\n\t\tconst updated = await this.findById(type, id);\n\t\tif (!updated) {\n\t\t\tthrow new Error(\"Content not found\");\n\t\t}\n\n\t\treturn updated;\n\t}\n\n\t/**\n\t * Find content that is ready to be published\n\t *\n\t * Returns all content where scheduled_at <= now, regardless of status.\n\t * This covers both draft-scheduled posts (status='scheduled') and\n\t * published posts with scheduled draft changes (status='published').\n\t */\n\tasync findReadyToPublish(type: string): Promise<ContentItem[]> {\n\t\tconst tableName = getTableName(type);\n\t\tconst now = new Date().toISOString();\n\n\t\tconst result = await sql<Record<string, unknown>>`\n\t\t\tSELECT * FROM ${sql.ref(tableName)}\n\t\t\tWHERE scheduled_at IS NOT NULL\n\t\t\tAND scheduled_at <= ${now}\n\t\t\tAND deleted_at IS NULL\n\t\t\tORDER BY scheduled_at ASC\n\t\t`.execute(this.db);\n\n\t\treturn result.rows.map((row) => this.mapRow(type, row));\n\t}\n\n\t/**\n\t * Find all translations in a translation group\n\t */\n\tasync findTranslations(type: string, translationGroup: string): Promise<ContentItem[]> {\n\t\tconst tableName = getTableName(type);\n\n\t\tconst result = await sql<Record<string, unknown>>`\n\t\t\tSELECT * FROM ${sql.ref(tableName)}\n\t\t\tWHERE translation_group = ${translationGroup}\n\t\t\tAND deleted_at IS NULL\n\t\t\tORDER BY locale ASC\n\t\t`.execute(this.db);\n\n\t\treturn result.rows.map((row) => this.mapRow(type, row));\n\t}\n\n\t/**\n\t * Publish the current draft\n\t *\n\t * Promotes draft_revision_id to live_revision_id and clears draft pointer.\n\t * Syncs the draft revision's data into the content table columns so the\n\t * content table always reflects the published version.\n\t * If no draft revision exists, creates one from current data and publishes it.\n\t */\n\tasync publish(type: string, id: string): Promise<ContentItem> {\n\t\tconst tableName = getTableName(type);\n\t\tconst now = new Date().toISOString();\n\n\t\tconst existing = await this.findById(type, id);\n\t\tif (!existing) {\n\t\t\tthrow new EmDashValidationError(\"Content item not found\");\n\t\t}\n\n\t\tconst revisionRepo = new RevisionRepository(this.db);\n\t\tlet revisionToPublish = existing.draftRevisionId || existing.liveRevisionId;\n\n\t\tif (!revisionToPublish) {\n\t\t\t// No revision exists - create one from current data\n\t\t\tconst revision = await revisionRepo.create({\n\t\t\t\tcollection: type,\n\t\t\t\tentryId: id,\n\t\t\t\tdata: existing.data,\n\t\t\t});\n\t\t\trevisionToPublish = revision.id;\n\t\t}\n\n\t\t// Sync the revision's data into the content table columns\n\t\t// so the content table always holds the published version\n\t\tconst revision = await revisionRepo.findById(revisionToPublish);\n\t\tif (revision) {\n\t\t\tawait this.syncDataColumns(type, id, revision.data);\n\n\t\t\t// Sync slug from revision if stored there\n\t\t\tif (typeof revision.data._slug === \"string\") {\n\t\t\t\tawait sql`\n\t\t\t\t\tUPDATE ${sql.ref(tableName)}\n\t\t\t\t\tSET slug = ${revision.data._slug}\n\t\t\t\t\tWHERE id = ${id}\n\t\t\t\t`.execute(this.db);\n\t\t\t}\n\t\t}\n\n\t\tawait sql`\n\t\t\tUPDATE ${sql.ref(tableName)}\n\t\t\tSET live_revision_id = ${revisionToPublish},\n\t\t\t\tdraft_revision_id = NULL,\n\t\t\t\tstatus = 'published',\n\t\t\t\tscheduled_at = NULL,\n\t\t\t\tpublished_at = COALESCE(published_at, ${now}),\n\t\t\t\tupdated_at = ${now}\n\t\t\tWHERE id = ${id}\n\t\t\tAND deleted_at IS NULL\n\t\t`.execute(this.db);\n\n\t\tconst updated = await this.findById(type, id);\n\t\tif (!updated) {\n\t\t\tthrow new Error(\"Content not found\");\n\t\t}\n\n\t\treturn updated;\n\t}\n\n\t/**\n\t * Unpublish content\n\t *\n\t * Removes live pointer but preserves draft. If no draft exists,\n\t * creates one from the live version so the content isn't lost.\n\t */\n\tasync unpublish(type: string, id: string): Promise<ContentItem> {\n\t\tconst tableName = getTableName(type);\n\t\tconst now = new Date().toISOString();\n\n\t\tconst existing = await this.findById(type, id);\n\t\tif (!existing) {\n\t\t\tthrow new EmDashValidationError(\"Content item not found\");\n\t\t}\n\n\t\t// If no draft exists, create one from the live version\n\t\tif (!existing.draftRevisionId && existing.liveRevisionId) {\n\t\t\tconst revisionRepo = new RevisionRepository(this.db);\n\t\t\tconst liveRevision = await revisionRepo.findById(existing.liveRevisionId);\n\t\t\tif (liveRevision) {\n\t\t\t\tconst draft = await revisionRepo.create({\n\t\t\t\t\tcollection: type,\n\t\t\t\t\tentryId: id,\n\t\t\t\t\tdata: liveRevision.data,\n\t\t\t\t});\n\n\t\t\t\tawait sql`\n\t\t\t\t\tUPDATE ${sql.ref(tableName)}\n\t\t\t\t\tSET draft_revision_id = ${draft.id}\n\t\t\t\t\tWHERE id = ${id}\n\t\t\t\t`.execute(this.db);\n\t\t\t}\n\t\t}\n\n\t\tawait sql`\n\t\t\tUPDATE ${sql.ref(tableName)}\n\t\t\tSET live_revision_id = NULL,\n\t\t\t\tstatus = 'draft',\n\t\t\t\tupdated_at = ${now}\n\t\t\tWHERE id = ${id}\n\t\t\tAND deleted_at IS NULL\n\t\t`.execute(this.db);\n\n\t\tconst updated = await this.findById(type, id);\n\t\tif (!updated) {\n\t\t\tthrow new Error(\"Content not found\");\n\t\t}\n\n\t\treturn updated;\n\t}\n\n\t/**\n\t * Discard pending draft changes\n\t *\n\t * Clears draft_revision_id. The content table columns already hold the\n\t * published version, so no data sync is needed.\n\t */\n\tasync discardDraft(type: string, id: string): Promise<ContentItem> {\n\t\tconst tableName = getTableName(type);\n\t\tconst now = new Date().toISOString();\n\n\t\tconst existing = await this.findById(type, id);\n\t\tif (!existing) {\n\t\t\tthrow new EmDashValidationError(\"Content item not found\");\n\t\t}\n\n\t\tif (!existing.draftRevisionId) {\n\t\t\t// No draft to discard\n\t\t\treturn existing;\n\t\t}\n\n\t\tawait sql`\n\t\t\tUPDATE ${sql.ref(tableName)}\n\t\t\tSET draft_revision_id = NULL,\n\t\t\t\tupdated_at = ${now}\n\t\t\tWHERE id = ${id}\n\t\t\tAND deleted_at IS NULL\n\t\t`.execute(this.db);\n\n\t\tconst updated = await this.findById(type, id);\n\t\tif (!updated) {\n\t\t\tthrow new Error(\"Content not found\");\n\t\t}\n\n\t\treturn updated;\n\t}\n\n\t/**\n\t * Sync data columns in the content table from a data object.\n\t * Used to promote revision data into the content table on publish.\n\t * Keys starting with _ are revision metadata (e.g. _slug) and are skipped.\n\t */\n\tprivate async syncDataColumns(\n\t\ttype: string,\n\t\tid: string,\n\t\tdata: Record<string, unknown>,\n\t): Promise<void> {\n\t\tconst tableName = getTableName(type);\n\t\tconst updates: Record<string, unknown> = {};\n\n\t\tfor (const [key, value] of Object.entries(data)) {\n\t\t\tif (SYSTEM_COLUMNS.has(key)) continue;\n\t\t\tif (key.startsWith(\"_\")) continue; // revision metadata\n\t\t\tupdates[key] = serializeValue(value);\n\t\t}\n\n\t\tif (Object.keys(updates).length === 0) return;\n\n\t\tawait this.db\n\t\t\t.updateTable(tableName as keyof Database)\n\t\t\t.set(updates)\n\t\t\t.where(\"id\", \"=\", id)\n\t\t\t.execute();\n\t}\n\n\t/**\n\t * Count content items with a pending schedule.\n\t * Includes both draft-scheduled (status='scheduled') and published\n\t * posts with scheduled draft changes (status='published', scheduled_at set).\n\t */\n\tasync countScheduled(type: string): Promise<number> {\n\t\tconst tableName = getTableName(type);\n\n\t\tconst result = await sql<{ count: number }>`\n\t\t\tSELECT COUNT(id) as count FROM ${sql.ref(tableName)}\n\t\t\tWHERE scheduled_at IS NOT NULL\n\t\t\tAND deleted_at IS NULL\n\t\t`.execute(this.db);\n\n\t\treturn Number(result.rows[0]?.count || 0);\n\t}\n\n\t/**\n\t * Map database row to ContentItem\n\t * Extracts system columns and puts content fields in data\n\t * Excludes null values from data to match input semantics\n\t */\n\tprivate mapRow(type: string, row: Record<string, unknown>): ContentItem {\n\t\tconst data: Record<string, unknown> = {};\n\n\t\tfor (const [key, value] of Object.entries(row)) {\n\t\t\tif (!SYSTEM_COLUMNS.has(key) && value !== null) {\n\t\t\t\tdata[key] = deserializeValue(value);\n\t\t\t}\n\t\t}\n\n\t\treturn {\n\t\t\tid: row.id as string,\n\t\t\ttype,\n\t\t\tslug: row.slug as string | null,\n\t\t\tstatus: row.status as string,\n\t\t\tdata,\n\t\t\tauthorId: row.author_id as string | null,\n\t\t\tprimaryBylineId: (row.primary_byline_id as string | null) ?? null,\n\t\t\tcreatedAt: row.created_at as string,\n\t\t\tupdatedAt: row.updated_at as string,\n\t\t\tpublishedAt: row.published_at as string | null,\n\t\t\tscheduledAt: row.scheduled_at as string | null,\n\t\t\tliveRevisionId: (row.live_revision_id as string | null) ?? null,\n\t\t\tdraftRevisionId: (row.draft_revision_id as string | null) ?? null,\n\t\t\tversion: typeof row.version === \"number\" ? row.version : 1,\n\t\t\tlocale: (row.locale as string) ?? null,\n\t\t\ttranslationGroup: (row.translation_group as string) ?? null,\n\t\t};\n\t}\n\n\t/**\n\t * Map order field names to database columns.\n\t * Only allows known fields to prevent column enumeration via crafted orderBy values.\n\t */\n\tprivate mapOrderField(field: string): string {\n\t\tconst mapping: Record<string, string> = {\n\t\t\tcreatedAt: \"created_at\",\n\t\t\tupdatedAt: \"updated_at\",\n\t\t\tpublishedAt: \"published_at\",\n\t\t\tscheduledAt: \"scheduled_at\",\n\t\t\tdeletedAt: \"deleted_at\",\n\t\t\ttitle: \"title\",\n\t\t\tslug: \"slug\",\n\t\t};\n\n\t\tconst mapped = mapping[field];\n\t\tif (!mapped) {\n\t\t\tthrow new EmDashValidationError(`Invalid order field: ${field}`);\n\t\t}\n\t\treturn mapped;\n\t}\n}\n"],"mappings":"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"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"dialect-helpers-B9uSp2GJ.mjs","names":[],"sources":["../src/database/dialect-helpers.ts"],"sourcesContent":["/**\n * Dialect-specific SQL helpers\n *\n * Every function takes a Kysely `db` instance and detects the dialect from\n * the adapter class. No module-level state, no globals, no heuristics —\n * the adapter is the source of truth.\n *\n * This is NOT an ORM abstraction — just targeted helpers for the ~15 places\n * that use raw dialect-specific SQL. Most Kysely schema builder code already\n * works cross-dialect.\n */\n\nimport type { ColumnDataType, Kysely, RawBuilder } from \"kysely\";\nimport { sql } from \"kysely\";\n\nimport type { DatabaseDialectType } from \"../db/adapters.js\";\n\nexport type { DatabaseDialectType };\n\n/**\n * Detect dialect type from a Kysely instance via the adapter class name.\n */\n// eslint-disable-next-line @typescript-eslint/no-explicit-any -- accepts any Kysely instance\nexport function detectDialect(db: Kysely<any>): DatabaseDialectType {\n\tconst name = db.getExecutor().adapter.constructor.name;\n\tif (name === \"PostgresAdapter\") return \"postgres\";\n\treturn \"sqlite\";\n}\n\n// eslint-disable-next-line @typescript-eslint/no-explicit-any -- accepts any Kysely instance\nexport function isSqlite(db: Kysely<any>): boolean {\n\treturn detectDialect(db) === \"sqlite\";\n}\n\n// eslint-disable-next-line @typescript-eslint/no-explicit-any -- accepts any Kysely instance\nexport function isPostgres(db: Kysely<any>): boolean {\n\treturn detectDialect(db) === \"postgres\";\n}\n\n/**\n * Default timestamp expression for column defaults.\n * Wrapped in parens for use in CREATE TABLE ... DEFAULT (...).\n *\n * sqlite: (datetime('now'))\n * postgres: CURRENT_TIMESTAMP\n */\n// eslint-disable-next-line @typescript-eslint/no-explicit-any -- accepts any Kysely instance\nexport function currentTimestamp(db: Kysely<any>): RawBuilder<string> {\n\tif (isPostgres(db)) {\n\t\treturn sql`CURRENT_TIMESTAMP`;\n\t}\n\treturn sql`(datetime('now'))`;\n}\n\n/**\n * Timestamp expression for use in WHERE clauses and SET expressions.\n * No wrapping parens.\n *\n * sqlite: datetime('now')\n * postgres: CURRENT_TIMESTAMP\n */\n// eslint-disable-next-line @typescript-eslint/no-explicit-any -- accepts any Kysely instance\nexport function currentTimestampValue(db: Kysely<any>): RawBuilder<string> {\n\tif (isPostgres(db)) {\n\t\treturn sql`CURRENT_TIMESTAMP`;\n\t}\n\treturn sql`datetime('now')`;\n}\n\n/**\n * Check if a table exists in the database.\n */\n// eslint-disable-next-line @typescript-eslint/no-explicit-any -- accepts any Kysely instance\nexport async function tableExists(db: Kysely<any>, tableName: string): Promise<boolean> {\n\tif (isPostgres(db)) {\n\t\tconst result = await sql<{ exists: boolean }>`\n\t\t\tSELECT EXISTS(\n\t\t\t\tSELECT 1 FROM information_schema.tables\n\t\t\t\tWHERE table_schema = 'public' AND table_name = ${tableName}\n\t\t\t) as exists\n\t\t`.execute(db);\n\t\treturn result.rows[0]?.exists === true;\n\t}\n\n\tconst result = await sql<{ name: string }>`\n\t\tSELECT name FROM sqlite_master\n\t\tWHERE type = 'table' AND name = ${tableName}\n\t`.execute(db);\n\treturn result.rows.length > 0;\n}\n\n/**\n * List tables matching a LIKE pattern.\n */\n// eslint-disable-next-line @typescript-eslint/no-explicit-any -- accepts any Kysely instance\nexport async function listTablesLike(db: Kysely<any>, pattern: string): Promise<string[]> {\n\tif (isPostgres(db)) {\n\t\tconst result = await sql<{ table_name: string }>`\n\t\t\tSELECT table_name FROM information_schema.tables\n\t\t\tWHERE table_schema = 'public' AND table_name LIKE ${pattern}\n\t\t`.execute(db);\n\t\treturn result.rows.map((r) => r.table_name);\n\t}\n\n\tconst result = await sql<{ name: string }>`\n\t\tSELECT name FROM sqlite_master\n\t\tWHERE type = 'table' AND name LIKE ${pattern}\n\t`.execute(db);\n\treturn result.rows.map((r) => r.name);\n}\n\n/**\n * Column type for binary data.\n *\n * sqlite: blob\n * postgres: bytea\n */\n// eslint-disable-next-line @typescript-eslint/no-explicit-any -- accepts any Kysely instance\nexport function binaryType(db: Kysely<any>): ColumnDataType {\n\tif (isPostgres(db)) {\n\t\treturn \"bytea\";\n\t}\n\treturn \"blob\";\n}\n\n/**\n * SQL expression for extracting a field from a JSON/JSONB column.\n *\n * sqlite: json_extract(column, '$.path')\n * postgres: column->>'path'\n */\n// eslint-disable-next-line @typescript-eslint/no-explicit-any -- accepts any Kysely instance\nexport function jsonExtractExpr(db: Kysely<any>, column: string, path: string): string {\n\tif (isPostgres(db)) {\n\t\treturn `${column}->>'${path}'`;\n\t}\n\treturn `json_extract(${column}, '$.${path}')`;\n}\n"],"mappings":";;;;;;AAuBA,SAAgB,cAAc,IAAsC;AAEnE,KADa,GAAG,aAAa,CAAC,QAAQ,YAAY,SACrC,kBAAmB,QAAO;AACvC,QAAO;;AAIR,SAAgB,SAAS,IAA0B;AAClD,QAAO,cAAc,GAAG,KAAK;;AAI9B,SAAgB,WAAW,IAA0B;AACpD,QAAO,cAAc,GAAG,KAAK;;;;;;;;;AAW9B,SAAgB,iBAAiB,IAAqC;AACrE,KAAI,WAAW,GAAG,CACjB,QAAO,GAAG;AAEX,QAAO,GAAG;;;;;;;;;AAWX,SAAgB,sBAAsB,IAAqC;AAC1E,KAAI,WAAW,GAAG,CACjB,QAAO,GAAG;AAEX,QAAO,GAAG;;;;;AAOX,eAAsB,YAAY,IAAiB,WAAqC;AACvF,KAAI,WAAW,GAAG,CAOjB,SANe,MAAM,GAAwB;;;qDAGM,UAAU;;IAE3D,QAAQ,GAAG,EACC,KAAK,IAAI,WAAW;AAOnC,SAJe,MAAM,GAAqB;;oCAEP,UAAU;GAC3C,QAAQ,GAAG,EACC,KAAK,SAAS;;;;;AAO7B,eAAsB,eAAe,IAAiB,SAAoC;AACzF,KAAI,WAAW,GAAG,CAKjB,SAJe,MAAM,GAA2B;;uDAEK,QAAQ;IAC3D,QAAQ,GAAG,EACC,KAAK,KAAK,MAAM,EAAE,WAAW;AAO5C,SAJe,MAAM,GAAqB;;uCAEJ,QAAQ;GAC5C,QAAQ,GAAG,EACC,KAAK,KAAK,MAAM,EAAE,KAAK;;;;;;;;AAUtC,SAAgB,WAAW,IAAiC;AAC3D,KAAI,WAAW,GAAG,CACjB,QAAO;AAER,QAAO;;;;;;;;AAUR,SAAgB,gBAAgB,IAAiB,QAAgB,MAAsB;AACtF,KAAI,WAAW,GAAG,CACjB,QAAO,GAAG,OAAO,MAAM,KAAK;AAE7B,QAAO,gBAAgB,OAAO,OAAO,KAAK"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"index-UHEVQMus.d.mts","names":[],"sources":["../src/database/connection.ts","../src/database/repositories/content.ts","../src/database/repositories/media.ts","../src/database/repositories/revision.ts","../src/database/repositories/comment.ts","../src/database/repositories/byline.ts","../src/fields/types.ts","../src/fields/image.ts","../src/fields/reference.ts","../src/fields/portable-text.ts","../src/api/types.ts","../src/api/handlers/content.ts","../src/api/handlers/manifest.ts","../src/api/handlers/revision.ts","../src/api/handlers/media.ts","../src/schema/registry.ts","../src/schema/query.ts","../src/sections/types.ts","../src/sections/index.ts","../src/plugins/sandbox/types.ts","../src/content/converters/types.ts","../src/content/converters/prosemirror-to-portable-text.ts","../src/content/converters/portable-text-to-prosemirror.ts","../src/utils/hash.ts","../src/utils/url.ts","../src/visual-editing/editable.ts","../src/query.ts","../src/i18n/config.ts","../src/loader.ts","../src/cli/wxr/parser.ts","../src/plugins/define-plugin.ts","../src/auth/types.ts","../src/astro/storage/types.ts","../src/astro/integration/runtime.ts","../src/plugins/manifest-schema.ts","../src/plugins/hooks.ts","../src/plugins/email.ts","../src/plugins/context.ts","../src/plugins/routes.ts","../src/plugins/manager.ts","../src/plugins/sandbox/noop.ts","../src/import/types.ts","../src/import/sections.ts","../src/import/registry.ts","../src/import/sources/wxr.ts","../src/import/sources/wordpress-rest.ts","../src/preview/tokens.ts","../src/preview/urls.ts","../src/preview/helpers.ts","../src/settings/index.ts","../src/comments/query.ts","../src/menus/types.ts","../src/menus/index.ts","../src/bylines/index.ts","../src/taxonomies/types.ts","../src/taxonomies/index.ts","../src/widgets/types.ts","../src/widgets/index.ts","../src/search/types.ts","../src/search/fts-manager.ts","../src/search/query.ts","../src/search/text-extraction.ts"],"mappings":";;;;;;;;;;;;;;;;UAKiB,cAAA;EAChB,GAAA;EACA,SAAA;AAAA;AAAA,cAGY,mBAAA,SAA4B,KAAA;EAGvB,KAAA;cADhB,OAAA,UACgB,KAAA;AAAA;;;;;;;;;cCqFL,iBAAA;EAAA,QACQ,EAAA;cAAA,EAAA,EAAI,MAAA,CAAO,QAAA;;;;EAKzB,MAAA,CAAO,KAAA,EAAO,kBAAA,GAAqB,OAAA,CAAQ,WAAA;EDnGjC;;;;;AAKjB;;;;ECgMO,kBAAA,CAAmB,IAAA,UAAc,IAAA,UAAc,MAAA,YAAkB,OAAA;ED7LtD;;;;;ECqPX,SAAA,CAAU,IAAA,UAAc,EAAA,UAAY,QAAA,YAAoB,OAAA,CAAQ,WAAA;;;;EA0ChE,QAAA,CAAS,IAAA,UAAc,EAAA,WAAa,OAAA,CAAQ,WAAA;EA1MrB;;;;EA+NvB,wBAAA,CAAyB,IAAA,UAAc,EAAA,WAAa,OAAA,CAAQ,WAAA;EAzNjB;;;;EA6O3C,cAAA,CACL,IAAA,UACA,UAAA,UACA,MAAA,YACE,OAAA,CAAQ,WAAA;EA7CuC;;;;EAqD5C,8BAAA,CACL,IAAA,UACA,UAAA,UACA,MAAA,YACE,OAAA,CAAQ,WAAA;EAAA,QAIG,eAAA;EAJH;;;EAmCL,UAAA,CAAW,IAAA,UAAc,IAAA,UAAc,MAAA,YAAkB,OAAA,CAAQ,WAAA;EAkC5D;;;;EAJL,0BAAA,CACL,IAAA,UACA,IAAA,UACA,MAAA,YACE,OAAA,CAAQ,WAAA;EA8BR;;;EAHG,QAAA,CACL,IAAA,UACA,OAAA,GAAS,eAAA,GACP,OAAA,CAAQ,cAAA,CAAe,WAAA;EAmJc;;;EA7DlC,MAAA,CAAO,IAAA,UAAc,EAAA,UAAY,KAAA,EAAO,kBAAA,GAAqB,OAAA,CAAQ,WAAA;EA8GjE;;;EAjDJ,MAAA,CAAO,IAAA,UAAc,EAAA,WAAa,OAAA;EA6HN;;;EA5G5B,OAAA,CAAQ,IAAA,UAAc,EAAA,WAAa,OAAA;EAiLsB;;;EAjKzD,eAAA,CAAgB,IAAA,UAAc,EAAA,WAAa,OAAA;EAqPT;;;EAvOlC,WAAA,CACL,IAAA,UACA,OAAA,GAAS,IAAA,CAAK,eAAA,aACZ,OAAA,CAAQ,cAAA,CAAe,WAAA;IAAgB,SAAA;EAAA;EA2UC;;;EAhQrC,YAAA,CAAa,IAAA,WAAe,OAAA;EAkXS;;;EAnWrC,KAAA,CACL,IAAA,UACA,KAAA;IAAU,MAAA;IAAiB,QAAA;IAAmB,MAAA;EAAA,IAC5C,OAAA;EAyBG,QAAA,CAAS,IAAA,WAAe,OAAA;IAAU,KAAA;IAAe,SAAA;IAAmB,KAAA;EAAA;EAzjBjD;;;;;;EAmlBnB,QAAA,CAAS,IAAA,UAAc,EAAA,UAAY,WAAA,WAAsB,OAAA,CAAQ,WAAA;EA3hB7B;;;;;;EAykBpC,UAAA,CAAW,IAAA,UAAc,EAAA,WAAa,OAAA,CAAQ,WAAA;EA/hBF;;;;;;;EAqkB5C,kBAAA,CAAmB,IAAA,WAAe,OAAA,CAAQ,WAAA;EA1hB/C;;;EA4iBK,gBAAA,CAAiB,IAAA,UAAc,gBAAA,WAA2B,OAAA,CAAQ,WAAA;EAliBlE;;;;;;;;EAujBA,OAAA,CAAQ,IAAA,UAAc,EAAA,WAAa,OAAA,CAAQ,WAAA;EAhhBlB;;;;;;EAglBzB,SAAA,CAAU,IAAA,UAAc,EAAA,WAAa,OAAA,CAAQ,WAAA;EA/iBlD;;;;;;EAkmBK,YAAA,CAAa,IAAA,UAAc,EAAA,WAAa,OAAA,CAAQ,WAAA;EAnkBnD;;;;;EAAA,QAsmBW,eAAA;EAhhBgC;;;;;EA4iBxC,cAAA,CAAe,IAAA,WAAe,OAAA;EA/eT;;;;;EAAA,QAggBnB,MAAA;EA/dF;;;;EAAA,QAggBE,aAAA;AAAA;;;KChnCG,WAAA;AAAA,UAEK,SAAA;EAChB,EAAA;EACA,QAAA;EACA,QAAA;EACA,IAAA;EACA,KAAA;EACA,MAAA;EACA,GAAA;EACA,OAAA;EACA,UAAA;EACA,MAAA,EAAQ,WAAA;EACR,WAAA;EACA,QAAA;EACA,aAAA;EACA,SAAA;EACA,QAAA;AAAA;AAAA,UAGgB,gBAAA;EAChB,QAAA;EACA,QAAA;EACA,IAAA;EACA,KAAA;EACA,MAAA;EACA,GAAA;EACA,OAAA;EACA,UAAA;EACA,WAAA;EACA,QAAA;EACA,aAAA;EACA,MAAA,GAAS,WAAA;EACT,QAAA;AAAA;AAAA,UAGgB,oBAAA;EAChB,KAAA;EACA,MAAA;EACA,QAAA;EACA,MAAA,GAAS,WAAA;AAAA;;;;cAMG,eAAA;EAAA,QACQ,EAAA;cAAA,EAAA,EAAI,MAAA,CAAO,QAAA;EDsQmC;;;ECjQ5D,MAAA,CAAO,KAAA,EAAO,gBAAA,GAAmB,OAAA,CAAQ,SAAA;EDqSpC;;;ECvQL,aAAA,CAAc,KAAA;IACnB,QAAA;IACA,QAAA;IACA,IAAA;IACA,UAAA;IACA,WAAA;IACA,QAAA;EAAA,IACG,OAAA,CAAQ,SAAA;EDyb+D;;;EC/arE,aAAA,CACL,EAAA,UACA,QAAA;IAAa,KAAA;IAAgB,MAAA;IAAiB,IAAA;EAAA,IAC5C,OAAA,CAAQ,SAAA;ED2hBA;;;ECtgBL,UAAA,CAAW,EAAA,WAAa,OAAA,CAAQ,SAAA;ED4nBR;;;EC9mBxB,QAAA,CAAS,EAAA,WAAa,OAAA,CAAQ,SAAA;EDsrBQ;;;;ECxqBtC,cAAA,CAAe,QAAA,WAAmB,OAAA,CAAQ,SAAA;EDqvBC;;;;ECvuB3C,iBAAA,CAAkB,WAAA,WAAsB,OAAA,CAAQ,SAAA;ED01BR;;;;;;ECz0BxC,QAAA,CAAS,OAAA,GAAS,oBAAA,GAA4B,OAAA,CAAQ,cAAA,CAAe,SAAA;ED/F5C;;;ECoJzB,MAAA,CACL,EAAA,UACA,KAAA,EAAO,OAAA,CAAQ,IAAA,CAAK,gBAAA,6CAClB,OAAA,CAAQ,SAAA;EDlJE;;;ECwKP,MAAA,CAAO,EAAA,WAAa,OAAA;EDtED;;;EC+EnB,KAAA,CAAM,QAAA,YAAoB,OAAA;EDvB1B;;;;;;;EC0CA,qBAAA,CAAsB,QAAA,YAAoC,OAAA;EDAnC;;;EAAA,QC0BrB,SAAA;AAAA;;;UC/TQ,QAAA;EAChB,EAAA;EACA,UAAA;EACA,OAAA;EACA,IAAA,EAAM,MAAA;EACN,QAAA;EACA,SAAA;AAAA;;;;UCoBgB,aAAA;EAChB,EAAA;EACA,QAAA;EACA,UAAA;EACA,gBAAA;EACA,IAAA;EACA,SAAA;EACA,OAAA,GAAU,aAAA;AAAA;;;UCHM,kBAAA;EAChB,QAAA;EACA,SAAA;AAAA;;;;;;KClCW,UAAA;;;;;;UAOK,eAAA;EAChB,IAAA;;;;EAIA,UAAA,EAAY,UAAA;EACZ,MAAA,EAAQ,CAAA,CAAE,UAAA;EACV,OAAA;EACA,EAAA,GAAK,YAAA;AAAA;;ANVN;;UMgBiB,YAAA;EAChB,MAAA;EACA,WAAA;EACA,QAAA;EACA,IAAA;EACA,GAAA;EACA,GAAA;EAAA,CACC,GAAA;AAAA;;;;UAMe,mBAAA;EAChB,KAAA;EACA,IAAA;EAAA,CACC,GAAA;AAAA;;;;KAUU,UAAA,GAAa,UAAA;;;;UAKR,SAAA;EAChB,EAAA;EACA,GAAA;EACA,QAAA;EACA,QAAA;EACA,IAAA;AAAA;;;;;;;iBC3Ce,KAAA,CAAM,OAAA;EACrB,QAAA;EACA,OAAA;EACA,YAAA;AAAA,IACG,eAAA,CAAgB,UAAA;;;;;;;iBCfJ,SAAA,CACf,UAAA,UACA,OAAA;EACC,QAAA;AAAA,IAEC,eAAA;;;;;;;iBCKa,YAAA,CAAa,OAAA;EAC5B,QAAA;AAAA,IACG,eAAA,CAAgB,mBAAA;;;;;;UCXH,YAAA;EAChB,KAAA,EAAO,CAAA;EACP,UAAA;AAAA;;;;UAMgB,mBAAA,SAA4B,YAAA,CAAa,WAAA;AAAA,UAEzC,eAAA;EAChB,IAAA,EAAM,WAAA;;EAEN,IAAA;AAAA;AVZD;;;AAAA,UUkBiB,gBAAA;EAChB,OAAA;EACA,IAAA;EACA,WAAA,EAAa,MAAA;IAGX,KAAA;IACA,aAAA;IACA,QAAA;IACA,MAAA,EAAQ,MAAA,SAAe,eAAA;EAAA;EAGzB,OAAA,EAAS,MAAA;IAGP,UAAA,GAAa,KAAA;MAAQ,IAAA;MAAc,SAAA;IAAA;IACnC,OAAA;EAAA;AAAA;AAAA,UAKc,eAAA;EAChB,IAAA;EACA,KAAA;EACA,QAAA;EACA,OAAA,GAAU,KAAA;IAAQ,KAAA;IAAe,KAAA;EAAA;AAAA;;;;;;;;;;;;;KAetB,SAAA;EACP,OAAA;EAAe,IAAA,EAAM,CAAA;AAAA;EAEvB,OAAA;EACA,KAAA;IAAS,IAAA,EAAM,CAAA;IAAG,OAAA;IAAiB,OAAA,GAAU,MAAA;EAAA;AAAA;;;;UAM/B,UAAA;EAChB,MAAA;EACA,QAAA;AAAA;;;;;;UCoIgB,kBAAA;EAChB,EAAA;EACA,IAAA;EACA,IAAA;EACA,MAAA;EACA,IAAA,EAAM,MAAA;EACN,QAAA;EACA,SAAA;EACA,SAAA;EACA,WAAA;EACA,SAAA;AAAA;;;;iBAMqB,iBAAA,CACrB,EAAA,EAAI,MAAA,CAAO,QAAA,GACX,UAAA,UACA,MAAA;EACC,MAAA;EACA,KAAA;EACA,MAAA;EACA,OAAA;EACA,KAAA;EACA,MAAA;AAAA,IAEC,OAAA,CAAQ,SAAA,CAAU,mBAAA;;AV7IrB;;iBUwLsB,gBAAA,CACrB,EAAA,EAAI,MAAA,CAAO,QAAA,GACX,UAAA,UACA,EAAA,UACA,MAAA,YACE,OAAA,CAAQ,SAAA,CAAU,eAAA;;;;;iBAwCC,gCAAA,CACrB,EAAA,EAAI,MAAA,CAAO,QAAA,GACX,UAAA,UACA,EAAA,UACA,MAAA,YACE,OAAA,CAAQ,SAAA,CAAU,eAAA;;;;;;;;iBA2CC,mBAAA,CACrB,EAAA,EAAI,MAAA,CAAO,QAAA,GACX,UAAA,UACA,IAAA;EACC,IAAA,EAAM,MAAA;EACN,IAAA;EACA,MAAA;EACA,QAAA;EACA,OAAA,GAAU,kBAAA;EACV,MAAA;EACA,aAAA;EACA,GAAA,GAAM,eAAA;EACN,SAAA;EACA,WAAA;AAAA,IAEC,OAAA,CAAQ,SAAA,CAAU,eAAA;;;;;;;;iBAkFC,mBAAA,CACrB,EAAA,EAAI,MAAA,CAAO,QAAA,GACX,UAAA,UACA,EAAA,UACA,IAAA;EACC,IAAA,GAAO,MAAA;EACP,IAAA;EACA,MAAA;EACA,QAAA;EACA,OAAA,GAAU,kBAAA;EACV,IAAA;EACA,GAAA,GAAM,eAAA;AAAA,IAEL,OAAA,CAAQ,SAAA,CAAU,eAAA;;;;;;;iBAoIC,sBAAA,CACrB,EAAA,EAAI,MAAA,CAAO,QAAA,GACX,UAAA,UACA,EAAA,UACA,QAAA,YACE,OAAA,CAAQ,SAAA;EAAY,IAAA,EAAM,WAAA;AAAA;;;;iBAgEP,mBAAA,CACrB,EAAA,EAAI,MAAA,CAAO,QAAA,GACX,UAAA,UACA,EAAA,WACE,OAAA,CAAQ,SAAA;EAAY,OAAA;AAAA;;;;iBAqCD,oBAAA,CACrB,EAAA,EAAI,MAAA,CAAO,QAAA,GACX,UAAA,UACA,EAAA,WACE,OAAA,CAAQ,SAAA;EAAY,QAAA;AAAA;;;;;iBAsCD,4BAAA,CACrB,EAAA,EAAI,MAAA,CAAO,QAAA,GACX,UAAA,UACA,EAAA,WACE,OAAA,CAAQ,SAAA;EAAY,OAAA;AAAA;;;;iBAsDD,wBAAA,CACrB,EAAA,EAAI,MAAA,CAAO,QAAA,GACX,UAAA,UACA,OAAA;EAAW,KAAA;EAAgB,MAAA;AAAA,IACzB,OAAA,CAAQ,SAAA;EAAY,KAAA,EAAO,kBAAA;EAAsB,UAAA;AAAA;;;;iBAyC9B,yBAAA,CACrB,EAAA,EAAI,MAAA,CAAO,QAAA,GACX,UAAA,WACE,OAAA,CAAQ,SAAA;EAAY,KAAA;AAAA;;;;iBAwBD,qBAAA,CACrB,EAAA,EAAI,MAAA,CAAO,QAAA,GACX,UAAA,UACA,EAAA,UACA,WAAA,WACE,OAAA,CAAQ,SAAA,CAAU,eAAA;;;;iBAuCC,uBAAA,CACrB,EAAA,EAAI,MAAA,CAAO,QAAA,GACX,UAAA,UACA,EAAA,WACE,OAAA,CAAQ,SAAA,CAAU,eAAA;;;;;;;;iBAkCC,oBAAA,CACrB,EAAA,EAAI,MAAA,CAAO,QAAA,GACX,UAAA,UACA,EAAA,WACE,OAAA,CAAQ,SAAA,CAAU,eAAA;;;;;;;iBAiCC,sBAAA,CACrB,EAAA,EAAI,MAAA,CAAO,QAAA,GACX,UAAA,UACA,EAAA,WACE,OAAA,CAAQ,SAAA,CAAU,eAAA;;;;iBA8BC,2BAAA,CACrB,EAAA,EAAI,MAAA,CAAO,QAAA,GACX,UAAA,WACE,OAAA,CAAQ,SAAA;EAAY,KAAA;AAAA;;;;iBAwBD,yBAAA,CACrB,EAAA,EAAI,MAAA,CAAO,QAAA,GACX,UAAA,UACA,EAAA,WACE,OAAA,CAAQ,SAAA,CAAU,eAAA;;;;iBAuCC,oBAAA,CACrB,EAAA,EAAI,MAAA,CAAO,QAAA,GACX,UAAA,UACA,EAAA,WACE,OAAA,CACF,SAAA;EACC,UAAA;EACA,IAAA,EAAM,MAAA;EACN,KAAA,EAAO,MAAA;AAAA;;;;;iBA+Ca,yBAAA,CACrB,EAAA,EAAI,MAAA,CAAO,QAAA,GACX,UAAA,UACA,EAAA,WACE,OAAA,CACF,SAAA;EACC,gBAAA;EACA,YAAA,EAAc,KAAA;IACb,EAAA;IACA,MAAA;IACA,IAAA;IACA,MAAA;IACA,SAAA;EAAA;AAAA;;;UCzpCO,oBAAA;EACT,MAAA;IACC,IAAA;MAAS,KAAA,SAAc,MAAA;IAAA;IACvB,KAAA,GAAQ,MAAA;EAAA;EAET,KAAA;IACC,KAAA;IACA,aAAA;IACA,QAAA;EAAA;AAAA;AAAA,KAGG,aAAA,GAAgB,MAAA,SAAe,oBAAA;;;;iBAKd,gBAAA,CACrB,WAAA,EAAa,aAAA,EACb,OAAA,GAAS,MAAA;EAGP,UAAA,GAAa,KAAA;IAAQ,IAAA;IAAc,SAAA;EAAA;EACnC,OAAA;AAAA,KAGA,OAAA,CAAQ,gBAAA;;;UC1BM,oBAAA;EAChB,KAAA,EAAO,QAAA;EACP,KAAA;AAAA;AAAA,UAGgB,gBAAA;EAChB,IAAA,EAAM,QAAA;AAAA;;;AbZP;iBakBsB,kBAAA,CACrB,EAAA,EAAI,MAAA,CAAO,QAAA,GACX,UAAA,UACA,OAAA,UACA,MAAA;EAAU,KAAA;AAAA,IACR,OAAA,CAAQ,SAAA,CAAU,oBAAA;;AblBrB;;iBa4CsB,iBAAA,CACrB,EAAA,EAAI,MAAA,CAAO,QAAA,GACX,UAAA,WACE,OAAA,CAAQ,SAAA,CAAU,gBAAA;;;;iBAiCC,qBAAA,CACrB,EAAA,EAAI,MAAA,CAAO,QAAA,GACX,UAAA,UACA,YAAA,WACE,OAAA,CAAQ,SAAA,CAAU,eAAA;;;UCpFJ,iBAAA;EAChB,KAAA,EAAO,SAAA;EACP,UAAA;AAAA;AAAA,UAGgB,aAAA;EAChB,IAAA,EAAM,SAAA;AAAA;;;AdXP;iBciBsB,eAAA,CACrB,EAAA,EAAI,MAAA,CAAO,QAAA,GACX,MAAA;EACC,MAAA;EACA,KAAA;EACA,QAAA;AAAA,IAEC,OAAA,CAAQ,SAAA,CAAU,iBAAA;;;;iBA8BC,cAAA,CACrB,EAAA,EAAI,MAAA,CAAO,QAAA,GACX,EAAA,WACE,OAAA,CAAQ,SAAA,CAAU,aAAA;;;;iBAiCC,iBAAA,CACrB,EAAA,EAAI,MAAA,CAAO,QAAA,GACX,KAAA;EACC,QAAA;EACA,QAAA;EACA,IAAA;EACA,KAAA;EACA,MAAA;EACA,GAAA;EACA,UAAA;EACA,WAAA;EACA,QAAA;EACA,aAAA;EACA,QAAA;AAAA,IAEC,OAAA,CAAQ,SAAA,CAAU,aAAA;;;;iBAuBC,iBAAA,CACrB,EAAA,EAAI,MAAA,CAAO,QAAA,GACX,EAAA,UACA,KAAA;EACC,GAAA;EACA,OAAA;EACA,KAAA;EACA,MAAA;AAAA,IAEC,OAAA,CAAQ,SAAA,CAAU,aAAA;;;;iBAiCC,iBAAA,CACrB,EAAA,EAAI,MAAA,CAAO,QAAA,GACX,EAAA,WACE,OAAA,CAAQ,SAAA;EAAY,OAAA;AAAA;;;;;;cC7HV,WAAA,SAAoB,KAAA;EAGxB,IAAA;EACA,OAAA,GAAU,MAAA;cAFjB,OAAA,UACO,IAAA,UACA,OAAA,GAAU,MAAA;AAAA;;;;;;AfpDnB;ceiEa,cAAA;EAAA,QACQ,EAAA;cAAA,EAAA,EAAI,MAAA,CAAO,QAAA;EfhEtB;AAGV;;EesEO,eAAA,CAAA,GAAmB,OAAA,CAAQ,UAAA;EftEY;;;EemFvC,aAAA,CAAc,IAAA,WAAe,OAAA,CAAQ,UAAA;EfjF1C;;;Ee8FK,uBAAA,CAAwB,IAAA,WAAe,OAAA,CAAQ,oBAAA;;;;EAY/C,gBAAA,CAAiB,KAAA,EAAO,qBAAA,GAAwB,OAAA,CAAQ,UAAA;EdpBjC;;;Ec0EvB,gBAAA,CAAiB,IAAA,UAAc,KAAA,EAAO,qBAAA,GAAwB,OAAA,CAAQ,UAAA;EdpExD;;;EcyId,gBAAA,CAAiB,IAAA,UAAc,OAAA;IAAY,KAAA;EAAA,IAAoB,OAAA;Ed2DnB;;;Ec5B5C,UAAA,CAAW,YAAA,WAAuB,OAAA,CAAQ,KAAA;EdyErC;;;Ec1DL,QAAA,CAAS,cAAA,UAAwB,SAAA,WAAoB,OAAA,CAAQ,KAAA;EdyGI;;;EcxFjE,WAAA,CAAY,cAAA,UAAwB,KAAA,EAAO,gBAAA,GAAmB,OAAA,CAAQ,KAAA;EduJlE;;;Ec/EJ,WAAA,CACL,cAAA,UACA,SAAA,UACA,KAAA,EAAO,gBAAA,GACL,OAAA,CAAQ,KAAA;EdkKmC;;;;;;EAAA,Qc9FhC,kBAAA;Ed4MJ;;;EcnLJ,WAAA,CAAY,cAAA,UAAwB,SAAA,WAAoB,OAAA;Ed+P5B;;;Ec5O5B,aAAA,CAAc,cAAA,UAAwB,UAAA,aAAuB,OAAA;EdiTJ;;;EAAA,QczRjD,kBAAA;Ed6W0B;;;EAAA,QclR1B,gBAAA;EdyT2B;;;EAAA,QcjT3B,SAAA;EdoagC;;;EAAA,QchYhC,UAAA;EdxiBM;;;EAAA,QcyjBN,oBAAA;EdzjBM;;;EAAA,Qc0kBZ,YAAA;EdrkBiC;;;EAAA,Qc4kBjC,aAAA;Ed1e+B;;;EAAA,Qcif/B,YAAA;EdzbQ;;;;;;;;;;;EAAA,QcqdR,kBAAA;EdtZqC;;;EAAA,QcucrC,eAAA;EdlbP;;;EAAA,QcocO,gBAAA;EdjcG;;;EAAA,Qc6dH,WAAA;EdldP;;;;;;EcifK,sBAAA,CAAA,GAA0B,OAAA,CAC/B,KAAA;IAAQ,IAAA;IAAc,SAAA;IAAmB,QAAA;EAAA;Ed/azC;;;;;EcoeK,qBAAA,CACL,IAAA,UACA,OAAA;IACC,KAAA;IACA,aAAA;IACA,WAAA;EAAA,IAEC,OAAA,CAAQ,UAAA;Ed1cA;;;EAAA,QcwfH,WAAA;AAAA;;;;;;;;;;;Af37BT;;;;;iBgBqBsB,iBAAA,CAAkB,IAAA,WAAe,OAAA,CAAQ,UAAA;;;;;;KCfnD,aAAA;;;;UAKK,OAAA;EAChB,EAAA;EACA,IAAA;EACA,KAAA;EACA,WAAA;EACA,QAAA;EACA,OAAA,EAAS,mBAAA;EACT,UAAA;EACA,MAAA,EAAQ,aAAA;EACR,OAAA;EACA,SAAA;EACA,SAAA;AAAA;;;;UAuBgB,kBAAA;EAChB,IAAA;EACA,KAAA;EACA,WAAA;EACA,QAAA;EACA,OAAA,EAAS,mBAAA;EACT,cAAA;EACA,MAAA,GAAS,aAAA;EACT,OAAA;AAAA;;;;UAMgB,kBAAA;EAChB,IAAA;EACA,KAAA;EACA,WAAA;EACA,QAAA;EACA,OAAA,GAAU,mBAAA;EACV,cAAA;AAAA;;;;UAMgB,kBAAA;EhBikBU;EgB/jB1B,MAAA,GAAS,aAAA;EhB+jBN;EgB7jBH,MAAA;EhB0pBG;EgBxpBH,KAAA;EhB2sBuE;EgBzsBvE,MAAA;AAAA;;;;;;;;;AjB/ED;;;;;AAKA;;iBkByBsB,UAAA,CAAW,IAAA,WAAe,OAAA,CAAQ,OAAA;;;;;;;;;;;;;;;iBA+DlC,WAAA,CACrB,OAAA,GAAS,kBAAA,GACP,OAAA,CAAQ,cAAA,CAAe,OAAA;;;;;;;UClFT,cAAA;EnBbA;EmBehB,KAAA;;EAEA,QAAA;EnBfS;EmBiBT,WAAA;EnBdgC;EmBgBhC,UAAA;AAAA;;;;;UAOgB,iBAAA;EnBpBgB;EmBsBhC,GAAA,CAAI,IAAA,WAAe,OAAA;;EAEnB,MAAA,CAAO,IAAA,WAAe,OAAA;AAAA;AlB6DvB;;;;AAAA,UkBtDiB,mBAAA;EAChB,EAAA;EACA,OAAA;EACA,IAAA;EACA,IAAA;AAAA;;;;;;;;KAUW,wBAAA,IACX,OAAA,EAAS,mBAAA,EACT,QAAA,aACI,OAAA;;;;UAKY,cAAA;ElBwWb;EkBtWH,OAAA,GAAU,iBAAA;ElBoYgB;EkBlY1B,EAAA,EAAI,MAAA,CAAO,QAAA;ElBkYR;EkBhYH,MAAA,GAAS,cAAA;ElBsdkE;EkBpd3E,QAAA;IAAa,IAAA;IAAc,GAAA;IAAa,MAAA;EAAA;ElBkkB9B;EkBhkBV,SAAA,GAAY,wBAAA;AAAA;;;;;UAOI,eAAA;ElB0sB+C;EAAA,SkBxsBtD,EAAA;ElBsvBmC;;;;;;;EkB7uB5C,UAAA,CAAW,QAAA,UAAkB,KAAA,YAAiB,OAAA;ElB03BH;;;;;;;;EkBh3B3C,WAAA,CAAY,SAAA,UAAmB,KAAA,WAAgB,OAAA,EAAS,iBAAA,GAAoB,OAAA;ElBL7C;;;;EkBW/B,SAAA,IAAa,OAAA;AAAA;;;;;UAOG,iBAAA;EAChB,GAAA;EACA,MAAA;EACA,OAAA,EAAS,MAAA;ElB0IqB;EkBxI9B,IAAA,EAAM,WAAA;AAAA;;;;;UAOU,aAAA;ElB2KkC;;;;EkBtKlD,WAAA;ElB2LkE;;;;;;;;EkBjLlE,IAAA,CAAK,QAAA,EAAU,cAAA,EAAgB,IAAA,WAAe,OAAA,CAAQ,eAAA;ElBmNrD;;;;;EkB5MD,YAAA,CAAa,QAAA,EAAU,wBAAA;ElBiPN;;;;EkB3OjB,YAAA,IAAgB,OAAA;AAAA;;;;;;;;;;;;;KAeL,oBAAA,IAAwB,OAAA,EAAS,cAAA,KAAmB,aAAA;;;;;;;;;;;UCnK/C,gBAAA;EAChB,KAAA;EACA,IAAA;EACA,IAAA;EACA,KAAA;AAAA;;;ApBRD;UoBciB,mBAAA;EAChB,KAAA;EACA,IAAA;EAAA,CACC,GAAA;AAAA;;;;UAMe,oBAAA,SAA6B,mBAAA;EAC7C,KAAA;EACA,IAAA;EACA,KAAA;AAAA;;;;UAMgB,qBAAA;EAChB,KAAA;EACA,IAAA;EACA,KAAA;EACA,QAAA;EACA,KAAA;EACA,QAAA,EAAU,gBAAA;EACV,QAAA,GAAW,mBAAA;AAAA;;;;UAMK,sBAAA;EAChB,KAAA;EACA,IAAA;EACA,KAAA;IACC,IAAA;IACA,GAAA,WnBkSE;ImBhSF,QAAA;EAAA;EAED,GAAA;EACA,OAAA;EnB8WW;EmB5WX,KAAA;EnByYU;EmBvYV,MAAA;EnBwYW;EmBtYX,YAAA;EnB4d8C;EmB1d9C,aAAA;AAAA;;;;UAMgB,qBAAA;EAChB,KAAA;EACA,IAAA;EACA,IAAA;EACA,QAAA;EACA,QAAA;AAAA;;;;UAMgB,wBAAA;EAChB,KAAA;EACA,IAAA;EAAA,CACC,GAAA;AAAA;;;;KAMU,mBAAA,GACT,qBAAA,GACA,sBAAA,GACA,qBAAA,GACA,wBAAA;;;;UAKc,eAAA;EAChB,IAAA;EACA,KAAA,GAAQ,MAAA;AAAA;AAAA,UAGQ,eAAA;EAChB,IAAA;EACA,KAAA,GAAQ,MAAA;EACR,OAAA,GAAU,eAAA;EACV,KAAA,GAAQ,eAAA;EACR,IAAA;AAAA;AAAA,UAGgB,mBAAA;EAChB,IAAA;EACA,OAAA,EAAS,eAAA;AAAA;;;;;;iBC1FM,yBAAA,CAA0B,GAAA,EAAK,mBAAA,GAAsB,mBAAA;;;;;;iBCPrD,yBAAA,CAA0B,MAAA,EAAQ,mBAAA,KAAsB,mBAAA;;;;;;;iBCjBlD,UAAA,CAAW,OAAA,WAAkB,OAAA;;;;;;;;;;iBAgB7B,kBAAA,CAAmB,OAAA,EAAS,UAAA,GAAa,WAAA,GAAc,OAAA;;;;;;;;;;;;;;;;;;;AvBf7E;;;;;AAKA;;iBwB2BgB,YAAA,CAAa,GAAA;;;;iBAQb,UAAA,CAAW,GAAA;;;;;;;;UCvCV,aAAA;EAChB,UAAA;EACA,EAAA;EACA,KAAA;;EAEA,MAAA;;EAEA,QAAA;AAAA;;UAIgB,eAAA;EAChB,iBAAA;AAAA;AAAA,UAGgB,eAAA;EzBfhB;EyBiBA,MAAA;EzBbY;EyBeZ,QAAA;AAAA;;;;;;;;;iBAWe,cAAA,CACf,UAAA,UACA,EAAA,UACA,OAAA,GAAU,eAAA,GACR,SAAA;;;AxB0DH;;iBwBjBgB,UAAA,CAAA,GAAc,SAAA;;;;;;;;;KAwBlB,SAAA;EAAA,UACD,KAAA,WAAgB,OAAA,CAAQ,eAAA;AAAA;;;;;AzBrGnC;;;;;AAKA;;;;;;;;;;;;;;U0BmCiB,iBAAA;;;;;KAML,mBAAA,qBAAwC,CAAA,eAAgB,iBAAA,GACjE,iBAAA,CAAkB,CAAA,IAClB,MAAA;;;;KAKS,eAAA;;;;;;;KAQA,aAAA,GAAc,MAAA,SAAe,eAAA;AAAA,UAExB,kBAAA;EAChB,MAAA;EACA,KAAA;EzBoWW;;;;;;;;;;;;EyBvVX,MAAA;EzByjBU;;;;;EyBnjBV,KAAA,GAAQ,MAAA;EzB0qBsB;;;;;;;EyBlqB9B,OAAA,GAAU,aAAA;EzBkyBsD;;;;;;EyB3xBhE,MAAA;AAAA;AAAA,UAGgB,YAAA,KAAiB,MAAA;EACjC,EAAA;EACA,IAAA,EAAM,CAAA;;EAEN,IAAA,EAAM,SAAA;AAAA;;UAIU,SAAA;EAChB,IAAA;EACA,YAAA,GAAe,IAAA;AAAA;;;;UAMC,gBAAA;EzB+EqC;EyB7ErD,OAAA,EAAS,YAAA,CAAa,CAAA;EzBqIhB;EyBnIN,KAAA,GAAQ,KAAA;EzBmIsB;EyBjI9B,SAAA,EAAW,SAAA;EzBiImD;;;;;EyB3H9D,UAAA;AAAA;;;;UAMgB,WAAA;EzBoLkD;EyBlLlE,KAAA,EAAO,YAAA,CAAa,CAAA;EzBuMnB;EyBrMD,KAAA,GAAQ,KAAA;EzBuMP;EyBrMD,SAAA;EzBsMW;EyBpMX,cAAA;EzB6MC;EyB3MD,SAAA,EAAW,SAAA;AAAA;;UASK,aAAA;EAChB,UAAA;EACA,EAAA;EACA,KAAA;AAAA;;;;;;iBAiBe,WAAA,CAAY,KAAA,YAAiB,aAAA;;;;;;;;;;;;;;;;;;;;;;;;iBAwFvB,mBAAA,uBAA0C,mBAAA,CAAoB,CAAA,EAAA,CACnF,IAAA,EAAM,CAAA,EACN,MAAA,GAAS,kBAAA,GACP,OAAA,CAAQ,gBAAA,CAAiB,CAAA;;;;;;;;;;;;;;;;;;;;;iBAsEN,cAAA,uBAAqC,mBAAA,CAAoB,CAAA,EAAA,CAC9E,IAAA,EAAM,CAAA,EACN,EAAA,UACA,OAAA;EAAY,MAAA;AAAA,IACV,OAAA,CAAQ,WAAA,CAAY,CAAA;;;;UAiMN,kBAAA;EzByOwB;EyBvOxC,EAAA;EzBuO0E;EyBrO1E,MAAA;EzB+Pe;EyB7Pf,IAAA;EzB6PyC;EyB3PzC,MAAA;AAAA;;;;UAMgB,kBAAA;EzBmSoC;EyBjSpD,gBAAA;EzBuUyB;EyBrUzB,YAAA,EAAc,kBAAA;EzBqUkC;EyBnUhD,KAAA,GAAQ,KAAA;AAAA;;;;;;;;;;;;;;;;iBAkBa,eAAA,CAAgB,IAAA,UAAc,EAAA,WAAa,OAAA,CAAQ,kBAAA;;;;UAyCxD,iBAAA,KAAsB,MAAA;EzBiejB;EyB/drB,KAAA,EAAO,YAAA,CAAa,CAAA;EzBgfZ;EyB9eR,UAAA;EzB+gBqB;EyB7gBrB,MAAA,EAAQ,MAAA;AAAA;;;AxBnmBT;;;;;AAEA;;;;;;;;;;;;iBwBooBsB,iBAAA,KAAsB,MAAA,kBAAA,CAC3C,IAAA,WACE,OAAA,CAAQ,iBAAA,CAAkB,CAAA;;;;;;;;;UC7oBZ,UAAA;EAChB,aAAA;EACA,OAAA;EACA,QAAA,GAAW,MAAA;EACX,mBAAA;AAAA;;;;;iBAiBe,aAAA,CAAA,GAAiB,UAAA;;;;;iBAQjB,aAAA,CAAA;;;;;;iBASA,gBAAA,CAAiB,MAAA;;;;A3BxCjC;;K4BoMY,SAAA,GAAY,MAAA;;;A5B/LxB;K4BoMY,aAAA;;;;;;KAOA,WAAA,GAAc,MAAA,SAAe,aAAA;;;;UA0HxB,gBAAA;EAChB,IAAA;EACA,MAAA;EACA,KAAA;E3BhP6B;;;;E2BqP7B,MAAA;E3B/OiD;;;E2BmPjD,KAAA,GAAQ,MAAA;E3BzFsD;;;;E2B8F9D,OAAA,GAAU,WAAA;E3BPC;;;;E2BYX,MAAA;AAAA;;;;UAMgB,WAAA;EAChB,IAAA;EACA,EAAA;E3BiL8C;;;;E2B5K9C,UAAA;E3B0QiD;;;;E2BrQjD,MAAA;AAAA;;;;;;;;;;;iBAgBqB,KAAA,CAAA,GAAS,OAAA,CAAQ,MAAA,CAAO,QAAA;;;;;;;;;;;;;;;;;;;;;;;iBA0C9B,YAAA,CAAA,GAAgB,UAAA,CAAW,SAAA,EAAW,WAAA,EAAa,gBAAA;;;;;;UC7ZlD,OAAA;;EAEhB,IAAA,EAAM,OAAA;;EAEN,KAAA,EAAO,OAAA;E7BnBuB;E6BqB9B,WAAA,EAAa,aAAA;E7BpBb;E6BsBA,UAAA,EAAY,WAAA;E7BlBA;E6BoBZ,IAAA,EAAM,MAAA;;EAEN,OAAA,EAAS,SAAA;E7BtB+B;E6BwBxC,KAAA,EAAO,OAAA;;EAEP,QAAA,EAAU,UAAA;AAAA;AAAA,UAGM,OAAA;EAChB,KAAA;EACA,IAAA;EACA,WAAA;EACA,QAAA;EACA,WAAA;EACA,WAAA;AAAA;AAAA,UAGgB,OAAA;EAChB,EAAA;EACA,KAAA;EACA,IAAA;EACA,OAAA;EACA,OAAA;EACA,IAAA;EACA,WAAA;EACA,OAAA;EACA,OAAA;EACA,QAAA;EACA,WAAA;EACA,YAAA;EACA,eAAA;EACA,aAAA;EACA,UAAA;EACA,MAAA;EACA,QAAA;EACA,QAAA;EACA,YAAA;EACA,QAAA;E5BoY0B;E4BlY1B,UAAA;E5BkYG;E4BhYH,SAAA;EACA,UAAA;EACA,IAAA;E5BihBwC;E4B/gBxC,gBAAA,GAAmB,GAAA;EACnB,IAAA,EAAM,GAAA;AAAA;AAAA,UAGU,aAAA;EAChB,EAAA;EACA,KAAA;EACA,GAAA;EACA,QAAA;EACA,IAAA,EAAM,GAAA;AAAA;AAAA,UAGU,WAAA;EAChB,EAAA;EACA,QAAA;EACA,IAAA;EACA,MAAA;EACA,WAAA;AAAA;AAAA,UAGgB,MAAA;EAChB,EAAA;EACA,IAAA;EACA,IAAA;EACA,WAAA;AAAA;;;;UAMgB,OAAA;EAChB,EAAA;EACA,QAAA;EACA,IAAA;EACA,IAAA;EACA,MAAA;EACA,WAAA;AAAA;;;;UAMgB,UAAA;EAChB,EAAA;EACA,IAAA;EACA,KAAA;EACA,KAAA,EAAO,cAAA;AAAA;;;;UAMS,cAAA;EAChB,EAAA;EACA,MAAA;EACA,QAAA;EACA,SAAA;EACA,IAAA;EACA,UAAA;EACA,QAAA;EACA,GAAA;EACA,KAAA;EACA,MAAA;EACA,OAAA;AAAA;AAAA,UAGgB,SAAA;EAChB,EAAA;EACA,KAAA;EACA,KAAA;EACA,WAAA;EACA,SAAA;EACA,QAAA;AAAA;;;;iBAuBe,QAAA,CAAS,MAAA,EAAQ,QAAA,GAAW,OAAA,CAAQ,OAAA;;;;;;;iBAsWpC,cAAA,CAAe,GAAA,WAAc,OAAA,CAAQ,OAAA;;;;A7B5gBrD;;;;;AAKA;;;;;;;;;;;;;;ACwFA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iB6BbgB,YAAA,kBAA8B,mBAAA,CAAA,CAC7C,UAAA,EAAY,gBAAA,CAAiB,QAAA,IAC3B,cAAA,CAAe,QAAA;AAAA,iBAEF,YAAA,CAAa,UAAA,EAAY,wBAAA,GAA2B,wBAAA;;;;;;;;;;;;UC/EnD,UAAA;;EAEhB,KAAA;;EAEA,IAAA;;EAEA,IAAA;E/BXgB;E+BahB,OAAA;;EAEA,QAAA,GAAW,MAAA;AAAA;A/BVZ;;;;;;AAAA,U+BmBiB,cAAA;E/BjBf;;;;E+BsBD,IAAA;;;A9BgED;;;E8BzDC,UAAA;E9B0DwB;;;E8BrDxB,MAAA;AAAA;;;;;;;UASgB,kBAAA;E9BkSb;;;;;;;E8B1RH,YAAA,CAAa,OAAA,EAAS,OAAA,EAAS,MAAA,YAAkB,OAAA,CAAQ,UAAA;AAAA;;;;UAMzC,kBAAA;E9BydmD;;;;E8BpdnE,aAAA;E9BkkBU;;;;E8B5jBV,WAAA;E9B0pBG;;;;;E8BnpBH,SAAA;E9B0xBgD;;;;;;;;;;;;;E8B3wBhD,WAAA,GAAc,MAAA;AAAA;;;;;;UCtFE,iBAAA;;EAEhB,UAAA;EhCb8B;EgCe9B,MAAA;AAAA;;;;UAgBgB,eAAA;;EAEhB,QAAA;E/B4DY;E+B1DZ,MAAA;;EAEA,WAAA;E/ByDwB;E+BvDxB,eAAA;E/B4DiD;E+B1DjD,MAAA;E/B4JuE;E+B1JvE,SAAA;AAAA;;;;UAMgB,kBAAA;E/BmSL;E+BjSX,SAAA;E/B6SW;E+B3SX,OAAA;AAAA;;;;AhCrDD;;UiCgBiB,eAAA;EAChB,IAAA;EACA,KAAA;EACA,IAAA;AAAA;;;;UAMgB,qBAAA;EAChB,EAAA;EACA,IAAA;EACA,KAAA;AAAA;;;;;AhCiED;;;;;;;;;;;;;;;;;;;UgCvCiB,4BAAA;EAChB,OAAA;EACA,aAAA;AAAA;AAAA,UAGgB,gBAAA,YAA4B,MAAA;EhCwYlB;EgCtY1B,EAAA;EhCsYG;EgCpYH,OAAA;EhC0d2E;EgCxd3E,UAAA;EhCqhBwC;;;;;EgC/gBxC,OAAA,GAAU,QAAA;EhCikBC;;;;;;;;;;;EgCrjBX,MAAA;EhC2yBgE;EgCzyBhE,UAAA;EhC8zByC;EgC5zBzC,eAAA;EhC43B2C;EgC13B3C,UAAA,GAAa,eAAA;EhC66BiC;EgC36B9C,YAAA,GAAe,qBAAA;EhC0+B4B;;;;;EgCj+B3C,YAAA;EhCNoB;;;;EgCWpB,YAAA;EhCNiD;;;;EgCWjD,OAAA,GAAU,MAAA,SAAe,4BAAA;AAAA;;;;;;;KASd,yBAAA,YAAqC,MAAA,qBAChD,gBAAA,CAAiB,QAAA;AAAA,UAED,YAAA;EhC6Ka;;;;;;;;;;;;;;;;;EgC3J7B,QAAA,GAAW,kBAAA;EhCoNR;;;EgChNH,OAAA,GAAU,iBAAA;EhCmPO;;;;;;;;;;;;;;;;EgClOjB,OAAA,GAAU,gBAAA;EhCkSgB;;;;;;;;;;;;;;;;;EgChR1B,SAAA,GAAY,yBAAA;EhCocwB;;;;;;;;;;;EgCxbpC,aAAA;EhCohBmB;;;;;;;;;;;;;;;;;;;;;;;;EgC1fnB,IAAA,GAAO,cAAA;EhC6mB6C;;;;;;;;;;;;;;;;;;;EgCxlBpD,GAAA;EhCwxBM;;;;;;;;;;;;;;;;AC//BP;E+B0PC,WAAA;;;;A/BxPD;;;;;;;;;;E+BuQC,OAAA;E/B/PA;;;;;;;;;;;AAUD;;;;;;;;;;;;;E+B+QC,UAAA;I/BpQA,iD+BsQC,oBAAA;EAAA;E/BpQD;;;AAGD;;;;;;;;;;;AAUA;;;;;;;E+B+QC,cAAA,GAAiB,uBAAA;AAAA;;;;;iBAOF,eAAA,CAAA,GAAmB,YAAA;AAAA,QAa3B,MAAA;EAAA,IAEH,cAAA,EAAgB,YAAA;AAAA;;;;;;;AjC1VrB;ckCgLa,oBAAA,EAAoB,GAAA,CAAA,SAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;KA0BrB,uBAAA,GAA0B,GAAA,CAAE,KAAA,QAAa,oBAAA;;;KCtJhD,UAAA;;;AnCpDL;UmC2GiB,UAAA;EAChB,OAAA;EACA,KAAA,GAAQ,CAAA;EACR,KAAA,GAAQ,KAAA;EACR,QAAA;EACA,QAAA;AAAA;;;;cAMY,YAAA;EAAA,QACJ,KAAA;EAAA,QACA,SAAA;EAAA,QACA,cAAA;EnCjHwB;EAAA,QmCmHxB,qBAAA;;UAGA,kBAAA;ElCjCI;;;;EAAA,QkCuCJ,mBAAA;cAEI,OAAA,EAAS,cAAA,IAAkB,cAAA,GAAiB,2BAAA;ElCnCP;;;;;;;;EkCuDjD,iBAAA,CAAkB,OAAA,EAAS,OAAA,CAAQ,2BAAA;ElC0LxB;;;EAAA,QkChLH,UAAA;ElC+N+D;;;;;;;;EAAA,QkC5M/D,aAAA;ElCkWmE;;;;;;;EAAA,QkC5UnE,eAAA;ElC2bG;;;;;;;EAAA,wBkCpZa,wBAAA;ElCklBoB;;;EAAA,QkCtjBpC,kBAAA;ElC8mBwD;;;EAAA,QkCllBxD,YAAA;ElCuqBmC;;;EAAA,QkC9pBnC,SAAA;ElCgxBmC;;;EAAA,QkCjvB7B,kBAAA;ElCtPU;;;EkCsQlB,gBAAA,CAAiB,QAAA,WAAmB,OAAA,CAAQ,UAAA;ElCjQ9B;;;EkCwQd,iBAAA,CAAkB,QAAA,WAAmB,OAAA,CAAQ,UAAA;ElCtK7C;;;EkC6KA,mBAAA,CAAoB,QAAA,WAAmB,OAAA,CAAQ,UAAA;ElC7KkB;;;EkCoLjE,kBAAA,CAAmB,QAAA,UAAkB,UAAA,YAAsB,OAAA,CAAQ,UAAA;EAAA,QAgC3D,gBAAA;ElC5JgD;;;;EkCuMxD,oBAAA,CACL,OAAA,EAAS,MAAA,mBACT,UAAA,UACA,KAAA,YACE,OAAA;IACF,OAAA,EAAS,MAAA;IACT,OAAA,EAAS,UAAA,CAAW,MAAA;EAAA;ElC9IU;;;EkC8LzB,mBAAA,CACL,OAAA,EAAS,MAAA,mBACT,UAAA,UACA,KAAA,YACE,OAAA,CAAQ,UAAA;ElC9KL;;;;EkCoNA,sBAAA,CACL,EAAA,UACA,UAAA,WACE,OAAA;IAAU,OAAA;IAAkB,OAAA,EAAS,UAAA;EAAA;ElCzMvC;;;EkCoPK,qBAAA,CAAsB,EAAA,UAAY,UAAA,WAAqB,OAAA,CAAQ,UAAA;ElC9OvD;;;EkCmRR,sBAAA,CACL,OAAA,EAAS,MAAA,mBACT,UAAA,WACE,OAAA,CAAQ,UAAA;ElCvPkC;;;EkC4RvC,wBAAA,CACL,OAAA,EAAS,MAAA,mBACT,UAAA,WACE,OAAA,CAAQ,UAAA;ElChQV;;;EkCySK,oBAAA,CAAqB,IAAA;IAAQ,IAAA;IAAc,IAAA;IAAc,IAAA;EAAA,IAAiB,OAAA;IAC/E,IAAA;MAAQ,IAAA;MAAc,IAAA;MAAc,IAAA;IAAA;IACpC,OAAA,EAAS,UAAA;MAAa,IAAA;MAAc,IAAA;MAAc,IAAA;IAAA;EAAA;ElCvH7C;;;EkCuKA,mBAAA,CAAoB,KAAA;IACzB,EAAA;IACA,QAAA;IACA,QAAA;IACA,IAAA;IACA,GAAA;IACA,SAAA;EAAA,IACG,OAAA,CAAQ,UAAA;ElC7IqC;;;;;;EkCyL3C,cAAA,CAAe,QAAA,UAAkB,KAAA,EAAO,SAAA,GAAY,OAAA,CAAQ,UAAA;ElCxKvD;;;;;;;EkCqNL,kBAAA,CACL,OAAA,EAAS,YAAA,EACT,MAAA,WACE,OAAA;IAAU,OAAA,EAAS,YAAA;IAAsB,OAAA,EAAS,UAAA,CAAW,YAAA;EAAA;ElC5H/D;;;;;EkCwLK,iBAAA,CAAkB,OAAA,EAAS,YAAA,EAAc,MAAA,WAAiB,OAAA,CAAQ,UAAA;ElC9JjB;;;;;;;EkC4MjD,sBAAA,CACL,KAAA,EAAO,wBAAA,GACL,OAAA,CAAQ,wBAAA;ElCtIL;;;;;EkCgLA,qBAAA,CAAsB,KAAA,EAAO,uBAAA,GAA0B,OAAA;ElC1IpC;;;;;EkCiKnB,uBAAA,CAAwB,KAAA,EAAO,yBAAA,GAA4B,OAAA;ElC/ID;;;;EkCyK1D,eAAA,CACL,KAAA,EAAO,iBAAA,GACL,OAAA,CAAQ,KAAA;IAAQ,QAAA;IAAkB,aAAA,EAAe,wBAAA;EAAA;ElCtFpC;;;;EkCuHV,gBAAA,CACL,KAAA,EAAO,iBAAA,GACL,OAAA,CAAQ,KAAA;IAAQ,QAAA;IAAkB,aAAA,EAAe,wBAAA;EAAA;ElCtEE;;;EkC0GtD,QAAA,CAAS,IAAA,EAAM,UAAA;ElC3CqB;;;EkCmDpC,YAAA,CAAa,IAAA,EAAM,UAAA;ElCDE;;;EkCQrB,kBAAA,CAAA,GAAsB,UAAA;EjCxnCX;;;EiCmoCX,2BAAA,CAAA;EjCnoCsB;AAEvB;;EiCwoCC,eAAA,CAAgB,IAAA;EjC9nCG;;;;EiCsoCnB,qBAAA,CAAsB,QAAA,UAAkB,QAAA;EjC3oCxC;;;EiCkpCA,uBAAA,CAAwB,QAAA;EjC9oCxB;;;EiCqpCA,qBAAA,CAAsB,QAAA;EjClpCtB;;;EiCypCA,yBAAA,CAA0B,QAAA,WAAmB,KAAA;IAAQ,QAAA;EAAA;EjCnpCrC;;;;;;;;;;;;EiCoqCV,mBAAA,CACL,QAAA,UACA,KAAA,YACE,OAAA;IAAU,MAAA;IAAiB,QAAA;IAAkB,KAAA,GAAQ,KAAA;IAAO,QAAA;EAAA;AAAA;;AjCvpChE;;iBiCmrCgB,kBAAA,CACf,OAAA,EAAS,cAAA,IACT,cAAA,GAAiB,2BAAA,GACf,YAAA;;;;;;;;;;AlCpoCH;cmC3Ba,aAAA;EAAA,QACJ,QAAA;cAEI,QAAA,EAAU,YAAA;EnCyBE;;;;;;;EmCdxB,WAAA,CAAY,QAAA,EAAU,YAAA;EnCuNoB;;;;;;;;;EmC1MpC,IAAA,CAAK,OAAA,EAAS,YAAA,EAAc,MAAA,WAAiB,OAAA;EnCwUhD;;;EAAA,QmC5SW,SAAA;EnC0UX;;;;;;;EmC3PH,WAAA,CAAA;AAAA;;;;;;UCiegB,eAAA;EpCjCb;EoCmCH,QAAA;EpC0DG;EoCxDH,OAAA;EpC2GuE;EoCzGvE,MAAA;AAAA;AAAA,UAwGgB,2BAAA;EAChB,EAAA,EAAI,MAAA,CAAO,QAAA;EpCrrBE;;;;EoC0rBb,OAAA,GAAU,OAAA;EpCxlB6B;;;;EoC6lBvC,YAAA,IACC,QAAA,UACA,WAAA,aACI,OAAA;IAAU,SAAA;IAAmB,OAAA;EAAA;EpCxiBoC;;;;EoC6iBtE,QAAA,GAAW,eAAA;EpCngBuC;;;;EoCwgBlD,cAAA;EpCnfkE;;;;EoCwflE,aAAA,GAAgB,aAAA;AAAA;;;;;;UChyBA,WAAA;EAChB,OAAA;EACA,IAAA,GAAO,CAAA;EACP,KAAA;IACC,IAAA;IACA,OAAA;IACA,OAAA;EAAA;EAED,MAAA;AAAA;;;;UAMgB,kBAAA;ErC2DJ;EqCzDZ,OAAA,EAAS,OAAA;;EAET,IAAA;AAAA;;;;;cA6HY,gBAAA,SAAyB,KAAA;EAE7B,IAAA;EAEA,MAAA;EACA,OAAA;cAHA,IAAA,UACP,OAAA,UACO,MAAA,WACA,OAAA;ErC6jBL;;;EAAA,OqCpjBI,UAAA,CAAW,OAAA,UAAiB,OAAA,aAAoB,gBAAA;ErCqpBH;;;EAAA,OqC9oB7C,YAAA,CAAa,OAAA,YAAmC,gBAAA;ErCssBiB;;;EAAA,OqC/rBjE,SAAA,CAAU,OAAA,YAAgC,gBAAA;ErCoxBE;;;EAAA,OqC7wB5C,QAAA,CAAS,OAAA,YAAgC,gBAAA;ErC+3BZ;;;EAAA,OqCx3B7B,QAAA,CAAS,OAAA,UAAiB,OAAA,aAAoB,gBAAA;;;;SAO9C,QAAA,CAAS,OAAA,YAAqC,gBAAA;AAAA;;;;;;KChL1C,WAAA;AvC/BZ;;;AAAA,UuC4CiB,oBAAA;EvC5CwB;EuC8CxC,EAAA,EAAI,MAAA,CAAO,QAAA;;EAEX,OAAA,GAAU,OAAA;EvC7CO;EuC+CjB,YAAA,IACC,QAAA,UACA,WAAA,aACI,OAAA;IAAU,SAAA;IAAmB,OAAA;EAAA;AAAA;AtCmCnC;;;;;AAAA,csC3Ba,aAAA;EAAA,QAOQ,OAAA;EAAA,QANZ,OAAA;EAAA,QACA,YAAA;EAAA,QACA,aAAA;EAAA,QACA,cAAA;EAAA,QACA,WAAA;cAEY,OAAA,EAAS,oBAAA;EtCmPqC;;;;EsCvOlE,gBAAA,CAAiB,QAAA,EAAU,aAAA;EtC2QxB;;;;EsC5PH,QAAA,kBAA0B,mBAAA,CAAA,CACzB,UAAA,EAAY,gBAAA,CAAiB,QAAA,IAC3B,cAAA,CAAe,QAAA;EtC4VR;;;EsCvUV,WAAA,CAAY,WAAA,EAAa,gBAAA;EtC8ZqB;;;;EsCpZ9C,UAAA,CAAW,QAAA;EtCkfsC;;;EsC9d3C,OAAA,CAAQ,QAAA,WAAmB,OAAA,CAAQ,UAAA;EtC+e9B;;;EsCndL,QAAA,CAAS,QAAA,WAAmB,OAAA,CAAQ,UAAA;EtCykBZ;;;EsC9hBxB,UAAA,CAAW,QAAA,WAAmB,OAAA,CAAQ,UAAA;EtCsmBA;;;EsCtkBtC,SAAA,CAAU,QAAA,UAAkB,UAAA,aAA8B,OAAA,CAAQ,UAAA;EtC8nBR;;;EsC1lB1D,oBAAA,CACL,OAAA,EAAS,MAAA,mBACT,UAAA,UACA,KAAA,YACE,OAAA;IACF,OAAA,EAAS,MAAA;IACT,OAAA,EAAS,UAAA,CAAW,MAAA;EAAA;EtC2xBe;;;EsClxB9B,mBAAA,CACL,OAAA,EAAS,MAAA,mBACT,UAAA,UACA,KAAA,YACE,OAAA,CAAQ,UAAA;;;;EAQL,sBAAA,CACL,EAAA,UACA,UAAA,WACE,OAAA;IAAU,OAAA;IAAkB,OAAA,EAAS,UAAA;EAAA;EtC/NC;;;EsCuOnC,qBAAA,CAAsB,EAAA,UAAY,UAAA,WAAqB,OAAA,CAAQ,UAAA;EtCrI9B;;;EsC6IjC,sBAAA,CACL,OAAA,EAAS,MAAA,mBACT,UAAA,WACE,OAAA,CAAQ,UAAA;EtCxFK;;;EsCgGV,wBAAA,CACL,OAAA,EAAS,MAAA,mBACT,UAAA,WACE,OAAA,CAAQ,UAAA;EtCnG2D;;;EsC2GhE,oBAAA,CAAqB,IAAA;IAAQ,IAAA;IAAc,IAAA;IAAc,IAAA;EAAA,IAAiB,OAAA;IAC/E,IAAA;MAAQ,IAAA;MAAc,IAAA;MAAc,IAAA;IAAA;IACpC,OAAA,EAAS,UAAA;MAAa,IAAA;MAAc,IAAA;MAAc,IAAA;IAAA;EAAA;EtCZlD;;;EsCqBK,mBAAA,CAAoB,KAAA,EAAO,WAAA,GAAY,OAAA,CAAQ,UAAA;EtCfvC;;;;EsCwBR,cAAA,CAAe,QAAA,UAAkB,KAAA,EAAO,SAAA,GAAY,OAAA;EtCOK;;;EsCQzD,WAAA,CACL,QAAA,UACA,SAAA,UACA,OAAA,EAAS,kBAAA,GACP,OAAA,CAAQ,WAAA;EtCoBV;;;EsCZD,eAAA,CAAgB,QAAA;EtCyCV;;;EsC7BN,SAAA,CAAU,QAAA,WAAmB,cAAA;EtCgC1B;;;EsCzBH,cAAA,CAAe,QAAA,WAAmB,WAAA;EtC+GrB;;;EsCxGb,aAAA,CAAA,GAAiB,KAAA;IAAQ,MAAA,EAAQ,cAAA;IAAgB,KAAA,EAAO,WAAA;EAAA;EtCqK3C;;;EsC3Jb,gBAAA,CAAA,GAAoB,cAAA;EtC4KN;;;EsCnKd,SAAA,CAAU,QAAA;EtCmLY;;;EsC5KtB,QAAA,CAAS,QAAA;EtC2LR;;;EsChLD,yBAAA,CAA0B,QAAA,WAAmB,KAAA;IAAQ,QAAA;IAAkB,UAAA;EAAA;EtCkL7B;;;EsCpKpC,yBAAA,CAA0B,QAAA,WAAmB,OAAA;EtC8P7C;;;;EsCrPA,yBAAA,CAA0B,QAAA,UAAkB,QAAA,kBAA0B,OAAA;EtCuP3E;;;;;;EsC1NK,qBAAA,CAAsB,cAAA,GAAiB,GAAA,qBAAwB,OAAA;EtCoPK;;;;EsC/NpE,qBAAA,CAAA,GAAyB,OAAA,CAC9B,KAAA;IACC,QAAA;IACA,SAAA,EAAW,KAAA;MAAQ,QAAA;IAAA;IACnB,gBAAA;EAAA;EtCmSkD;;;EAAA,QsCxQ5C,iBAAA;EtC8SwC;;;EsCvRhD,YAAA,CAAA;EtCySgE;;;;EAAA,QsChSlD,eAAA;AAAA;;;;iBAeC,mBAAA,CAAoB,OAAA,EAAS,oBAAA,GAAuB,aAAA;;;;;;cCpmBvD,wBAAA,SAAiC,KAAA;EAAA,WAAA,CAAA;AAAA;;AxCT9C;;;;;AAKA;;;cwCwBa,iBAAA,YAA6B,aAAA;ExCxBD;;;EwC4BxC,WAAA,CAAA;ExCzBiB;;;EwCgCX,IAAA,CAEL,SAAA,EAAW,cAAA,EAEX,KAAA,WACE,OAAA,CAAQ,eAAA;;;AvCgDZ;EuCzCC,YAAA,CAAA;;;;EAOM,YAAA,CAAA,GAAgB,OAAA;AAAA;;;;;iBASP,uBAAA,CAAwB,QAAA,GAAW,cAAA,GAAiB,aAAA;;;;UC3DnD,YAAA;EAChB,EAAA;EACA,KAAA;EACA,KAAA;EACA,WAAA;EACA,SAAA;AAAA;;UAQgB,SAAA;EAChB,IAAA;EACA,IAAA,EAAM,IAAA;AAAA;;UAIU,QAAA;EAChB,IAAA;EACA,GAAA;EzCzB6C;EyC2B7C,KAAA;AAAA;;UAIgB,UAAA;EAChB,IAAA;EACA,GAAA;EACA,WAAA;;EAEA,MAAA;AAAA;AAAA,KAGW,WAAA,GAAc,SAAA,GAAY,QAAA,GAAW,UAAA;;UAOhC,UAAA;EAChB,IAAA;ExC0CwB;EwCxCxB,QAAA;ExC6CiD;EwC3CjD,QAAA;ExC6IuE;EwC3IvE,YAAA;AAAA;;UAIgB,kBAAA;ExC8PkD;EwC5PlE,aAAA;ExCoRW;EwClRX,cAAA;ExC8RW;EwC5RX,eAAA;ExC+TuE;EwC7TvE,OAAA;ExC+VW;EwC7VX,WAAA;AAAA;;KAIW,eAAA;EACP,IAAA;AAAA;EACA,IAAA;EAAe,GAAA;EAAa,QAAA;AAAA;EAC5B,IAAA;EAAgB,YAAA;AAAA;EAChB,IAAA;EAAwB,YAAA;AAAA;;UAGZ,aAAA;ExC2qBc;EwCzqB9B,MAAA;ExCmsB+D;EwCjsB/D,aAAA;ExC+uB4C;EwC7uB5C,OAAA;AAAA;;UAIgB,iBAAA;ExCszBiC;EwCpzBjD,QAAA;ExCo3BmD;EwCj3BnD,UAAA;ExCo6BsD;EwCj6BtD,QAAA;IACC,QAAA;IACA,OAAA;IACA,SAAA;IACA,OAAA;EAAA;ExCXuB;EwCexB,YAAA,EAAc,kBAAA;ExCfM;EwCkBpB,IAAA,GAAO,UAAA;ExCba;EwCgBpB,eAAA,EAAiB,eAAA;ExChBwB;EwCmBzC,OAAA;IACC,KAAA;IACA,KAAA;IACA,KAAA;EAAA;ExC4EsE;EwCxEvE,IAAA,GAAO,aAAA;AAAA;;UAIS,WAAA;EAChB,GAAA;EACA,WAAA;ExCoKM;EwClKN,SAAA,EAAW,iBAAA;ExCkKkB;EwChK7B,UAAA,EAAY,iBAAA;AAAA;;UAQI,cAAA;EAChB,IAAA;EACA,KAAA;EACA,IAAA;EACA,QAAA;EACA,UAAA;AAAA;;KAIW,kBAAA;;UAGK,sBAAA;EAChB,MAAA;EACA,WAAA,EAAa,MAAA;IAGX,MAAA,EAAQ,kBAAA;IACR,YAAA;IACA,YAAA;EAAA;EAGF,SAAA;EACA,MAAA;AAAA;;UAIgB,gBAAA;EAChB,IAAA;EACA,KAAA;EACA,mBAAA;EACA,cAAA,EAAgB,cAAA;EAChB,YAAA,EAAc,sBAAA;AAAA;;UAIE,cAAA;EAChB,EAAA;EACA,KAAA;EACA,GAAA;EACA,QAAA;EACA,QAAA;EACA,GAAA;EACA,OAAA;EACA,KAAA;EACA,MAAA;AAAA;;UAIgB,eAAA;ExCyV2D;EwCvV3E,IAAA;ExCoZa;EwClZb,KAAA;ExCkZwC;EwChZxC,SAAA;AAAA;;UAIgB,gBAAA;ExC6aV;EwC3aN,IAAA;ExC2aoC;EwCzapC,SAAA;ExCubM;EwCrbN,WAAA;AAAA;;UAIgB,qBAAA;ExCobb;EwClbH,EAAA;ExCkb0B;EwChb1B,KAAA;ExC2fM;EwCzfN,IAAA;AAAA;;UAIgB,cAAA;ExCsgBL;EwCpgBX,QAAA;EAEA,IAAA;IACC,KAAA;IACA,GAAA;EAAA;EAGD,SAAA,EAAW,gBAAA;EAEX,WAAA;IACC,KAAA;IACA,KAAA,EAAO,cAAA;EAAA;EAGR,UAAA;EACA,IAAA;EACA,OAAA,EAAS,YAAA;ExCwiBgC;EwCriBzC,QAAA,GAAW,eAAA;ExCqiB4D;EwCliBvE,gBAAA,GAAmB,gBAAA;ExCglBF;EwC7kBjB,cAAA,GAAiB,qBAAA;ExC6kB2B;EwC1kB5C,YAAA,GAAe,KAAA;IACd,GAAA;IACA,KAAA;IACA,OAAA;IACA,cAAA;IACA,aAAA;IACA,UAAA;EAAA;ExC4nB+D;EwCxnBhE,IAAA,GAAO,aAAA;AAAA;;UAQS,cAAA;ExCqoByB;EwCnoBzC,QAAA;ExCmsBM;EwCjsBN,QAAA;ExCisB8B;EwC/rB9B,MAAA;ExC+rBmD;EwC7rBnD,IAAA;ExCgvBmB;EwC9uBnB,KAAA;ExC8uB8C;EwC5uB9C,OAAA,EAAS,iBAAA;ExC+wBK;EwC7wBd,OAAA;ExCyyBqB;EwCvyBrB,IAAA,EAAM,IAAA;ExCwzBE;EwCtzBR,QAAA,GAAW,IAAA;ExCu1BU;EwCr1BrB,MAAA;;EAEA,UAAA;;EAEA,IAAA;EvC/RsB;EuCiStB,IAAA,GAAO,MAAA;EvCjSe;EuCmStB,aAAA;EvCjSgB;EuCmShB,QAAA;;EAEA,SAAA;EvCpSA;EuCsSA,gBAAA,GAAmB,MAAA;EvCpSnB;EuCuSA,MAAA;EvCrSA;;;;;EuC4SA,gBAAA;AAAA;;UAQgB,eAAA;EAChB,OAAA;EACA,UAAA;AAAA;;UAIgB,YAAA;EAChB,gBAAA,EAAkB,MAAA,SAAe,eAAA;EACjC,YAAA;AAAA;;UAIgB,YAAA;EvCjThB;EuCmTA,SAAA;EvCjTA;EuCmTA,aAAA;EvCjTA;EuCmTA,KAAA;AAAA;;UAIgB,YAAA;EAChB,OAAA;EACA,QAAA;EACA,OAAA;EACA,MAAA,EAAQ,KAAA;IAAQ,KAAA;IAAe,KAAA;EAAA;EAC/B,YAAA,EAAc,MAAA;AAAA;;;;;UAWE,YAAA;EvCzTP;EuC2TT,EAAA;EvC3ToB;EuC8TpB,IAAA;EvCxT2B;EuC2T3B,WAAA;EvC1T+B;EuC6T/B,IAAA;EvCxToB;EuC2TpB,YAAA;EvC3TuC;EuC8TvC,QAAA;EvCzRI;;;;EuC+RJ,KAAA,EAAO,GAAA,WAAc,OAAA,CAAQ,iBAAA;EvC/OO;;;;EuCqPpC,OAAA,CAAQ,KAAA,EAAO,WAAA,EAAa,OAAA,EAAS,aAAA,GAAgB,OAAA,CAAQ,cAAA;EvCzNf;;;;EuC+N9C,YAAA,CAAa,KAAA,EAAO,WAAA,EAAa,OAAA,EAAS,YAAA,GAAe,cAAA,CAAe,cAAA;EvCvJnD;;;;EuC6JrB,UAAA,EAAY,GAAA,UAAa,KAAA,EAAO,WAAA,GAAc,OAAA,CAAQ,IAAA;AAAA;;UAItC,aAAA;EvC9GuD;EuCgHvE,EAAA;EvCjWoB;EuCmWpB,sBAAA,SAA+B,OAAA,CAC9B,GAAA;IAAc,IAAA;IAAc,MAAA,EAAQ,GAAA;MAAc,IAAA;IAAA;EAAA;AAAA;;;;;;UC7YnC,oBAAA;;EAEhB,eAAA;;EAEA,eAAA;E1CjBgB;E0CmBhB,MAAA,EAAQ,KAAA;IAAQ,KAAA;IAAe,KAAA;EAAA;AAAA;;;;;;;;iBAUV,8BAAA,CACrB,KAAA,EAAO,OAAA,IACP,EAAA,EAAI,MAAA,CAAO,QAAA,IACT,OAAA,CAAQ,oBAAA;;;;;;iBCnBK,cAAA,CAAe,MAAA,EAAQ,YAAA;;;;iBAOvB,SAAA,CAAU,EAAA,WAAa,YAAA;;;A3CpBvC;iB2C2BgB,aAAA,CAAA,GAAiB,YAAA;;;;iBAOjB,cAAA,CAAA,GAAkB,YAAA;;;;iBAOlB,aAAA,CAAA,GAAiB,YAAA;;;;;;iBASX,QAAA,CAAS,GAAA,WAAc,OAAA,CAAQ,WAAA;;;;iBAqDrC,YAAA,CAAA;;;cCrEH,SAAA,EAAW,YAAA;;;;;;;;;A3C2DxB;iB2C4OgB,YAAA,CACf,OAAA,sBACA,OAAA,sBACA,SAAA,uBACE,IAAA;;;cC/SU,mBAAA,EAAqB,YAAA;;;;;;;;;;;;;;UClBjB,mBAAA;;EAEhB,GAAA;;EAEA,GAAA;E9ChBgB;E8CkBhB,GAAA;AAAA;;;A9CbD;U8CmBiB,2BAAA;;EAEhB,SAAA;E9CrBwC;E8CuBxC,SAAA;;EAEA,MAAA;AAAA;;;;;;A7C+DD;;;;;;;iB6C0BsB,oBAAA,CAAqB,OAAA,EAAS,2BAAA,GAA8B,OAAA;;;;KAkCtE,wBAAA;EACP,KAAA;EAAa,OAAA,EAAS,mBAAA;AAAA;EACtB,KAAA;EAAc,KAAA;AAAA;;;;KAKP,yBAAA;E7CqQR,sC6CnQH,MAAA;AAAA;EAE8C,GAAA,EAAK,GAAA;AAAA;E7CqXL,yC6CnXF,KAAA;AAAA;;;;;;;;;;;;;;;;;;;;;;;iBA0BvB,kBAAA,CACrB,OAAA,EAAS,yBAAA,GACP,OAAA,CAAQ,wBAAA;;;;iBAmEK,cAAA,CAAe,SAAA;EAC9B,UAAA;EACA,EAAA;AAAA;;;;;;;;;;;UCjQgB,oBAAA;;EAEhB,UAAA;;EAEA,EAAA;;EAEA,MAAA;;EAEA,SAAA;E/Cd8B;E+CgB9B,OAAA;E/CfA;E+CiBA,WAAA;AAAA;;;;;;;;;;;;;;A9C2ED;;;;;;;;;;;;;;;;;;;;iB8CvCsB,aAAA,CAAc,OAAA,EAAS,oBAAA,GAAuB,OAAA;;;;;;;;;;;;iBA2CpD,eAAA,CAAgB,OAAA;EAC/B,IAAA;EACA,KAAA;EACA,OAAA;AAAA;;;;;;;;;;;;;;iBC7Fe,gBAAA,CAAiB,GAAA,EAAK,GAAA;;;;;AhDPtC;;;;iBgDmBgB,eAAA,CAAgB,GAAA,EAAK,GAAA;;;;;;;;;AhDnBrC;;;;;AAKA;;;;;;;iBiDgEsB,cAAA,WAAyB,cAAA,CAAA,CAC9C,GAAA,EAAK,CAAA,GACH,OAAA,CAAQ,YAAA,CAAa,CAAA;;;;;;;;;;;;;;;;iBAkDF,eAAA,CAAA,GAAmB,OAAA,CAAQ,OAAA,CAAQ,YAAA;;;;;;;;;;;;;;;;;;;;;;;iBA6DnC,eAAA,CACrB,QAAA,EAAU,OAAA,CAAQ,YAAA,GAClB,EAAA,EAAI,MAAA,CAAO,QAAA,IACT,OAAA;;;;;;;iBAoBmB,gBAAA,aAAA,CACrB,QAAA,UACA,GAAA,WACE,OAAA,CAAQ,CAAA;;;;;;;iBA0BW,iBAAA,CAAkB,QAAA,WAAmB,OAAA,CAAQ,MAAA;;;UCjOlD,kBAAA;EAChB,UAAA;EACA,SAAA;EACA,QAAA;AAAA;AAAA,UAGgB,iBAAA;EAChB,KAAA,EAAO,aAAA;EACP,KAAA;AAAA;;;;AlDZD;;;;;;;;;;;iBkD6BsB,WAAA,CAAY,OAAA,EAAS,kBAAA,GAAqB,OAAA,CAAQ,iBAAA;;;;;;;;;;;iBAgDlD,eAAA,CAAgB,UAAA,UAAoB,SAAA,WAAoB,OAAA;;;;;;KCpFlE,YAAA;;;;UAKK,QAAA;EAChB,EAAA;EACA,KAAA;EACA,GAAA;EACA,MAAA;EACA,SAAA;EACA,UAAA;EACA,QAAA,EAAU,QAAA;AAAA;AnDVX;;;AAAA,UmDgBiB,IAAA;EAChB,EAAA;EACA,IAAA;EACA,KAAA;EACA,KAAA,EAAO,QAAA;AAAA;;;;UAoCS,mBAAA;EAChB,IAAA,EAAM,YAAA;EACN,KAAA;EACA,mBAAA;EACA,WAAA;EACA,SAAA;EACA,MAAA;EACA,SAAA;EACA,UAAA;EACA,QAAA;EACA,SAAA;AAAA;;;;UAMgB,mBAAA;EAChB,KAAA;EACA,SAAA;EACA,MAAA;EACA,SAAA;EACA,UAAA;EACA,QAAA;EACA,SAAA;AAAA;;;;UAMgB,eAAA;EAChB,IAAA;EACA,KAAA;AAAA;;;;UAMgB,eAAA;EAChB,KAAA;AAAA;;;;UAMgB,qBAAA;EAChB,KAAA,EAAO,KAAA;IACN,EAAA;IACA,QAAA;IACA,SAAA;EAAA;AAAA;;;;;;;;;;;AnDxGF;;;;;iBoDsBsB,OAAA,CAAQ,IAAA,WAAe,OAAA,CAAQ,IAAA;;;;;;;AnDuErD;;;;;iBmDjBsB,QAAA,CAAA,GAAY,OAAA,CAAQ,KAAA;EAAQ,EAAA;EAAY,IAAA;EAAc,KAAA;AAAA;;;;;;;;;;;ApD5E5E;;;;;iBqDwBsB,SAAA,CAAU,EAAA,WAAa,OAAA,CAAQ,aAAA;;;;;;;;;;;;;;iBAmB/B,eAAA,CAAgB,IAAA,WAAe,OAAA,CAAQ,aAAA;;;;;;;;;UCzC5C,WAAA;EAChB,EAAA;EACA,IAAA;EACA,KAAA;EACA,aAAA;EACA,YAAA;EACA,WAAA;AAAA;;;AtDRD;UsDciB,YAAA;EAChB,EAAA;EACA,IAAA;EACA,IAAA;EACA,KAAA;EACA,QAAA;EACA,WAAA;EACA,QAAA,EAAU,YAAA;EACV,KAAA;AAAA;;;;UAMgB,eAAA;EAChB,EAAA;EACA,IAAA;EACA,IAAA;EACA,KAAA;EACA,SAAA;EACA,IAAA;AAAA;;;;UAMgB,eAAA;EAChB,IAAA;EACA,KAAA;EACA,QAAA;EACA,WAAA;AAAA;;;;UAMgB,eAAA;EAChB,IAAA;EACA,KAAA;EACA,QAAA;EACA,WAAA;AAAA;;;;;;iBC/CqB,eAAA,CAAA,GAAmB,OAAA,CAAQ,WAAA;;;;iBAkB3B,cAAA,CAAe,IAAA,WAAe,OAAA,CAAQ,WAAA;;;AvDzB5D;iBuDiDsB,gBAAA,CAAiB,YAAA,WAAuB,OAAA,CAAQ,YAAA;;;;iBAuDhD,OAAA,CAAQ,YAAA,UAAsB,IAAA,WAAe,OAAA,CAAQ,YAAA;;;;iBAqDrD,aAAA,CACrB,UAAA,UACA,OAAA,UACA,YAAA,YACE,OAAA,CAAQ,YAAA;;;;;;;;;;AtDpEX;;iBsDyGsB,kBAAA,CACrB,UAAA,UACA,QAAA,YACA,YAAA,WACE,OAAA,CAAQ,GAAA,SAAY,YAAA;;;;iBAqDD,gBAAA,CACrB,UAAA,UACA,YAAA,UACA,QAAA,WACE,OAAA,CAAQ,KAAA;EAAQ,EAAA;EAAY,IAAA,EAAM,MAAA;AAAA;;;KCtQzB,UAAA;AAAA,UAEK,MAAA;EAChB,EAAA;EACA,IAAA,EAAM,UAAA;EACN,KAAA;EAEA,OAAA,GAAU,mBAAA;EACV,QAAA;EACA,WAAA;EACA,cAAA,GAAiB,MAAA;AAAA;AAAA,UAGD,UAAA;EAChB,EAAA;EACA,IAAA;EACA,KAAA;EACA,WAAA;EACA,OAAA,EAAS,MAAA;AAAA;AAAA,UA0BO,kBAAA;EAChB,EAAA;EACA,KAAA;EACA,WAAA;EACA,KAAA,EAAO,MAAA,SAAe,OAAA;AAAA;AAAA,UAGN,OAAA;EAChB,IAAA;EACA,KAAA;EACA,OAAA;EACA,OAAA,GAAU,KAAA;IAAQ,KAAA;IAAe,KAAA;EAAA;AAAA;AAAA,UAIjB,qBAAA;EAChB,IAAA;EACA,KAAA;EACA,WAAA;AAAA;AAAA,UAGgB,iBAAA;EAChB,IAAA,EAAM,UAAA;EACN,KAAA;EACA,OAAA,GAAU,mBAAA;EACV,QAAA;EACA,WAAA;EACA,cAAA,GAAiB,MAAA;AAAA;AAAA,UAGD,iBAAA,SAA0B,OAAA,CAAQ,iBAAA;AAAA,UAElC,mBAAA;EAChB,SAAA;AAAA;;;;;;iBC5DqB,aAAA,CAAc,IAAA,WAAe,OAAA,CAAQ,UAAA;;;;iBAqCrC,cAAA,CAAA,GAAkB,OAAA,CAAQ,UAAA;;;;iBAmChC,mBAAA,CAAA,GAAuB,kBAAA;;;;;;;;;;;UClFtB,YAAA;;EAEhB,OAAA;;EAEA,OAAA,GAAU,MAAA;AAAA;;;A1DRX;U0DciB,aAAA;;EAEhB,WAAA;E1DdS;E0DgBT,MAAA;E1DbgC;E0DehC,MAAA;E1Df6C;E0DiB7C,KAAA;E1DdiB;E0DgBjB,MAAA;AAAA;;;;UAMgB,uBAAA;;EAEhB,MAAA;EzD6DY;EyD3DZ,MAAA;;EAEA,KAAA;EzD0DwB;EyDxDxB,MAAA;AAAA;;;;UAMgB,YAAA;EzD2PkC;EyDzPlD,UAAA;EzD8QkE;EyD5QlE,EAAA;EzDoSW;EyDlSX,IAAA;EzD8SW;EyD5SX,MAAA;EzD+UuE;EyD7UvE,KAAA;EzD+WW;EyD7WX,OAAA;EzD0YU;EyDxYV,KAAA;AAAA;;;;UAMgB,cAAA;EzDshBwB;EyDphBxC,KAAA,EAAO,YAAA;EzDqjB0C;EyDnjBjD,UAAA;AAAA;;;;UAMgB,cAAA;EzD2pBb;EyDzpBH,WAAA;EzD4sBuE;EyD1sBvE,MAAA;EzDwvBoD;EyDtvBpD,KAAA;AAAA;;;;UAMgB,UAAA;EzD6zByB;EyD3zBzC,UAAA;EzD23B2C;EyDz3B3C,EAAA;EzD46B8C;EyD16B9C,KAAA;AAAA;;;;UAMgB,WAAA;EAChB,WAAA,EAAa,MAAA;IzDLO,gCyDSlB,OAAA,UzDJkB;IyDMlB,WAAA;EAAA;AAAA;;;;;;;;;cC1FU,UAAA;EAAA,QACQ,EAAA;cAAA,EAAA,EAAI,MAAA,CAAO,QAAA;E3DhBD;;;;EAAA,Q2DsBtB,cAAA;E3DjBwB;;;;E2D8BhC,eAAA,CAAgB,cAAA;;;;EAOhB,mBAAA,CAAoB,cAAA;E3DlCY;;;E2DyC1B,cAAA,CAAe,cAAA,WAAyB,OAAA;E1D4ClC;;;;;;;;E0D/BN,cAAA,CACL,cAAA,UACA,gBAAA,YACA,QAAA,GAAW,MAAA,mBACT,OAAA;E1D2LmE;;;EAAA,Q0D5JxD,cAAA;E1D2NoD;;;EAAA,Q0D7KpD,YAAA;E1DiNH;;;E0DtML,YAAA,CAAa,cAAA,WAAyB,OAAA;E1D2QjC;;;;;E0D1PL,YAAA,CACL,cAAA,UACA,gBAAA,YACA,OAAA,GAAU,MAAA,mBACR,OAAA;E1D0W2C;;;E0D3VxC,mBAAA,CAAoB,cAAA,UAAwB,gBAAA,aAA6B,OAAA;E1DyatC;;;E0DrZnC,eAAA,CAAgB,cAAA,WAAyB,OAAA,CAAQ,YAAA;E1Dsb7B;;;E0D7YpB,eAAA,CAAgB,cAAA,UAAwB,MAAA,EAAQ,YAAA,GAAe,OAAA;E1D0elE;;;E0D/dG,mBAAA,CAAoB,cAAA,WAAyB,OAAA;E1DgkBC;;;;;E0DtiB9C,YAAA,CACL,cAAA,UACA,OAAA;IAAY,OAAA,GAAU,MAAA;EAAA,IACpB,OAAA;E1DgrBgD;;;;;E0DhpB7C,aAAA,CAAc,cAAA,WAAyB,OAAA;E1DkwBF;;;E0DzvBrC,aAAA,CACL,cAAA,WACE,OAAA;IAAU,OAAA;IAAiB,WAAA;EAAA;E1D3OV;;;;;;;E0DsQd,oBAAA,CAAqB,cAAA,WAAyB,OAAA;E1DpKmB;;;;;;E0DgNjE,kBAAA,CAAA,GAAsB,OAAA;AAAA;;;;;;;;;;;A3DrZ7B;;;;;AAKA;;;;;;iB4DqCsB,MAAA,CAAO,KAAA,UAAe,OAAA,GAAS,aAAA,GAAqB,OAAA,CAAQ,cAAA;;;;;;;;A3DmDlF;;;;iB2DnCsB,YAAA,CACrB,EAAA,EAAI,MAAA,CAAO,QAAA,GACX,KAAA,UACA,OAAA,GAAS,aAAA,GACP,OAAA,CAAQ,cAAA;;;;;;;;;;;;;;;;;iBAgEW,gBAAA,CACrB,EAAA,EAAI,MAAA,CAAO,QAAA,GACX,UAAA,UACA,KAAA,UACA,OAAA,GAAS,uBAAA,GACP,OAAA,CAAQ,cAAA;;;;;;;;;iBA4GW,cAAA,CACrB,EAAA,EAAI,MAAA,CAAO,QAAA,GACX,KAAA,UACA,OAAA,GAAS,cAAA,GACP,OAAA,CAAQ,UAAA;;;;iBAoEW,cAAA,CAAe,EAAA,EAAI,MAAA,CAAO,QAAA,IAAY,OAAA,CAAQ,WAAA;;;;;;;;;;;;A5DvTpE;;;;;AAKA;;;;;;;iB6D4DgB,gBAAA,CAAiB,MAAA,EAAQ,mBAAA;;;;;;;A5D4BzC;;;iB4DwBgB,uBAAA,CACf,KAAA,EAAO,MAAA,mBACP,MAAA,aACE,MAAA"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"loader-CHb2v0jm.mjs","names":[],"sources":["../src/loader.ts"],"sourcesContent":["/**\n * Astro Live Collections loader for EmDash\n *\n * This loader implements the Astro LiveLoader interface to fetch content\n * at runtime from the database, enabling live editing without rebuilds.\n *\n * Architecture:\n * - Single `_emdash` Astro collection handles all content types\n * - Dialect comes from virtual module (configured in astro.config.mjs)\n * - Each content type maps to its own database table: ec_posts, ec_products, etc.\n * - `getEmDashCollection()` / `getEmDashEntry()` wrap Astro's live collection API\n */\n\nimport type { LiveLoader } from \"astro/loaders\";\nimport { Kysely, sql, type Dialect } from \"kysely\";\n\nimport { currentTimestampValue, isPostgres } from \"./database/dialect-helpers.js\";\nimport { decodeCursor, encodeCursor } from \"./database/repositories/types.js\";\nimport type { Database } from \"./index.js\";\nimport { getRequestContext } from \"./request-context.js\";\n\nconst FIELD_NAME_PATTERN = /^[a-zA-Z_][a-zA-Z0-9_]*$/;\n\n/**\n * System columns that are not part of the content data\n */\n/**\n * System columns excluded from entry.data\n * Note: slug is intentionally NOT excluded - it's useful as data.slug in templates\n */\nconst SYSTEM_COLUMNS = new Set([\n\t\"id\",\n\t// \"slug\" - kept in data for template access\n\t\"status\",\n\t\"author_id\",\n\t\"primary_byline_id\",\n\t\"created_at\",\n\t\"updated_at\",\n\t\"published_at\",\n\t\"scheduled_at\",\n\t\"deleted_at\",\n\t\"version\",\n\t\"live_revision_id\",\n\t\"draft_revision_id\",\n\t\"locale\",\n\t\"translation_group\",\n]);\n\n/**\n * Get the table name for a collection type\n */\nfunction getTableName(type: string): string {\n\treturn `ec_${type}`;\n}\n\n/**\n * Cache for taxonomy names (only used for the primary database).\n * Skipped when a per-request DB override is active (e.g. preview mode)\n * because the override DB may have different taxonomies.\n */\nlet taxonomyNames: Set<string> | null = null;\n\n/**\n * Get all taxonomy names (cached for primary DB, fresh for overrides)\n */\nasync function getTaxonomyNames(db: Kysely<Database>): Promise<Set<string>> {\n\tconst hasDbOverride = !!getRequestContext()?.db;\n\n\tif (!hasDbOverride && taxonomyNames) {\n\t\treturn taxonomyNames;\n\t}\n\n\ttry {\n\t\tconst defs = await db.selectFrom(\"_emdash_taxonomy_defs\").select(\"name\").execute();\n\t\tconst names = new Set(defs.map((d) => d.name));\n\t\tif (!hasDbOverride) {\n\t\t\ttaxonomyNames = names;\n\t\t}\n\t\treturn names;\n\t} catch {\n\t\t// Table doesn't exist yet, return empty set\n\t\tconst empty = new Set<string>();\n\t\tif (!hasDbOverride) {\n\t\t\ttaxonomyNames = empty;\n\t\t}\n\t\treturn empty;\n\t}\n}\n\n/**\n * System columns to include in data (mapped to camelCase where needed)\n */\nconst INCLUDE_IN_DATA: Record<string, string> = {\n\tid: \"id\",\n\tstatus: \"status\",\n\tauthor_id: \"authorId\",\n\tprimary_byline_id: \"primaryBylineId\",\n\tcreated_at: \"createdAt\",\n\tupdated_at: \"updatedAt\",\n\tpublished_at: \"publishedAt\",\n\tscheduled_at: \"scheduledAt\",\n\tdraft_revision_id: \"draftRevisionId\",\n\tlive_revision_id: \"liveRevisionId\",\n\tlocale: \"locale\",\n\ttranslation_group: \"translationGroup\",\n};\n\n/** System date columns that should be converted to Date objects */\nconst DATE_COLUMNS = new Set([\"created_at\", \"updated_at\", \"published_at\", \"scheduled_at\"]);\n\n/** Safely extract a string value from a record, returning fallback if not a string */\nfunction rowStr(row: Record<string, unknown>, key: string, fallback = \"\"): string {\n\tconst val = row[key];\n\treturn typeof val === \"string\" ? val : fallback;\n}\n\n/**\n * Map a database row to entry data\n * Extracts content fields (non-system columns) and parses JSON where needed.\n * System columns needed for templates (id, status, dates) are included with camelCase names.\n */\nfunction mapRowToData(row: Record<string, unknown>): Record<string, unknown> {\n\tconst data: Record<string, unknown> = {};\n\n\tfor (const [key, value] of Object.entries(row)) {\n\t\t// Include certain system columns (mapped to camelCase where needed)\n\t\tif (key in INCLUDE_IN_DATA) {\n\t\t\t// Convert date columns from ISO strings to Date objects\n\t\t\tif (DATE_COLUMNS.has(key)) {\n\t\t\t\tdata[INCLUDE_IN_DATA[key]] = typeof value === \"string\" ? new Date(value) : null;\n\t\t\t} else {\n\t\t\t\tdata[INCLUDE_IN_DATA[key]] = value;\n\t\t\t}\n\t\t\tcontinue;\n\t\t}\n\n\t\tif (SYSTEM_COLUMNS.has(key)) continue;\n\n\t\t// Try to parse JSON strings (for portableText, json fields, etc.)\n\t\tif (typeof value === \"string\") {\n\t\t\ttry {\n\t\t\t\t// Only parse if it looks like JSON (starts with { or [)\n\t\t\t\tif (value.startsWith(\"{\") || value.startsWith(\"[\")) {\n\t\t\t\t\tdata[key] = JSON.parse(value);\n\t\t\t\t} else {\n\t\t\t\t\tdata[key] = value;\n\t\t\t\t}\n\t\t\t} catch {\n\t\t\t\tdata[key] = value;\n\t\t\t}\n\t\t} else {\n\t\t\tdata[key] = value;\n\t\t}\n\t}\n\n\treturn data;\n}\n\n/**\n * Map revision data (already-parsed JSON object) to entry data.\n * Strips _-prefixed metadata keys (e.g. _slug) used internally by revisions.\n */\nfunction mapRevisionData(data: Record<string, unknown>): Record<string, unknown> {\n\tconst result: Record<string, unknown> = {};\n\tfor (const [key, value] of Object.entries(data)) {\n\t\tif (key.startsWith(\"_\")) continue; // revision metadata\n\t\tresult[key] = value;\n\t}\n\treturn result;\n}\n\n// Virtual module imports are lazy-loaded to avoid errors when importing\n// emdash outside of Astro/Vite context (e.g., in astro.config.mjs)\nlet virtualConfig:\n\t| {\n\t\t\tdatabase?: { config: unknown };\n\t\t\ti18n?: { defaultLocale: string; locales: string[]; prefixDefaultLocale?: boolean } | null;\n\t }\n\t| undefined;\nlet virtualCreateDialect: ((config: unknown) => Dialect) | undefined;\n\nasync function loadVirtualModules() {\n\tif (virtualConfig === undefined) {\n\t\t// eslint-disable-next-line @typescript-eslint/ban-ts-comment\n\t\t// @ts-ignore - virtual module\n\t\tconst configModule = await import(\"virtual:emdash/config\");\n\t\tvirtualConfig = configModule.default;\n\t}\n\tif (virtualCreateDialect === undefined) {\n\t\t// eslint-disable-next-line @typescript-eslint/ban-ts-comment\n\t\t// @ts-ignore - virtual module\n\t\tconst dialectModule = await import(\"virtual:emdash/dialect\");\n\t\tvirtualCreateDialect = dialectModule.createDialect;\n\t\t// dialectType is no longer needed here — dialect detection is\n\t\t// done via the db adapter instance in dialect-helpers.ts\n\t}\n}\n\n/**\n * Entry data type - generic object\n */\nexport type EntryData = Record<string, unknown>;\n\n/**\n * Sort direction\n */\nexport type SortDirection = \"asc\" | \"desc\";\n\n/**\n * Order by specification - field name to direction\n * @example { created_at: \"desc\" } - Sort by created_at descending\n * @example { title: \"asc\" } - Sort by title ascending\n */\nexport type OrderBySpec = Record<string, SortDirection>;\n\n/**\n * Build WHERE clause for status filtering.\n * When filtering for 'published' status, also include scheduled content\n * whose scheduled_at time has passed (treating it as effectively published).\n */\n// eslint-disable-next-line @typescript-eslint/no-explicit-any -- accepts any Kysely instance\nfunction buildStatusCondition(\n\tdb: Kysely<any>,\n\tstatus: string,\n\ttablePrefix?: string,\n): ReturnType<typeof sql> {\n\tconst statusField = tablePrefix ? `${tablePrefix}.status` : \"status\";\n\tconst scheduledAtField = tablePrefix ? `${tablePrefix}.scheduled_at` : \"scheduled_at\";\n\n\tif (status === \"published\") {\n\t\t// Include both published content AND scheduled content past its publish time.\n\t\t// scheduled_at is stored as text (ISO 8601). On Postgres, we must cast it\n\t\t// to timestamptz for the comparison with CURRENT_TIMESTAMP to work.\n\t\tconst scheduledAtExpr = isPostgres(db)\n\t\t\t? sql`${sql.ref(scheduledAtField)}::timestamptz`\n\t\t\t: sql.ref(scheduledAtField);\n\t\treturn sql`(${sql.ref(statusField)} = 'published' OR (${sql.ref(statusField)} = 'scheduled' AND ${scheduledAtExpr} <= ${currentTimestampValue(db)}))`;\n\t}\n\n\t// For other statuses (draft, archived), just match exactly\n\treturn sql`${sql.ref(statusField)} = ${status}`;\n}\n\n/**\n * Resolved primary sort field and direction (used for cursor pagination).\n */\ninterface PrimarySort {\n\tfield: string;\n\tdirection: SortDirection;\n}\n\n/**\n * Get the primary sort field from an orderBy spec (first valid field, or default).\n */\nfunction getPrimarySort(orderBy: OrderBySpec | undefined, tablePrefix?: string): PrimarySort {\n\tif (orderBy) {\n\t\tfor (const [field, direction] of Object.entries(orderBy)) {\n\t\t\tif (FIELD_NAME_PATTERN.test(field)) {\n\t\t\t\tconst fullField = tablePrefix ? `${tablePrefix}.${field}` : field;\n\t\t\t\treturn { field: fullField, direction };\n\t\t\t}\n\t\t}\n\t}\n\tconst defaultField = tablePrefix ? `${tablePrefix}.created_at` : \"created_at\";\n\treturn { field: defaultField, direction: \"desc\" };\n}\n\n/**\n * Build ORDER BY clause from orderBy spec\n * Validates field names to prevent SQL injection (alphanumeric + underscore only)\n * Supports multiple sort fields in object key order\n */\nfunction buildOrderByClause(\n\torderBy: OrderBySpec | undefined,\n\ttablePrefix?: string,\n): ReturnType<typeof sql> {\n\t// Default to created_at DESC\n\tif (!orderBy || Object.keys(orderBy).length === 0) {\n\t\tconst field = tablePrefix ? `${tablePrefix}.created_at` : \"created_at\";\n\t\treturn sql`ORDER BY ${sql.ref(field)} DESC, ${sql.ref(tablePrefix ? `${tablePrefix}.id` : \"id\")} DESC`;\n\t}\n\n\tconst sortParts: ReturnType<typeof sql>[] = [];\n\n\tfor (const [field, direction] of Object.entries(orderBy)) {\n\t\t// Validate field name (alphanumeric + underscore only)\n\t\tif (!FIELD_NAME_PATTERN.test(field)) {\n\t\t\tcontinue; // Skip invalid field names\n\t\t}\n\n\t\tconst fullField = tablePrefix ? `${tablePrefix}.${field}` : field;\n\t\tconst dir = direction === \"asc\" ? sql`ASC` : sql`DESC`;\n\t\tsortParts.push(sql`${sql.ref(fullField)} ${dir}`);\n\t}\n\n\t// If no valid sort fields, fall back to default\n\tif (sortParts.length === 0) {\n\t\tconst defaultField = tablePrefix ? `${tablePrefix}.created_at` : \"created_at\";\n\t\treturn sql`ORDER BY ${sql.ref(defaultField)} DESC, ${sql.ref(tablePrefix ? `${tablePrefix}.id` : \"id\")} DESC`;\n\t}\n\n\t// Add id as tiebreaker to ensure stable cursor ordering\n\tconst primary = getPrimarySort(orderBy, tablePrefix);\n\tconst idField = tablePrefix ? `${tablePrefix}.id` : \"id\";\n\tconst idDir = primary.direction === \"asc\" ? sql`ASC` : sql`DESC`;\n\tsortParts.push(sql`${sql.ref(idField)} ${idDir}`);\n\n\treturn sql`ORDER BY ${sql.join(sortParts, sql`, `)}`;\n}\n\n/**\n * Build a cursor WHERE condition for keyset pagination.\n * Uses the primary sort field + id as tiebreaker for stable ordering.\n */\nfunction buildCursorCondition(\n\tcursor: string,\n\torderBy: OrderBySpec | undefined,\n\ttablePrefix?: string,\n): ReturnType<typeof sql> | null {\n\tconst decoded = decodeCursor(cursor);\n\tif (!decoded) return null;\n\n\tconst { orderValue, id: cursorId } = decoded;\n\tconst primary = getPrimarySort(orderBy, tablePrefix);\n\tconst idField = tablePrefix ? `${tablePrefix}.id` : \"id\";\n\n\tif (primary.direction === \"desc\") {\n\t\treturn sql`(${sql.ref(primary.field)} < ${orderValue} OR (${sql.ref(primary.field)} = ${orderValue} AND ${sql.ref(idField)} < ${cursorId}))`;\n\t}\n\treturn sql`(${sql.ref(primary.field)} > ${orderValue} OR (${sql.ref(primary.field)} = ${orderValue} AND ${sql.ref(idField)} > ${cursorId}))`;\n}\n\n/**\n * Filter for loadCollection - type is required\n */\nexport interface CollectionFilter {\n\ttype: string;\n\tstatus?: \"draft\" | \"published\" | \"archived\";\n\tlimit?: number;\n\t/**\n\t * Opaque cursor for keyset pagination.\n\t * Pass the `nextCursor` value from a previous result to fetch the next page.\n\t */\n\tcursor?: string;\n\t/**\n\t * Filter by field values or taxonomy terms\n\t */\n\twhere?: Record<string, string | string[]>;\n\t/**\n\t * Order results by field(s)\n\t * @default { created_at: \"desc\" }\n\t */\n\torderBy?: OrderBySpec;\n\t/**\n\t * Filter by locale (e.g. 'en', 'fr').\n\t * When set, only returns content in this locale.\n\t */\n\tlocale?: string;\n}\n\n/**\n * Filter for loadEntry - type and id are required\n */\nexport interface EntryFilter {\n\ttype: string;\n\tid: string;\n\t/**\n\t * When set, fetch content data from this revision instead of the content table.\n\t * Used by preview mode to serve draft revision data.\n\t */\n\trevisionId?: string;\n\t/**\n\t * Locale to scope slug lookup. Only affects slug resolution;\n\t * IDs are globally unique and always resolve regardless of locale.\n\t */\n\tlocale?: string;\n}\n\n// Cached database instance (shared across calls)\nlet dbInstance: Kysely<Database> | null = null;\n\n/**\n * Get the database instance. Used by query wrapper functions and middleware.\n *\n * Checks the ALS request context first — if a per-request DB override is set\n * (e.g. by DO preview middleware), it takes precedence over the module-level\n * cached instance. This allows preview mode to route queries to an isolated\n * Durable Object database without modifying any calling code.\n *\n * Initializes the default database on first call using config from virtual module.\n */\nexport async function getDb(): Promise<Kysely<Database>> {\n\t// Per-request DB override via ALS (normal mode)\n\tconst ctx = getRequestContext();\n\tif (ctx?.db) {\n\t\treturn ctx.db as Kysely<Database>; // eslint-disable-line typescript-eslint(no-unsafe-type-assertion) -- db is typed as unknown in RequestContext to avoid circular deps\n\t}\n\n\tif (!dbInstance) {\n\t\tawait loadVirtualModules();\n\t\tif (!virtualConfig?.database || typeof virtualCreateDialect !== \"function\") {\n\t\t\tthrow new Error(\n\t\t\t\t\"EmDash database not configured. Add database config to emdash() in astro.config.mjs\",\n\t\t\t);\n\t\t}\n\t\tconst dialect = virtualCreateDialect(virtualConfig.database.config);\n\t\tdbInstance = new Kysely<Database>({ dialect });\n\t}\n\treturn dbInstance;\n}\n\n/**\n * Create an EmDash Live Collections loader\n *\n * This loader handles ALL content types in a single Astro collection.\n * Use `getEmDashCollection()` and `getEmDashEntry()` to query\n * specific content types.\n *\n * Database is configured in astro.config.mjs via the emdash() integration.\n *\n * @example\n * ```ts\n * // src/live.config.ts\n * import { defineLiveCollection } from \"astro:content\";\n * import { emdashLoader } from \"emdash\";\n *\n * export const collections = {\n * emdash: defineLiveCollection({\n * loader: emdashLoader(),\n * }),\n * };\n * ```\n */\nexport function emdashLoader(): LiveLoader<EntryData, EntryFilter, CollectionFilter> {\n\treturn {\n\t\tname: \"emdash\",\n\n\t\t/**\n\t\t * Load all entries for a content type\n\t\t */\n\t\tasync loadCollection({ filter }) {\n\t\t\ttry {\n\t\t\t\t// Get DB instance (initializes on first use)\n\t\t\t\tconst db = await getDb();\n\n\t\t\t\t// Type filter is required\n\t\t\t\tconst type = filter?.type;\n\t\t\t\tif (!type) {\n\t\t\t\t\treturn {\n\t\t\t\t\t\terror: new Error(\n\t\t\t\t\t\t\t\"type filter is required. Use getEmDashCollection() instead of getLiveCollection() directly.\",\n\t\t\t\t\t\t),\n\t\t\t\t\t};\n\t\t\t\t}\n\n\t\t\t\t// Query the per-collection table (ec_posts, ec_products, etc.)\n\t\t\t\tconst tableName = getTableName(type);\n\n\t\t\t\t// Build query with dynamic table name\n\t\t\t\tconst status = filter?.status || \"published\";\n\t\t\t\tconst limit = filter?.limit;\n\t\t\t\tconst cursor = filter?.cursor;\n\t\t\t\tconst where = filter?.where;\n\t\t\t\tconst orderBy = filter?.orderBy;\n\t\t\t\tconst locale = filter?.locale;\n\n\t\t\t\t// Cursor pagination: over-fetch by 1 to detect next page\n\t\t\t\tconst fetchLimit = limit ? limit + 1 : undefined;\n\n\t\t\t\t// Build cursor condition if cursor is provided\n\t\t\t\tconst cursorCondition = cursor ? buildCursorCondition(cursor, orderBy) : null;\n\t\t\t\tconst cursorConditionPrefixed = cursor\n\t\t\t\t\t? buildCursorCondition(cursor, orderBy, tableName)\n\t\t\t\t\t: null;\n\n\t\t\t\t// Check if we need taxonomy filtering\n\t\t\t\tlet result: { rows: Record<string, unknown>[] };\n\n\t\t\t\tif (where && Object.keys(where).length > 0) {\n\t\t\t\t\t// Get taxonomy names to detect taxonomy filters\n\t\t\t\t\tconst taxNames = await getTaxonomyNames(db);\n\t\t\t\t\tconst taxonomyFilters: Record<string, string | string[]> = {};\n\n\t\t\t\t\tfor (const [key, value] of Object.entries(where)) {\n\t\t\t\t\t\tif (taxNames.has(key)) {\n\t\t\t\t\t\t\ttaxonomyFilters[key] = value;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\t// If we have taxonomy filters, use JOIN\n\t\t\t\t\tif (Object.keys(taxonomyFilters).length > 0) {\n\t\t\t\t\t\t// Build query with taxonomy JOIN\n\t\t\t\t\t\t// For now, support single taxonomy filter (can extend later for multiple)\n\t\t\t\t\t\tconst [taxName, termSlugs] = Object.entries(taxonomyFilters)[0];\n\t\t\t\t\t\tconst slugs = Array.isArray(termSlugs) ? termSlugs : [termSlugs];\n\t\t\t\t\t\tconst orderByClause = buildOrderByClause(orderBy, tableName);\n\n\t\t\t\t\t\tconst statusCondition = buildStatusCondition(db, status, tableName);\n\t\t\t\t\t\tconst localeCondition = locale\n\t\t\t\t\t\t\t? sql`AND ${sql.ref(tableName)}.locale = ${locale}`\n\t\t\t\t\t\t\t: sql``;\n\t\t\t\t\t\tconst cursorCond = cursorConditionPrefixed\n\t\t\t\t\t\t\t? sql`AND ${cursorConditionPrefixed}`\n\t\t\t\t\t\t\t: sql``;\n\t\t\t\t\t\tresult = await sql<Record<string, unknown>>`\n\t\t\t\t\t\t\tSELECT DISTINCT ${sql.ref(tableName)}.* FROM ${sql.ref(tableName)}\n\t\t\t\t\t\t\tINNER JOIN content_taxonomies ct\n\t\t\t\t\t\t\t\tON ct.collection = ${type}\n\t\t\t\t\t\t\t\tAND ct.entry_id = ${sql.ref(tableName)}.id\n\t\t\t\t\t\t\tINNER JOIN taxonomies t\n\t\t\t\t\t\t\t\tON t.id = ct.taxonomy_id\n\t\t\t\t\t\t\tWHERE ${sql.ref(tableName)}.deleted_at IS NULL\n\t\t\t\t\t\t\t\tAND ${statusCondition}\n\t\t\t\t\t\t\t\t${localeCondition}\n\t\t\t\t\t\t\t\t${cursorCond}\n\t\t\t\t\t\t\t\tAND t.name = ${taxName}\n\t\t\t\t\t\t\t\tAND t.slug IN (${sql.join(slugs.map((s) => sql`${s}`))})\n\t\t\t\t\t\t\t${orderByClause}\n\t\t\t\t\t\t\t${fetchLimit ? sql`LIMIT ${fetchLimit}` : sql``}\n\t\t\t\t\t\t`.execute(db);\n\t\t\t\t\t} else {\n\t\t\t\t\t\t// No taxonomy filters, use simple query\n\t\t\t\t\t\tconst orderByClause = buildOrderByClause(orderBy);\n\t\t\t\t\t\tconst statusCondition = buildStatusCondition(db, status);\n\t\t\t\t\t\tconst localeFilter = locale ? sql`AND locale = ${locale}` : sql``;\n\t\t\t\t\t\tconst cursorCond = cursorCondition ? sql`AND ${cursorCondition}` : sql``;\n\t\t\t\t\t\tresult = await sql<Record<string, unknown>>`\n\t\t\t\t\t\t\tSELECT * FROM ${sql.ref(tableName)}\n\t\t\t\t\t\t\tWHERE deleted_at IS NULL\n\t\t\t\t\t\t\tAND ${statusCondition}\n\t\t\t\t\t\t\t${localeFilter}\n\t\t\t\t\t\t\t${cursorCond}\n\t\t\t\t\t\t\t${orderByClause}\n\t\t\t\t\t\t\t${fetchLimit ? sql`LIMIT ${fetchLimit}` : sql``}\n\t\t\t\t\t\t`.execute(db);\n\t\t\t\t\t}\n\t\t\t\t} else {\n\t\t\t\t\t// No where clause, use simple query\n\t\t\t\t\tconst orderByClause = buildOrderByClause(orderBy);\n\t\t\t\t\tconst statusCondition = buildStatusCondition(db, status);\n\t\t\t\t\tconst localeFilter = locale ? sql`AND locale = ${locale}` : sql``;\n\t\t\t\t\tconst cursorCond = cursorCondition ? sql`AND ${cursorCondition}` : sql``;\n\t\t\t\t\tresult = await sql<Record<string, unknown>>`\n\t\t\t\t\t\tSELECT * FROM ${sql.ref(tableName)}\n\t\t\t\t\t\tWHERE deleted_at IS NULL\n\t\t\t\t\t\tAND ${statusCondition}\n\t\t\t\t\t\t${localeFilter}\n\t\t\t\t\t\t${cursorCond}\n\t\t\t\t\t\t${orderByClause}\n\t\t\t\t\t\t${fetchLimit ? sql`LIMIT ${fetchLimit}` : sql``}\n\t\t\t\t\t`.execute(db);\n\t\t\t\t}\n\n\t\t\t\t// Detect whether there are more results (over-fetched by 1)\n\t\t\t\tconst hasMore = limit ? result.rows.length > limit : false;\n\t\t\t\tconst rows = hasMore ? result.rows.slice(0, limit) : result.rows;\n\n\t\t\t\t// Map rows to entries\n\t\t\t\tconst i18nConfig = virtualConfig?.i18n;\n\t\t\t\tconst i18nEnabled = i18nConfig && i18nConfig.locales.length > 1;\n\t\t\t\tconst entries = rows.map((row) => {\n\t\t\t\t\tconst slug = rowStr(row, \"slug\") || rowStr(row, \"id\");\n\t\t\t\t\tconst rowLocale = rowStr(row, \"locale\");\n\t\t\t\t\tconst shouldPrefix =\n\t\t\t\t\t\ti18nEnabled &&\n\t\t\t\t\t\trowLocale !== \"\" &&\n\t\t\t\t\t\t(rowLocale !== i18nConfig.defaultLocale || i18nConfig.prefixDefaultLocale);\n\t\t\t\t\tconst id = shouldPrefix ? `${rowLocale}/${slug}` : slug;\n\t\t\t\t\treturn {\n\t\t\t\t\t\tid,\n\t\t\t\t\t\tslug: rowStr(row, \"slug\"),\n\t\t\t\t\t\tstatus: rowStr(row, \"status\", \"draft\"),\n\t\t\t\t\t\tdata: mapRowToData(row),\n\t\t\t\t\t\tcacheHint: {\n\t\t\t\t\t\t\ttags: [rowStr(row, \"id\")],\n\t\t\t\t\t\t\tlastModified: row.updated_at ? new Date(rowStr(row, \"updated_at\")) : undefined,\n\t\t\t\t\t\t},\n\t\t\t\t\t};\n\t\t\t\t});\n\n\t\t\t\t// Encode nextCursor from the last row if there are more results\n\t\t\t\tlet nextCursor: string | undefined;\n\t\t\t\tif (hasMore && rows.length > 0) {\n\t\t\t\t\tconst lastRow = rows.at(-1)!;\n\t\t\t\t\tconst primary = getPrimarySort(orderBy);\n\t\t\t\t\t// Strip table prefix from field name for row lookup\n\t\t\t\t\tconst fieldName = primary.field.includes(\".\")\n\t\t\t\t\t\t? primary.field.split(\".\").pop()!\n\t\t\t\t\t\t: primary.field;\n\t\t\t\t\tconst lastOrderValue = lastRow[fieldName];\n\t\t\t\t\tconst orderStr =\n\t\t\t\t\t\ttypeof lastOrderValue === \"string\" || typeof lastOrderValue === \"number\"\n\t\t\t\t\t\t\t? String(lastOrderValue)\n\t\t\t\t\t\t\t: \"\";\n\t\t\t\t\tnextCursor = encodeCursor(orderStr, String(lastRow.id));\n\t\t\t\t}\n\n\t\t\t\t// Collection-level cache hint uses the most recent updated_at\n\t\t\t\tlet collectionLastModified: Date | undefined;\n\t\t\t\tfor (const row of rows) {\n\t\t\t\t\tif (row.updated_at) {\n\t\t\t\t\t\tconst d = new Date(rowStr(row, \"updated_at\"));\n\t\t\t\t\t\tif (!collectionLastModified || d > collectionLastModified) {\n\t\t\t\t\t\t\tcollectionLastModified = d;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\treturn {\n\t\t\t\t\tentries,\n\t\t\t\t\tnextCursor,\n\t\t\t\t\tcacheHint: {\n\t\t\t\t\t\ttags: [type],\n\t\t\t\t\t\tlastModified: collectionLastModified,\n\t\t\t\t\t},\n\t\t\t\t};\n\t\t\t} catch (error) {\n\t\t\t\t// Handle missing table gracefully - return empty collection\n\t\t\t\t// This happens before migrations have run\n\t\t\t\tconst message = error instanceof Error ? error.message : String(error);\n\t\t\t\tconst lowerMessage = message.toLowerCase();\n\t\t\t\tif (\n\t\t\t\t\tlowerMessage.includes(\"no such table\") ||\n\t\t\t\t\t(lowerMessage.includes(\"table\") && lowerMessage.includes(\"does not exist\")) ||\n\t\t\t\t\t(lowerMessage.includes(\"relation\") && lowerMessage.includes(\"does not exist\"))\n\t\t\t\t) {\n\t\t\t\t\treturn { entries: [] };\n\t\t\t\t}\n\n\t\t\t\treturn {\n\t\t\t\t\terror: new Error(`Failed to load collection: ${message}`),\n\t\t\t\t};\n\t\t\t}\n\t\t},\n\n\t\t/**\n\t\t * Load a single entry by type and ID/slug\n\t\t *\n\t\t * When filter.revisionId is set (preview mode), the entry's data\n\t\t * comes from the revisions table instead of the content table columns.\n\t\t */\n\t\tasync loadEntry({ filter }) {\n\t\t\ttry {\n\t\t\t\t// Get DB instance\n\t\t\t\tconst db = await getDb();\n\n\t\t\t\t// Both type and id are required\n\t\t\t\tconst type = filter?.type;\n\t\t\t\tconst id = filter?.id;\n\n\t\t\t\tif (!type || !id) {\n\t\t\t\t\treturn {\n\t\t\t\t\t\terror: new Error(\n\t\t\t\t\t\t\t\"type and id filters are required. Use getEmDashEntry() instead of getLiveEntry() directly.\",\n\t\t\t\t\t\t),\n\t\t\t\t\t};\n\t\t\t\t}\n\n\t\t\t\t// Query the per-collection table\n\t\t\t\tconst tableName = getTableName(type);\n\t\t\t\tconst locale = filter?.locale;\n\n\t\t\t\t// Use raw SQL for dynamic table name, match by slug or id\n\t\t\t\t// When locale is specified, prefer locale-scoped slug match,\n\t\t\t\t// but IDs are globally unique so always check id without locale scope\n\t\t\t\tconst result = locale\n\t\t\t\t\t? await sql<Record<string, unknown>>`\n\t\t\t\t\t\t\tSELECT * FROM ${sql.ref(tableName)}\n\t\t\t\t\t\t\tWHERE deleted_at IS NULL\n\t\t\t\t\t\t\tAND ((slug = ${id} AND locale = ${locale}) OR id = ${id})\n\t\t\t\t\t\t\tLIMIT 1\n\t\t\t\t\t\t`.execute(db)\n\t\t\t\t\t: await sql<Record<string, unknown>>`\n\t\t\t\t\t\t\tSELECT * FROM ${sql.ref(tableName)}\n\t\t\t\t\t\t\tWHERE deleted_at IS NULL\n\t\t\t\t\t\t\tAND (slug = ${id} OR id = ${id})\n\t\t\t\t\t\t\tLIMIT 1\n\t\t\t\t\t\t`.execute(db);\n\n\t\t\t\tconst row = result.rows[0];\n\t\t\t\tif (!row) {\n\t\t\t\t\treturn undefined;\n\t\t\t\t}\n\n\t\t\t\tconst i18nConfig = virtualConfig?.i18n;\n\t\t\t\tconst i18nEnabled = i18nConfig && i18nConfig.locales.length > 1;\n\t\t\t\tconst entrySlug = rowStr(row, \"slug\") || rowStr(row, \"id\");\n\t\t\t\tconst entryLocale = rowStr(row, \"locale\");\n\t\t\t\tconst shouldPrefixEntry =\n\t\t\t\t\ti18nEnabled &&\n\t\t\t\t\tentryLocale !== \"\" &&\n\t\t\t\t\t(entryLocale !== i18nConfig.defaultLocale || i18nConfig.prefixDefaultLocale);\n\t\t\t\tconst entryId = shouldPrefixEntry ? `${entryLocale}/${entrySlug}` : entrySlug;\n\n\t\t\t\t// Preview mode: override content fields with revision data,\n\t\t\t\t// keeping system metadata from the content table row.\n\t\t\t\tconst revisionId = filter?.revisionId;\n\t\t\t\tif (revisionId) {\n\t\t\t\t\tconst revRow = await sql<{ data: string }>`\n\t\t\t\t\t\tSELECT data FROM revisions\n\t\t\t\t\t\tWHERE id = ${revisionId}\n\t\t\t\t\t\tLIMIT 1\n\t\t\t\t\t`.execute(db);\n\n\t\t\t\t\tconst revData = revRow.rows[0];\n\t\t\t\t\tif (revData) {\n\t\t\t\t\t\tconst parsed: Record<string, unknown> = JSON.parse(revData.data);\n\t\t\t\t\t\t// System metadata from content table + content fields from revision\n\t\t\t\t\t\tconst systemData: Record<string, unknown> = {};\n\t\t\t\t\t\tfor (const [key, mappedKey] of Object.entries(INCLUDE_IN_DATA)) {\n\t\t\t\t\t\t\tif (key in row) {\n\t\t\t\t\t\t\t\tif (DATE_COLUMNS.has(key)) {\n\t\t\t\t\t\t\t\t\tsystemData[mappedKey] = typeof row[key] === \"string\" ? new Date(row[key]) : null;\n\t\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\t\tsystemData[mappedKey] = row[key];\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t\t// Use slug from revision metadata if present, else from content table\n\t\t\t\t\t\tconst slug = typeof parsed._slug === \"string\" ? parsed._slug : rowStr(row, \"slug\");\n\t\t\t\t\t\tconst revSlug = slug || rowStr(row, \"id\");\n\t\t\t\t\t\tconst revLocale = rowStr(row, \"locale\");\n\t\t\t\t\t\tconst shouldPrefixRev =\n\t\t\t\t\t\t\ti18nEnabled &&\n\t\t\t\t\t\t\trevLocale !== \"\" &&\n\t\t\t\t\t\t\t(revLocale !== i18nConfig.defaultLocale || i18nConfig.prefixDefaultLocale);\n\t\t\t\t\t\tconst revId = shouldPrefixRev ? `${revLocale}/${revSlug}` : revSlug;\n\t\t\t\t\t\treturn {\n\t\t\t\t\t\t\tid: revId,\n\t\t\t\t\t\t\tslug,\n\t\t\t\t\t\t\tstatus: rowStr(row, \"status\", \"draft\"),\n\t\t\t\t\t\t\tdata: { ...systemData, slug, ...mapRevisionData(parsed) },\n\t\t\t\t\t\t\tcacheHint: {\n\t\t\t\t\t\t\t\ttags: [rowStr(row, \"id\")],\n\t\t\t\t\t\t\t\tlastModified: row.updated_at ? new Date(rowStr(row, \"updated_at\")) : undefined,\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t};\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\treturn {\n\t\t\t\t\tid: entryId,\n\t\t\t\t\tslug: rowStr(row, \"slug\"),\n\t\t\t\t\tstatus: rowStr(row, \"status\", \"draft\"),\n\t\t\t\t\tdata: mapRowToData(row),\n\t\t\t\t\tcacheHint: {\n\t\t\t\t\t\ttags: [rowStr(row, \"id\")],\n\t\t\t\t\t\tlastModified: row.updated_at ? new Date(rowStr(row, \"updated_at\")) : undefined,\n\t\t\t\t\t},\n\t\t\t\t};\n\t\t\t} catch (error) {\n\t\t\t\t// Handle missing table gracefully - return undefined (not found)\n\t\t\t\t// This happens before migrations have run\n\t\t\t\tconst message = error instanceof Error ? error.message : String(error);\n\t\t\t\tconst lowerMessage = message.toLowerCase();\n\t\t\t\tif (\n\t\t\t\t\tlowerMessage.includes(\"no such table\") ||\n\t\t\t\t\t(lowerMessage.includes(\"table\") && lowerMessage.includes(\"does not exist\")) ||\n\t\t\t\t\t(lowerMessage.includes(\"relation\") && lowerMessage.includes(\"does not exist\"))\n\t\t\t\t) {\n\t\t\t\t\treturn undefined;\n\t\t\t\t}\n\n\t\t\t\treturn {\n\t\t\t\t\terror: new Error(`Failed to load entry: ${message}`),\n\t\t\t\t};\n\t\t\t}\n\t\t},\n\t};\n}\n"],"mappings":"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"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"redirect-DIfIni3r.mjs","names":[],"sources":["../src/redirects/patterns.ts","../src/database/repositories/redirect.ts"],"sourcesContent":["/**\n * URL pattern matching for redirects.\n *\n * Uses Astro's route syntax: [param] for named segments, [...rest] for catch-all.\n * Compiles patterns to safe regexes -- no user-supplied regex, no ReDoS risk.\n *\n * @example\n * ```ts\n * const compiled = compilePattern(\"/old-blog/[...path]\");\n * const match = matchPattern(compiled, \"/old-blog/2024/01/post\");\n * // match = { path: \"2024/01/post\" }\n *\n * interpolateDestination(\"/blog/[...path]\", match);\n * // \"/blog/2024/01/post\"\n * ```\n */\n\n/** Matches [paramName] placeholders */\nconst PARAM_PATTERN = /\\[(\\w+)\\]/g;\n\n/** Matches [...splatName] placeholders */\nconst SPLAT_PATTERN = /\\[\\.\\.\\.(\\w+)\\]/g;\n\n/** Combined pattern for validation: matches both [param] and [...splat] */\nconst ANY_PLACEHOLDER = /\\[(?:\\.\\.\\.)?(\\w+)\\]/g;\n\n/** Nested brackets check: [foo[ */\nconst NESTED_BRACKETS = /\\[[^\\]]*\\[/;\n\n/** Empty brackets: [] */\nconst EMPTY_BRACKETS = /\\[\\]/;\n\n/** Count open brackets */\nconst OPEN_BRACKET = /\\[/g;\n\n/** Count close brackets */\nconst CLOSE_BRACKET = /\\]/g;\n\n/** Split on capture groups in compiled regex string */\nconst CAPTURE_GROUP_SPLIT = /(\\([^)]+\\))/;\n\n/** Escape regex-special characters in literal parts */\nconst REGEX_SPECIAL_CHARS = /[.*+?^${}|\\\\]/g;\n\nexport interface CompiledPattern {\n\tregex: RegExp;\n\tparamNames: string[];\n\tsource: string;\n}\n\n/**\n * Returns true if a source string contains [param] or [...splat] placeholders.\n */\nexport function isPattern(source: string): boolean {\n\t// Use match() instead of test() to avoid lastIndex issues with the global regex\n\treturn source.match(ANY_PLACEHOLDER) !== null;\n}\n\n/**\n * Validate that a pattern string is well-formed.\n * Returns null if valid, or an error message if invalid.\n */\nexport function validatePattern(source: string): string | null {\n\tif (!source.startsWith(\"/\")) {\n\t\treturn \"Pattern must start with /\";\n\t}\n\n\t// Check for nested brackets\n\tif (NESTED_BRACKETS.test(source)) {\n\t\treturn \"Nested brackets are not allowed\";\n\t}\n\n\t// Check for empty brackets\n\tif (EMPTY_BRACKETS.test(source)) {\n\t\treturn \"Empty brackets are not allowed\";\n\t}\n\n\t// Check for unmatched brackets\n\tconst openCount = (source.match(OPEN_BRACKET) ?? []).length;\n\tconst closeCount = (source.match(CLOSE_BRACKET) ?? []).length;\n\tif (openCount !== closeCount) {\n\t\treturn \"Unmatched brackets\";\n\t}\n\n\t// Check that [...splat] is only in the last segment\n\tconst segments = source.split(\"/\").filter(Boolean);\n\tfor (let i = 0; i < segments.length; i++) {\n\t\tconst segment = segments[i];\n\t\tif (SPLAT_PATTERN.test(segment) && i !== segments.length - 1) {\n\t\t\tSPLAT_PATTERN.lastIndex = 0;\n\t\t\treturn \"Catch-all [...param] must be in the last segment\";\n\t\t}\n\t\tSPLAT_PATTERN.lastIndex = 0;\n\t}\n\n\t// Check that a segment is either all literal or a single placeholder\n\tfor (const segment of segments) {\n\t\tconst placeholders = segment.match(ANY_PLACEHOLDER);\n\t\tif (placeholders && placeholders.length > 1) {\n\t\t\treturn \"Each segment can contain at most one placeholder\";\n\t\t}\n\t\tif (placeholders && placeholders[0] !== segment) {\n\t\t\treturn \"A placeholder must be the entire segment, not mixed with literal text\";\n\t\t}\n\t}\n\n\t// Check for duplicate param names\n\tconst names: string[] = [];\n\tfor (const m of source.matchAll(ANY_PLACEHOLDER)) {\n\t\tconst name = m[1];\n\t\tif (names.includes(name)) {\n\t\t\treturn `Duplicate parameter name: ${name}`;\n\t\t}\n\t\tnames.push(name);\n\t}\n\n\treturn null;\n}\n\n/**\n * Validate that all placeholders in a destination exist in the source.\n * Returns null if valid, or an error message if invalid.\n */\nexport function validateDestinationParams(source: string, destination: string): string | null {\n\tconst sourceNames = new Set<string>();\n\tfor (const m of source.matchAll(ANY_PLACEHOLDER)) {\n\t\tsourceNames.add(m[1]);\n\t}\n\n\tfor (const m of destination.matchAll(ANY_PLACEHOLDER)) {\n\t\tconst name = m[1];\n\t\tif (!sourceNames.has(name)) {\n\t\t\treturn `Destination references [${name}] which is not captured in the source pattern`;\n\t\t}\n\t}\n\n\treturn null;\n}\n\n/**\n * Compile a URL pattern into a regex for matching.\n *\n * - `[param]` matches a single path segment (`[^/]+`)\n * - `[...rest]` matches one or more remaining segments (`.+`)\n */\nexport function compilePattern(source: string): CompiledPattern {\n\tconst paramNames: string[] = [];\n\n\t// Replace [...splat] first (before [param]) since [...x] contains [x]\n\tlet regexStr = source.replace(SPLAT_PATTERN, (_match, name: string) => {\n\t\tparamNames.push(name);\n\t\treturn \"(.+)\";\n\t});\n\n\t// Then replace [param]\n\tregexStr = regexStr.replace(PARAM_PATTERN, (_match, name: string) => {\n\t\tparamNames.push(name);\n\t\treturn \"([^/]+)\";\n\t});\n\n\t// Escape any regex-special characters in the literal parts\n\t// We need to be careful: the replacement groups are already valid regex\n\t// Split on capture groups, escape literals, rejoin\n\tconst parts = regexStr.split(CAPTURE_GROUP_SPLIT);\n\tconst escaped = parts\n\t\t.map((part, i) => {\n\t\t\t// Odd indices are the capture groups -- leave them alone\n\t\t\tif (i % 2 === 1) return part;\n\t\t\t// Even indices are literal text -- escape special regex chars\n\t\t\treturn part.replace(REGEX_SPECIAL_CHARS, \"\\\\$&\");\n\t\t})\n\t\t.join(\"\");\n\n\treturn {\n\t\tregex: new RegExp(`^${escaped}$`),\n\t\tparamNames,\n\t\tsource,\n\t};\n}\n\n/**\n * Match a path against a compiled pattern.\n * Returns captured params or null if no match.\n */\nexport function matchPattern(\n\tcompiled: CompiledPattern,\n\tpath: string,\n): Record<string, string> | null {\n\tconst match = path.match(compiled.regex);\n\tif (!match) return null;\n\n\tconst params: Record<string, string> = {};\n\tfor (let i = 0; i < compiled.paramNames.length; i++) {\n\t\tconst value = match[i + 1];\n\t\tif (value !== undefined) {\n\t\t\tparams[compiled.paramNames[i]] = value;\n\t\t}\n\t}\n\treturn params;\n}\n\n/**\n * Interpolate captured params into a destination pattern.\n *\n * @example\n * interpolateDestination(\"/blog/[...path]\", { path: \"2024/01/post\" })\n * // \"/blog/2024/01/post\"\n */\nexport function interpolateDestination(\n\tdestination: string,\n\tparams: Record<string, string>,\n): string {\n\t// Replace [...splat] first\n\tlet result = destination.replace(SPLAT_PATTERN, (_match, name: string) => {\n\t\treturn params[name] ?? \"\";\n\t});\n\n\t// Then [param]\n\tresult = result.replace(PARAM_PATTERN, (_match, name: string) => {\n\t\treturn params[name] ?? \"\";\n\t});\n\n\treturn result;\n}\n","import { sql, type Kysely } from \"kysely\";\nimport { ulid } from \"ulidx\";\n\nimport {\n\tcompilePattern,\n\tmatchPattern,\n\tinterpolateDestination,\n\tisPattern,\n} from \"../../redirects/patterns.js\";\nimport { currentTimestampValue } from \"../dialect-helpers.js\";\nimport type { Database, RedirectTable } from \"../types.js\";\nimport { encodeCursor, decodeCursor, type FindManyResult } from \"./types.js\";\n\n// ---------------------------------------------------------------------------\n// Types\n// ---------------------------------------------------------------------------\n\nexport interface Redirect {\n\tid: string;\n\tsource: string;\n\tdestination: string;\n\ttype: number;\n\tisPattern: boolean;\n\tenabled: boolean;\n\thits: number;\n\tlastHitAt: string | null;\n\tgroupName: string | null;\n\tauto: boolean;\n\tcreatedAt: string;\n\tupdatedAt: string;\n}\n\nexport interface CreateRedirectInput {\n\tsource: string;\n\tdestination: string;\n\ttype?: number;\n\tisPattern?: boolean;\n\tenabled?: boolean;\n\tgroupName?: string | null;\n\tauto?: boolean;\n}\n\nexport interface UpdateRedirectInput {\n\tsource?: string;\n\tdestination?: string;\n\ttype?: number;\n\tisPattern?: boolean;\n\tenabled?: boolean;\n\tgroupName?: string | null;\n}\n\nexport interface NotFoundEntry {\n\tid: string;\n\tpath: string;\n\treferrer: string | null;\n\tuserAgent: string | null;\n\tip: string | null;\n\tcreatedAt: string;\n}\n\nexport interface NotFoundSummary {\n\tpath: string;\n\tcount: number;\n\tlastSeen: string;\n\ttopReferrer: string | null;\n}\n\nexport interface RedirectMatch {\n\tredirect: Redirect;\n\tresolvedDestination: string;\n}\n\n// ---------------------------------------------------------------------------\n// Row mapping\n// ---------------------------------------------------------------------------\n\nfunction rowToRedirect(row: RedirectTable): Redirect {\n\treturn {\n\t\tid: row.id,\n\t\tsource: row.source,\n\t\tdestination: row.destination,\n\t\ttype: row.type,\n\t\tisPattern: row.is_pattern === 1,\n\t\tenabled: row.enabled === 1,\n\t\thits: row.hits,\n\t\tlastHitAt: row.last_hit_at,\n\t\tgroupName: row.group_name,\n\t\tauto: row.auto === 1,\n\t\tcreatedAt: row.created_at,\n\t\tupdatedAt: row.updated_at,\n\t};\n}\n\n// ---------------------------------------------------------------------------\n// Repository\n// ---------------------------------------------------------------------------\n\nexport class RedirectRepository {\n\tconstructor(private db: Kysely<Database>) {}\n\n\t// --- CRUD ---------------------------------------------------------------\n\n\tasync findById(id: string): Promise<Redirect | null> {\n\t\tconst row = await this.db\n\t\t\t.selectFrom(\"_emdash_redirects\")\n\t\t\t.selectAll()\n\t\t\t.where(\"id\", \"=\", id)\n\t\t\t.executeTakeFirst();\n\t\treturn row ? rowToRedirect(row) : null;\n\t}\n\n\tasync findBySource(source: string): Promise<Redirect | null> {\n\t\tconst row = await this.db\n\t\t\t.selectFrom(\"_emdash_redirects\")\n\t\t\t.selectAll()\n\t\t\t.where(\"source\", \"=\", source)\n\t\t\t.executeTakeFirst();\n\t\treturn row ? rowToRedirect(row) : null;\n\t}\n\n\tasync findMany(opts: {\n\t\tcursor?: string;\n\t\tlimit?: number;\n\t\tsearch?: string;\n\t\tgroup?: string;\n\t\tenabled?: boolean;\n\t\tauto?: boolean;\n\t}): Promise<FindManyResult<Redirect>> {\n\t\tconst limit = Math.min(Math.max(opts.limit ?? 50, 1), 100);\n\n\t\tlet query = this.db\n\t\t\t.selectFrom(\"_emdash_redirects\")\n\t\t\t.selectAll()\n\t\t\t.orderBy(\"created_at\", \"desc\")\n\t\t\t.orderBy(\"id\", \"desc\")\n\t\t\t.limit(limit + 1);\n\n\t\tif (opts.search) {\n\t\t\tconst term = `%${opts.search}%`;\n\t\t\tquery = query.where((eb) =>\n\t\t\t\teb.or([eb(\"source\", \"like\", term), eb(\"destination\", \"like\", term)]),\n\t\t\t);\n\t\t}\n\n\t\tif (opts.group !== undefined) {\n\t\t\tquery = query.where(\"group_name\", \"=\", opts.group);\n\t\t}\n\n\t\tif (opts.enabled !== undefined) {\n\t\t\tquery = query.where(\"enabled\", \"=\", opts.enabled ? 1 : 0);\n\t\t}\n\n\t\tif (opts.auto !== undefined) {\n\t\t\tquery = query.where(\"auto\", \"=\", opts.auto ? 1 : 0);\n\t\t}\n\n\t\tif (opts.cursor) {\n\t\t\tconst decoded = decodeCursor(opts.cursor);\n\t\t\tif (decoded) {\n\t\t\t\tquery = query.where((eb) =>\n\t\t\t\t\teb.or([\n\t\t\t\t\t\teb(\"created_at\", \"<\", decoded.orderValue),\n\t\t\t\t\t\teb.and([eb(\"created_at\", \"=\", decoded.orderValue), eb(\"id\", \"<\", decoded.id)]),\n\t\t\t\t\t]),\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\n\t\tconst rows = await query.execute();\n\t\tconst items = rows.slice(0, limit).map(rowToRedirect);\n\t\tconst result: FindManyResult<Redirect> = { items };\n\n\t\tif (rows.length > limit) {\n\t\t\tconst last = items.at(-1)!;\n\t\t\tresult.nextCursor = encodeCursor(last.createdAt, last.id);\n\t\t}\n\n\t\treturn result;\n\t}\n\n\tasync create(input: CreateRedirectInput): Promise<Redirect> {\n\t\tconst id = ulid();\n\t\tconst now = new Date().toISOString();\n\t\tconst patternFlag = input.isPattern ?? isPattern(input.source);\n\n\t\tawait this.db\n\t\t\t.insertInto(\"_emdash_redirects\")\n\t\t\t.values({\n\t\t\t\tid,\n\t\t\t\tsource: input.source,\n\t\t\t\tdestination: input.destination,\n\t\t\t\ttype: input.type ?? 301,\n\t\t\t\tis_pattern: patternFlag ? 1 : 0,\n\t\t\t\tenabled: input.enabled !== false ? 1 : 0,\n\t\t\t\thits: 0,\n\t\t\t\tlast_hit_at: null,\n\t\t\t\tgroup_name: input.groupName ?? null,\n\t\t\t\tauto: input.auto ? 1 : 0,\n\t\t\t\tcreated_at: now,\n\t\t\t\tupdated_at: now,\n\t\t\t})\n\t\t\t.execute();\n\n\t\treturn (await this.findById(id))!;\n\t}\n\n\tasync update(id: string, input: UpdateRedirectInput): Promise<Redirect | null> {\n\t\tconst existing = await this.findById(id);\n\t\tif (!existing) return null;\n\n\t\tconst now = new Date().toISOString();\n\t\tconst values: Record<string, unknown> = { updated_at: now };\n\n\t\tif (input.source !== undefined) {\n\t\t\tvalues.source = input.source;\n\t\t\tvalues.is_pattern =\n\t\t\t\tinput.isPattern !== undefined ? (input.isPattern ? 1 : 0) : isPattern(input.source) ? 1 : 0;\n\t\t} else if (input.isPattern !== undefined) {\n\t\t\tvalues.is_pattern = input.isPattern ? 1 : 0;\n\t\t}\n\n\t\tif (input.destination !== undefined) values.destination = input.destination;\n\t\tif (input.type !== undefined) values.type = input.type;\n\t\tif (input.enabled !== undefined) values.enabled = input.enabled ? 1 : 0;\n\t\tif (input.groupName !== undefined) values.group_name = input.groupName;\n\n\t\tawait this.db.updateTable(\"_emdash_redirects\").set(values).where(\"id\", \"=\", id).execute();\n\n\t\treturn (await this.findById(id))!;\n\t}\n\n\tasync delete(id: string): Promise<boolean> {\n\t\tconst result = await this.db\n\t\t\t.deleteFrom(\"_emdash_redirects\")\n\t\t\t.where(\"id\", \"=\", id)\n\t\t\t.executeTakeFirst();\n\t\treturn BigInt(result.numDeletedRows) > 0n;\n\t}\n\n\t// --- Matching -----------------------------------------------------------\n\n\tasync findExactMatch(path: string): Promise<Redirect | null> {\n\t\tconst row = await this.db\n\t\t\t.selectFrom(\"_emdash_redirects\")\n\t\t\t.selectAll()\n\t\t\t.where(\"source\", \"=\", path)\n\t\t\t.where(\"enabled\", \"=\", 1)\n\t\t\t.where(\"is_pattern\", \"=\", 0)\n\t\t\t.executeTakeFirst();\n\t\treturn row ? rowToRedirect(row) : null;\n\t}\n\n\tasync findEnabledPatternRules(): Promise<Redirect[]> {\n\t\tconst rows = await this.db\n\t\t\t.selectFrom(\"_emdash_redirects\")\n\t\t\t.selectAll()\n\t\t\t.where(\"enabled\", \"=\", 1)\n\t\t\t.where(\"is_pattern\", \"=\", 1)\n\t\t\t.execute();\n\t\treturn rows.map(rowToRedirect);\n\t}\n\n\t/**\n\t * Match a request path against all enabled redirect rules.\n\t * Checks exact matches first (indexed), then pattern rules.\n\t * Returns the matched redirect and the resolved destination URL.\n\t */\n\tasync matchPath(path: string): Promise<RedirectMatch | null> {\n\t\t// 1. Exact match (fast, indexed)\n\t\tconst exact = await this.findExactMatch(path);\n\t\tif (exact) {\n\t\t\treturn { redirect: exact, resolvedDestination: exact.destination };\n\t\t}\n\n\t\t// 2. Pattern match\n\t\tconst patterns = await this.findEnabledPatternRules();\n\t\tfor (const redirect of patterns) {\n\t\t\tconst compiled = compilePattern(redirect.source);\n\t\t\tconst params = matchPattern(compiled, path);\n\t\t\tif (params) {\n\t\t\t\tconst resolved = interpolateDestination(redirect.destination, params);\n\t\t\t\treturn { redirect, resolvedDestination: resolved };\n\t\t\t}\n\t\t}\n\n\t\treturn null;\n\t}\n\n\t// --- Hit tracking -------------------------------------------------------\n\n\tasync recordHit(id: string): Promise<void> {\n\t\tawait sql`\n\t\t\tUPDATE _emdash_redirects\n\t\t\tSET hits = hits + 1, last_hit_at = ${currentTimestampValue(this.db)}, updated_at = ${currentTimestampValue(this.db)}\n\t\t\tWHERE id = ${id}\n\t\t`.execute(this.db);\n\t}\n\n\t// --- Auto-redirects (slug change) ---------------------------------------\n\n\t/**\n\t * Create an auto-redirect when a content slug changes.\n\t * Uses the collection's URL pattern to compute old/new URLs.\n\t * Collapses existing redirect chains pointing to the old URL.\n\t */\n\tasync createAutoRedirect(\n\t\tcollection: string,\n\t\toldSlug: string,\n\t\tnewSlug: string,\n\t\tcontentId: string,\n\t\turlPattern: string | null,\n\t): Promise<Redirect> {\n\t\tconst oldUrl = urlPattern\n\t\t\t? urlPattern.replace(\"{slug}\", oldSlug).replace(\"{id}\", contentId)\n\t\t\t: `/${collection}/${oldSlug}`;\n\t\tconst newUrl = urlPattern\n\t\t\t? urlPattern.replace(\"{slug}\", newSlug).replace(\"{id}\", contentId)\n\t\t\t: `/${collection}/${newSlug}`;\n\n\t\t// Collapse chains: update any existing redirects pointing to the old URL\n\t\tawait this.collapseChains(oldUrl, newUrl);\n\n\t\t// Check if a redirect from this source already exists\n\t\tconst existing = await this.findBySource(oldUrl);\n\t\tif (existing) {\n\t\t\t// Update the existing redirect to point to the new URL\n\t\t\treturn (await this.update(existing.id, { destination: newUrl }))!;\n\t\t}\n\n\t\treturn this.create({\n\t\t\tsource: oldUrl,\n\t\t\tdestination: newUrl,\n\t\t\ttype: 301,\n\t\t\tisPattern: false,\n\t\t\tauto: true,\n\t\t\tgroupName: \"Auto: slug change\",\n\t\t});\n\t}\n\n\t/**\n\t * Update all redirects whose destination matches oldDestination\n\t * to point to newDestination instead. Prevents redirect chains.\n\t * Returns the number of updated rows.\n\t */\n\tasync collapseChains(oldDestination: string, newDestination: string): Promise<number> {\n\t\tconst result = await this.db\n\t\t\t.updateTable(\"_emdash_redirects\")\n\t\t\t.set({\n\t\t\t\tdestination: newDestination,\n\t\t\t\tupdated_at: new Date().toISOString(),\n\t\t\t})\n\t\t\t.where(\"destination\", \"=\", oldDestination)\n\t\t\t.executeTakeFirst();\n\t\treturn Number(result.numUpdatedRows);\n\t}\n\n\t// --- 404 log ------------------------------------------------------------\n\n\tasync log404(entry: {\n\t\tpath: string;\n\t\treferrer?: string | null;\n\t\tuserAgent?: string | null;\n\t\tip?: string | null;\n\t}): Promise<void> {\n\t\tawait this.db\n\t\t\t.insertInto(\"_emdash_404_log\")\n\t\t\t.values({\n\t\t\t\tid: ulid(),\n\t\t\t\tpath: entry.path,\n\t\t\t\treferrer: entry.referrer ?? null,\n\t\t\t\tuser_agent: entry.userAgent ?? null,\n\t\t\t\tip: entry.ip ?? null,\n\t\t\t\tcreated_at: new Date().toISOString(),\n\t\t\t})\n\t\t\t.execute();\n\t}\n\n\tasync find404s(opts: {\n\t\tcursor?: string;\n\t\tlimit?: number;\n\t\tsearch?: string;\n\t}): Promise<FindManyResult<NotFoundEntry>> {\n\t\tconst limit = Math.min(Math.max(opts.limit ?? 50, 1), 100);\n\n\t\tlet query = this.db\n\t\t\t.selectFrom(\"_emdash_404_log\")\n\t\t\t.selectAll()\n\t\t\t.orderBy(\"created_at\", \"desc\")\n\t\t\t.orderBy(\"id\", \"desc\")\n\t\t\t.limit(limit + 1);\n\n\t\tif (opts.search) {\n\t\t\tquery = query.where(\"path\", \"like\", `%${opts.search}%`);\n\t\t}\n\n\t\tif (opts.cursor) {\n\t\t\tconst decoded = decodeCursor(opts.cursor);\n\t\t\tif (decoded) {\n\t\t\t\tquery = query.where((eb) =>\n\t\t\t\t\teb.or([\n\t\t\t\t\t\teb(\"created_at\", \"<\", decoded.orderValue),\n\t\t\t\t\t\teb.and([eb(\"created_at\", \"=\", decoded.orderValue), eb(\"id\", \"<\", decoded.id)]),\n\t\t\t\t\t]),\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\n\t\tconst rows = await query.execute();\n\t\tconst items: NotFoundEntry[] = rows.slice(0, limit).map((row) => ({\n\t\t\tid: row.id,\n\t\t\tpath: row.path,\n\t\t\treferrer: row.referrer,\n\t\t\tuserAgent: row.user_agent,\n\t\t\tip: row.ip,\n\t\t\tcreatedAt: row.created_at,\n\t\t}));\n\n\t\tconst result: FindManyResult<NotFoundEntry> = { items };\n\t\tif (rows.length > limit) {\n\t\t\tconst last = items.at(-1)!;\n\t\t\tresult.nextCursor = encodeCursor(last.createdAt, last.id);\n\t\t}\n\n\t\treturn result;\n\t}\n\n\tasync get404Summary(limit = 50): Promise<NotFoundSummary[]> {\n\t\tconst rows = await sql<{\n\t\t\tpath: string;\n\t\t\tcount: number;\n\t\t\tlast_seen: string;\n\t\t\ttop_referrer: string | null;\n\t\t}>`\n\t\t\tSELECT\n\t\t\t\tpath,\n\t\t\t\tCOUNT(*) as count,\n\t\t\t\tMAX(created_at) as last_seen,\n\t\t\t\t(\n\t\t\t\t\tSELECT referrer FROM _emdash_404_log AS inner_log\n\t\t\t\t\tWHERE inner_log.path = _emdash_404_log.path\n\t\t\t\t\t\tAND referrer IS NOT NULL AND referrer != ''\n\t\t\t\t\tGROUP BY referrer\n\t\t\t\t\tORDER BY COUNT(*) DESC\n\t\t\t\t\tLIMIT 1\n\t\t\t\t) as top_referrer\n\t\t\tFROM _emdash_404_log\n\t\t\tGROUP BY path\n\t\t\tORDER BY count DESC\n\t\t\tLIMIT ${limit}\n\t\t`.execute(this.db);\n\n\t\treturn rows.rows.map((row) => ({\n\t\t\tpath: row.path,\n\t\t\tcount: Number(row.count),\n\t\t\tlastSeen: row.last_seen,\n\t\t\ttopReferrer: row.top_referrer,\n\t\t}));\n\t}\n\n\tasync delete404(id: string): Promise<boolean> {\n\t\tconst result = await this.db\n\t\t\t.deleteFrom(\"_emdash_404_log\")\n\t\t\t.where(\"id\", \"=\", id)\n\t\t\t.executeTakeFirst();\n\t\treturn BigInt(result.numDeletedRows) > 0n;\n\t}\n\n\tasync clear404s(): Promise<number> {\n\t\tconst result = await this.db.deleteFrom(\"_emdash_404_log\").executeTakeFirst();\n\t\treturn Number(result.numDeletedRows);\n\t}\n\n\tasync prune404s(olderThan: string): Promise<number> {\n\t\tconst result = await this.db\n\t\t\t.deleteFrom(\"_emdash_404_log\")\n\t\t\t.where(\"created_at\", \"<\", olderThan)\n\t\t\t.executeTakeFirst();\n\t\treturn Number(result.numDeletedRows);\n\t}\n}\n"],"mappings":"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"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"registry-1EvbAfsC.mjs","names":["dialectTableExists"],"sources":["../src/database/transaction.ts","../src/search/fts-manager.ts","../src/schema/registry.ts"],"sourcesContent":["/**\n * Transaction utility for D1 compatibility\n *\n * D1 (via kysely-d1) does not support transactions. On workerd, the error\n * from beginTransaction() crosses request contexts and can hang the worker.\n *\n * This utility provides a drop-in replacement that runs the callback directly\n * against the db instance when transactions are unavailable. D1 is single-writer\n * so atomicity is not a concern for individual statements — multi-statement\n * atomicity is lost, but that's a known D1 limitation.\n *\n * Usage:\n * import { withTransaction } from \"../database/transaction.js\";\n * const result = await withTransaction(db, async (trx) => { ... });\n */\n\nimport type { Kysely, Transaction } from \"kysely\";\n\n/**\n * Run a callback inside a transaction if supported, or directly if not.\n *\n * Probes the database once on first call to determine if transactions work.\n * The result is cached for the lifetime of the process/worker.\n */\nlet transactionsSupported: boolean | null = null;\nconst TRANSACTIONS_NOT_SUPPORTED_RE = /transactions are not supported/i;\n\nexport async function withTransaction<DB, T>(\n\tdb: Kysely<DB>,\n\tfn: (trx: Kysely<DB> | Transaction<DB>) => Promise<T>,\n): Promise<T> {\n\t// Fast path: we already know transactions work\n\tif (transactionsSupported === true) {\n\t\treturn db.transaction().execute(fn);\n\t}\n\n\t// Fast path: we already know they don't\n\tif (transactionsSupported === false) {\n\t\treturn fn(db);\n\t}\n\n\t// First call: probe\n\ttry {\n\t\tconst result = await db.transaction().execute(fn);\n\t\ttransactionsSupported = true;\n\t\treturn result;\n\t} catch (error) {\n\t\tif (error instanceof Error && TRANSACTIONS_NOT_SUPPORTED_RE.test(error.message)) {\n\t\t\ttransactionsSupported = false;\n\t\t\treturn fn(db);\n\t\t}\n\t\tthrow error;\n\t}\n}\n","/**\n * FTS5 Manager\n *\n * Manages FTS5 virtual tables and triggers for search indexing.\n */\n\nimport type { Kysely } from \"kysely\";\nimport { sql } from \"kysely\";\n\nimport { isSqlite, tableExists as dialectTableExists } from \"../database/dialect-helpers.js\";\nimport type { Database } from \"../database/types.js\";\nimport { validateIdentifier } from \"../database/validate.js\";\nimport type { SearchConfig } from \"./types.js\";\n\n/**\n * FTS5 Manager\n *\n * Handles creation, deletion, and management of FTS5 virtual tables\n * for full-text search on content collections.\n */\nexport class FTSManager {\n\tconstructor(private db: Kysely<Database>) {}\n\n\t/**\n\t * Validate a collection slug and its searchable field names.\n\t * Must be called before any raw SQL interpolation.\n\t */\n\tprivate validateInputs(collectionSlug: string, searchableFields?: string[]): void {\n\t\tvalidateIdentifier(collectionSlug, \"collection slug\");\n\t\tif (searchableFields) {\n\t\t\tfor (const field of searchableFields) {\n\t\t\t\tvalidateIdentifier(field, \"searchable field name\");\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * Get the FTS table name for a collection\n\t * Uses _emdash_ prefix to clearly mark as internal/system table\n\t */\n\tgetFtsTableName(collectionSlug: string): string {\n\t\treturn `_emdash_fts_${collectionSlug}`;\n\t}\n\n\t/**\n\t * Get the content table name for a collection\n\t */\n\tgetContentTableName(collectionSlug: string): string {\n\t\treturn `ec_${collectionSlug}`;\n\t}\n\n\t/**\n\t * Check if an FTS table exists for a collection\n\t */\n\tasync ftsTableExists(collectionSlug: string): Promise<boolean> {\n\t\tconst ftsTable = this.getFtsTableName(collectionSlug);\n\t\treturn dialectTableExists(this.db, ftsTable);\n\t}\n\n\t/**\n\t * Create an FTS5 virtual table for a collection.\n\t * FTS5 is SQLite-only; on other dialects this is a no-op.\n\t *\n\t * @param collectionSlug - The collection slug\n\t * @param searchableFields - Array of field names to index\n\t * @param weights - Optional field weights for ranking\n\t */\n\tasync createFtsTable(\n\t\tcollectionSlug: string,\n\t\tsearchableFields: string[],\n\t\t_weights?: Record<string, number>,\n\t): Promise<void> {\n\t\tif (!isSqlite(this.db)) return;\n\t\tthis.validateInputs(collectionSlug, searchableFields);\n\t\tconst ftsTable = this.getFtsTableName(collectionSlug);\n\t\tconst contentTable = this.getContentTableName(collectionSlug);\n\n\t\t// Build the column list for FTS5\n\t\t// id and locale are UNINDEXED (used for joining/filtering, not searched)\n\t\tconst columns = [\"id UNINDEXED\", \"locale UNINDEXED\", ...searchableFields].join(\", \");\n\n\t\t// Create the FTS5 virtual table\n\t\t// Using content= to make it a contentless FTS table (we manage sync ourselves)\n\t\t// tokenize='porter unicode61' enables stemming (run matches running, ran, etc.)\n\t\tawait sql\n\t\t\t.raw(`\n\t\t\tCREATE VIRTUAL TABLE IF NOT EXISTS \"${ftsTable}\" USING fts5(\n\t\t\t\t${columns},\n\t\t\t\tcontent='${contentTable}',\n\t\t\t\tcontent_rowid='rowid',\n\t\t\t\ttokenize='porter unicode61'\n\t\t\t)\n\t\t`)\n\t\t\t.execute(this.db);\n\n\t\t// Create triggers for automatic sync\n\t\tawait this.createTriggers(collectionSlug, searchableFields);\n\t}\n\n\t/**\n\t * Create triggers to keep FTS table in sync with content table\n\t */\n\tprivate async createTriggers(collectionSlug: string, searchableFields: string[]): Promise<void> {\n\t\tconst ftsTable = this.getFtsTableName(collectionSlug);\n\t\tconst contentTable = this.getContentTableName(collectionSlug);\n\t\tconst fieldList = searchableFields.join(\", \");\n\t\tconst newFieldList = searchableFields.map((f) => `NEW.${f}`).join(\", \");\n\n\t\t// Insert trigger\n\t\tawait sql\n\t\t\t.raw(`\n\t\t\tCREATE TRIGGER IF NOT EXISTS \"${ftsTable}_insert\" \n\t\t\tAFTER INSERT ON \"${contentTable}\" \n\t\t\tBEGIN\n\t\t\t\tINSERT INTO \"${ftsTable}\"(rowid, id, locale, ${fieldList})\n\t\t\t\tVALUES (NEW.rowid, NEW.id, NEW.locale, ${newFieldList});\n\t\t\tEND\n\t\t`)\n\t\t\t.execute(this.db);\n\n\t\t// Update trigger - delete old, insert new\n\t\tawait sql\n\t\t\t.raw(`\n\t\t\tCREATE TRIGGER IF NOT EXISTS \"${ftsTable}_update\" \n\t\t\tAFTER UPDATE ON \"${contentTable}\" \n\t\t\tBEGIN\n\t\t\t\tDELETE FROM \"${ftsTable}\" WHERE rowid = OLD.rowid;\n\t\t\t\tINSERT INTO \"${ftsTable}\"(rowid, id, locale, ${fieldList})\n\t\t\t\tVALUES (NEW.rowid, NEW.id, NEW.locale, ${newFieldList});\n\t\t\tEND\n\t\t`)\n\t\t\t.execute(this.db);\n\n\t\t// Delete trigger\n\t\tawait sql\n\t\t\t.raw(`\n\t\t\tCREATE TRIGGER IF NOT EXISTS \"${ftsTable}_delete\" \n\t\t\tAFTER DELETE ON \"${contentTable}\" \n\t\t\tBEGIN\n\t\t\t\tDELETE FROM \"${ftsTable}\" WHERE rowid = OLD.rowid;\n\t\t\tEND\n\t\t`)\n\t\t\t.execute(this.db);\n\t}\n\n\t/**\n\t * Drop triggers for a collection\n\t */\n\tprivate async dropTriggers(collectionSlug: string): Promise<void> {\n\t\tconst ftsTable = this.getFtsTableName(collectionSlug);\n\n\t\tawait sql.raw(`DROP TRIGGER IF EXISTS \"${ftsTable}_insert\"`).execute(this.db);\n\t\tawait sql.raw(`DROP TRIGGER IF EXISTS \"${ftsTable}_update\"`).execute(this.db);\n\t\tawait sql.raw(`DROP TRIGGER IF EXISTS \"${ftsTable}_delete\"`).execute(this.db);\n\t}\n\n\t/**\n\t * Drop the FTS table and triggers for a collection\n\t */\n\tasync dropFtsTable(collectionSlug: string): Promise<void> {\n\t\tif (!isSqlite(this.db)) return;\n\t\tthis.validateInputs(collectionSlug);\n\t\tconst ftsTable = this.getFtsTableName(collectionSlug);\n\n\t\t// Drop triggers first\n\t\tawait this.dropTriggers(collectionSlug);\n\n\t\t// Drop the FTS table\n\t\tawait sql.raw(`DROP TABLE IF EXISTS \"${ftsTable}\"`).execute(this.db);\n\t}\n\n\t/**\n\t * Rebuild the FTS index for a collection\n\t *\n\t * This is useful after bulk imports or if the index gets out of sync.\n\t */\n\tasync rebuildIndex(\n\t\tcollectionSlug: string,\n\t\tsearchableFields: string[],\n\t\tweights?: Record<string, number>,\n\t): Promise<void> {\n\t\tif (!isSqlite(this.db)) return;\n\t\t// Drop existing table and triggers\n\t\tawait this.dropFtsTable(collectionSlug);\n\n\t\t// Recreate table and triggers\n\t\tawait this.createFtsTable(collectionSlug, searchableFields, weights);\n\n\t\t// Populate from existing content\n\t\tawait this.populateFromContent(collectionSlug, searchableFields);\n\t}\n\n\t/**\n\t * Populate the FTS table from existing content\n\t */\n\tasync populateFromContent(collectionSlug: string, searchableFields: string[]): Promise<void> {\n\t\tif (!isSqlite(this.db)) return;\n\t\tthis.validateInputs(collectionSlug, searchableFields);\n\t\tconst ftsTable = this.getFtsTableName(collectionSlug);\n\t\tconst contentTable = this.getContentTableName(collectionSlug);\n\t\tconst fieldList = searchableFields.join(\", \");\n\n\t\t// Insert all existing content into FTS table\n\t\tawait sql\n\t\t\t.raw(`\n\t\t\tINSERT INTO \"${ftsTable}\"(rowid, id, locale, ${fieldList})\n\t\t\tSELECT rowid, id, locale, ${fieldList} FROM \"${contentTable}\"\n\t\t\tWHERE deleted_at IS NULL\n\t\t`)\n\t\t\t.execute(this.db);\n\t}\n\n\t/**\n\t * Get the search configuration for a collection\n\t */\n\tasync getSearchConfig(collectionSlug: string): Promise<SearchConfig | null> {\n\t\tconst result = await this.db\n\t\t\t.selectFrom(\"_emdash_collections\")\n\t\t\t.select(\"search_config\")\n\t\t\t.where(\"slug\", \"=\", collectionSlug)\n\t\t\t.executeTakeFirst();\n\n\t\tif (!result?.search_config) {\n\t\t\treturn null;\n\t\t}\n\n\t\ttry {\n\t\t\tconst parsed: unknown = JSON.parse(result.search_config);\n\t\t\tif (\n\t\t\t\ttypeof parsed !== \"object\" ||\n\t\t\t\tparsed === null ||\n\t\t\t\t!(\"enabled\" in parsed) ||\n\t\t\t\ttypeof parsed.enabled !== \"boolean\"\n\t\t\t) {\n\t\t\t\treturn null;\n\t\t\t}\n\t\t\tconst config: SearchConfig = { enabled: parsed.enabled };\n\t\t\tif (\"weights\" in parsed && typeof parsed.weights === \"object\" && parsed.weights !== null) {\n\t\t\t\t// weights is a JSON-parsed object — safe to treat as Record<string, number>\n\t\t\t\tconst weights: Record<string, number> = {};\n\t\t\t\tfor (const [k, v] of Object.entries(parsed.weights)) {\n\t\t\t\t\tif (typeof v === \"number\") {\n\t\t\t\t\t\tweights[k] = v;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tconfig.weights = weights;\n\t\t\t}\n\t\t\treturn config;\n\t\t} catch {\n\t\t\treturn null;\n\t\t}\n\t}\n\n\t/**\n\t * Update the search configuration for a collection\n\t */\n\tasync setSearchConfig(collectionSlug: string, config: SearchConfig): Promise<void> {\n\t\tawait this.db\n\t\t\t.updateTable(\"_emdash_collections\")\n\t\t\t.set({ search_config: JSON.stringify(config) })\n\t\t\t.where(\"slug\", \"=\", collectionSlug)\n\t\t\t.execute();\n\t}\n\n\t/**\n\t * Get searchable fields for a collection\n\t */\n\tasync getSearchableFields(collectionSlug: string): Promise<string[]> {\n\t\tconst collection = await this.db\n\t\t\t.selectFrom(\"_emdash_collections\")\n\t\t\t.select(\"id\")\n\t\t\t.where(\"slug\", \"=\", collectionSlug)\n\t\t\t.executeTakeFirst();\n\n\t\tif (!collection) {\n\t\t\treturn [];\n\t\t}\n\n\t\tconst fields = await this.db\n\t\t\t.selectFrom(\"_emdash_fields\")\n\t\t\t.select(\"slug\")\n\t\t\t.where(\"collection_id\", \"=\", collection.id)\n\t\t\t.where(\"searchable\", \"=\", 1)\n\t\t\t.execute();\n\n\t\treturn fields.map((f) => f.slug);\n\t}\n\n\t/**\n\t * Enable search for a collection\n\t *\n\t * Creates the FTS table and triggers, and populates from existing content.\n\t */\n\tasync enableSearch(\n\t\tcollectionSlug: string,\n\t\toptions?: { weights?: Record<string, number> },\n\t): Promise<void> {\n\t\tif (!isSqlite(this.db)) {\n\t\t\tthrow new Error(\"Full-text search is only available with SQLite databases\");\n\t\t}\n\t\t// Get searchable fields\n\t\tconst searchableFields = await this.getSearchableFields(collectionSlug);\n\n\t\tif (searchableFields.length === 0) {\n\t\t\tthrow new Error(\n\t\t\t\t`No searchable fields defined for collection \"${collectionSlug}\". ` +\n\t\t\t\t\t`Mark at least one field as searchable before enabling search.`,\n\t\t\t);\n\t\t}\n\n\t\t// Create FTS table\n\t\tawait this.createFtsTable(collectionSlug, searchableFields, options?.weights);\n\n\t\t// Populate from existing content\n\t\tawait this.populateFromContent(collectionSlug, searchableFields);\n\n\t\t// Update search config\n\t\tawait this.setSearchConfig(collectionSlug, {\n\t\t\tenabled: true,\n\t\t\tweights: options?.weights,\n\t\t});\n\t}\n\n\t/**\n\t * Disable search for a collection\n\t *\n\t * Drops the FTS table and triggers.\n\t */\n\tasync disableSearch(collectionSlug: string): Promise<void> {\n\t\tif (!isSqlite(this.db)) return;\n\t\tawait this.dropFtsTable(collectionSlug);\n\t\tawait this.setSearchConfig(collectionSlug, { enabled: false });\n\t}\n\n\t/**\n\t * Get index statistics for a collection\n\t */\n\tasync getIndexStats(\n\t\tcollectionSlug: string,\n\t): Promise<{ indexed: number; lastRebuilt?: string } | null> {\n\t\tif (!isSqlite(this.db)) return null;\n\t\tthis.validateInputs(collectionSlug);\n\t\tconst ftsTable = this.getFtsTableName(collectionSlug);\n\n\t\t// Check if table exists\n\t\tif (!(await this.ftsTableExists(collectionSlug))) {\n\t\t\treturn null;\n\t\t}\n\n\t\t// Count indexed rows\n\t\tconst result = await sql<{ count: number }>`\n\t\t\tSELECT COUNT(*) as count FROM \"${sql.raw(ftsTable)}\"\n\t\t`.execute(this.db);\n\n\t\treturn {\n\t\t\tindexed: result.rows[0]?.count ?? 0,\n\t\t};\n\t}\n\n\t/**\n\t * Verify FTS index integrity and rebuild if corrupted.\n\t *\n\t * Checks for row count mismatch between content table and FTS table.\n\t *\n\t * Returns true if the index was rebuilt, false if it was healthy.\n\t */\n\tasync verifyAndRepairIndex(collectionSlug: string): Promise<boolean> {\n\t\tif (!isSqlite(this.db)) return false;\n\t\tthis.validateInputs(collectionSlug);\n\t\tconst ftsTable = this.getFtsTableName(collectionSlug);\n\t\tconst contentTable = this.getContentTableName(collectionSlug);\n\n\t\tif (!(await this.ftsTableExists(collectionSlug))) {\n\t\t\treturn false;\n\t\t}\n\n\t\t// Check 1: Row count mismatch\n\t\tconst contentCount = await sql<{ count: number }>`\n\t\t\tSELECT COUNT(*) as count FROM ${sql.ref(contentTable)}\n\t\t\tWHERE deleted_at IS NULL\n\t\t`.execute(this.db);\n\n\t\tconst ftsCount = await sql<{ count: number }>`\n\t\t\tSELECT COUNT(*) as count FROM \"${sql.raw(ftsTable)}\"\n\t\t`.execute(this.db);\n\n\t\tconst contentRows = contentCount.rows[0]?.count ?? 0;\n\t\tconst ftsRows = ftsCount.rows[0]?.count ?? 0;\n\n\t\tif (contentRows !== ftsRows) {\n\t\t\tconsole.warn(\n\t\t\t\t`FTS index for \"${collectionSlug}\" has ${ftsRows} rows but content table has ${contentRows}. Rebuilding.`,\n\t\t\t);\n\t\t\tconst fields = await this.getSearchableFields(collectionSlug);\n\t\t\tconst config = await this.getSearchConfig(collectionSlug);\n\t\t\tif (fields.length > 0) {\n\t\t\t\tawait this.rebuildIndex(collectionSlug, fields, config?.weights);\n\t\t\t}\n\t\t\treturn true;\n\t\t}\n\n\t\treturn false;\n\t}\n\n\t/**\n\t * Verify and repair FTS indexes for all search-enabled collections.\n\t *\n\t * Intended to run at startup to auto-heal any corruption from\n\t * previous process crashes.\n\t */\n\tasync verifyAndRepairAll(): Promise<number> {\n\t\tif (!isSqlite(this.db)) return 0;\n\n\t\tconst collections = await this.db\n\t\t\t.selectFrom(\"_emdash_collections\")\n\t\t\t.select(\"slug\")\n\t\t\t.where(\"search_config\", \"is not\", null)\n\t\t\t.execute();\n\n\t\tlet repaired = 0;\n\t\tfor (const { slug } of collections) {\n\t\t\tconst config = await this.getSearchConfig(slug);\n\t\t\tif (!config?.enabled) continue;\n\n\t\t\ttry {\n\t\t\t\tconst wasRepaired = await this.verifyAndRepairIndex(slug);\n\t\t\t\tif (wasRepaired) repaired++;\n\t\t\t} catch (error) {\n\t\t\t\tconsole.error(`Failed to verify/repair FTS index for \"${slug}\":`, error);\n\t\t\t}\n\t\t}\n\n\t\treturn repaired;\n\t}\n}\n","import type { Kysely } from \"kysely\";\nimport type { Selectable } from \"kysely\";\nimport { sql } from \"kysely\";\nimport { ulid } from \"ulidx\";\n\nimport { currentTimestamp, listTablesLike, tableExists } from \"../database/dialect-helpers.js\";\nimport { withTransaction } from \"../database/transaction.js\";\nimport type { CollectionTable, Database, FieldTable } from \"../database/types.js\";\nimport { FTSManager } from \"../search/fts-manager.js\";\nimport {\n\ttype Collection,\n\ttype CollectionSource,\n\ttype ColumnType,\n\ttype Field,\n\ttype CreateCollectionInput,\n\ttype UpdateCollectionInput,\n\ttype CreateFieldInput,\n\ttype UpdateFieldInput,\n\ttype CollectionWithFields,\n\ttype FieldType,\n\tFIELD_TYPE_TO_COLUMN,\n\tRESERVED_FIELD_SLUGS,\n\tRESERVED_COLLECTION_SLUGS,\n} from \"./types.js\";\n\n// Regex patterns for schema registry\nconst SLUG_VALIDATION_PATTERN = /^[a-z][a-z0-9_]*$/;\nconst EC_PREFIX_PATTERN = /^ec_/;\nconst SINGLE_QUOTE_PATTERN = /'/g;\nconst UNDERSCORE_PATTERN = /_/g;\nconst WORD_BOUNDARY_PATTERN = /\\b\\w/g;\n\n/** Valid column types for runtime validation */\nconst COLUMN_TYPES: ReadonlySet<string> = new Set([\"TEXT\", \"REAL\", \"INTEGER\", \"JSON\"]);\n\n/** Valid collection source prefixes/values */\nconst VALID_SOURCES: ReadonlySet<string> = new Set([\"manual\", \"discovered\", \"seed\"]);\n\nfunction isCollectionSource(value: string): value is CollectionSource {\n\treturn VALID_SOURCES.has(value) || value.startsWith(\"template:\") || value.startsWith(\"import:\");\n}\n\nfunction isFieldType(value: string): value is FieldType {\n\treturn value in FIELD_TYPE_TO_COLUMN;\n}\n\nfunction isColumnType(value: string): value is ColumnType {\n\treturn COLUMN_TYPES.has(value);\n}\n\n/**\n * Error thrown when a schema operation fails\n */\nexport class SchemaError extends Error {\n\tconstructor(\n\t\tmessage: string,\n\t\tpublic code: string,\n\t\tpublic details?: Record<string, unknown>,\n\t) {\n\t\tsuper(message);\n\t\tthis.name = \"SchemaError\";\n\t}\n}\n\n/**\n * Schema Registry\n *\n * Manages collection and field definitions stored in D1.\n * Handles runtime DDL operations (CREATE TABLE, ALTER TABLE).\n */\nexport class SchemaRegistry {\n\tconstructor(private db: Kysely<Database>) {}\n\n\t// ============================================\n\t// Collection Operations\n\t// ============================================\n\n\t/**\n\t * List all collections\n\t */\n\tasync listCollections(): Promise<Collection[]> {\n\t\tconst rows = await this.db\n\t\t\t.selectFrom(\"_emdash_collections\")\n\t\t\t.selectAll()\n\t\t\t.orderBy(\"slug\", \"asc\")\n\t\t\t.execute();\n\n\t\treturn rows.map(this.mapCollectionRow);\n\t}\n\n\t/**\n\t * Get a collection by slug\n\t */\n\tasync getCollection(slug: string): Promise<Collection | null> {\n\t\tconst row = await this.db\n\t\t\t.selectFrom(\"_emdash_collections\")\n\t\t\t.where(\"slug\", \"=\", slug)\n\t\t\t.selectAll()\n\t\t\t.executeTakeFirst();\n\n\t\treturn row ? this.mapCollectionRow(row) : null;\n\t}\n\n\t/**\n\t * Get a collection with all its fields\n\t */\n\tasync getCollectionWithFields(slug: string): Promise<CollectionWithFields | null> {\n\t\tconst collection = await this.getCollection(slug);\n\t\tif (!collection) return null;\n\n\t\tconst fields = await this.listFields(collection.id);\n\n\t\treturn { ...collection, fields };\n\t}\n\n\t/**\n\t * Create a new collection\n\t */\n\tasync createCollection(input: CreateCollectionInput): Promise<Collection> {\n\t\t// Validate slug\n\t\tthis.validateSlug(input.slug, \"collection\");\n\t\tif (RESERVED_COLLECTION_SLUGS.includes(input.slug)) {\n\t\t\tthrow new SchemaError(`Collection slug \"${input.slug}\" is reserved`, \"RESERVED_SLUG\");\n\t\t}\n\n\t\t// Check if collection already exists\n\t\tconst existing = await this.getCollection(input.slug);\n\t\tif (existing) {\n\t\t\tthrow new SchemaError(`Collection \"${input.slug}\" already exists`, \"COLLECTION_EXISTS\");\n\t\t}\n\n\t\tconst id = ulid();\n\n\t\t// Insert collection record and create content table in a transaction\n\t\t// so a failure in table creation doesn't leave an orphaned row.\n\t\t// Uses withTransaction for D1 compatibility (no transaction support).\n\t\t// Derive hasSeo from supports array if not explicitly set\n\t\tconst hasSeo = input.hasSeo ?? input.supports?.includes(\"seo\") ?? false;\n\n\t\tawait withTransaction(this.db, async (trx) => {\n\t\t\tawait trx\n\t\t\t\t.insertInto(\"_emdash_collections\")\n\t\t\t\t.values({\n\t\t\t\t\tid,\n\t\t\t\t\tslug: input.slug,\n\t\t\t\t\tlabel: input.label,\n\t\t\t\t\tlabel_singular: input.labelSingular ?? null,\n\t\t\t\t\tdescription: input.description ?? null,\n\t\t\t\t\ticon: input.icon ?? null,\n\t\t\t\t\tsupports: input.supports ? JSON.stringify(input.supports) : null,\n\t\t\t\t\tsource: input.source ?? \"manual\",\n\t\t\t\t\thas_seo: hasSeo ? 1 : 0,\n\t\t\t\t\tcomments_enabled: input.commentsEnabled ? 1 : 0,\n\t\t\t\t\turl_pattern: input.urlPattern ?? null,\n\t\t\t\t})\n\t\t\t\t.execute();\n\n\t\t\t// Create the content table for this collection\n\t\t\tawait this.createContentTable(input.slug, trx);\n\t\t});\n\n\t\tconst collection = await this.getCollection(input.slug);\n\t\tif (!collection) {\n\t\t\tthrow new SchemaError(\"Failed to create collection\", \"CREATE_FAILED\");\n\t\t}\n\n\t\treturn collection;\n\t}\n\n\t/**\n\t * Update a collection\n\t */\n\tasync updateCollection(slug: string, input: UpdateCollectionInput): Promise<Collection> {\n\t\tconst existing = await this.getCollection(slug);\n\t\tif (!existing) {\n\t\t\tthrow new SchemaError(`Collection \"${slug}\" not found`, \"COLLECTION_NOT_FOUND\");\n\t\t}\n\n\t\tconst now = new Date().toISOString();\n\n\t\t// Derive hasSeo from supports array if supports is being updated and hasSeo not explicitly set\n\t\tconst supportsArray = input.supports ?? existing.supports;\n\t\tconst hasSeo =\n\t\t\tinput.hasSeo !== undefined\n\t\t\t\t? input.hasSeo\n\t\t\t\t: input.supports !== undefined\n\t\t\t\t\t? supportsArray.includes(\"seo\")\n\t\t\t\t\t: existing.hasSeo;\n\n\t\tawait this.db\n\t\t\t.updateTable(\"_emdash_collections\")\n\t\t\t.set({\n\t\t\t\tlabel: input.label ?? existing.label,\n\t\t\t\tlabel_singular: input.labelSingular ?? existing.labelSingular ?? null,\n\t\t\t\tdescription: input.description ?? existing.description ?? null,\n\t\t\t\ticon: input.icon ?? existing.icon ?? null,\n\t\t\t\tsupports: input.supports\n\t\t\t\t\t? JSON.stringify(input.supports)\n\t\t\t\t\t: JSON.stringify(existing.supports),\n\t\t\t\turl_pattern:\n\t\t\t\t\tinput.urlPattern !== undefined\n\t\t\t\t\t\t? (input.urlPattern ?? null)\n\t\t\t\t\t\t: (existing.urlPattern ?? null),\n\t\t\t\thas_seo: hasSeo ? 1 : 0,\n\t\t\t\tcomments_enabled:\n\t\t\t\t\tinput.commentsEnabled !== undefined\n\t\t\t\t\t\t? input.commentsEnabled\n\t\t\t\t\t\t\t? 1\n\t\t\t\t\t\t\t: 0\n\t\t\t\t\t\t: existing.commentsEnabled\n\t\t\t\t\t\t\t? 1\n\t\t\t\t\t\t\t: 0,\n\t\t\t\tcomments_moderation: input.commentsModeration ?? existing.commentsModeration,\n\t\t\t\tcomments_closed_after_days:\n\t\t\t\t\tinput.commentsClosedAfterDays !== undefined\n\t\t\t\t\t\t? input.commentsClosedAfterDays\n\t\t\t\t\t\t: existing.commentsClosedAfterDays,\n\t\t\t\tcomments_auto_approve_users:\n\t\t\t\t\tinput.commentsAutoApproveUsers !== undefined\n\t\t\t\t\t\t? input.commentsAutoApproveUsers\n\t\t\t\t\t\t\t? 1\n\t\t\t\t\t\t\t: 0\n\t\t\t\t\t\t: existing.commentsAutoApproveUsers\n\t\t\t\t\t\t\t? 1\n\t\t\t\t\t\t\t: 0,\n\t\t\t\tupdated_at: now,\n\t\t\t})\n\t\t\t.where(\"slug\", \"=\", slug)\n\t\t\t.execute();\n\n\t\tconst updated = await this.getCollection(slug);\n\t\tif (!updated) {\n\t\t\tthrow new SchemaError(\"Failed to update collection\", \"UPDATE_FAILED\");\n\t\t}\n\n\t\treturn updated;\n\t}\n\n\t/**\n\t * Delete a collection\n\t */\n\tasync deleteCollection(slug: string, options?: { force?: boolean }): Promise<void> {\n\t\tconst existing = await this.getCollection(slug);\n\t\tif (!existing) {\n\t\t\tthrow new SchemaError(`Collection \"${slug}\" not found`, \"COLLECTION_NOT_FOUND\");\n\t\t}\n\n\t\t// Check if collection has content\n\t\tif (!options?.force) {\n\t\t\tconst hasContent = await this.collectionHasContent(slug);\n\t\t\tif (hasContent) {\n\t\t\t\tthrow new SchemaError(\n\t\t\t\t\t`Collection \"${slug}\" has content. Use force: true to delete.`,\n\t\t\t\t\t\"COLLECTION_HAS_CONTENT\",\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\n\t\t// Drop the content table\n\t\tawait this.dropContentTable(slug);\n\n\t\t// Delete the collection record (fields will cascade)\n\t\tawait this.db.deleteFrom(\"_emdash_collections\").where(\"id\", \"=\", existing.id).execute();\n\t}\n\n\t// ============================================\n\t// Field Operations\n\t// ============================================\n\n\t/**\n\t * List fields for a collection\n\t */\n\tasync listFields(collectionId: string): Promise<Field[]> {\n\t\tconst rows = await this.db\n\t\t\t.selectFrom(\"_emdash_fields\")\n\t\t\t.where(\"collection_id\", \"=\", collectionId)\n\t\t\t.selectAll()\n\t\t\t.orderBy(\"sort_order\", \"asc\")\n\t\t\t.orderBy(\"created_at\", \"asc\")\n\t\t\t.execute();\n\n\t\treturn rows.map(this.mapFieldRow);\n\t}\n\n\t/**\n\t * Get a field by slug within a collection\n\t */\n\tasync getField(collectionSlug: string, fieldSlug: string): Promise<Field | null> {\n\t\tconst collection = await this.getCollection(collectionSlug);\n\t\tif (!collection) return null;\n\n\t\tconst row = await this.db\n\t\t\t.selectFrom(\"_emdash_fields\")\n\t\t\t.where(\"collection_id\", \"=\", collection.id)\n\t\t\t.where(\"slug\", \"=\", fieldSlug)\n\t\t\t.selectAll()\n\t\t\t.executeTakeFirst();\n\n\t\treturn row ? this.mapFieldRow(row) : null;\n\t}\n\n\t/**\n\t * Create a new field\n\t */\n\tasync createField(collectionSlug: string, input: CreateFieldInput): Promise<Field> {\n\t\tconst collection = await this.getCollection(collectionSlug);\n\t\tif (!collection) {\n\t\t\tthrow new SchemaError(`Collection \"${collectionSlug}\" not found`, \"COLLECTION_NOT_FOUND\");\n\t\t}\n\n\t\t// Validate slug\n\t\tthis.validateSlug(input.slug, \"field\");\n\t\tif (RESERVED_FIELD_SLUGS.includes(input.slug)) {\n\t\t\tthrow new SchemaError(`Field slug \"${input.slug}\" is reserved`, \"RESERVED_SLUG\");\n\t\t}\n\n\t\t// Check if field already exists\n\t\tconst existing = await this.getField(collectionSlug, input.slug);\n\t\tif (existing) {\n\t\t\tthrow new SchemaError(\n\t\t\t\t`Field \"${input.slug}\" already exists in collection \"${collectionSlug}\"`,\n\t\t\t\t\"FIELD_EXISTS\",\n\t\t\t);\n\t\t}\n\n\t\tconst id = ulid();\n\t\tconst columnType = FIELD_TYPE_TO_COLUMN[input.type];\n\n\t\t// Get max sort order\n\t\tconst maxSort = await this.db\n\t\t\t.selectFrom(\"_emdash_fields\")\n\t\t\t.where(\"collection_id\", \"=\", collection.id)\n\t\t\t.select((eb) => eb.fn.max<number>(\"sort_order\").as(\"max\"))\n\t\t\t.executeTakeFirst();\n\n\t\tconst sortOrder = input.sortOrder ?? (maxSort?.max ?? -1) + 1;\n\n\t\t// Insert field record\n\t\tawait this.db\n\t\t\t.insertInto(\"_emdash_fields\")\n\t\t\t.values({\n\t\t\t\tid,\n\t\t\t\tcollection_id: collection.id,\n\t\t\t\tslug: input.slug,\n\t\t\t\tlabel: input.label,\n\t\t\t\ttype: input.type,\n\t\t\t\tcolumn_type: columnType,\n\t\t\t\trequired: input.required ? 1 : 0,\n\t\t\t\tunique: input.unique ? 1 : 0,\n\t\t\t\tdefault_value: input.defaultValue !== undefined ? JSON.stringify(input.defaultValue) : null,\n\t\t\t\tvalidation: input.validation ? JSON.stringify(input.validation) : null,\n\t\t\t\twidget: input.widget ?? null,\n\t\t\t\toptions: input.options ? JSON.stringify(input.options) : null,\n\t\t\t\tsort_order: sortOrder,\n\t\t\t\tsearchable: input.searchable ? 1 : 0,\n\t\t\t\ttranslatable: input.translatable === false ? 0 : 1,\n\t\t\t})\n\t\t\t.execute();\n\n\t\t// Add column to content table\n\t\tawait this.addColumn(collectionSlug, input.slug, input.type, {\n\t\t\trequired: input.required,\n\t\t\tdefaultValue: input.defaultValue,\n\t\t});\n\n\t\tconst field = await this.getField(collectionSlug, input.slug);\n\t\tif (!field) {\n\t\t\tthrow new SchemaError(\"Failed to create field\", \"CREATE_FAILED\");\n\t\t}\n\n\t\treturn field;\n\t}\n\n\t/**\n\t * Update a field\n\t */\n\tasync updateField(\n\t\tcollectionSlug: string,\n\t\tfieldSlug: string,\n\t\tinput: UpdateFieldInput,\n\t): Promise<Field> {\n\t\tconst field = await this.getField(collectionSlug, fieldSlug);\n\t\tif (!field) {\n\t\t\tthrow new SchemaError(\n\t\t\t\t`Field \"${fieldSlug}\" not found in collection \"${collectionSlug}\"`,\n\t\t\t\t\"FIELD_NOT_FOUND\",\n\t\t\t);\n\t\t}\n\n\t\tawait this.db\n\t\t\t.updateTable(\"_emdash_fields\")\n\t\t\t.set({\n\t\t\t\tlabel: input.label ?? field.label,\n\t\t\t\trequired: input.required !== undefined ? (input.required ? 1 : 0) : field.required ? 1 : 0,\n\t\t\t\tunique: input.unique !== undefined ? (input.unique ? 1 : 0) : field.unique ? 1 : 0,\n\t\t\t\tsearchable:\n\t\t\t\t\tinput.searchable !== undefined ? (input.searchable ? 1 : 0) : field.searchable ? 1 : 0,\n\t\t\t\ttranslatable:\n\t\t\t\t\tinput.translatable !== undefined\n\t\t\t\t\t\t? input.translatable\n\t\t\t\t\t\t\t? 1\n\t\t\t\t\t\t\t: 0\n\t\t\t\t\t\t: field.translatable\n\t\t\t\t\t\t\t? 1\n\t\t\t\t\t\t\t: 0,\n\t\t\t\tdefault_value:\n\t\t\t\t\tinput.defaultValue !== undefined\n\t\t\t\t\t\t? JSON.stringify(input.defaultValue)\n\t\t\t\t\t\t: field.defaultValue !== undefined\n\t\t\t\t\t\t\t? JSON.stringify(field.defaultValue)\n\t\t\t\t\t\t\t: null,\n\t\t\t\tvalidation: input.validation\n\t\t\t\t\t? JSON.stringify(input.validation)\n\t\t\t\t\t: field.validation\n\t\t\t\t\t\t? JSON.stringify(field.validation)\n\t\t\t\t\t\t: null,\n\t\t\t\twidget: input.widget ?? field.widget ?? null,\n\t\t\t\toptions: input.options\n\t\t\t\t\t? JSON.stringify(input.options)\n\t\t\t\t\t: field.options\n\t\t\t\t\t\t? JSON.stringify(field.options)\n\t\t\t\t\t\t: null,\n\t\t\t\tsort_order: input.sortOrder ?? field.sortOrder,\n\t\t\t})\n\t\t\t.where(\"id\", \"=\", field.id)\n\t\t\t.execute();\n\n\t\tconst updated = await this.getField(collectionSlug, fieldSlug);\n\t\tif (!updated) {\n\t\t\tthrow new SchemaError(\"Failed to update field\", \"UPDATE_FAILED\");\n\t\t}\n\n\t\t// If searchable changed, rebuild the FTS index for this collection\n\t\tconst searchableChanged =\n\t\t\tinput.searchable !== undefined && input.searchable !== field.searchable;\n\t\tif (searchableChanged) {\n\t\t\tawait this.rebuildSearchIndex(collectionSlug);\n\t\t}\n\n\t\treturn updated;\n\t}\n\n\t/**\n\t * Rebuild the search index for a collection\n\t *\n\t * Called when searchable fields change. If search is enabled for the collection,\n\t * this will rebuild the FTS table with the updated field list.\n\t */\n\tprivate async rebuildSearchIndex(collectionSlug: string): Promise<void> {\n\t\tconst ftsManager = new FTSManager(this.db);\n\n\t\t// Check if search is enabled for this collection\n\t\tconst config = await ftsManager.getSearchConfig(collectionSlug);\n\t\tif (!config?.enabled) {\n\t\t\t// Search not enabled, nothing to do\n\t\t\treturn;\n\t\t}\n\n\t\t// Get current searchable fields\n\t\tconst searchableFields = await ftsManager.getSearchableFields(collectionSlug);\n\n\t\tif (searchableFields.length === 0) {\n\t\t\t// No searchable fields left, disable search\n\t\t\tawait ftsManager.disableSearch(collectionSlug);\n\t\t} else {\n\t\t\t// Rebuild the index with updated fields\n\t\t\tawait ftsManager.rebuildIndex(collectionSlug, searchableFields, config.weights);\n\t\t}\n\t}\n\n\t/**\n\t * Delete a field\n\t */\n\tasync deleteField(collectionSlug: string, fieldSlug: string): Promise<void> {\n\t\tconst field = await this.getField(collectionSlug, fieldSlug);\n\t\tif (!field) {\n\t\t\tthrow new SchemaError(\n\t\t\t\t`Field \"${fieldSlug}\" not found in collection \"${collectionSlug}\"`,\n\t\t\t\t\"FIELD_NOT_FOUND\",\n\t\t\t);\n\t\t}\n\n\t\t// Drop column from content table\n\t\tawait this.dropColumn(collectionSlug, fieldSlug);\n\n\t\t// Delete field record\n\t\tawait this.db.deleteFrom(\"_emdash_fields\").where(\"id\", \"=\", field.id).execute();\n\t}\n\n\t/**\n\t * Reorder fields\n\t */\n\tasync reorderFields(collectionSlug: string, fieldSlugs: string[]): Promise<void> {\n\t\tconst collection = await this.getCollection(collectionSlug);\n\t\tif (!collection) {\n\t\t\tthrow new SchemaError(`Collection \"${collectionSlug}\" not found`, \"COLLECTION_NOT_FOUND\");\n\t\t}\n\n\t\t// Update sort_order for each field\n\t\tfor (let i = 0; i < fieldSlugs.length; i++) {\n\t\t\tawait this.db\n\t\t\t\t.updateTable(\"_emdash_fields\")\n\t\t\t\t.set({ sort_order: i })\n\t\t\t\t.where(\"collection_id\", \"=\", collection.id)\n\t\t\t\t.where(\"slug\", \"=\", fieldSlugs[i])\n\t\t\t\t.execute();\n\t\t}\n\t}\n\n\t// ============================================\n\t// DDL Operations\n\t// ============================================\n\n\t/**\n\t * Create a content table for a collection\n\t */\n\tprivate async createContentTable(slug: string, db?: Kysely<Database>): Promise<void> {\n\t\tconst conn = db ?? this.db;\n\t\tconst tableName = this.getTableName(slug);\n\n\t\tawait conn.schema\n\t\t\t.createTable(tableName)\n\t\t\t.addColumn(\"id\", \"text\", (col) => col.primaryKey())\n\t\t\t.addColumn(\"slug\", \"text\")\n\t\t\t.addColumn(\"status\", \"text\", (col) => col.defaultTo(\"draft\"))\n\t\t\t.addColumn(\"author_id\", \"text\")\n\t\t\t.addColumn(\"primary_byline_id\", \"text\")\n\t\t\t.addColumn(\"created_at\", \"text\", (col) => col.defaultTo(currentTimestamp(conn)))\n\t\t\t.addColumn(\"updated_at\", \"text\", (col) => col.defaultTo(currentTimestamp(conn)))\n\t\t\t.addColumn(\"published_at\", \"text\")\n\t\t\t.addColumn(\"scheduled_at\", \"text\")\n\t\t\t.addColumn(\"deleted_at\", \"text\")\n\t\t\t.addColumn(\"version\", \"integer\", (col) => col.defaultTo(1))\n\t\t\t.addColumn(\"live_revision_id\", \"text\", (col) => col.references(\"revisions.id\"))\n\t\t\t.addColumn(\"draft_revision_id\", \"text\", (col) => col.references(\"revisions.id\"))\n\t\t\t.addColumn(\"locale\", \"text\", (col) => col.notNull().defaultTo(\"en\"))\n\t\t\t.addColumn(\"translation_group\", \"text\")\n\t\t\t.addUniqueConstraint(`${tableName}_slug_locale_unique`, [\"slug\", \"locale\"])\n\t\t\t.execute();\n\n\t\t// Create standard indexes\n\t\tawait sql`\n\t\t\tCREATE INDEX ${sql.ref(`idx_${tableName}_slug`)}\n\t\t\tON ${sql.ref(tableName)} (slug)\n\t\t`.execute(conn);\n\n\t\tawait sql`\n\t\t\tCREATE INDEX ${sql.ref(`idx_${tableName}_scheduled`)}\n\t\t\tON ${sql.ref(tableName)} (scheduled_at)\n\t\t\tWHERE scheduled_at IS NOT NULL\n\t\t`.execute(conn);\n\n\t\tawait sql`\n\t\t\tCREATE INDEX ${sql.ref(`idx_${tableName}_live_revision`)}\n\t\t\tON ${sql.ref(tableName)} (live_revision_id)\n\t\t`.execute(conn);\n\n\t\tawait sql`\n\t\t\tCREATE INDEX ${sql.ref(`idx_${tableName}_draft_revision`)}\n\t\t\tON ${sql.ref(tableName)} (draft_revision_id)\n\t\t`.execute(conn);\n\n\t\tawait sql`\n\t\t\tCREATE INDEX ${sql.ref(`idx_${tableName}_author`)}\n\t\t\tON ${sql.ref(tableName)} (author_id)\n\t\t`.execute(conn);\n\n\t\tawait sql`\n\t\t\tCREATE INDEX ${sql.ref(`idx_${tableName}_primary_byline`)}\n\t\t\tON ${sql.ref(tableName)} (primary_byline_id)\n\t\t`.execute(conn);\n\n\t\tawait sql`\n\t\t\tCREATE INDEX ${sql.ref(`idx_${tableName}_locale`)}\n\t\t\tON ${sql.ref(tableName)} (locale)\n\t\t`.execute(conn);\n\n\t\tawait sql`\n\t\t\tCREATE INDEX ${sql.ref(`idx_${tableName}_translation_group`)}\n\t\t\tON ${sql.ref(tableName)} (translation_group)\n\t\t`.execute(conn);\n\n\t\t// Composite indexes for optimized query performance (see migration 033)\n\t\tawait sql`\n\t\t\tCREATE INDEX ${sql.ref(`idx_${tableName}_deleted_updated_id`)}\n\t\t\tON ${sql.ref(tableName)} (deleted_at, updated_at DESC, id DESC)\n\t\t`.execute(conn);\n\n\t\tawait sql`\n\t\t\tCREATE INDEX ${sql.ref(`idx_${tableName}_deleted_status`)}\n\t\t\tON ${sql.ref(tableName)} (deleted_at, status)\n\t\t`.execute(conn);\n\n\t\tawait sql`\n\t\t\tCREATE INDEX ${sql.ref(`idx_${tableName}_deleted_created_id`)}\n\t\t\tON ${sql.ref(tableName)} (deleted_at, created_at DESC, id DESC)\n\t\t`.execute(conn);\n\n\t\tawait sql`\n\t\t\tCREATE INDEX ${sql.ref(`idx_${tableName}_deleted_published_id`)}\n\t\t\tON ${sql.ref(tableName)} (deleted_at, published_at DESC, id DESC)\n\t\t`.execute(conn);\n\t}\n\n\t/**\n\t * Drop a content table\n\t */\n\tprivate async dropContentTable(slug: string): Promise<void> {\n\t\tconst tableName = this.getTableName(slug);\n\t\tawait sql`DROP TABLE IF EXISTS ${sql.ref(tableName)}`.execute(this.db);\n\t}\n\n\t/**\n\t * Add a column to a content table\n\t */\n\tprivate async addColumn(\n\t\tcollectionSlug: string,\n\t\tfieldSlug: string,\n\t\tfieldType: FieldType,\n\t\toptions?: { required?: boolean; defaultValue?: unknown },\n\t): Promise<void> {\n\t\tconst tableName = this.getTableName(collectionSlug);\n\t\tconst columnType = FIELD_TYPE_TO_COLUMN[fieldType];\n\t\tconst columnName = this.getColumnName(fieldSlug);\n\n\t\t// Build ALTER TABLE statement\n\t\t// Note: SQLite requires DEFAULT for NOT NULL columns in ALTER TABLE\n\t\tif (options?.required && options?.defaultValue !== undefined) {\n\t\t\tconst defaultVal = this.formatDefaultValue(options.defaultValue, fieldType);\n\t\t\tawait sql`\n\t\t\t\tALTER TABLE ${sql.ref(tableName)} \n\t\t\t\tADD COLUMN ${sql.ref(columnName)} ${sql.raw(columnType)} NOT NULL DEFAULT ${sql.raw(defaultVal)}\n\t\t\t`.execute(this.db);\n\t\t} else if (options?.required) {\n\t\t\t// For required fields without default, use empty string/0 as default\n\t\t\tconst defaultVal = this.getEmptyDefault(fieldType);\n\t\t\tawait sql`\n\t\t\t\tALTER TABLE ${sql.ref(tableName)} \n\t\t\t\tADD COLUMN ${sql.ref(columnName)} ${sql.raw(columnType)} NOT NULL DEFAULT ${sql.raw(defaultVal)}\n\t\t\t`.execute(this.db);\n\t\t} else {\n\t\t\tawait sql`\n\t\t\t\tALTER TABLE ${sql.ref(tableName)} \n\t\t\t\tADD COLUMN ${sql.ref(columnName)} ${sql.raw(columnType)}\n\t\t\t`.execute(this.db);\n\t\t}\n\t}\n\n\t/**\n\t * Drop a column from a content table\n\t */\n\tprivate async dropColumn(collectionSlug: string, fieldSlug: string): Promise<void> {\n\t\tconst tableName = this.getTableName(collectionSlug);\n\t\tconst columnName = this.getColumnName(fieldSlug);\n\n\t\tawait sql`\n\t\t\tALTER TABLE ${sql.ref(tableName)} \n\t\t\tDROP COLUMN ${sql.ref(columnName)}\n\t\t`.execute(this.db);\n\t}\n\n\t// ============================================\n\t// Helpers\n\t// ============================================\n\n\t/**\n\t * Check if a collection has any content\n\t */\n\tprivate async collectionHasContent(slug: string): Promise<boolean> {\n\t\tconst tableName = this.getTableName(slug);\n\t\ttry {\n\t\t\tconst result = await sql<{ count: number }>`\n\t\t\t\tSELECT COUNT(*) as count FROM ${sql.ref(tableName)} \n\t\t\t\tWHERE deleted_at IS NULL\n\t\t\t`.execute(this.db);\n\t\t\treturn (result.rows[0]?.count ?? 0) > 0;\n\t\t} catch {\n\t\t\t// Table might not exist\n\t\t\treturn false;\n\t\t}\n\t}\n\n\t/**\n\t * Get table name for a collection\n\t */\n\tprivate getTableName(slug: string): string {\n\t\treturn `ec_${slug}`;\n\t}\n\n\t/**\n\t * Get column name for a field\n\t */\n\tprivate getColumnName(slug: string): string {\n\t\treturn slug;\n\t}\n\n\t/**\n\t * Validate a slug\n\t */\n\tprivate validateSlug(slug: string, type: \"collection\" | \"field\"): void {\n\t\tif (!slug || typeof slug !== \"string\") {\n\t\t\tthrow new SchemaError(`${type} slug is required`, \"INVALID_SLUG\");\n\t\t}\n\n\t\tif (!SLUG_VALIDATION_PATTERN.test(slug)) {\n\t\t\tthrow new SchemaError(\n\t\t\t\t`${type} slug must start with a letter and contain only lowercase letters, numbers, and underscores`,\n\t\t\t\t\"INVALID_SLUG\",\n\t\t\t);\n\t\t}\n\n\t\tif (slug.length > 63) {\n\t\t\tthrow new SchemaError(`${type} slug must be 63 characters or less`, \"INVALID_SLUG\");\n\t\t}\n\t}\n\n\t/**\n\t * Format a default value for SQL.\n\t *\n\t * SQLite `ALTER TABLE ADD COLUMN ... DEFAULT` requires a literal constant\n\t * expression — parameterized values cannot be used here. We manually escape\n\t * single quotes and coerce types to ensure the output is safe.\n\t *\n\t * INTEGER/REAL values are coerced through `Number()` which can only produce\n\t * digits, `.`, `-`, `e`, `Infinity`, or `NaN` — all safe in SQL.\n\t * TEXT/JSON values have single quotes escaped via SQL standard doubling (`''`).\n\t */\n\tprivate formatDefaultValue(value: unknown, fieldType: FieldType): string {\n\t\tif (value === null || value === undefined) {\n\t\t\treturn \"NULL\";\n\t\t}\n\n\t\tconst columnType = FIELD_TYPE_TO_COLUMN[fieldType];\n\n\t\tif (columnType === \"JSON\") {\n\t\t\t// JSON.stringify produces valid JSON; escape single quotes for SQL literal\n\t\t\tconst json = JSON.stringify(value);\n\t\t\treturn `'${json.replace(SINGLE_QUOTE_PATTERN, \"''\")}'`;\n\t\t}\n\n\t\tif (columnType === \"INTEGER\") {\n\t\t\tif (typeof value === \"boolean\") {\n\t\t\t\treturn value ? \"1\" : \"0\";\n\t\t\t}\n\t\t\tconst num = Number(value);\n\t\t\tif (!Number.isFinite(num)) {\n\t\t\t\treturn \"0\";\n\t\t\t}\n\t\t\treturn String(Math.trunc(num));\n\t\t}\n\n\t\tif (columnType === \"REAL\") {\n\t\t\tconst num = Number(value);\n\t\t\tif (!Number.isFinite(num)) {\n\t\t\t\treturn \"0\";\n\t\t\t}\n\t\t\treturn String(num);\n\t\t}\n\n\t\t// TEXT — escape single quotes via SQL standard doubling\n\t\tlet text: string;\n\t\tif (typeof value === \"string\") {\n\t\t\ttext = value;\n\t\t} else if (typeof value === \"number\" || typeof value === \"boolean\") {\n\t\t\ttext = String(value);\n\t\t} else if (typeof value === \"object\" && value !== null) {\n\t\t\ttext = JSON.stringify(value);\n\t\t} else {\n\t\t\ttext = \"\";\n\t\t}\n\t\treturn `'${text.replace(SINGLE_QUOTE_PATTERN, \"''\")}'`;\n\t}\n\n\t/**\n\t * Get empty default for a field type\n\t */\n\tprivate getEmptyDefault(fieldType: FieldType): string {\n\t\tconst columnType = FIELD_TYPE_TO_COLUMN[fieldType];\n\n\t\tswitch (columnType) {\n\t\t\tcase \"INTEGER\":\n\t\t\t\treturn \"0\";\n\t\t\tcase \"REAL\":\n\t\t\t\treturn \"0.0\";\n\t\t\tcase \"JSON\":\n\t\t\t\treturn \"'null'\";\n\t\t\tdefault:\n\t\t\t\treturn \"''\";\n\t\t}\n\t}\n\n\t/**\n\t * Map a collection row to a Collection object\n\t */\n\tprivate mapCollectionRow = (row: Selectable<CollectionTable>): Collection => {\n\t\tconst moderation = row.comments_moderation;\n\t\treturn {\n\t\t\tid: row.id,\n\t\t\tslug: row.slug,\n\t\t\tlabel: row.label,\n\t\t\tlabelSingular: row.label_singular ?? undefined,\n\t\t\tdescription: row.description ?? undefined,\n\t\t\ticon: row.icon ?? undefined,\n\t\t\tsupports: row.supports ? JSON.parse(row.supports) : [],\n\t\t\tsource: row.source && isCollectionSource(row.source) ? row.source : undefined,\n\t\t\thasSeo: row.has_seo === 1,\n\t\t\turlPattern: row.url_pattern ?? undefined,\n\t\t\tcommentsEnabled: row.comments_enabled === 1,\n\t\t\tcommentsModeration:\n\t\t\t\tmoderation === \"all\" || moderation === \"first_time\" || moderation === \"none\"\n\t\t\t\t\t? moderation\n\t\t\t\t\t: \"first_time\",\n\t\t\tcommentsClosedAfterDays: row.comments_closed_after_days ?? 90,\n\t\t\tcommentsAutoApproveUsers: row.comments_auto_approve_users === 1,\n\t\t\tcreatedAt: row.created_at,\n\t\t\tupdatedAt: row.updated_at,\n\t\t};\n\t};\n\n\t/**\n\t * Map a field row to a Field object\n\t */\n\tprivate mapFieldRow = (row: Selectable<FieldTable>): Field => {\n\t\treturn {\n\t\t\tid: row.id,\n\t\t\tcollectionId: row.collection_id,\n\t\t\tslug: row.slug,\n\t\t\tlabel: row.label,\n\t\t\ttype: isFieldType(row.type) ? row.type : \"string\",\n\t\t\tcolumnType: isColumnType(row.column_type) ? row.column_type : \"TEXT\",\n\t\t\trequired: row.required === 1,\n\t\t\tunique: row.unique === 1,\n\t\t\tdefaultValue: row.default_value ? JSON.parse(row.default_value) : undefined,\n\t\t\tvalidation: row.validation ? JSON.parse(row.validation) : undefined,\n\t\t\twidget: row.widget ?? undefined,\n\t\t\toptions: row.options ? JSON.parse(row.options) : undefined,\n\t\t\tsortOrder: row.sort_order,\n\t\t\tsearchable: row.searchable === 1,\n\t\t\ttranslatable: row.translatable !== 0,\n\t\t\tcreatedAt: row.created_at,\n\t\t};\n\t};\n\n\t// ============================================\n\t// Discovery\n\t// ============================================\n\n\t/**\n\t * Discover orphaned content tables\n\t *\n\t * Finds ec_* tables that exist in the database but don't have a\n\t * corresponding entry in _emdash_collections.\n\t */\n\tasync discoverOrphanedTables(): Promise<\n\t\tArray<{ slug: string; tableName: string; rowCount: number }>\n\t> {\n\t\t// Get all ec_* tables\n\t\t// Content tables are ec_* (e.g., ec_posts, ec_pages)\n\t\t// Internal tables are _emdash_* (e.g., _emdash_collections, _emdash_fts_posts)\n\t\tconst allTables = await listTablesLike(this.db, \"ec_%\");\n\n\t\t// Get registered collections\n\t\tconst registered = await this.listCollections();\n\t\tconst registeredSlugs = new Set(registered.map((c) => c.slug));\n\n\t\t// Find orphans\n\t\tconst orphans: Array<{\n\t\t\tslug: string;\n\t\t\ttableName: string;\n\t\t\trowCount: number;\n\t\t}> = [];\n\n\t\tfor (const tableName of allTables) {\n\t\t\tconst slug = tableName.replace(EC_PREFIX_PATTERN, \"\");\n\n\t\t\tif (!registeredSlugs.has(slug)) {\n\t\t\t\t// Count rows in the orphaned table\n\t\t\t\ttry {\n\t\t\t\t\tconst countResult = await sql<{ count: number }>`\n\t\t\t\t\t\tSELECT COUNT(*) as count FROM ${sql.ref(tableName)}\n\t\t\t\t\t\tWHERE deleted_at IS NULL\n\t\t\t\t\t`.execute(this.db);\n\n\t\t\t\t\torphans.push({\n\t\t\t\t\t\tslug,\n\t\t\t\t\t\ttableName,\n\t\t\t\t\t\trowCount: countResult.rows[0]?.count ?? 0,\n\t\t\t\t\t});\n\t\t\t\t} catch {\n\t\t\t\t\t// Table might have unexpected schema, still report it\n\t\t\t\t\torphans.push({\n\t\t\t\t\t\tslug,\n\t\t\t\t\t\ttableName,\n\t\t\t\t\t\trowCount: 0,\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn orphans;\n\t}\n\n\t/**\n\t * Register an orphaned table as a collection\n\t *\n\t * Creates a _emdash_collections entry for an existing ec_* table.\n\t */\n\tasync registerOrphanedTable(\n\t\tslug: string,\n\t\toptions?: {\n\t\t\tlabel?: string;\n\t\t\tlabelSingular?: string;\n\t\t\tdescription?: string;\n\t\t},\n\t): Promise<Collection> {\n\t\t// Verify table exists\n\t\tconst tableName = this.getTableName(slug);\n\t\tconst exists = await tableExists(this.db, tableName);\n\n\t\tif (!exists) {\n\t\t\tthrow new SchemaError(`Table \"${tableName}\" does not exist`, \"TABLE_NOT_FOUND\");\n\t\t}\n\n\t\t// Check if already registered\n\t\tconst existing = await this.getCollection(slug);\n\t\tif (existing) {\n\t\t\tthrow new SchemaError(`Collection \"${slug}\" is already registered`, \"COLLECTION_EXISTS\");\n\t\t}\n\n\t\t// Create collection entry\n\t\tconst id = ulid();\n\t\tconst label = options?.label || this.slugToLabel(slug);\n\n\t\tawait this.db\n\t\t\t.insertInto(\"_emdash_collections\")\n\t\t\t.values({\n\t\t\t\tid,\n\t\t\t\tslug,\n\t\t\t\tlabel,\n\t\t\t\tlabel_singular: options?.labelSingular ?? null,\n\t\t\t\tdescription: options?.description ?? null,\n\t\t\t\ticon: null,\n\t\t\t\tsupports: JSON.stringify([]),\n\t\t\t\tsource: \"discovered\",\n\t\t\t\thas_seo: 0,\n\t\t\t\turl_pattern: null,\n\t\t\t})\n\t\t\t.execute();\n\n\t\tconst collection = await this.getCollection(slug);\n\t\tif (!collection) {\n\t\t\tthrow new SchemaError(\"Failed to register orphaned table\", \"REGISTER_FAILED\");\n\t\t}\n\n\t\treturn collection;\n\t}\n\n\t/**\n\t * Convert slug to human-readable label\n\t */\n\tprivate slugToLabel(slug: string): string {\n\t\treturn slug\n\t\t\t.replace(UNDERSCORE_PATTERN, \" \")\n\t\t\t.replace(WORD_BOUNDARY_PATTERN, (c) => c.toUpperCase());\n\t}\n}\n"],"mappings":"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"}
|