emdash 0.1.1 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (202) hide show
  1. package/dist/{apply-kC39ev1Z.mjs → apply-Bqoekfbe.mjs} +57 -10
  2. package/dist/apply-Bqoekfbe.mjs.map +1 -0
  3. package/dist/astro/index.d.mts +23 -9
  4. package/dist/astro/index.d.mts.map +1 -1
  5. package/dist/astro/index.mjs +90 -25
  6. package/dist/astro/index.mjs.map +1 -1
  7. package/dist/astro/middleware/auth.d.mts +3 -3
  8. package/dist/astro/middleware/auth.d.mts.map +1 -1
  9. package/dist/astro/middleware/auth.mjs +126 -55
  10. package/dist/astro/middleware/auth.mjs.map +1 -1
  11. package/dist/astro/middleware/redirect.mjs +2 -2
  12. package/dist/astro/middleware/request-context.mjs +1 -1
  13. package/dist/astro/middleware.d.mts.map +1 -1
  14. package/dist/astro/middleware.mjs +80 -41
  15. package/dist/astro/middleware.mjs.map +1 -1
  16. package/dist/astro/types.d.mts +27 -6
  17. package/dist/astro/types.d.mts.map +1 -1
  18. package/dist/{byline-CL847F26.mjs → byline-BGj9p9Ht.mjs} +53 -31
  19. package/dist/byline-BGj9p9Ht.mjs.map +1 -0
  20. package/dist/{bylines-C2a-2TGt.mjs → bylines-BihaoIDY.mjs} +12 -10
  21. package/dist/{bylines-C2a-2TGt.mjs.map → bylines-BihaoIDY.mjs.map} +1 -1
  22. package/dist/cli/index.mjs +17 -14
  23. package/dist/cli/index.mjs.map +1 -1
  24. package/dist/{config-CKE8p9xM.mjs → config-Cq8H0SfX.mjs} +2 -10
  25. package/dist/{config-CKE8p9xM.mjs.map → config-Cq8H0SfX.mjs.map} +1 -1
  26. package/dist/{content-D6C2WsZC.mjs → content-BsBoyj8G.mjs} +35 -5
  27. package/dist/content-BsBoyj8G.mjs.map +1 -0
  28. package/dist/db/index.mjs +2 -2
  29. package/dist/{default-Cyi4aAxu.mjs → default-WYlzADZL.mjs} +1 -1
  30. package/dist/{default-Cyi4aAxu.mjs.map → default-WYlzADZL.mjs.map} +1 -1
  31. package/dist/{dialect-helpers-B9uSp2GJ.mjs → dialect-helpers-DhTzaUxP.mjs} +4 -1
  32. package/dist/dialect-helpers-DhTzaUxP.mjs.map +1 -0
  33. package/dist/{error-Cxz0tQeO.mjs → error-DrxtnGPg.mjs} +1 -1
  34. package/dist/{error-Cxz0tQeO.mjs.map → error-DrxtnGPg.mjs.map} +1 -1
  35. package/dist/{index-CLBc4gw-.d.mts → index-Cff7AimE.d.mts} +77 -15
  36. package/dist/index-Cff7AimE.d.mts.map +1 -0
  37. package/dist/index.d.mts +6 -6
  38. package/dist/index.mjs +19 -19
  39. package/dist/{load-yOOlckBj.mjs → load-Veizk2cT.mjs} +1 -1
  40. package/dist/{load-yOOlckBj.mjs.map → load-Veizk2cT.mjs.map} +1 -1
  41. package/dist/{loader-fz8Q_3EO.mjs → loader-BmYdf3Dr.mjs} +4 -2
  42. package/dist/loader-BmYdf3Dr.mjs.map +1 -0
  43. package/dist/{manifest-schema-CL8DWO9b.mjs → manifest-schema-CuMio1A9.mjs} +1 -1
  44. package/dist/{manifest-schema-CL8DWO9b.mjs.map → manifest-schema-CuMio1A9.mjs.map} +1 -1
  45. package/dist/media/local-runtime.d.mts +4 -4
  46. package/dist/page/index.d.mts +10 -1
  47. package/dist/page/index.d.mts.map +1 -1
  48. package/dist/page/index.mjs +8 -4
  49. package/dist/page/index.mjs.map +1 -1
  50. package/dist/plugins/adapt-sandbox-entry.d.mts +3 -3
  51. package/dist/plugins/adapt-sandbox-entry.mjs +1 -1
  52. package/dist/{query-BVYN0PJ6.mjs → query-sesiOndV.mjs} +20 -8
  53. package/dist/{query-BVYN0PJ6.mjs.map → query-sesiOndV.mjs.map} +1 -1
  54. package/dist/{redirect-DIfIni3r.mjs → redirect-DUAk-Yl_.mjs} +9 -2
  55. package/dist/redirect-DUAk-Yl_.mjs.map +1 -0
  56. package/dist/{registry-BNYQKX_d.mjs → registry-DU18yVo0.mjs} +14 -4
  57. package/dist/registry-DU18yVo0.mjs.map +1 -0
  58. package/dist/{runner-BraqvGYk.mjs → runner-Biufrii2.mjs} +157 -132
  59. package/dist/runner-Biufrii2.mjs.map +1 -0
  60. package/dist/runner-EAtf0ZIe.d.mts.map +1 -1
  61. package/dist/runtime.d.mts +3 -3
  62. package/dist/runtime.mjs +2 -2
  63. package/dist/{search-C1gg67nN.mjs → search-BXB-jfu2.mjs} +241 -109
  64. package/dist/search-BXB-jfu2.mjs.map +1 -0
  65. package/dist/seed/index.d.mts +1 -1
  66. package/dist/seed/index.mjs +10 -10
  67. package/dist/seo/index.d.mts +1 -1
  68. package/dist/storage/local.d.mts +1 -1
  69. package/dist/storage/local.mjs +1 -1
  70. package/dist/storage/s3.d.mts +11 -3
  71. package/dist/storage/s3.d.mts.map +1 -1
  72. package/dist/storage/s3.mjs +76 -15
  73. package/dist/storage/s3.mjs.map +1 -1
  74. package/dist/{tokens-DpgrkrXK.mjs → tokens-DrB-W6Q-.mjs} +1 -1
  75. package/dist/{tokens-DpgrkrXK.mjs.map → tokens-DrB-W6Q-.mjs.map} +1 -1
  76. package/dist/{types-BRuPJGdV.d.mts → types-BbsYgi_R.d.mts} +3 -1
  77. package/dist/types-BbsYgi_R.d.mts.map +1 -0
  78. package/dist/{types-CUBbjgmP.mjs → types-Bec-r_3_.mjs} +1 -1
  79. package/dist/types-Bec-r_3_.mjs.map +1 -0
  80. package/dist/{types-DaNLHo_T.d.mts → types-C1-PVaS_.d.mts} +14 -6
  81. package/dist/types-C1-PVaS_.d.mts.map +1 -0
  82. package/dist/types-CMMN0pNg.mjs.map +1 -1
  83. package/dist/{types-BQo5JS0J.d.mts → types-CaKte3hR.d.mts} +78 -6
  84. package/dist/types-CaKte3hR.d.mts.map +1 -0
  85. package/dist/{types-CiA5Gac0.mjs → types-DuNbGKjF.mjs} +1 -1
  86. package/dist/{types-CiA5Gac0.mjs.map → types-DuNbGKjF.mjs.map} +1 -1
  87. package/dist/{validate-_rsF-Dx_.mjs → validate-CXnRKfJK.mjs} +2 -2
  88. package/dist/{validate-_rsF-Dx_.mjs.map → validate-CXnRKfJK.mjs.map} +1 -1
  89. package/dist/{validate-CqRJb_xU.mjs → validate-VPnKoIzW.mjs} +11 -11
  90. package/dist/{validate-CqRJb_xU.mjs.map → validate-VPnKoIzW.mjs.map} +1 -1
  91. package/dist/{validate-HtxZeaBi.d.mts → validate-bfg9OR6N.d.mts} +2 -2
  92. package/dist/{validate-HtxZeaBi.d.mts.map → validate-bfg9OR6N.d.mts.map} +1 -1
  93. package/dist/version-REAapfsU.mjs +7 -0
  94. package/dist/version-REAapfsU.mjs.map +1 -0
  95. package/package.json +6 -6
  96. package/src/api/csrf.ts +13 -2
  97. package/src/api/handlers/content.ts +7 -0
  98. package/src/api/handlers/dashboard.ts +4 -8
  99. package/src/api/handlers/device-flow.ts +55 -37
  100. package/src/api/handlers/index.ts +6 -1
  101. package/src/api/handlers/redirects.ts +95 -3
  102. package/src/api/handlers/seo.ts +48 -21
  103. package/src/api/public-url.ts +84 -0
  104. package/src/api/schemas/content.ts +2 -2
  105. package/src/api/schemas/menus.ts +12 -2
  106. package/src/api/schemas/redirects.ts +1 -0
  107. package/src/astro/integration/index.ts +30 -7
  108. package/src/astro/integration/routes.ts +13 -2
  109. package/src/astro/integration/runtime.ts +7 -5
  110. package/src/astro/integration/vite-config.ts +55 -9
  111. package/src/astro/middleware/auth.ts +60 -56
  112. package/src/astro/middleware/csp.ts +25 -0
  113. package/src/astro/middleware.ts +31 -3
  114. package/src/astro/routes/PluginRegistry.tsx +8 -2
  115. package/src/astro/routes/admin.astro +7 -2
  116. package/src/astro/routes/api/admin/users/[id]/disable.ts +18 -12
  117. package/src/astro/routes/api/admin/users/[id]/index.ts +26 -5
  118. package/src/astro/routes/api/auth/invite/complete.ts +3 -2
  119. package/src/astro/routes/api/auth/oauth/[provider]/callback.ts +2 -1
  120. package/src/astro/routes/api/auth/oauth/[provider].ts +2 -1
  121. package/src/astro/routes/api/auth/passkey/options.ts +3 -2
  122. package/src/astro/routes/api/auth/passkey/register/options.ts +3 -2
  123. package/src/astro/routes/api/auth/passkey/register/verify.ts +3 -2
  124. package/src/astro/routes/api/auth/passkey/verify.ts +3 -2
  125. package/src/astro/routes/api/auth/signup/complete.ts +3 -2
  126. package/src/astro/routes/api/comments/[collection]/[contentId]/index.ts +2 -0
  127. package/src/astro/routes/api/content/[collection]/index.ts +31 -3
  128. package/src/astro/routes/api/import/wordpress/execute.ts +9 -0
  129. package/src/astro/routes/api/import/wordpress/rewrite-urls.ts +2 -0
  130. package/src/astro/routes/api/import/wordpress-plugin/execute.ts +10 -0
  131. package/src/astro/routes/api/manifest.ts +4 -1
  132. package/src/astro/routes/api/media/providers/[providerId]/[itemId].ts +7 -2
  133. package/src/astro/routes/api/oauth/authorize.ts +12 -7
  134. package/src/astro/routes/api/oauth/device/code.ts +5 -1
  135. package/src/astro/routes/api/setup/admin-verify.ts +3 -2
  136. package/src/astro/routes/api/setup/admin.ts +3 -2
  137. package/src/astro/routes/api/setup/dev-bypass.ts +2 -1
  138. package/src/astro/routes/api/setup/index.ts +3 -2
  139. package/src/astro/routes/api/snapshot.ts +2 -1
  140. package/src/astro/routes/api/themes/preview.ts +2 -1
  141. package/src/astro/routes/api/well-known/auth.ts +1 -0
  142. package/src/astro/routes/api/well-known/oauth-authorization-server.ts +3 -2
  143. package/src/astro/routes/api/well-known/oauth-protected-resource.ts +3 -2
  144. package/src/astro/routes/robots.txt.ts +5 -1
  145. package/src/astro/routes/sitemap-[collection].xml.ts +104 -0
  146. package/src/astro/routes/sitemap.xml.ts +18 -23
  147. package/src/astro/storage/adapters.ts +19 -5
  148. package/src/astro/storage/types.ts +12 -4
  149. package/src/astro/types.ts +28 -1
  150. package/src/auth/passkey-config.ts +6 -10
  151. package/src/bylines/index.ts +13 -10
  152. package/src/cli/commands/login.ts +5 -2
  153. package/src/components/InlinePortableTextEditor.tsx +5 -3
  154. package/src/content/converters/portable-text-to-prosemirror.ts +50 -2
  155. package/src/database/dialect-helpers.ts +3 -0
  156. package/src/database/migrations/034_published_at_index.ts +29 -0
  157. package/src/database/migrations/runner.ts +2 -0
  158. package/src/database/repositories/byline.ts +48 -42
  159. package/src/database/repositories/content.ts +28 -1
  160. package/src/database/repositories/options.ts +9 -3
  161. package/src/database/repositories/redirect.ts +13 -0
  162. package/src/database/repositories/seo.ts +34 -17
  163. package/src/database/repositories/types.ts +2 -0
  164. package/src/database/validate.ts +10 -10
  165. package/src/emdash-runtime.ts +66 -19
  166. package/src/import/index.ts +1 -1
  167. package/src/import/sources/wxr.ts +45 -2
  168. package/src/index.ts +10 -1
  169. package/src/loader.ts +2 -0
  170. package/src/mcp/server.ts +85 -5
  171. package/src/menus/index.ts +6 -1
  172. package/src/page/context.ts +13 -1
  173. package/src/page/jsonld.ts +10 -6
  174. package/src/page/seo-contributions.ts +1 -1
  175. package/src/plugins/context.ts +145 -35
  176. package/src/plugins/manager.ts +12 -0
  177. package/src/plugins/types.ts +80 -4
  178. package/src/query.ts +18 -0
  179. package/src/redirects/loops.ts +318 -0
  180. package/src/schema/registry.ts +8 -0
  181. package/src/search/fts-manager.ts +4 -0
  182. package/src/settings/index.ts +64 -0
  183. package/src/storage/s3.ts +94 -25
  184. package/src/storage/types.ts +13 -5
  185. package/src/utils/chunks.ts +17 -0
  186. package/src/utils/slugify.ts +11 -0
  187. package/src/version.ts +12 -0
  188. package/dist/apply-kC39ev1Z.mjs.map +0 -1
  189. package/dist/byline-CL847F26.mjs.map +0 -1
  190. package/dist/content-D6C2WsZC.mjs.map +0 -1
  191. package/dist/dialect-helpers-B9uSp2GJ.mjs.map +0 -1
  192. package/dist/index-CLBc4gw-.d.mts.map +0 -1
  193. package/dist/loader-fz8Q_3EO.mjs.map +0 -1
  194. package/dist/redirect-DIfIni3r.mjs.map +0 -1
  195. package/dist/registry-BNYQKX_d.mjs.map +0 -1
  196. package/dist/runner-BraqvGYk.mjs.map +0 -1
  197. package/dist/search-C1gg67nN.mjs.map +0 -1
  198. package/dist/types-BQo5JS0J.d.mts.map +0 -1
  199. package/dist/types-BRuPJGdV.d.mts.map +0 -1
  200. package/dist/types-CUBbjgmP.mjs.map +0 -1
  201. package/dist/types-DaNLHo_T.d.mts.map +0 -1
  202. /package/src/astro/routes/api/media/file/{[key].ts → [...key].ts} +0 -0
package/src/version.ts ADDED
@@ -0,0 +1,12 @@
1
+ /**
2
+ * Build-time version constants, replaced by tsdown/Vite `define`.
3
+ * Falls back to "dev" when running uncompiled (tests, dev).
4
+ */
5
+
6
+ declare const __EMDASH_VERSION__: string;
7
+ declare const __EMDASH_COMMIT__: string;
8
+
9
+ export const VERSION: string =
10
+ typeof __EMDASH_VERSION__ !== "undefined" ? __EMDASH_VERSION__ : "dev";
11
+
12
+ export const COMMIT: string = typeof __EMDASH_COMMIT__ !== "undefined" ? __EMDASH_COMMIT__ : "dev";
@@ -1 +0,0 @@
1
- {"version":3,"file":"apply-kC39ev1Z.mjs","names":[],"sources":["../src/database/repositories/taxonomy.ts","../src/database/repositories/options.ts","../src/settings/index.ts","../src/import/ssrf.ts","../src/seed/apply.ts"],"sourcesContent":["import type { Kysely } from \"kysely\";\nimport { ulid } from \"ulidx\";\n\nimport type { Database, TaxonomyTable, ContentTaxonomyTable } from \"../types.js\";\n\nexport interface Taxonomy {\n\tid: string;\n\tname: string;\n\tslug: string;\n\tlabel: string;\n\tparentId: string | null;\n\tdata: Record<string, unknown> | null;\n}\n\nexport interface CreateTaxonomyInput {\n\tname: string;\n\tslug: string;\n\tlabel: string;\n\tparentId?: string;\n\tdata?: Record<string, unknown>;\n}\n\nexport interface UpdateTaxonomyInput {\n\tslug?: string;\n\tlabel?: string;\n\tparentId?: string | null;\n\tdata?: Record<string, unknown>;\n}\n\n/**\n * Taxonomy repository for categories, tags, and other classification\n *\n * Taxonomies are hierarchical (via parentId) and can be attached to content entries.\n */\nexport class TaxonomyRepository {\n\tconstructor(private db: Kysely<Database>) {}\n\n\t/**\n\t * Create a new taxonomy term\n\t */\n\tasync create(input: CreateTaxonomyInput): Promise<Taxonomy> {\n\t\tconst id = ulid();\n\n\t\tconst row: TaxonomyTable = {\n\t\t\tid,\n\t\t\tname: input.name,\n\t\t\tslug: input.slug,\n\t\t\tlabel: input.label,\n\t\t\tparent_id: input.parentId ?? null,\n\t\t\tdata: input.data ? JSON.stringify(input.data) : null,\n\t\t};\n\n\t\tawait this.db.insertInto(\"taxonomies\").values(row).execute();\n\n\t\tconst taxonomy = await this.findById(id);\n\t\tif (!taxonomy) {\n\t\t\tthrow new Error(\"Failed to create taxonomy\");\n\t\t}\n\t\treturn taxonomy;\n\t}\n\n\t/**\n\t * Find taxonomy by ID\n\t */\n\tasync findById(id: string): Promise<Taxonomy | null> {\n\t\tconst row = await this.db\n\t\t\t.selectFrom(\"taxonomies\")\n\t\t\t.selectAll()\n\t\t\t.where(\"id\", \"=\", id)\n\t\t\t.executeTakeFirst();\n\n\t\treturn row ? this.rowToTaxonomy(row) : null;\n\t}\n\n\t/**\n\t * Find taxonomy by name and slug (unique constraint)\n\t */\n\tasync findBySlug(name: string, slug: string): Promise<Taxonomy | null> {\n\t\tconst row = await this.db\n\t\t\t.selectFrom(\"taxonomies\")\n\t\t\t.selectAll()\n\t\t\t.where(\"name\", \"=\", name)\n\t\t\t.where(\"slug\", \"=\", slug)\n\t\t\t.executeTakeFirst();\n\n\t\treturn row ? this.rowToTaxonomy(row) : null;\n\t}\n\n\t/**\n\t * Get all terms for a taxonomy (e.g., all categories)\n\t */\n\tasync findByName(name: string, options: { parentId?: string | null } = {}): Promise<Taxonomy[]> {\n\t\tlet query = this.db\n\t\t\t.selectFrom(\"taxonomies\")\n\t\t\t.selectAll()\n\t\t\t.where(\"name\", \"=\", name)\n\t\t\t.orderBy(\"label\", \"asc\");\n\n\t\tif (options.parentId !== undefined) {\n\t\t\tif (options.parentId === null) {\n\t\t\t\tquery = query.where(\"parent_id\", \"is\", null);\n\t\t\t} else {\n\t\t\t\tquery = query.where(\"parent_id\", \"=\", options.parentId);\n\t\t\t}\n\t\t}\n\n\t\tconst rows = await query.execute();\n\t\treturn rows.map((row) => this.rowToTaxonomy(row));\n\t}\n\n\t/**\n\t * Get children of a taxonomy term\n\t */\n\tasync findChildren(parentId: string): Promise<Taxonomy[]> {\n\t\tconst rows = await this.db\n\t\t\t.selectFrom(\"taxonomies\")\n\t\t\t.selectAll()\n\t\t\t.where(\"parent_id\", \"=\", parentId)\n\t\t\t.orderBy(\"label\", \"asc\")\n\t\t\t.execute();\n\n\t\treturn rows.map((row) => this.rowToTaxonomy(row));\n\t}\n\n\t/**\n\t * Update a taxonomy term\n\t */\n\tasync update(id: string, input: UpdateTaxonomyInput): Promise<Taxonomy | null> {\n\t\tconst existing = await this.findById(id);\n\t\tif (!existing) return null;\n\n\t\tconst updates: Partial<TaxonomyTable> = {};\n\t\tif (input.slug !== undefined) updates.slug = input.slug;\n\t\tif (input.label !== undefined) updates.label = input.label;\n\t\tif (input.parentId !== undefined) updates.parent_id = input.parentId;\n\t\tif (input.data !== undefined) updates.data = JSON.stringify(input.data);\n\n\t\tif (Object.keys(updates).length > 0) {\n\t\t\tawait this.db.updateTable(\"taxonomies\").set(updates).where(\"id\", \"=\", id).execute();\n\t\t}\n\n\t\treturn this.findById(id);\n\t}\n\n\t/**\n\t * Delete a taxonomy term\n\t */\n\tasync delete(id: string): Promise<boolean> {\n\t\t// First remove any content associations\n\t\tawait this.db.deleteFrom(\"content_taxonomies\").where(\"taxonomy_id\", \"=\", id).execute();\n\n\t\tconst result = await this.db.deleteFrom(\"taxonomies\").where(\"id\", \"=\", id).executeTakeFirst();\n\n\t\treturn (result.numDeletedRows ?? 0) > 0;\n\t}\n\n\t// --- Content-Taxonomy Junction ---\n\n\t/**\n\t * Attach a taxonomy term to a content entry\n\t */\n\tasync attachToEntry(collection: string, entryId: string, taxonomyId: string): Promise<void> {\n\t\tconst row: ContentTaxonomyTable = {\n\t\t\tcollection,\n\t\t\tentry_id: entryId,\n\t\t\ttaxonomy_id: taxonomyId,\n\t\t};\n\n\t\t// Use INSERT OR IGNORE pattern for idempotency\n\t\tawait this.db\n\t\t\t.insertInto(\"content_taxonomies\")\n\t\t\t.values(row)\n\t\t\t.onConflict((oc) => oc.doNothing())\n\t\t\t.execute();\n\t}\n\n\t/**\n\t * Detach a taxonomy term from a content entry\n\t */\n\tasync detachFromEntry(collection: string, entryId: string, taxonomyId: string): Promise<void> {\n\t\tawait this.db\n\t\t\t.deleteFrom(\"content_taxonomies\")\n\t\t\t.where(\"collection\", \"=\", collection)\n\t\t\t.where(\"entry_id\", \"=\", entryId)\n\t\t\t.where(\"taxonomy_id\", \"=\", taxonomyId)\n\t\t\t.execute();\n\t}\n\n\t/**\n\t * Get all taxonomy terms for a content entry\n\t */\n\tasync getTermsForEntry(\n\t\tcollection: string,\n\t\tentryId: string,\n\t\ttaxonomyName?: string,\n\t): Promise<Taxonomy[]> {\n\t\tlet query = this.db\n\t\t\t.selectFrom(\"content_taxonomies\")\n\t\t\t.innerJoin(\"taxonomies\", \"taxonomies.id\", \"content_taxonomies.taxonomy_id\")\n\t\t\t.selectAll(\"taxonomies\")\n\t\t\t.where(\"content_taxonomies.collection\", \"=\", collection)\n\t\t\t.where(\"content_taxonomies.entry_id\", \"=\", entryId);\n\n\t\tif (taxonomyName) {\n\t\t\tquery = query.where(\"taxonomies.name\", \"=\", taxonomyName);\n\t\t}\n\n\t\tconst rows = await query.execute();\n\t\treturn rows.map((row) => this.rowToTaxonomy(row));\n\t}\n\n\t/**\n\t * Set all taxonomy terms for a content entry (replaces existing)\n\t * Uses batch operations to avoid N+1 queries.\n\t */\n\tasync setTermsForEntry(\n\t\tcollection: string,\n\t\tentryId: string,\n\t\ttaxonomyName: string,\n\t\ttaxonomyIds: string[],\n\t): Promise<void> {\n\t\t// Get current terms of this taxonomy type\n\t\tconst current = await this.getTermsForEntry(collection, entryId, taxonomyName);\n\t\tconst currentIds = new Set(current.map((t) => t.id));\n\t\tconst newIds = new Set(taxonomyIds);\n\n\t\t// Batch remove terms no longer present\n\t\tconst toRemove = current.filter((t) => !newIds.has(t.id)).map((t) => t.id);\n\t\tif (toRemove.length > 0) {\n\t\t\tawait this.db\n\t\t\t\t.deleteFrom(\"content_taxonomies\")\n\t\t\t\t.where(\"collection\", \"=\", collection)\n\t\t\t\t.where(\"entry_id\", \"=\", entryId)\n\t\t\t\t.where(\"taxonomy_id\", \"in\", toRemove)\n\t\t\t\t.execute();\n\t\t}\n\n\t\t// Batch add new terms\n\t\tconst toAdd = taxonomyIds.filter((id) => !currentIds.has(id));\n\t\tif (toAdd.length > 0) {\n\t\t\tawait this.db\n\t\t\t\t.insertInto(\"content_taxonomies\")\n\t\t\t\t.values(\n\t\t\t\t\ttoAdd.map((taxonomy_id) => ({\n\t\t\t\t\t\tcollection,\n\t\t\t\t\t\tentry_id: entryId,\n\t\t\t\t\t\ttaxonomy_id,\n\t\t\t\t\t})),\n\t\t\t\t)\n\t\t\t\t.onConflict((oc) => oc.doNothing())\n\t\t\t\t.execute();\n\t\t}\n\t}\n\n\t/**\n\t * Remove all taxonomy associations for an entry (use when entry is deleted)\n\t */\n\tasync clearEntryTerms(collection: string, entryId: string): Promise<number> {\n\t\tconst result = await this.db\n\t\t\t.deleteFrom(\"content_taxonomies\")\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 * Count entries that have a specific taxonomy term\n\t */\n\tasync countEntriesWithTerm(taxonomyId: string): Promise<number> {\n\t\tconst result = await this.db\n\t\t\t.selectFrom(\"content_taxonomies\")\n\t\t\t.select((eb) => eb.fn.count(\"entry_id\").as(\"count\"))\n\t\t\t.where(\"taxonomy_id\", \"=\", taxonomyId)\n\t\t\t.executeTakeFirst();\n\n\t\treturn Number(result?.count || 0);\n\t}\n\n\t/**\n\t * Convert database row to Taxonomy object\n\t */\n\tprivate rowToTaxonomy(row: TaxonomyTable): Taxonomy {\n\t\treturn {\n\t\t\tid: row.id,\n\t\t\tname: row.name,\n\t\t\tslug: row.slug,\n\t\t\tlabel: row.label,\n\t\t\tparentId: row.parent_id,\n\t\t\tdata: row.data ? JSON.parse(row.data) : null,\n\t\t};\n\t}\n}\n","import type { Kysely } from \"kysely\";\n\nimport type { Database, OptionTable } from \"../types.js\";\n\n/**\n * Options repository for key-value settings storage\n *\n * Used for site settings, plugin configuration, and other arbitrary key-value data.\n * Values are stored as JSON for flexibility.\n */\nexport class OptionsRepository {\n\tconstructor(private db: Kysely<Database>) {}\n\n\t/**\n\t * Get an option value\n\t */\n\tasync get<T = unknown>(name: string): Promise<T | null> {\n\t\tconst row = await this.db\n\t\t\t.selectFrom(\"options\")\n\t\t\t.select(\"value\")\n\t\t\t.where(\"name\", \"=\", name)\n\t\t\t.executeTakeFirst();\n\n\t\tif (!row) return null;\n\t\t// eslint-disable-next-line typescript-eslint(no-unsafe-type-assertion) -- JSON.parse returns any; generic callers provide T\n\t\treturn JSON.parse(row.value) as T;\n\t}\n\n\t/**\n\t * Get an option value with a default\n\t */\n\tasync getOrDefault<T>(name: string, defaultValue: T): Promise<T> {\n\t\tconst value = await this.get<T>(name);\n\t\treturn value ?? defaultValue;\n\t}\n\n\t/**\n\t * Set an option value (creates or updates)\n\t */\n\tasync set<T = unknown>(name: string, value: T): Promise<void> {\n\t\tconst row: OptionTable = {\n\t\t\tname,\n\t\t\tvalue: JSON.stringify(value),\n\t\t};\n\n\t\t// Upsert: insert or replace\n\t\tawait this.db\n\t\t\t.insertInto(\"options\")\n\t\t\t.values(row)\n\t\t\t.onConflict((oc) => oc.column(\"name\").doUpdateSet({ value: row.value }))\n\t\t\t.execute();\n\t}\n\n\t/**\n\t * Delete an option\n\t */\n\tasync delete(name: string): Promise<boolean> {\n\t\tconst result = await this.db.deleteFrom(\"options\").where(\"name\", \"=\", name).executeTakeFirst();\n\n\t\treturn (result.numDeletedRows ?? 0) > 0;\n\t}\n\n\t/**\n\t * Check if an option exists\n\t */\n\tasync exists(name: string): Promise<boolean> {\n\t\tconst row = await this.db\n\t\t\t.selectFrom(\"options\")\n\t\t\t.select(\"name\")\n\t\t\t.where(\"name\", \"=\", name)\n\t\t\t.executeTakeFirst();\n\n\t\treturn !!row;\n\t}\n\n\t/**\n\t * Get multiple options at once\n\t */\n\tasync getMany<T = unknown>(names: string[]): Promise<Map<string, T>> {\n\t\tif (names.length === 0) return new Map();\n\n\t\tconst rows = await this.db\n\t\t\t.selectFrom(\"options\")\n\t\t\t.select([\"name\", \"value\"])\n\t\t\t.where(\"name\", \"in\", names)\n\t\t\t.execute();\n\n\t\tconst result = new Map<string, T>();\n\t\tfor (const row of rows) {\n\t\t\t// eslint-disable-next-line typescript-eslint(no-unsafe-type-assertion) -- JSON.parse returns any; generic callers provide T\n\t\t\tresult.set(row.name, JSON.parse(row.value) as T);\n\t\t}\n\t\treturn result;\n\t}\n\n\t/**\n\t * Set multiple options at once\n\t */\n\tasync setMany<T = unknown>(options: Record<string, T>): Promise<void> {\n\t\tconst entries = Object.entries(options);\n\t\tif (entries.length === 0) return;\n\n\t\tfor (const [name, value] of entries) {\n\t\t\tawait this.set(name, value);\n\t\t}\n\t}\n\n\t/**\n\t * Get all options (use sparingly)\n\t */\n\tasync getAll(): Promise<Map<string, unknown>> {\n\t\tconst rows = await this.db.selectFrom(\"options\").select([\"name\", \"value\"]).execute();\n\n\t\tconst result = new Map<string, unknown>();\n\t\tfor (const row of rows) {\n\t\t\tresult.set(row.name, JSON.parse(row.value));\n\t\t}\n\t\treturn result;\n\t}\n\n\t/**\n\t * Get all options matching a prefix\n\t */\n\tasync getByPrefix<T = unknown>(prefix: string): Promise<Map<string, T>> {\n\t\tconst rows = await this.db\n\t\t\t.selectFrom(\"options\")\n\t\t\t.select([\"name\", \"value\"])\n\t\t\t.where(\"name\", \"like\", `${prefix}%`)\n\t\t\t.execute();\n\n\t\tconst result = new Map<string, T>();\n\t\tfor (const row of rows) {\n\t\t\t// eslint-disable-next-line typescript-eslint(no-unsafe-type-assertion) -- JSON.parse returns any; generic callers provide T\n\t\t\tresult.set(row.name, JSON.parse(row.value) as T);\n\t\t}\n\t\treturn result;\n\t}\n\n\t/**\n\t * Delete all options matching a prefix\n\t */\n\tasync deleteByPrefix(prefix: string): Promise<number> {\n\t\tconst result = await this.db\n\t\t\t.deleteFrom(\"options\")\n\t\t\t.where(\"name\", \"like\", `${prefix}%`)\n\t\t\t.executeTakeFirst();\n\n\t\treturn Number(result.numDeletedRows ?? 0);\n\t}\n}\n","/**\n * Site Settings API\n *\n * Functions for getting and setting global site configuration.\n * Settings are stored in the options table with 'site:' prefix.\n */\n\nimport type { Kysely } from \"kysely\";\n\nimport { MediaRepository } from \"../database/repositories/media.js\";\nimport { OptionsRepository } from \"../database/repositories/options.js\";\nimport type { Database } from \"../database/types.js\";\nimport { getDb } from \"../loader.js\";\nimport type { Storage } from \"../storage/types.js\";\nimport type { SiteSettings, SiteSettingKey, MediaReference } from \"./types.js\";\n\n/** Prefix for site settings in the options table */\nconst SETTINGS_PREFIX = \"site:\";\n\n/**\n * Type guard for MediaReference values\n */\nfunction isMediaReference(value: unknown): value is MediaReference {\n\treturn typeof value === \"object\" && value !== null && \"mediaId\" in value;\n}\n\n/**\n * Resolve a media reference to include the full URL\n */\nasync function resolveMediaReference(\n\tmediaRef: MediaReference | undefined,\n\tdb: Kysely<Database>,\n\t_storage: Storage | null,\n): Promise<(MediaReference & { url?: string }) | undefined> {\n\tif (!mediaRef?.mediaId) {\n\t\treturn mediaRef;\n\t}\n\n\ttry {\n\t\tconst mediaRepo = new MediaRepository(db);\n\t\tconst media = await mediaRepo.findById(mediaRef.mediaId);\n\n\t\tif (media) {\n\t\t\t// Construct URL using the same pattern as API handlers\n\t\t\treturn {\n\t\t\t\t...mediaRef,\n\t\t\t\turl: `/_emdash/api/media/file/${media.storageKey}`,\n\t\t\t};\n\t\t}\n\t} catch {\n\t\t// If media not found or error, return the reference as-is\n\t}\n\n\treturn mediaRef;\n}\n\n/**\n * Get a single site setting by key\n *\n * Returns `undefined` if the setting has not been configured.\n * For media settings (logo, favicon), the URL is resolved automatically.\n *\n * @param key - The setting key (e.g., \"title\", \"logo\", \"social\")\n * @returns The setting value, or undefined if not set\n *\n * @example\n * ```ts\n * import { getSiteSetting } from \"emdash\";\n *\n * const title = await getSiteSetting(\"title\");\n * const logo = await getSiteSetting(\"logo\");\n * console.log(logo?.url); // Resolved URL\n * ```\n */\nexport async function getSiteSetting<K extends SiteSettingKey>(\n\tkey: K,\n): Promise<SiteSettings[K] | undefined> {\n\tconst db = await getDb();\n\treturn getSiteSettingWithDb(key, db);\n}\n\n/**\n * Get a single site setting by key (with explicit db)\n *\n * @internal Use `getSiteSetting()` in templates. This variant is for admin routes\n * that already have a database handle.\n */\nexport async function getSiteSettingWithDb<K extends SiteSettingKey>(\n\tkey: K,\n\tdb: Kysely<Database>,\n\tstorage: Storage | null = null,\n): Promise<SiteSettings[K] | undefined> {\n\tconst options = new OptionsRepository(db);\n\tconst value = await options.get<SiteSettings[K]>(`${SETTINGS_PREFIX}${key}`);\n\n\tif (!value) {\n\t\treturn undefined;\n\t}\n\n\t// Resolve media references if needed.\n\t// TS cannot narrow generic K from key equality checks — this is a known limitation.\n\t// We use the non-generic getSiteSettingsWithDb for media resolution instead.\n\tif ((key === \"logo\" || key === \"favicon\") && isMediaReference(value)) {\n\t\tconst resolved = await resolveMediaReference(value, db, storage);\n\t\t// eslint-disable-next-line typescript-eslint(no-unsafe-type-assertion) -- TS can't narrow generic K from key equality; resolved type is correct\n\t\treturn resolved as SiteSettings[K] | undefined;\n\t}\n\n\treturn value;\n}\n\n/**\n * Get all site settings\n *\n * Returns all configured settings. Unset values are undefined.\n * Media references (logo/favicon) are resolved to include URLs.\n *\n * @example\n * ```ts\n * import { getSiteSettings } from \"emdash\";\n *\n * const settings = await getSiteSettings();\n * console.log(settings.title); // \"My Site\"\n * console.log(settings.logo?.url); // \"/_emdash/api/media/file/abc123\"\n * ```\n */\nexport async function getSiteSettings(): Promise<Partial<SiteSettings>> {\n\tconst db = await getDb();\n\treturn getSiteSettingsWithDb(db);\n}\n\n/**\n * Get all site settings (with explicit db)\n *\n * @internal Use `getSiteSettings()` in templates. This variant is for admin routes\n * that already have a database handle.\n */\nexport async function getSiteSettingsWithDb(\n\tdb: Kysely<Database>,\n\tstorage: Storage | null = null,\n): Promise<Partial<SiteSettings>> {\n\tconst options = new OptionsRepository(db);\n\tconst allOptions = await options.getByPrefix(SETTINGS_PREFIX);\n\n\tconst settings: Record<string, unknown> = {};\n\n\t// Convert Map to settings object, removing the prefix\n\tfor (const [key, value] of allOptions) {\n\t\tconst settingKey = key.replace(SETTINGS_PREFIX, \"\");\n\t\tsettings[settingKey] = value;\n\t}\n\n\tconst typedSettings = settings as Partial<SiteSettings>;\n\n\t// Resolve media references\n\tif (typedSettings.logo) {\n\t\ttypedSettings.logo = await resolveMediaReference(typedSettings.logo, db, storage);\n\t}\n\tif (typedSettings.favicon) {\n\t\ttypedSettings.favicon = await resolveMediaReference(typedSettings.favicon, db, storage);\n\t}\n\n\treturn typedSettings;\n}\n\n/**\n * Set site settings (internal function used by admin API)\n *\n * Merges provided settings with existing ones. Only provided fields are updated.\n * Media references should include just the mediaId; URLs are resolved on read.\n *\n * @param settings - Partial settings object with values to update\n * @param db - Kysely database instance\n * @returns Promise that resolves when settings are saved\n *\n * @internal\n *\n * @example\n * ```ts\n * // Update multiple settings at once\n * await setSiteSettings({\n * title: \"My Site\",\n * tagline: \"Welcome\",\n * logo: { mediaId: \"med_123\", alt: \"Logo\" }\n * }, db);\n * ```\n */\nexport async function setSiteSettings(\n\tsettings: Partial<SiteSettings>,\n\tdb: Kysely<Database>,\n): Promise<void> {\n\tconst options = new OptionsRepository(db);\n\n\t// Convert settings to options format\n\tconst updates: Record<string, unknown> = {};\n\tfor (const [key, value] of Object.entries(settings)) {\n\t\tif (value !== undefined) {\n\t\t\tupdates[`${SETTINGS_PREFIX}${key}`] = value;\n\t\t}\n\t}\n\n\tawait options.setMany(updates);\n}\n","/**\n * SSRF protection for import URLs.\n *\n * Validates that URLs don't target internal/private network addresses.\n * Applied before any fetch() call in the import pipeline.\n */\n\nconst IPV4_MAPPED_IPV6_DOTTED_PATTERN = /^::ffff:(\\d+\\.\\d+\\.\\d+\\.\\d+)$/i;\nconst IPV4_MAPPED_IPV6_HEX_PATTERN = /^::ffff:([0-9a-f]{1,4}):([0-9a-f]{1,4})$/i;\nconst IPV4_TRANSLATED_HEX_PATTERN = /^::ffff:0:([0-9a-f]{1,4}):([0-9a-f]{1,4})$/i;\nconst IPV6_EXPANDED_MAPPED_PATTERN =\n\t/^0{0,4}:0{0,4}:0{0,4}:0{0,4}:0{0,4}:ffff:([0-9a-f]{1,4}):([0-9a-f]{1,4})$/i;\n\n/**\n * IPv4-compatible (deprecated) addresses: ::XXXX:XXXX\n *\n * The WHATWG URL parser normalizes [::127.0.0.1] to [::7f00:1] (no ffff prefix).\n * These are deprecated but still parsed, and bypass the ffff-based checks.\n */\nconst IPV4_COMPATIBLE_HEX_PATTERN = /^::([0-9a-f]{1,4}):([0-9a-f]{1,4})$/i;\n\n/**\n * NAT64 prefix (RFC 6052): 64:ff9b::XXXX:XXXX\n *\n * Used by NAT64 gateways to embed IPv4 addresses in IPv6.\n * [64:ff9b::127.0.0.1] normalizes to [64:ff9b::7f00:1].\n */\nconst NAT64_HEX_PATTERN = /^64:ff9b::([0-9a-f]{1,4}):([0-9a-f]{1,4})$/i;\n\nconst IPV6_BRACKET_PATTERN = /^\\[|\\]$/g;\n\n/**\n * Private and reserved IP ranges that should never be fetched.\n *\n * Includes:\n * - Loopback (127.0.0.0/8)\n * - Private (10.0.0.0/8, 172.16.0.0/12, 192.168.0.0/16)\n * - Link-local (169.254.0.0/16)\n * - Cloud metadata (169.254.169.254 — AWS/GCP/Azure)\n * - IPv6 loopback and link-local\n */\nconst BLOCKED_PATTERNS: Array<{ start: number; end: number }> = [\n\t// 127.0.0.0/8 — loopback\n\t{ start: ip4ToNum(127, 0, 0, 0), end: ip4ToNum(127, 255, 255, 255) },\n\t// 10.0.0.0/8 — private\n\t{ start: ip4ToNum(10, 0, 0, 0), end: ip4ToNum(10, 255, 255, 255) },\n\t// 172.16.0.0/12 — private\n\t{ start: ip4ToNum(172, 16, 0, 0), end: ip4ToNum(172, 31, 255, 255) },\n\t// 192.168.0.0/16 — private\n\t{ start: ip4ToNum(192, 168, 0, 0), end: ip4ToNum(192, 168, 255, 255) },\n\t// 169.254.0.0/16 — link-local (includes cloud metadata endpoint)\n\t{ start: ip4ToNum(169, 254, 0, 0), end: ip4ToNum(169, 254, 255, 255) },\n\t// 0.0.0.0/8 — current network\n\t{ start: ip4ToNum(0, 0, 0, 0), end: ip4ToNum(0, 255, 255, 255) },\n];\n\nconst BLOCKED_HOSTNAMES = new Set([\n\t\"localhost\",\n\t\"metadata.google.internal\",\n\t\"metadata.google\",\n\t\"[::1]\",\n]);\n\n/** Blocked URL schemes */\nconst ALLOWED_SCHEMES = new Set([\"http:\", \"https:\"]);\n\nfunction ip4ToNum(a: number, b: number, c: number, d: number): number {\n\treturn ((a << 24) | (b << 16) | (c << 8) | d) >>> 0;\n}\n\nfunction parseIpv4(ip: string): number | null {\n\tconst parts = ip.split(\".\");\n\tif (parts.length !== 4) return null;\n\n\tconst nums = parts.map(Number);\n\tif (nums.some((n) => isNaN(n) || n < 0 || n > 255)) return null;\n\n\treturn ip4ToNum(nums[0], nums[1], nums[2], nums[3]);\n}\n\n/**\n * Convert IPv4-mapped/translated IPv6 addresses from hex form back to IPv4.\n *\n * The WHATWG URL parser normalizes dotted-decimal to hex:\n * [::ffff:127.0.0.1] -> [::ffff:7f00:1]\n * [::ffff:169.254.169.254] -> [::ffff:a9fe:a9fe]\n *\n * Without this conversion, the hex forms bypass isPrivateIp() regex checks.\n */\nexport function normalizeIPv6MappedToIPv4(ip: string): string | null {\n\t// Match hex-form IPv4-mapped IPv6: ::ffff:XXXX:XXXX\n\tlet match = ip.match(IPV4_MAPPED_IPV6_HEX_PATTERN);\n\tif (!match) {\n\t\t// Match IPv4-translated (RFC 6052): ::ffff:0:XXXX:XXXX\n\t\tmatch = ip.match(IPV4_TRANSLATED_HEX_PATTERN);\n\t}\n\tif (!match) {\n\t\t// Match fully expanded form: 0000:0000:0000:0000:0000:ffff:XXXX:XXXX\n\t\tmatch = ip.match(IPV6_EXPANDED_MAPPED_PATTERN);\n\t}\n\tif (!match) {\n\t\t// Match IPv4-compatible (deprecated) form: ::XXXX:XXXX (no ffff prefix)\n\t\tmatch = ip.match(IPV4_COMPATIBLE_HEX_PATTERN);\n\t}\n\tif (!match) {\n\t\t// Match NAT64 prefix (RFC 6052): 64:ff9b::XXXX:XXXX\n\t\tmatch = ip.match(NAT64_HEX_PATTERN);\n\t}\n\tif (match) {\n\t\tconst high = parseInt(match[1] ?? \"\", 16);\n\t\tconst low = parseInt(match[2] ?? \"\", 16);\n\t\treturn `${(high >> 8) & 0xff}.${high & 0xff}.${(low >> 8) & 0xff}.${low & 0xff}`;\n\t}\n\treturn null;\n}\n\nfunction isPrivateIp(ip: string): boolean {\n\t// Handle IPv6 loopback\n\tif (ip === \"::1\" || ip === \"::ffff:127.0.0.1\") return true;\n\n\t// Handle IPv4-mapped IPv6 in hex form (WHATWG URL parser normalizes to this)\n\t// e.g. ::ffff:7f00:1 -> 127.0.0.1, ::ffff:a9fe:a9fe -> 169.254.169.254\n\tconst hexIpv4 = normalizeIPv6MappedToIPv4(ip);\n\tif (hexIpv4) return isPrivateIp(hexIpv4);\n\n\t// Handle IPv4-mapped IPv6 in dotted-decimal form\n\tconst v4Match = ip.match(IPV4_MAPPED_IPV6_DOTTED_PATTERN);\n\tconst ipv4 = v4Match ? v4Match[1] : ip;\n\n\tconst num = parseIpv4(ipv4);\n\tif (num === null) {\n\t\t// If we can't parse it, block IPv6 addresses that look internal\n\t\treturn ip.startsWith(\"fe80:\") || ip.startsWith(\"fc\") || ip.startsWith(\"fd\");\n\t}\n\n\treturn BLOCKED_PATTERNS.some((range) => num >= range.start && num <= range.end);\n}\n\n/**\n * Error thrown when SSRF protection blocks a URL.\n */\nexport class SsrfError extends Error {\n\tcode = \"SSRF_BLOCKED\" as const;\n\n\tconstructor(message: string) {\n\t\tsuper(message);\n\t\tthis.name = \"SsrfError\";\n\t}\n}\n\n/**\n * Validate that a URL is safe to fetch (not targeting internal networks).\n *\n * Checks:\n * 1. URL is well-formed with http/https scheme\n * 2. Hostname is not a known internal name (localhost, metadata endpoints)\n * 3. If hostname is an IP literal, it's not in a private range\n *\n * Note: DNS rebinding attacks are not fully mitigated (hostname could resolve\n * to a private IP). Full protection requires resolving DNS and checking the IP\n * before connecting, which needs a custom fetch implementation. This covers\n * the most common SSRF vectors.\n *\n * @throws SsrfError if the URL targets an internal address\n */\n/** Maximum number of redirects to follow in ssrfSafeFetch */\nconst MAX_REDIRECTS = 5;\n\nexport function validateExternalUrl(url: string): URL {\n\tlet parsed: URL;\n\ttry {\n\t\tparsed = new URL(url);\n\t} catch {\n\t\tthrow new SsrfError(\"Invalid URL\");\n\t}\n\n\t// Only allow http/https\n\tif (!ALLOWED_SCHEMES.has(parsed.protocol)) {\n\t\tthrow new SsrfError(`Scheme '${parsed.protocol}' is not allowed`);\n\t}\n\n\t// Strip brackets from IPv6 hostname\n\tconst hostname = parsed.hostname.replace(IPV6_BRACKET_PATTERN, \"\");\n\n\t// Check against known internal hostnames\n\tif (BLOCKED_HOSTNAMES.has(hostname.toLowerCase())) {\n\t\tthrow new SsrfError(\"URLs targeting internal hosts are not allowed\");\n\t}\n\n\t// Check if hostname is an IP address in a private range\n\tif (isPrivateIp(hostname)) {\n\t\tthrow new SsrfError(\"URLs targeting private IP addresses are not allowed\");\n\t}\n\n\treturn parsed;\n}\n\n/**\n * Fetch a URL with SSRF protection on redirects.\n *\n * Uses `redirect: \"manual\"` to intercept redirects and re-validate each\n * redirect target against SSRF rules before following it. This prevents\n * an attacker from setting up an allowed external URL that redirects to\n * an internal IP (e.g. 169.254.169.254 for cloud metadata).\n *\n * @throws SsrfError if the initial URL or any redirect target is internal\n */\n/** Headers that must be stripped when a redirect crosses origins */\nconst CREDENTIAL_HEADERS = [\"authorization\", \"cookie\", \"proxy-authorization\"];\n\nexport async function ssrfSafeFetch(url: string, init?: RequestInit): Promise<Response> {\n\tlet currentUrl = url;\n\tlet currentInit = init;\n\n\tfor (let i = 0; i <= MAX_REDIRECTS; i++) {\n\t\tvalidateExternalUrl(currentUrl);\n\n\t\tconst response = await globalThis.fetch(currentUrl, {\n\t\t\t...currentInit,\n\t\t\tredirect: \"manual\",\n\t\t});\n\n\t\t// Not a redirect -- return directly\n\t\tif (response.status < 300 || response.status >= 400) {\n\t\t\treturn response;\n\t\t}\n\n\t\t// Extract redirect target\n\t\tconst location = response.headers.get(\"Location\");\n\t\tif (!location) {\n\t\t\treturn response;\n\t\t}\n\n\t\t// Resolve relative redirects against the current URL\n\t\tconst previousOrigin = new URL(currentUrl).origin;\n\t\tcurrentUrl = new URL(location, currentUrl).href;\n\t\tconst nextOrigin = new URL(currentUrl).origin;\n\n\t\t// Strip credential headers on cross-origin redirects\n\t\tif (previousOrigin !== nextOrigin && currentInit) {\n\t\t\tcurrentInit = stripCredentialHeaders(currentInit);\n\t\t}\n\t}\n\n\tthrow new SsrfError(`Too many redirects (max ${MAX_REDIRECTS})`);\n}\n\n/**\n * Return a copy of init with credential headers removed.\n */\nexport function stripCredentialHeaders(init: RequestInit): RequestInit {\n\tif (!init.headers) return init;\n\n\tconst headers = new Headers(init.headers);\n\tfor (const name of CREDENTIAL_HEADERS) {\n\t\theaders.delete(name);\n\t}\n\n\treturn { ...init, headers };\n}\n","/**\n * Seed engine - applies seed files to database\n *\n * This is the core implementation that bootstraps an EmDash site from a seed file.\n * Apply order is critical for foreign keys and references.\n */\n\nimport { imageSize } from \"image-size\";\nimport type { Kysely } from \"kysely\";\nimport mime from \"mime/lite\";\nimport { ulid } from \"ulidx\";\n\nimport { BylineRepository } from \"../database/repositories/byline.js\";\nimport { ContentRepository } from \"../database/repositories/content.js\";\nimport { MediaRepository } from \"../database/repositories/media.js\";\nimport { RedirectRepository } from \"../database/repositories/redirect.js\";\nimport { TaxonomyRepository } from \"../database/repositories/taxonomy.js\";\nimport type { Database } from \"../database/types.js\";\nimport type { MediaValue } from \"../fields/types.js\";\nimport { ssrfSafeFetch, validateExternalUrl } from \"../import/ssrf.js\";\nimport { SchemaRegistry } from \"../schema/registry.js\";\nimport { FTSManager } from \"../search/fts-manager.js\";\nimport { setSiteSettings } from \"../settings/index.js\";\nimport type { Storage } from \"../storage/types.js\";\nimport type {\n\tSeedFile,\n\tSeedApplyOptions,\n\tSeedApplyResult,\n\tSeedTaxonomyTerm,\n\tSeedMenuItem,\n\tSeedWidget,\n\tSeedMediaReference,\n} from \"./types.js\";\n\nconst FILE_EXTENSION_PATTERN = /\\.([a-z0-9]+)(?:\\?|$)/i;\nimport { validateSeed } from \"./validate.js\";\n\n/** Pattern to remove file extensions */\nconst EXTENSION_PATTERN = /\\.[^.]+$/;\n\n/** Pattern to remove query parameters */\nconst QUERY_PARAM_PATTERN = /\\?.*$/;\n\n/** Pattern to remove non-alphanumeric characters (except dash and underscore) */\nconst SANITIZE_PATTERN = /[^a-zA-Z0-9_-]/g;\n\n/** Pattern to collapse multiple hyphens */\nconst MULTIPLE_HYPHENS_PATTERN = /-+/g;\n\n/**\n * Apply a seed file to the database\n *\n * This function is idempotent - safe to run multiple times.\n *\n * @param db - Kysely database instance\n * @param seed - Seed file to apply\n * @param options - Application options\n * @returns Result summary\n */\nexport async function applySeed(\n\tdb: Kysely<Database>,\n\tseed: SeedFile,\n\toptions: SeedApplyOptions = {},\n): Promise<SeedApplyResult> {\n\t// Validate seed first\n\tconst validation = validateSeed(seed);\n\tif (!validation.valid) {\n\t\tthrow new Error(`Invalid seed file:\\n${validation.errors.join(\"\\n\")}`);\n\t}\n\n\tconst {\n\t\tincludeContent = false,\n\t\tstorage,\n\t\tskipMediaDownload = false,\n\t\tonConflict = \"skip\",\n\t} = options;\n\n\t// Result counters\n\tconst result: SeedApplyResult = {\n\t\tcollections: { created: 0, skipped: 0, updated: 0 },\n\t\tfields: { created: 0, skipped: 0, updated: 0 },\n\t\ttaxonomies: { created: 0, terms: 0 },\n\t\tbylines: { created: 0, skipped: 0, updated: 0 },\n\t\tmenus: { created: 0, items: 0 },\n\t\tredirects: { created: 0, skipped: 0, updated: 0 },\n\t\twidgetAreas: { created: 0, widgets: 0 },\n\t\tsections: { created: 0, skipped: 0, updated: 0 },\n\t\tsettings: { applied: 0 },\n\t\tcontent: { created: 0, skipped: 0, updated: 0 },\n\t\tmedia: { created: 0, skipped: 0 },\n\t};\n\n\t// Media context for $media resolution\n\tconst mediaContext: MediaContext = {\n\t\tdb,\n\t\tstorage: storage ?? null,\n\t\tskipMediaDownload,\n\t\tmediaCache: new Map(), // Cache downloaded media by URL to avoid re-downloading\n\t};\n\n\t// Apply order (critical for foreign keys and references):\n\t// 1. Site settings\n\t// 2. Collections + Fields\n\t// 3. Taxonomy definitions + Terms\n\t// 4. Content (so menu refs can resolve)\n\t// 5. Menus + Menu items (can now resolve content refs)\n\t// 6. Redirects\n\t// 7. Widget areas + Widgets\n\n\t// Track seed content IDs for reference resolution (shared across content and menus)\n\tconst seedIdMap = new Map<string, string>(); // seed id -> real entry id\n\tconst seedBylineIdMap = new Map<string, string>(); // seed byline id -> real byline id\n\n\t// 1. Site settings\n\tif (seed.settings) {\n\t\tawait setSiteSettings(seed.settings, db);\n\t\tresult.settings.applied = Object.keys(seed.settings).length;\n\t}\n\n\t// 2-3. Collections and Fields\n\tif (seed.collections) {\n\t\tconst registry = new SchemaRegistry(db);\n\n\t\tfor (const collection of seed.collections) {\n\t\t\t// Check if collection exists\n\t\t\tconst existing = await registry.getCollection(collection.slug);\n\n\t\t\tif (existing) {\n\t\t\t\tif (onConflict === \"error\") {\n\t\t\t\t\tthrow new Error(`Conflict: collection \"${collection.slug}\" already exists`);\n\t\t\t\t}\n\n\t\t\t\tif (onConflict === \"update\") {\n\t\t\t\t\tawait registry.updateCollection(collection.slug, {\n\t\t\t\t\t\tlabel: collection.label,\n\t\t\t\t\t\tlabelSingular: collection.labelSingular,\n\t\t\t\t\t\tdescription: collection.description,\n\t\t\t\t\t\ticon: collection.icon,\n\t\t\t\t\t\tsupports: collection.supports || [],\n\t\t\t\t\t\turlPattern: collection.urlPattern,\n\t\t\t\t\t\tcommentsEnabled: collection.commentsEnabled,\n\t\t\t\t\t});\n\t\t\t\t\tresult.collections.updated++;\n\n\t\t\t\t\t// Update or create fields\n\t\t\t\t\tfor (const field of collection.fields) {\n\t\t\t\t\t\tconst existingField = await registry.getField(collection.slug, field.slug);\n\t\t\t\t\t\tif (existingField) {\n\t\t\t\t\t\t\tawait registry.updateField(collection.slug, field.slug, {\n\t\t\t\t\t\t\t\tlabel: field.label,\n\t\t\t\t\t\t\t\trequired: field.required || false,\n\t\t\t\t\t\t\t\tunique: field.unique || false,\n\t\t\t\t\t\t\t\tsearchable: field.searchable || false,\n\t\t\t\t\t\t\t\tdefaultValue: field.defaultValue,\n\t\t\t\t\t\t\t\tvalidation: field.validation,\n\t\t\t\t\t\t\t\twidget: field.widget,\n\t\t\t\t\t\t\t\toptions: field.options,\n\t\t\t\t\t\t\t});\n\t\t\t\t\t\t\tresult.fields.updated++;\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\tawait registry.createField(collection.slug, {\n\t\t\t\t\t\t\t\tslug: field.slug,\n\t\t\t\t\t\t\t\tlabel: field.label,\n\t\t\t\t\t\t\t\ttype: field.type,\n\t\t\t\t\t\t\t\trequired: field.required || false,\n\t\t\t\t\t\t\t\tunique: field.unique || false,\n\t\t\t\t\t\t\t\tsearchable: field.searchable || false,\n\t\t\t\t\t\t\t\tdefaultValue: field.defaultValue,\n\t\t\t\t\t\t\t\tvalidation: field.validation,\n\t\t\t\t\t\t\t\twidget: field.widget,\n\t\t\t\t\t\t\t\toptions: field.options,\n\t\t\t\t\t\t\t});\n\t\t\t\t\t\t\tresult.fields.created++;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\n\t\t\t\t// skip\n\t\t\t\tresult.collections.skipped++;\n\t\t\t\tresult.fields.skipped += collection.fields.length;\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\t// Create collection\n\t\t\tawait registry.createCollection({\n\t\t\t\tslug: collection.slug,\n\t\t\t\tlabel: collection.label,\n\t\t\t\tlabelSingular: collection.labelSingular,\n\t\t\t\tdescription: collection.description,\n\t\t\t\ticon: collection.icon,\n\t\t\t\tsupports: collection.supports || [],\n\t\t\t\tsource: \"seed\",\n\t\t\t\turlPattern: collection.urlPattern,\n\t\t\t\tcommentsEnabled: collection.commentsEnabled,\n\t\t\t});\n\t\t\tresult.collections.created++;\n\n\t\t\t// Create fields\n\t\t\tfor (const field of collection.fields) {\n\t\t\t\tawait registry.createField(collection.slug, {\n\t\t\t\t\tslug: field.slug,\n\t\t\t\t\tlabel: field.label,\n\t\t\t\t\ttype: field.type,\n\t\t\t\t\trequired: field.required || false,\n\t\t\t\t\tunique: field.unique || false,\n\t\t\t\t\tsearchable: field.searchable || false,\n\t\t\t\t\tdefaultValue: field.defaultValue,\n\t\t\t\t\tvalidation: field.validation,\n\t\t\t\t\twidget: field.widget,\n\t\t\t\t\toptions: field.options,\n\t\t\t\t});\n\t\t\t\tresult.fields.created++;\n\t\t\t}\n\t\t}\n\t}\n\n\t// 4-5. Taxonomies\n\tif (seed.taxonomies) {\n\t\tfor (const taxonomy of seed.taxonomies) {\n\t\t\t// Check if taxonomy definition exists\n\t\t\tconst existingDef = await db\n\t\t\t\t.selectFrom(\"_emdash_taxonomy_defs\")\n\t\t\t\t.selectAll()\n\t\t\t\t.where(\"name\", \"=\", taxonomy.name)\n\t\t\t\t.executeTakeFirst();\n\n\t\t\tif (existingDef) {\n\t\t\t\tif (onConflict === \"error\") {\n\t\t\t\t\tthrow new Error(`Conflict: taxonomy \"${taxonomy.name}\" already exists`);\n\t\t\t\t}\n\t\t\t\tif (onConflict === \"update\") {\n\t\t\t\t\tawait db\n\t\t\t\t\t\t.updateTable(\"_emdash_taxonomy_defs\")\n\t\t\t\t\t\t.set({\n\t\t\t\t\t\t\tlabel: taxonomy.label,\n\t\t\t\t\t\t\tlabel_singular: taxonomy.labelSingular ?? null,\n\t\t\t\t\t\t\thierarchical: taxonomy.hierarchical ? 1 : 0,\n\t\t\t\t\t\t\tcollections: JSON.stringify(taxonomy.collections),\n\t\t\t\t\t\t})\n\t\t\t\t\t\t.where(\"id\", \"=\", existingDef.id)\n\t\t\t\t\t\t.execute();\n\t\t\t\t\t// Taxonomy defs don't track an \"updated\" counter -- just the definition is updated\n\t\t\t\t}\n\t\t\t\t// skip: do nothing for the definition\n\t\t\t} else {\n\t\t\t\t// Create taxonomy definition\n\t\t\t\tawait db\n\t\t\t\t\t.insertInto(\"_emdash_taxonomy_defs\")\n\t\t\t\t\t.values({\n\t\t\t\t\t\tid: ulid(),\n\t\t\t\t\t\tname: taxonomy.name,\n\t\t\t\t\t\tlabel: taxonomy.label,\n\t\t\t\t\t\tlabel_singular: taxonomy.labelSingular ?? null,\n\t\t\t\t\t\thierarchical: taxonomy.hierarchical ? 1 : 0,\n\t\t\t\t\t\tcollections: JSON.stringify(taxonomy.collections),\n\t\t\t\t\t})\n\t\t\t\t\t.execute();\n\t\t\t\tresult.taxonomies.created++;\n\t\t\t}\n\n\t\t\t// Create terms (if provided)\n\t\t\tif (taxonomy.terms && taxonomy.terms.length > 0) {\n\t\t\t\tconst termRepo = new TaxonomyRepository(db);\n\n\t\t\t\t// For hierarchical taxonomies, we need to create parents before children\n\t\t\t\tif (taxonomy.hierarchical) {\n\t\t\t\t\tawait applyHierarchicalTerms(termRepo, taxonomy.name, taxonomy.terms, result, onConflict);\n\t\t\t\t} else {\n\t\t\t\t\t// Flat taxonomy - create all terms\n\t\t\t\t\tfor (const term of taxonomy.terms) {\n\t\t\t\t\t\tconst existing = await termRepo.findBySlug(taxonomy.name, term.slug);\n\t\t\t\t\t\tif (existing) {\n\t\t\t\t\t\t\tif (onConflict === \"error\") {\n\t\t\t\t\t\t\t\tthrow new Error(\n\t\t\t\t\t\t\t\t\t`Conflict: taxonomy term \"${term.slug}\" in \"${taxonomy.name}\" already exists`,\n\t\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tif (onConflict === \"update\") {\n\t\t\t\t\t\t\t\tawait termRepo.update(existing.id, {\n\t\t\t\t\t\t\t\t\tlabel: term.label,\n\t\t\t\t\t\t\t\t\tdata: term.description ? { description: term.description } : {},\n\t\t\t\t\t\t\t\t});\n\t\t\t\t\t\t\t\tresult.taxonomies.terms++;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t// skip: do nothing\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\tawait termRepo.create({\n\t\t\t\t\t\t\t\tname: taxonomy.name,\n\t\t\t\t\t\t\t\tslug: term.slug,\n\t\t\t\t\t\t\t\tlabel: term.label,\n\t\t\t\t\t\t\t\tdata: term.description ? { description: term.description } : undefined,\n\t\t\t\t\t\t\t});\n\t\t\t\t\t\t\tresult.taxonomies.terms++;\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\t}\n\n\t// 6. Bylines\n\tif (seed.bylines) {\n\t\tconst bylineRepo = new BylineRepository(db);\n\t\tfor (const byline of seed.bylines) {\n\t\t\tconst existing = await bylineRepo.findBySlug(byline.slug);\n\t\t\tif (existing) {\n\t\t\t\tif (onConflict === \"error\") {\n\t\t\t\t\tthrow new Error(`Conflict: byline \"${byline.slug}\" already exists`);\n\t\t\t\t}\n\n\t\t\t\tif (onConflict === \"update\") {\n\t\t\t\t\tawait bylineRepo.update(existing.id, {\n\t\t\t\t\t\tdisplayName: byline.displayName,\n\t\t\t\t\t\tbio: byline.bio ?? null,\n\t\t\t\t\t\twebsiteUrl: byline.websiteUrl ?? null,\n\t\t\t\t\t\tisGuest: byline.isGuest,\n\t\t\t\t\t});\n\t\t\t\t\tseedBylineIdMap.set(byline.id, existing.id);\n\t\t\t\t\tresult.bylines.updated++;\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\n\t\t\t\t// skip\n\t\t\t\tseedBylineIdMap.set(byline.id, existing.id);\n\t\t\t\tresult.bylines.skipped++;\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tconst created = await bylineRepo.create({\n\t\t\t\tslug: byline.slug,\n\t\t\t\tdisplayName: byline.displayName,\n\t\t\t\tbio: byline.bio ?? null,\n\t\t\t\twebsiteUrl: byline.websiteUrl ?? null,\n\t\t\t\tisGuest: byline.isGuest,\n\t\t\t});\n\t\t\tseedBylineIdMap.set(byline.id, created.id);\n\t\t\tresult.bylines.created++;\n\t\t}\n\t}\n\n\t// 7. Content (created before menus so refs can resolve)\n\tif (includeContent && seed.content) {\n\t\tconst contentRepo = new ContentRepository(db);\n\t\tconst bylineRepo = new BylineRepository(db);\n\n\t\t// Create content entries\n\t\tfor (const [collectionSlug, entries] of Object.entries(seed.content)) {\n\t\t\tfor (const entry of entries) {\n\t\t\t\t// Check if entry exists (by slug + locale for locale-aware lookup)\n\t\t\t\tconst existing = await contentRepo.findBySlug(collectionSlug, entry.slug, entry.locale);\n\n\t\t\t\tif (existing) {\n\t\t\t\t\tif (onConflict === \"error\") {\n\t\t\t\t\t\tthrow new Error(\n\t\t\t\t\t\t\t`Conflict: content \"${entry.slug}\" in \"${collectionSlug}\" already exists`,\n\t\t\t\t\t\t);\n\t\t\t\t\t}\n\n\t\t\t\t\tif (onConflict === \"update\") {\n\t\t\t\t\t\t// Resolve $ref and $media in data\n\t\t\t\t\t\tconst resolvedData = await resolveReferences(\n\t\t\t\t\t\t\tentry.data,\n\t\t\t\t\t\t\tseedIdMap,\n\t\t\t\t\t\t\tmediaContext,\n\t\t\t\t\t\t\tresult,\n\t\t\t\t\t\t);\n\n\t\t\t\t\t\tconst status = entry.status || \"published\";\n\t\t\t\t\t\tawait contentRepo.update(collectionSlug, existing.id, {\n\t\t\t\t\t\t\tstatus,\n\t\t\t\t\t\t\tdata: resolvedData,\n\t\t\t\t\t\t});\n\n\t\t\t\t\t\tseedIdMap.set(entry.id, existing.id);\n\t\t\t\t\t\tresult.content.updated++;\n\n\t\t\t\t\t\t// Update bylines and taxonomy assignments\n\t\t\t\t\t\tawait applyContentBylines(\n\t\t\t\t\t\t\tbylineRepo,\n\t\t\t\t\t\t\tcollectionSlug,\n\t\t\t\t\t\t\texisting.id,\n\t\t\t\t\t\t\tentry,\n\t\t\t\t\t\t\tseedBylineIdMap,\n\t\t\t\t\t\t\ttrue,\n\t\t\t\t\t\t);\n\t\t\t\t\t\tawait applyContentTaxonomies(db, collectionSlug, existing.id, entry, true);\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\t}\n\n\t\t\t\t\t// skip\n\t\t\t\t\tresult.content.skipped++;\n\t\t\t\t\tseedIdMap.set(entry.id, existing.id);\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\n\t\t\t\t// Resolve $ref and $media in data\n\t\t\t\tconst resolvedData = await resolveReferences(entry.data, seedIdMap, mediaContext, result);\n\n\t\t\t\t// Resolve translationOf: map from seed-local ID to real EmDash ID\n\t\t\t\tlet translationOf: string | undefined;\n\t\t\t\tif (entry.translationOf) {\n\t\t\t\t\tconst sourceId = seedIdMap.get(entry.translationOf);\n\t\t\t\t\tif (!sourceId) {\n\t\t\t\t\t\tconsole.warn(\n\t\t\t\t\t\t\t`content.${collectionSlug}: translationOf \"${entry.translationOf}\" not found (not yet created or missing). Skipping translation link.`,\n\t\t\t\t\t\t);\n\t\t\t\t\t} else {\n\t\t\t\t\t\ttranslationOf = sourceId;\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\t// Create entry\n\t\t\t\tconst status = entry.status || \"published\";\n\t\t\t\tconst created = await contentRepo.create({\n\t\t\t\t\ttype: collectionSlug,\n\t\t\t\t\tslug: entry.slug,\n\t\t\t\t\tstatus,\n\t\t\t\t\tdata: resolvedData,\n\t\t\t\t\tlocale: entry.locale,\n\t\t\t\t\ttranslationOf,\n\t\t\t\t\t// Set published_at for published content so RSS/Archives work correctly\n\t\t\t\t\tpublishedAt: status === \"published\" ? new Date().toISOString() : null,\n\t\t\t\t});\n\n\t\t\t\tseedIdMap.set(entry.id, created.id);\n\t\t\t\tresult.content.created++;\n\n\t\t\t\tawait applyContentBylines(bylineRepo, collectionSlug, created.id, entry, seedBylineIdMap);\n\t\t\t\tawait applyContentTaxonomies(db, collectionSlug, created.id, entry, false);\n\t\t\t}\n\t\t}\n\t}\n\n\t// 8. Menus and Menu Items (after content so refs can resolve)\n\tif (seed.menus) {\n\t\tfor (const menu of seed.menus) {\n\t\t\t// Check if menu exists\n\t\t\tconst existingMenu = await db\n\t\t\t\t.selectFrom(\"_emdash_menus\")\n\t\t\t\t.selectAll()\n\t\t\t\t.where(\"name\", \"=\", menu.name)\n\t\t\t\t.executeTakeFirst();\n\n\t\t\tlet menuId: string;\n\n\t\t\tif (existingMenu) {\n\t\t\t\tmenuId = existingMenu.id;\n\t\t\t\t// Clear existing items (menus are recreated)\n\t\t\t\tawait db.deleteFrom(\"_emdash_menu_items\").where(\"menu_id\", \"=\", menuId).execute();\n\t\t\t} else {\n\t\t\t\t// Create menu\n\t\t\t\tmenuId = ulid();\n\t\t\t\tawait db\n\t\t\t\t\t.insertInto(\"_emdash_menus\")\n\t\t\t\t\t.values({\n\t\t\t\t\t\tid: menuId,\n\t\t\t\t\t\tname: menu.name,\n\t\t\t\t\t\tlabel: menu.label,\n\t\t\t\t\t\tcreated_at: new Date().toISOString(),\n\t\t\t\t\t\tupdated_at: new Date().toISOString(),\n\t\t\t\t\t})\n\t\t\t\t\t.execute();\n\t\t\t\tresult.menus.created++;\n\t\t\t}\n\n\t\t\t// Create menu items\n\t\t\tconst itemCount = await applyMenuItems(\n\t\t\t\tdb,\n\t\t\t\tmenuId,\n\t\t\t\tmenu.items,\n\t\t\t\tnull, // parent_id\n\t\t\t\t0, // sort_order\n\t\t\t\tseedIdMap,\n\t\t\t);\n\t\t\tresult.menus.items += itemCount;\n\t\t}\n\t}\n\n\t// 9. Redirects\n\tif (seed.redirects) {\n\t\tconst redirectRepo = new RedirectRepository(db);\n\n\t\tfor (const redirect of seed.redirects) {\n\t\t\tconst existing = await redirectRepo.findBySource(redirect.source);\n\t\t\tif (existing) {\n\t\t\t\tif (onConflict === \"error\") {\n\t\t\t\t\tthrow new Error(`Conflict: redirect \"${redirect.source}\" already exists`);\n\t\t\t\t}\n\n\t\t\t\tif (onConflict === \"update\") {\n\t\t\t\t\tawait redirectRepo.update(existing.id, {\n\t\t\t\t\t\tdestination: redirect.destination,\n\t\t\t\t\t\ttype: redirect.type,\n\t\t\t\t\t\tenabled: redirect.enabled,\n\t\t\t\t\t\tgroupName: redirect.groupName,\n\t\t\t\t\t});\n\t\t\t\t\tresult.redirects.updated++;\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\n\t\t\t\t// skip\n\t\t\t\tresult.redirects.skipped++;\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tawait redirectRepo.create({\n\t\t\t\tsource: redirect.source,\n\t\t\t\tdestination: redirect.destination,\n\t\t\t\ttype: redirect.type,\n\t\t\t\tenabled: redirect.enabled,\n\t\t\t\tgroupName: redirect.groupName,\n\t\t\t});\n\t\t\tresult.redirects.created++;\n\t\t}\n\t}\n\n\t// 10. Widget Areas and Widgets\n\tif (seed.widgetAreas) {\n\t\tfor (const area of seed.widgetAreas) {\n\t\t\t// Check if area exists\n\t\t\tconst existingArea = await db\n\t\t\t\t.selectFrom(\"_emdash_widget_areas\")\n\t\t\t\t.selectAll()\n\t\t\t\t.where(\"name\", \"=\", area.name)\n\t\t\t\t.executeTakeFirst();\n\n\t\t\tlet areaId: string;\n\n\t\t\tif (existingArea) {\n\t\t\t\tareaId = existingArea.id;\n\t\t\t\t// Clear existing widgets (areas are recreated)\n\t\t\t\tawait db.deleteFrom(\"_emdash_widgets\").where(\"area_id\", \"=\", areaId).execute();\n\t\t\t} else {\n\t\t\t\t// Create area\n\t\t\t\tareaId = ulid();\n\t\t\t\tawait db\n\t\t\t\t\t.insertInto(\"_emdash_widget_areas\")\n\t\t\t\t\t.values({\n\t\t\t\t\t\tid: areaId,\n\t\t\t\t\t\tname: area.name,\n\t\t\t\t\t\tlabel: area.label,\n\t\t\t\t\t\tdescription: area.description ?? null,\n\t\t\t\t\t})\n\t\t\t\t\t.execute();\n\t\t\t\tresult.widgetAreas.created++;\n\t\t\t}\n\n\t\t\t// Create widgets\n\t\t\tfor (let i = 0; i < area.widgets.length; i++) {\n\t\t\t\tconst widget = area.widgets[i];\n\t\t\t\tawait applyWidget(db, areaId, widget, i);\n\t\t\t\tresult.widgetAreas.widgets++;\n\t\t\t}\n\t\t}\n\t}\n\n\t// 11. Sections\n\tif (seed.sections) {\n\t\tfor (const section of seed.sections) {\n\t\t\t// Check if section exists\n\t\t\tconst existing = await db\n\t\t\t\t.selectFrom(\"_emdash_sections\")\n\t\t\t\t.select(\"id\")\n\t\t\t\t.where(\"slug\", \"=\", section.slug)\n\t\t\t\t.executeTakeFirst();\n\n\t\t\tif (existing) {\n\t\t\t\tif (onConflict === \"error\") {\n\t\t\t\t\tthrow new Error(`Conflict: section \"${section.slug}\" already exists`);\n\t\t\t\t}\n\n\t\t\t\tif (onConflict === \"update\") {\n\t\t\t\t\tawait db\n\t\t\t\t\t\t.updateTable(\"_emdash_sections\")\n\t\t\t\t\t\t.set({\n\t\t\t\t\t\t\ttitle: section.title,\n\t\t\t\t\t\t\tdescription: section.description ?? null,\n\t\t\t\t\t\t\tkeywords: section.keywords ? JSON.stringify(section.keywords) : null,\n\t\t\t\t\t\t\tcontent: JSON.stringify(section.content),\n\t\t\t\t\t\t\tsource: section.source || \"theme\",\n\t\t\t\t\t\t\tupdated_at: new Date().toISOString(),\n\t\t\t\t\t\t})\n\t\t\t\t\t\t.where(\"id\", \"=\", existing.id)\n\t\t\t\t\t\t.execute();\n\t\t\t\t\tresult.sections.updated++;\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\n\t\t\t\t// skip\n\t\t\t\tresult.sections.skipped++;\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tconst id = ulid();\n\t\t\tconst now = new Date().toISOString();\n\n\t\t\tawait db\n\t\t\t\t.insertInto(\"_emdash_sections\")\n\t\t\t\t.values({\n\t\t\t\t\tid,\n\t\t\t\t\tslug: section.slug,\n\t\t\t\t\ttitle: section.title,\n\t\t\t\t\tdescription: section.description ?? null,\n\t\t\t\t\tkeywords: section.keywords ? JSON.stringify(section.keywords) : null,\n\t\t\t\t\tcontent: JSON.stringify(section.content),\n\t\t\t\t\tpreview_media_id: null,\n\t\t\t\t\tsource: section.source || \"theme\",\n\t\t\t\t\ttheme_id: section.source === \"theme\" ? section.slug : null,\n\t\t\t\t\tcreated_at: now,\n\t\t\t\t\tupdated_at: now,\n\t\t\t\t})\n\t\t\t\t.execute();\n\n\t\t\tresult.sections.created++;\n\t\t}\n\t}\n\n\t// 11. Enable search for collections that have `search` in supports\n\tif (seed.collections) {\n\t\tconst ftsManager = new FTSManager(db);\n\n\t\tfor (const collection of seed.collections) {\n\t\t\tif (collection.supports?.includes(\"search\")) {\n\t\t\t\t// Check if there are searchable fields\n\t\t\t\tconst searchableFields = await ftsManager.getSearchableFields(collection.slug);\n\t\t\t\tif (searchableFields.length > 0) {\n\t\t\t\t\ttry {\n\t\t\t\t\t\tawait ftsManager.enableSearch(collection.slug);\n\t\t\t\t\t} catch (err) {\n\t\t\t\t\t\t// Log but don't fail - search can be enabled manually later\n\t\t\t\t\t\tconsole.warn(`Failed to enable search for ${collection.slug}:`, err);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\treturn result;\n}\n\n/**\n * Apply hierarchical taxonomy terms (parents before children)\n */\nasync function applyHierarchicalTerms(\n\ttermRepo: TaxonomyRepository,\n\ttaxonomyName: string,\n\tterms: SeedTaxonomyTerm[],\n\tresult: SeedApplyResult,\n\tonConflict: \"skip\" | \"update\" | \"error\" = \"skip\",\n): Promise<void> {\n\t// Map slugs to IDs\n\tconst slugToId = new Map<string, string>();\n\n\t// Multiple passes to handle deep nesting\n\tlet remaining = [...terms];\n\tlet maxPasses = 10; // Prevent infinite loop\n\n\twhile (remaining.length > 0 && maxPasses > 0) {\n\t\tconst processedThisPass: string[] = [];\n\n\t\tfor (const term of remaining) {\n\t\t\t// Check if parent exists (or no parent)\n\t\t\tif (!term.parent || slugToId.has(term.parent)) {\n\t\t\t\tconst parentId = term.parent ? slugToId.get(term.parent) : undefined;\n\n\t\t\t\tconst existing = await termRepo.findBySlug(taxonomyName, term.slug);\n\t\t\t\tif (existing) {\n\t\t\t\t\tif (onConflict === \"error\") {\n\t\t\t\t\t\tthrow new Error(\n\t\t\t\t\t\t\t`Conflict: taxonomy term \"${term.slug}\" in \"${taxonomyName}\" already exists`,\n\t\t\t\t\t\t);\n\t\t\t\t\t}\n\t\t\t\t\tif (onConflict === \"update\") {\n\t\t\t\t\t\tawait termRepo.update(existing.id, {\n\t\t\t\t\t\t\tlabel: term.label,\n\t\t\t\t\t\t\tparentId,\n\t\t\t\t\t\t\tdata: term.description ? { description: term.description } : {},\n\t\t\t\t\t\t});\n\t\t\t\t\t\tresult.taxonomies.terms++;\n\t\t\t\t\t}\n\t\t\t\t\tslugToId.set(term.slug, existing.id);\n\t\t\t\t} else {\n\t\t\t\t\tconst created = await termRepo.create({\n\t\t\t\t\t\tname: taxonomyName,\n\t\t\t\t\t\tslug: term.slug,\n\t\t\t\t\t\tlabel: term.label,\n\t\t\t\t\t\tparentId,\n\t\t\t\t\t\tdata: term.description ? { description: term.description } : undefined,\n\t\t\t\t\t});\n\t\t\t\t\tslugToId.set(term.slug, created.id);\n\t\t\t\t\tresult.taxonomies.terms++;\n\t\t\t\t}\n\n\t\t\t\tprocessedThisPass.push(term.slug);\n\t\t\t}\n\t\t}\n\n\t\t// Remove processed terms\n\t\tremaining = remaining.filter((t) => !processedThisPass.includes(t.slug));\n\t\tmaxPasses--;\n\t}\n\n\tif (remaining.length > 0) {\n\t\tconsole.warn(`Could not process ${remaining.length} terms due to missing parents`);\n\t}\n}\n\n/**\n * Apply byline credits to a content entry.\n * In update mode, clears existing credits even if the seed has none.\n */\nasync function applyContentBylines(\n\tbylineRepo: BylineRepository,\n\tcollectionSlug: string,\n\tcontentId: string,\n\tentry: { slug: string; bylines?: Array<{ byline: string; roleLabel?: string }> },\n\tseedBylineIdMap: Map<string, string>,\n\tisUpdate = false,\n): Promise<void> {\n\tif (!entry.bylines || entry.bylines.length === 0) {\n\t\t// In update mode, clear existing bylines when the seed entry has none\n\t\tif (isUpdate) {\n\t\t\tawait bylineRepo.setContentBylines(collectionSlug, contentId, []);\n\t\t}\n\t\treturn;\n\t}\n\n\tconst credits = entry.bylines\n\t\t.map((credit) => {\n\t\t\tconst bylineId = seedBylineIdMap.get(credit.byline);\n\t\t\tif (!bylineId) return null;\n\t\t\treturn {\n\t\t\t\tbylineId,\n\t\t\t\troleLabel: credit.roleLabel ?? null,\n\t\t\t};\n\t\t})\n\t\t.filter((credit): credit is { bylineId: string; roleLabel: string | null } => Boolean(credit));\n\n\tif (credits.length !== entry.bylines.length) {\n\t\tconsole.warn(\n\t\t\t`content.${collectionSlug}.${entry.slug}: one or more byline refs could not be resolved`,\n\t\t);\n\t}\n\n\t// In update mode, always call setContentBylines (even with empty credits)\n\t// to clear stale assignments when all byline refs fail to resolve.\n\t// In create mode, only call if there are credits to assign.\n\tif (credits.length > 0 || isUpdate) {\n\t\tawait bylineRepo.setContentBylines(collectionSlug, contentId, credits);\n\t}\n}\n\n/**\n * Apply taxonomy term assignments to a content entry.\n * In update mode, clears existing assignments before re-attaching.\n */\nasync function applyContentTaxonomies(\n\tdb: Kysely<Database>,\n\tcollectionSlug: string,\n\tcontentId: string,\n\tentry: { taxonomies?: Record<string, string[]> },\n\tisUpdate: boolean,\n): Promise<void> {\n\t// In update mode, clear existing taxonomy assignments first\n\tif (isUpdate) {\n\t\tawait db\n\t\t\t.deleteFrom(\"content_taxonomies\")\n\t\t\t.where(\"collection\", \"=\", collectionSlug)\n\t\t\t.where(\"entry_id\", \"=\", contentId)\n\t\t\t.execute();\n\t}\n\n\tif (!entry.taxonomies) return;\n\n\tfor (const [taxonomyName, termSlugs] of Object.entries(entry.taxonomies)) {\n\t\tconst termRepo = new TaxonomyRepository(db);\n\n\t\tfor (const termSlug of termSlugs) {\n\t\t\tconst term = await termRepo.findBySlug(taxonomyName, termSlug);\n\t\t\tif (term) {\n\t\t\t\tawait termRepo.attachToEntry(collectionSlug, contentId, term.id);\n\t\t\t}\n\t\t}\n\t}\n}\n\n/**\n * Apply menu items recursively\n */\nasync function applyMenuItems(\n\tdb: Kysely<Database>,\n\tmenuId: string,\n\titems: SeedMenuItem[],\n\tparentId: string | null,\n\tstartOrder: number,\n\tseedIdMap: Map<string, string>,\n): Promise<number> {\n\tlet count = 0;\n\tlet order = startOrder;\n\n\tfor (const item of items) {\n\t\tconst itemId = ulid();\n\n\t\t// Resolve reference if needed\n\t\tlet referenceId: string | null = null;\n\t\tlet referenceCollection: string | null = null;\n\n\t\tif (item.type === \"page\" || item.type === \"post\") {\n\t\t\t// Try to resolve from seedIdMap\n\t\t\tif (item.ref && seedIdMap.has(item.ref)) {\n\t\t\t\treferenceId = seedIdMap.get(item.ref)!;\n\t\t\t\t// Default to plural collection name (pages/posts) if not specified\n\t\t\t\treferenceCollection = item.collection || `${item.type}s`;\n\t\t\t}\n\t\t\t// If not in map, the content might not exist yet (will be broken link)\n\t\t}\n\n\t\t// Insert menu item\n\t\tawait db\n\t\t\t.insertInto(\"_emdash_menu_items\")\n\t\t\t.values({\n\t\t\t\tid: itemId,\n\t\t\t\tmenu_id: menuId,\n\t\t\t\tparent_id: parentId,\n\t\t\t\tsort_order: order,\n\t\t\t\ttype: item.type,\n\t\t\t\treference_collection: referenceCollection,\n\t\t\t\treference_id: referenceId,\n\t\t\t\tcustom_url: item.url ?? null,\n\t\t\t\tlabel: item.label || \"\",\n\t\t\t\ttitle_attr: item.titleAttr ?? null,\n\t\t\t\ttarget: item.target ?? null,\n\t\t\t\tcss_classes: item.cssClasses ?? null,\n\t\t\t\tcreated_at: new Date().toISOString(),\n\t\t\t})\n\t\t\t.execute();\n\n\t\tcount++;\n\t\torder++;\n\n\t\t// Process children\n\t\tif (item.children && item.children.length > 0) {\n\t\t\tconst childCount = await applyMenuItems(db, menuId, item.children, itemId, 0, seedIdMap);\n\t\t\tcount += childCount;\n\t\t}\n\t}\n\n\treturn count;\n}\n\n/**\n * Apply a widget\n */\nasync function applyWidget(\n\tdb: Kysely<Database>,\n\tareaId: string,\n\twidget: SeedWidget,\n\tsortOrder: number,\n): Promise<void> {\n\tawait db\n\t\t.insertInto(\"_emdash_widgets\")\n\t\t.values({\n\t\t\tid: ulid(),\n\t\t\tarea_id: areaId,\n\t\t\tsort_order: sortOrder,\n\t\t\ttype: widget.type,\n\t\t\ttitle: widget.title ?? null,\n\t\t\tcontent: widget.content ? JSON.stringify(widget.content) : null,\n\t\t\tmenu_name: widget.menuName ?? null,\n\t\t\tcomponent_id: widget.componentId ?? null,\n\t\t\tcomponent_props: widget.props ? JSON.stringify(widget.props) : null,\n\t\t})\n\t\t.execute();\n}\n\n/**\n * Context for media resolution during seed application\n */\ninterface MediaContext {\n\tdb: Kysely<Database>;\n\tstorage: Storage | null;\n\tskipMediaDownload: boolean;\n\tmediaCache: Map<string, MediaValue>; // URL -> resolved MediaValue\n}\n\n/**\n * Type guard for $media reference\n */\nfunction isSeedMediaReference(value: unknown): value is SeedMediaReference {\n\tif (typeof value !== \"object\" || value === null || !(\"$media\" in value)) {\n\t\treturn false;\n\t}\n\tconst media = (value as Record<string, unknown>).$media;\n\treturn (\n\t\ttypeof media === \"object\" &&\n\t\tmedia !== null &&\n\t\t\"url\" in media &&\n\t\ttypeof (media as Record<string, unknown>).url === \"string\"\n\t);\n}\n\n/**\n * Resolve $ref: and $media references in content data\n */\nasync function resolveReferences(\n\tdata: Record<string, unknown>,\n\tseedIdMap: Map<string, string>,\n\tmediaContext: MediaContext,\n\tresult: SeedApplyResult,\n): Promise<Record<string, unknown>> {\n\tconst resolved: Record<string, unknown> = {};\n\n\tfor (const [key, value] of Object.entries(data)) {\n\t\tresolved[key] = await resolveValue(value, seedIdMap, mediaContext, result);\n\t}\n\n\treturn resolved;\n}\n\n/**\n * Resolve a single value recursively\n */\nasync function resolveValue(\n\tvalue: unknown,\n\tseedIdMap: Map<string, string>,\n\tmediaContext: MediaContext,\n\tresult: SeedApplyResult,\n): Promise<unknown> {\n\t// Handle $ref: syntax\n\tif (typeof value === \"string\" && value.startsWith(\"$ref:\")) {\n\t\tconst seedId = value.slice(5);\n\t\treturn seedIdMap.get(seedId) ?? value; // Return unresolved if not found\n\t}\n\n\t// Handle $media syntax\n\tif (isSeedMediaReference(value)) {\n\t\treturn resolveMedia(value, mediaContext, result);\n\t}\n\n\t// Handle arrays\n\tif (Array.isArray(value)) {\n\t\treturn Promise.all(value.map((item) => resolveValue(item, seedIdMap, mediaContext, result)));\n\t}\n\n\t// Handle objects recursively\n\tif (typeof value === \"object\" && value !== null) {\n\t\tconst resolved: Record<string, unknown> = {};\n\t\tfor (const [k, v] of Object.entries(value)) {\n\t\t\tresolved[k] = await resolveValue(v, seedIdMap, mediaContext, result);\n\t\t}\n\t\treturn resolved;\n\t}\n\n\treturn value;\n}\n\n/**\n * Resolve a $media reference by downloading and uploading the media\n */\nasync function resolveMedia(\n\tref: SeedMediaReference,\n\tctx: MediaContext,\n\tresult: SeedApplyResult,\n): Promise<MediaValue | null> {\n\tconst { url, alt, filename, caption } = ref.$media;\n\n\t// Check cache first\n\tconst cached = ctx.mediaCache.get(url);\n\tif (cached) {\n\t\tresult.media.skipped++;\n\t\treturn { ...cached, alt: alt ?? cached.alt };\n\t}\n\n\t// When skipMediaDownload is set, resolve $media to an external URL reference\n\t// without downloading or storing anything. Used by playground mode.\n\tif (ctx.skipMediaDownload) {\n\t\tconst mediaValue: MediaValue = {\n\t\t\tprovider: \"external\",\n\t\t\tid: ulid(),\n\t\t\tsrc: url,\n\t\t\talt: alt ?? undefined,\n\t\t\tfilename: filename ?? undefined,\n\t\t};\n\t\tctx.mediaCache.set(url, mediaValue);\n\t\tresult.media.created++;\n\t\treturn mediaValue;\n\t}\n\n\t// Storage is required for $media resolution\n\tif (!ctx.storage) {\n\t\tconsole.warn(`Skipping $media reference (no storage configured): ${url}`);\n\t\tresult.media.skipped++;\n\t\treturn null;\n\t}\n\n\ttry {\n\t\t// SSRF protection: validate URL before downloading\n\t\tvalidateExternalUrl(url);\n\n\t\t// Download the media (ssrfSafeFetch re-validates redirect targets)\n\t\tconsole.log(` 📥 Downloading: ${url}`);\n\t\tconst response = await ssrfSafeFetch(url, {\n\t\t\theaders: {\n\t\t\t\t// Some services like Unsplash require a user-agent\n\t\t\t\t\"User-Agent\": \"EmDash-CMS/1.0\",\n\t\t\t},\n\t\t});\n\n\t\tif (!response.ok) {\n\t\t\tconsole.warn(` ⚠️ Failed to download ${url}: ${response.status}`);\n\t\t\tresult.media.skipped++;\n\t\t\treturn null;\n\t\t}\n\n\t\t// Get content type and determine extension\n\t\tconst contentType = response.headers.get(\"content-type\") || \"application/octet-stream\";\n\t\tconst ext = getExtensionFromContentType(contentType) || getExtensionFromUrl(url) || \".bin\";\n\n\t\t// Generate filename and storage key\n\t\tconst id = ulid();\n\t\tconst finalFilename = filename || generateFilename(url, ext);\n\t\tconst storageKey = `${id}${ext}`;\n\n\t\t// Get the body as buffer\n\t\tconst arrayBuffer = await response.arrayBuffer();\n\t\tconst body = new Uint8Array(arrayBuffer);\n\n\t\t// Get image dimensions if it's an image\n\t\tlet width: number | undefined;\n\t\tlet height: number | undefined;\n\t\tif (contentType.startsWith(\"image/\")) {\n\t\t\tconst dimensions = getImageDimensions(body);\n\t\t\twidth = dimensions?.width;\n\t\t\theight = dimensions?.height;\n\t\t}\n\n\t\t// Upload to storage\n\t\tawait ctx.storage.upload({\n\t\t\tkey: storageKey,\n\t\t\tbody,\n\t\t\tcontentType,\n\t\t});\n\n\t\t// Create media record\n\t\tconst mediaRepo = new MediaRepository(ctx.db);\n\t\tawait mediaRepo.create({\n\t\t\tfilename: finalFilename,\n\t\t\tmimeType: contentType,\n\t\t\tsize: body.length,\n\t\t\twidth,\n\t\t\theight,\n\t\t\talt,\n\t\t\tcaption,\n\t\t\tstorageKey,\n\t\t\tstatus: \"ready\",\n\t\t});\n\n\t\t// Create the MediaValue - only store id, URL is built at runtime by EmDashMedia\n\t\tconst mediaValue: MediaValue = {\n\t\t\tprovider: \"local\",\n\t\t\tid,\n\t\t\talt: alt ?? undefined,\n\t\t\twidth,\n\t\t\theight,\n\t\t\tmimeType: contentType,\n\t\t\tfilename: finalFilename,\n\t\t\tmeta: { storageKey },\n\t\t};\n\n\t\t// Cache for reuse\n\t\tctx.mediaCache.set(url, mediaValue);\n\t\tresult.media.created++;\n\n\t\tconsole.log(` ✅ Uploaded: ${finalFilename}`);\n\t\treturn mediaValue;\n\t} catch (error) {\n\t\tconsole.warn(\n\t\t\t` ⚠️ Error processing $media ${url}:`,\n\t\t\terror instanceof Error ? error.message : error,\n\t\t);\n\t\tresult.media.skipped++;\n\t\treturn null;\n\t}\n}\n\n/**\n * Get file extension from content type\n */\nfunction getExtensionFromContentType(contentType: string): string | null {\n\t// Handle content-type with parameters like \"image/jpeg; charset=utf-8\"\n\tconst baseMime = contentType.split(\";\")[0].trim();\n\tconst ext = mime.getExtension(baseMime);\n\treturn ext ? `.${ext}` : null;\n}\n\n/**\n * Get file extension from URL\n */\nfunction getExtensionFromUrl(url: string): string | null {\n\ttry {\n\t\tconst pathname = new URL(url).pathname;\n\t\tconst match = pathname.match(FILE_EXTENSION_PATTERN);\n\t\treturn match ? `.${match[1]}` : null;\n\t} catch {\n\t\treturn null;\n\t}\n}\n\n/**\n * Generate a filename from URL\n */\nfunction generateFilename(url: string, ext: string): string {\n\ttry {\n\t\tconst pathname = new URL(url).pathname;\n\t\tconst basename = pathname.split(\"/\").pop() || \"media\";\n\t\t// Remove any existing extension and query params\n\t\tconst name = basename.replace(EXTENSION_PATTERN, \"\").replace(QUERY_PARAM_PATTERN, \"\");\n\t\t// Sanitize: only alphanumeric, dash, underscore\n\t\tconst sanitized = name.replace(SANITIZE_PATTERN, \"-\").replace(MULTIPLE_HYPHENS_PATTERN, \"-\");\n\t\treturn `${sanitized || \"media\"}${ext}`;\n\t} catch {\n\t\treturn `media${ext}`;\n\t}\n}\n\n/**\n * Get image dimensions from buffer using image-size.\n * Supports PNG, JPEG, GIF, WebP, AVIF, SVG, TIFF, and more.\n */\nfunction getImageDimensions(buffer: Uint8Array): { width: number; height: number } | null {\n\ttry {\n\t\tconst result = imageSize(buffer);\n\t\tif (result.width != null && result.height != null) {\n\t\t\treturn { width: result.width, height: result.height };\n\t\t}\n\t\treturn null;\n\t} catch {\n\t\treturn null;\n\t}\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;AAkCA,IAAa,qBAAb,MAAgC;CAC/B,YAAY,AAAQ,IAAsB;EAAtB;;;;;CAKpB,MAAM,OAAO,OAA+C;EAC3D,MAAM,KAAK,MAAM;EAEjB,MAAM,MAAqB;GAC1B;GACA,MAAM,MAAM;GACZ,MAAM,MAAM;GACZ,OAAO,MAAM;GACb,WAAW,MAAM,YAAY;GAC7B,MAAM,MAAM,OAAO,KAAK,UAAU,MAAM,KAAK,GAAG;GAChD;AAED,QAAM,KAAK,GAAG,WAAW,aAAa,CAAC,OAAO,IAAI,CAAC,SAAS;EAE5D,MAAM,WAAW,MAAM,KAAK,SAAS,GAAG;AACxC,MAAI,CAAC,SACJ,OAAM,IAAI,MAAM,4BAA4B;AAE7C,SAAO;;;;;CAMR,MAAM,SAAS,IAAsC;EACpD,MAAM,MAAM,MAAM,KAAK,GACrB,WAAW,aAAa,CACxB,WAAW,CACX,MAAM,MAAM,KAAK,GAAG,CACpB,kBAAkB;AAEpB,SAAO,MAAM,KAAK,cAAc,IAAI,GAAG;;;;;CAMxC,MAAM,WAAW,MAAc,MAAwC;EACtE,MAAM,MAAM,MAAM,KAAK,GACrB,WAAW,aAAa,CACxB,WAAW,CACX,MAAM,QAAQ,KAAK,KAAK,CACxB,MAAM,QAAQ,KAAK,KAAK,CACxB,kBAAkB;AAEpB,SAAO,MAAM,KAAK,cAAc,IAAI,GAAG;;;;;CAMxC,MAAM,WAAW,MAAc,UAAwC,EAAE,EAAuB;EAC/F,IAAI,QAAQ,KAAK,GACf,WAAW,aAAa,CACxB,WAAW,CACX,MAAM,QAAQ,KAAK,KAAK,CACxB,QAAQ,SAAS,MAAM;AAEzB,MAAI,QAAQ,aAAa,OACxB,KAAI,QAAQ,aAAa,KACxB,SAAQ,MAAM,MAAM,aAAa,MAAM,KAAK;MAE5C,SAAQ,MAAM,MAAM,aAAa,KAAK,QAAQ,SAAS;AAKzD,UADa,MAAM,MAAM,SAAS,EACtB,KAAK,QAAQ,KAAK,cAAc,IAAI,CAAC;;;;;CAMlD,MAAM,aAAa,UAAuC;AAQzD,UAPa,MAAM,KAAK,GACtB,WAAW,aAAa,CACxB,WAAW,CACX,MAAM,aAAa,KAAK,SAAS,CACjC,QAAQ,SAAS,MAAM,CACvB,SAAS,EAEC,KAAK,QAAQ,KAAK,cAAc,IAAI,CAAC;;;;;CAMlD,MAAM,OAAO,IAAY,OAAsD;AAE9E,MAAI,CADa,MAAM,KAAK,SAAS,GAAG,CACzB,QAAO;EAEtB,MAAM,UAAkC,EAAE;AAC1C,MAAI,MAAM,SAAS,OAAW,SAAQ,OAAO,MAAM;AACnD,MAAI,MAAM,UAAU,OAAW,SAAQ,QAAQ,MAAM;AACrD,MAAI,MAAM,aAAa,OAAW,SAAQ,YAAY,MAAM;AAC5D,MAAI,MAAM,SAAS,OAAW,SAAQ,OAAO,KAAK,UAAU,MAAM,KAAK;AAEvE,MAAI,OAAO,KAAK,QAAQ,CAAC,SAAS,EACjC,OAAM,KAAK,GAAG,YAAY,aAAa,CAAC,IAAI,QAAQ,CAAC,MAAM,MAAM,KAAK,GAAG,CAAC,SAAS;AAGpF,SAAO,KAAK,SAAS,GAAG;;;;;CAMzB,MAAM,OAAO,IAA8B;AAE1C,QAAM,KAAK,GAAG,WAAW,qBAAqB,CAAC,MAAM,eAAe,KAAK,GAAG,CAAC,SAAS;AAItF,WAFe,MAAM,KAAK,GAAG,WAAW,aAAa,CAAC,MAAM,MAAM,KAAK,GAAG,CAAC,kBAAkB,EAE9E,kBAAkB,KAAK;;;;;CAQvC,MAAM,cAAc,YAAoB,SAAiB,YAAmC;EAC3F,MAAM,MAA4B;GACjC;GACA,UAAU;GACV,aAAa;GACb;AAGD,QAAM,KAAK,GACT,WAAW,qBAAqB,CAChC,OAAO,IAAI,CACX,YAAY,OAAO,GAAG,WAAW,CAAC,CAClC,SAAS;;;;;CAMZ,MAAM,gBAAgB,YAAoB,SAAiB,YAAmC;AAC7F,QAAM,KAAK,GACT,WAAW,qBAAqB,CAChC,MAAM,cAAc,KAAK,WAAW,CACpC,MAAM,YAAY,KAAK,QAAQ,CAC/B,MAAM,eAAe,KAAK,WAAW,CACrC,SAAS;;;;;CAMZ,MAAM,iBACL,YACA,SACA,cACsB;EACtB,IAAI,QAAQ,KAAK,GACf,WAAW,qBAAqB,CAChC,UAAU,cAAc,iBAAiB,iCAAiC,CAC1E,UAAU,aAAa,CACvB,MAAM,iCAAiC,KAAK,WAAW,CACvD,MAAM,+BAA+B,KAAK,QAAQ;AAEpD,MAAI,aACH,SAAQ,MAAM,MAAM,mBAAmB,KAAK,aAAa;AAI1D,UADa,MAAM,MAAM,SAAS,EACtB,KAAK,QAAQ,KAAK,cAAc,IAAI,CAAC;;;;;;CAOlD,MAAM,iBACL,YACA,SACA,cACA,aACgB;EAEhB,MAAM,UAAU,MAAM,KAAK,iBAAiB,YAAY,SAAS,aAAa;EAC9E,MAAM,aAAa,IAAI,IAAI,QAAQ,KAAK,MAAM,EAAE,GAAG,CAAC;EACpD,MAAM,SAAS,IAAI,IAAI,YAAY;EAGnC,MAAM,WAAW,QAAQ,QAAQ,MAAM,CAAC,OAAO,IAAI,EAAE,GAAG,CAAC,CAAC,KAAK,MAAM,EAAE,GAAG;AAC1E,MAAI,SAAS,SAAS,EACrB,OAAM,KAAK,GACT,WAAW,qBAAqB,CAChC,MAAM,cAAc,KAAK,WAAW,CACpC,MAAM,YAAY,KAAK,QAAQ,CAC/B,MAAM,eAAe,MAAM,SAAS,CACpC,SAAS;EAIZ,MAAM,QAAQ,YAAY,QAAQ,OAAO,CAAC,WAAW,IAAI,GAAG,CAAC;AAC7D,MAAI,MAAM,SAAS,EAClB,OAAM,KAAK,GACT,WAAW,qBAAqB,CAChC,OACA,MAAM,KAAK,iBAAiB;GAC3B;GACA,UAAU;GACV;GACA,EAAE,CACH,CACA,YAAY,OAAO,GAAG,WAAW,CAAC,CAClC,SAAS;;;;;CAOb,MAAM,gBAAgB,YAAoB,SAAkC;EAC3E,MAAM,SAAS,MAAM,KAAK,GACxB,WAAW,qBAAqB,CAChC,MAAM,cAAc,KAAK,WAAW,CACpC,MAAM,YAAY,KAAK,QAAQ,CAC/B,kBAAkB;AAEpB,SAAO,OAAO,OAAO,kBAAkB,EAAE;;;;;CAM1C,MAAM,qBAAqB,YAAqC;EAC/D,MAAM,SAAS,MAAM,KAAK,GACxB,WAAW,qBAAqB,CAChC,QAAQ,OAAO,GAAG,GAAG,MAAM,WAAW,CAAC,GAAG,QAAQ,CAAC,CACnD,MAAM,eAAe,KAAK,WAAW,CACrC,kBAAkB;AAEpB,SAAO,OAAO,QAAQ,SAAS,EAAE;;;;;CAMlC,AAAQ,cAAc,KAA8B;AACnD,SAAO;GACN,IAAI,IAAI;GACR,MAAM,IAAI;GACV,MAAM,IAAI;GACV,OAAO,IAAI;GACX,UAAU,IAAI;GACd,MAAM,IAAI,OAAO,KAAK,MAAM,IAAI,KAAK,GAAG;GACxC;;;;;;;;;;;;ACzRH,IAAa,oBAAb,MAA+B;CAC9B,YAAY,AAAQ,IAAsB;EAAtB;;;;;CAKpB,MAAM,IAAiB,MAAiC;EACvD,MAAM,MAAM,MAAM,KAAK,GACrB,WAAW,UAAU,CACrB,OAAO,QAAQ,CACf,MAAM,QAAQ,KAAK,KAAK,CACxB,kBAAkB;AAEpB,MAAI,CAAC,IAAK,QAAO;AAEjB,SAAO,KAAK,MAAM,IAAI,MAAM;;;;;CAM7B,MAAM,aAAgB,MAAc,cAA6B;AAEhE,SADc,MAAM,KAAK,IAAO,KAAK,IACrB;;;;;CAMjB,MAAM,IAAiB,MAAc,OAAyB;EAC7D,MAAM,MAAmB;GACxB;GACA,OAAO,KAAK,UAAU,MAAM;GAC5B;AAGD,QAAM,KAAK,GACT,WAAW,UAAU,CACrB,OAAO,IAAI,CACX,YAAY,OAAO,GAAG,OAAO,OAAO,CAAC,YAAY,EAAE,OAAO,IAAI,OAAO,CAAC,CAAC,CACvE,SAAS;;;;;CAMZ,MAAM,OAAO,MAAgC;AAG5C,WAFe,MAAM,KAAK,GAAG,WAAW,UAAU,CAAC,MAAM,QAAQ,KAAK,KAAK,CAAC,kBAAkB,EAE/E,kBAAkB,KAAK;;;;;CAMvC,MAAM,OAAO,MAAgC;AAO5C,SAAO,CAAC,CANI,MAAM,KAAK,GACrB,WAAW,UAAU,CACrB,OAAO,OAAO,CACd,MAAM,QAAQ,KAAK,KAAK,CACxB,kBAAkB;;;;;CAQrB,MAAM,QAAqB,OAA0C;AACpE,MAAI,MAAM,WAAW,EAAG,wBAAO,IAAI,KAAK;EAExC,MAAM,OAAO,MAAM,KAAK,GACtB,WAAW,UAAU,CACrB,OAAO,CAAC,QAAQ,QAAQ,CAAC,CACzB,MAAM,QAAQ,MAAM,MAAM,CAC1B,SAAS;EAEX,MAAM,yBAAS,IAAI,KAAgB;AACnC,OAAK,MAAM,OAAO,KAEjB,QAAO,IAAI,IAAI,MAAM,KAAK,MAAM,IAAI,MAAM,CAAM;AAEjD,SAAO;;;;;CAMR,MAAM,QAAqB,SAA2C;EACrE,MAAM,UAAU,OAAO,QAAQ,QAAQ;AACvC,MAAI,QAAQ,WAAW,EAAG;AAE1B,OAAK,MAAM,CAAC,MAAM,UAAU,QAC3B,OAAM,KAAK,IAAI,MAAM,MAAM;;;;;CAO7B,MAAM,SAAwC;EAC7C,MAAM,OAAO,MAAM,KAAK,GAAG,WAAW,UAAU,CAAC,OAAO,CAAC,QAAQ,QAAQ,CAAC,CAAC,SAAS;EAEpF,MAAM,yBAAS,IAAI,KAAsB;AACzC,OAAK,MAAM,OAAO,KACjB,QAAO,IAAI,IAAI,MAAM,KAAK,MAAM,IAAI,MAAM,CAAC;AAE5C,SAAO;;;;;CAMR,MAAM,YAAyB,QAAyC;EACvE,MAAM,OAAO,MAAM,KAAK,GACtB,WAAW,UAAU,CACrB,OAAO,CAAC,QAAQ,QAAQ,CAAC,CACzB,MAAM,QAAQ,QAAQ,GAAG,OAAO,GAAG,CACnC,SAAS;EAEX,MAAM,yBAAS,IAAI,KAAgB;AACnC,OAAK,MAAM,OAAO,KAEjB,QAAO,IAAI,IAAI,MAAM,KAAK,MAAM,IAAI,MAAM,CAAM;AAEjD,SAAO;;;;;CAMR,MAAM,eAAe,QAAiC;EACrD,MAAM,SAAS,MAAM,KAAK,GACxB,WAAW,UAAU,CACrB,MAAM,QAAQ,QAAQ,GAAG,OAAO,GAAG,CACnC,kBAAkB;AAEpB,SAAO,OAAO,OAAO,kBAAkB,EAAE;;;;;;;AClI3C,MAAM,kBAAkB;;;;AAKxB,SAAS,iBAAiB,OAAyC;AAClE,QAAO,OAAO,UAAU,YAAY,UAAU,QAAQ,aAAa;;;;;AAMpE,eAAe,sBACd,UACA,IACA,UAC2D;AAC3D,KAAI,CAAC,UAAU,QACd,QAAO;AAGR,KAAI;EAEH,MAAM,QAAQ,MADI,IAAI,gBAAgB,GAAG,CACX,SAAS,SAAS,QAAQ;AAExD,MAAI,MAEH,QAAO;GACN,GAAG;GACH,KAAK,2BAA2B,MAAM;GACtC;SAEK;AAIR,QAAO;;;;;;;;;;;;;;;;;;;;AAqBR,eAAsB,eACrB,KACuC;AAEvC,QAAO,qBAAqB,KADjB,MAAM,OAAO,CACY;;;;;;;;AASrC,eAAsB,qBACrB,KACA,IACA,UAA0B,MACa;CAEvC,MAAM,QAAQ,MADE,IAAI,kBAAkB,GAAG,CACb,IAAqB,GAAG,kBAAkB,MAAM;AAE5E,KAAI,CAAC,MACJ;AAMD,MAAK,QAAQ,UAAU,QAAQ,cAAc,iBAAiB,MAAM,CAGnE,QAFiB,MAAM,sBAAsB,OAAO,IAAI,QAAQ;AAKjE,QAAO;;;;;;;;;;;;;;;;;AAkBR,eAAsB,kBAAkD;AAEvE,QAAO,sBADI,MAAM,OAAO,CACQ;;;;;;;;AASjC,eAAsB,sBACrB,IACA,UAA0B,MACO;CAEjC,MAAM,aAAa,MADH,IAAI,kBAAkB,GAAG,CACR,YAAY,gBAAgB;CAE7D,MAAM,WAAoC,EAAE;AAG5C,MAAK,MAAM,CAAC,KAAK,UAAU,YAAY;EACtC,MAAM,aAAa,IAAI,QAAQ,iBAAiB,GAAG;AACnD,WAAS,cAAc;;CAGxB,MAAM,gBAAgB;AAGtB,KAAI,cAAc,KACjB,eAAc,OAAO,MAAM,sBAAsB,cAAc,MAAM,IAAI,QAAQ;AAElF,KAAI,cAAc,QACjB,eAAc,UAAU,MAAM,sBAAsB,cAAc,SAAS,IAAI,QAAQ;AAGxF,QAAO;;;;;;;;;;;;;;;;;;;;;;;;AAyBR,eAAsB,gBACrB,UACA,IACgB;CAChB,MAAM,UAAU,IAAI,kBAAkB,GAAG;CAGzC,MAAM,UAAmC,EAAE;AAC3C,MAAK,MAAM,CAAC,KAAK,UAAU,OAAO,QAAQ,SAAS,CAClD,KAAI,UAAU,OACb,SAAQ,GAAG,kBAAkB,SAAS;AAIxC,OAAM,QAAQ,QAAQ,QAAQ;;;;;;;;;;;AClM/B,MAAM,kCAAkC;AACxC,MAAM,+BAA+B;AACrC,MAAM,8BAA8B;AACpC,MAAM,+BACL;;;;;;;AAQD,MAAM,8BAA8B;;;;;;;AAQpC,MAAM,oBAAoB;AAE1B,MAAM,uBAAuB;;;;;;;;;;;AAY7B,MAAM,mBAA0D;CAE/D;EAAE,OAAO,SAAS,KAAK,GAAG,GAAG,EAAE;EAAE,KAAK,SAAS,KAAK,KAAK,KAAK,IAAI;EAAE;CAEpE;EAAE,OAAO,SAAS,IAAI,GAAG,GAAG,EAAE;EAAE,KAAK,SAAS,IAAI,KAAK,KAAK,IAAI;EAAE;CAElE;EAAE,OAAO,SAAS,KAAK,IAAI,GAAG,EAAE;EAAE,KAAK,SAAS,KAAK,IAAI,KAAK,IAAI;EAAE;CAEpE;EAAE,OAAO,SAAS,KAAK,KAAK,GAAG,EAAE;EAAE,KAAK,SAAS,KAAK,KAAK,KAAK,IAAI;EAAE;CAEtE;EAAE,OAAO,SAAS,KAAK,KAAK,GAAG,EAAE;EAAE,KAAK,SAAS,KAAK,KAAK,KAAK,IAAI;EAAE;CAEtE;EAAE,OAAO,SAAS,GAAG,GAAG,GAAG,EAAE;EAAE,KAAK,SAAS,GAAG,KAAK,KAAK,IAAI;EAAE;CAChE;AAED,MAAM,oBAAoB,IAAI,IAAI;CACjC;CACA;CACA;CACA;CACA,CAAC;;AAGF,MAAM,kBAAkB,IAAI,IAAI,CAAC,SAAS,SAAS,CAAC;AAEpD,SAAS,SAAS,GAAW,GAAW,GAAW,GAAmB;AACrE,SAAS,KAAK,KAAO,KAAK,KAAO,KAAK,IAAK,OAAO;;AAGnD,SAAS,UAAU,IAA2B;CAC7C,MAAM,QAAQ,GAAG,MAAM,IAAI;AAC3B,KAAI,MAAM,WAAW,EAAG,QAAO;CAE/B,MAAM,OAAO,MAAM,IAAI,OAAO;AAC9B,KAAI,KAAK,MAAM,MAAM,MAAM,EAAE,IAAI,IAAI,KAAK,IAAI,IAAI,CAAE,QAAO;AAE3D,QAAO,SAAS,KAAK,IAAI,KAAK,IAAI,KAAK,IAAI,KAAK,GAAG;;;;;;;;;;;AAYpD,SAAgB,0BAA0B,IAA2B;CAEpE,IAAI,QAAQ,GAAG,MAAM,6BAA6B;AAClD,KAAI,CAAC,MAEJ,SAAQ,GAAG,MAAM,4BAA4B;AAE9C,KAAI,CAAC,MAEJ,SAAQ,GAAG,MAAM,6BAA6B;AAE/C,KAAI,CAAC,MAEJ,SAAQ,GAAG,MAAM,4BAA4B;AAE9C,KAAI,CAAC,MAEJ,SAAQ,GAAG,MAAM,kBAAkB;AAEpC,KAAI,OAAO;EACV,MAAM,OAAO,SAAS,MAAM,MAAM,IAAI,GAAG;EACzC,MAAM,MAAM,SAAS,MAAM,MAAM,IAAI,GAAG;AACxC,SAAO,GAAI,QAAQ,IAAK,IAAK,GAAG,OAAO,IAAK,GAAI,OAAO,IAAK,IAAK,GAAG,MAAM;;AAE3E,QAAO;;AAGR,SAAS,YAAY,IAAqB;AAEzC,KAAI,OAAO,SAAS,OAAO,mBAAoB,QAAO;CAItD,MAAM,UAAU,0BAA0B,GAAG;AAC7C,KAAI,QAAS,QAAO,YAAY,QAAQ;CAGxC,MAAM,UAAU,GAAG,MAAM,gCAAgC;CAGzD,MAAM,MAAM,UAFC,UAAU,QAAQ,KAAK,GAET;AAC3B,KAAI,QAAQ,KAEX,QAAO,GAAG,WAAW,QAAQ,IAAI,GAAG,WAAW,KAAK,IAAI,GAAG,WAAW,KAAK;AAG5E,QAAO,iBAAiB,MAAM,UAAU,OAAO,MAAM,SAAS,OAAO,MAAM,IAAI;;;;;AAMhF,IAAa,YAAb,cAA+B,MAAM;CACpC,OAAO;CAEP,YAAY,SAAiB;AAC5B,QAAM,QAAQ;AACd,OAAK,OAAO;;;;;;;;;;;;;;;;;;;AAoBd,MAAM,gBAAgB;AAEtB,SAAgB,oBAAoB,KAAkB;CACrD,IAAI;AACJ,KAAI;AACH,WAAS,IAAI,IAAI,IAAI;SACd;AACP,QAAM,IAAI,UAAU,cAAc;;AAInC,KAAI,CAAC,gBAAgB,IAAI,OAAO,SAAS,CACxC,OAAM,IAAI,UAAU,WAAW,OAAO,SAAS,kBAAkB;CAIlE,MAAM,WAAW,OAAO,SAAS,QAAQ,sBAAsB,GAAG;AAGlE,KAAI,kBAAkB,IAAI,SAAS,aAAa,CAAC,CAChD,OAAM,IAAI,UAAU,gDAAgD;AAIrE,KAAI,YAAY,SAAS,CACxB,OAAM,IAAI,UAAU,sDAAsD;AAG3E,QAAO;;;;;;;;;;;;;AAcR,MAAM,qBAAqB;CAAC;CAAiB;CAAU;CAAsB;AAE7E,eAAsB,cAAc,KAAa,MAAuC;CACvF,IAAI,aAAa;CACjB,IAAI,cAAc;AAElB,MAAK,IAAI,IAAI,GAAG,KAAK,eAAe,KAAK;AACxC,sBAAoB,WAAW;EAE/B,MAAM,WAAW,MAAM,WAAW,MAAM,YAAY;GACnD,GAAG;GACH,UAAU;GACV,CAAC;AAGF,MAAI,SAAS,SAAS,OAAO,SAAS,UAAU,IAC/C,QAAO;EAIR,MAAM,WAAW,SAAS,QAAQ,IAAI,WAAW;AACjD,MAAI,CAAC,SACJ,QAAO;EAIR,MAAM,iBAAiB,IAAI,IAAI,WAAW,CAAC;AAC3C,eAAa,IAAI,IAAI,UAAU,WAAW,CAAC;AAI3C,MAAI,mBAHe,IAAI,IAAI,WAAW,CAAC,UAGF,YACpC,eAAc,uBAAuB,YAAY;;AAInD,OAAM,IAAI,UAAU,2BAA2B,cAAc,GAAG;;;;;AAMjE,SAAgB,uBAAuB,MAAgC;AACtE,KAAI,CAAC,KAAK,QAAS,QAAO;CAE1B,MAAM,UAAU,IAAI,QAAQ,KAAK,QAAQ;AACzC,MAAK,MAAM,QAAQ,mBAClB,SAAQ,OAAO,KAAK;AAGrB,QAAO;EAAE,GAAG;EAAM;EAAS;;;;;;;;;;;;AChO5B,MAAM,yBAAyB;;AAI/B,MAAM,oBAAoB;;AAG1B,MAAM,sBAAsB;;AAG5B,MAAM,mBAAmB;;AAGzB,MAAM,2BAA2B;;;;;;;;;;;AAYjC,eAAsB,UACrB,IACA,MACA,UAA4B,EAAE,EACH;CAE3B,MAAM,aAAa,aAAa,KAAK;AACrC,KAAI,CAAC,WAAW,MACf,OAAM,IAAI,MAAM,uBAAuB,WAAW,OAAO,KAAK,KAAK,GAAG;CAGvE,MAAM,EACL,iBAAiB,OACjB,SACA,oBAAoB,OACpB,aAAa,WACV;CAGJ,MAAM,SAA0B;EAC/B,aAAa;GAAE,SAAS;GAAG,SAAS;GAAG,SAAS;GAAG;EACnD,QAAQ;GAAE,SAAS;GAAG,SAAS;GAAG,SAAS;GAAG;EAC9C,YAAY;GAAE,SAAS;GAAG,OAAO;GAAG;EACpC,SAAS;GAAE,SAAS;GAAG,SAAS;GAAG,SAAS;GAAG;EAC/C,OAAO;GAAE,SAAS;GAAG,OAAO;GAAG;EAC/B,WAAW;GAAE,SAAS;GAAG,SAAS;GAAG,SAAS;GAAG;EACjD,aAAa;GAAE,SAAS;GAAG,SAAS;GAAG;EACvC,UAAU;GAAE,SAAS;GAAG,SAAS;GAAG,SAAS;GAAG;EAChD,UAAU,EAAE,SAAS,GAAG;EACxB,SAAS;GAAE,SAAS;GAAG,SAAS;GAAG,SAAS;GAAG;EAC/C,OAAO;GAAE,SAAS;GAAG,SAAS;GAAG;EACjC;CAGD,MAAM,eAA6B;EAClC;EACA,SAAS,WAAW;EACpB;EACA,4BAAY,IAAI,KAAK;EACrB;CAYD,MAAM,4BAAY,IAAI,KAAqB;CAC3C,MAAM,kCAAkB,IAAI,KAAqB;AAGjD,KAAI,KAAK,UAAU;AAClB,QAAM,gBAAgB,KAAK,UAAU,GAAG;AACxC,SAAO,SAAS,UAAU,OAAO,KAAK,KAAK,SAAS,CAAC;;AAItD,KAAI,KAAK,aAAa;EACrB,MAAM,WAAW,IAAI,eAAe,GAAG;AAEvC,OAAK,MAAM,cAAc,KAAK,aAAa;AAI1C,OAFiB,MAAM,SAAS,cAAc,WAAW,KAAK,EAEhD;AACb,QAAI,eAAe,QAClB,OAAM,IAAI,MAAM,yBAAyB,WAAW,KAAK,kBAAkB;AAG5E,QAAI,eAAe,UAAU;AAC5B,WAAM,SAAS,iBAAiB,WAAW,MAAM;MAChD,OAAO,WAAW;MAClB,eAAe,WAAW;MAC1B,aAAa,WAAW;MACxB,MAAM,WAAW;MACjB,UAAU,WAAW,YAAY,EAAE;MACnC,YAAY,WAAW;MACvB,iBAAiB,WAAW;MAC5B,CAAC;AACF,YAAO,YAAY;AAGnB,UAAK,MAAM,SAAS,WAAW,OAE9B,KADsB,MAAM,SAAS,SAAS,WAAW,MAAM,MAAM,KAAK,EACvD;AAClB,YAAM,SAAS,YAAY,WAAW,MAAM,MAAM,MAAM;OACvD,OAAO,MAAM;OACb,UAAU,MAAM,YAAY;OAC5B,QAAQ,MAAM,UAAU;OACxB,YAAY,MAAM,cAAc;OAChC,cAAc,MAAM;OACpB,YAAY,MAAM;OAClB,QAAQ,MAAM;OACd,SAAS,MAAM;OACf,CAAC;AACF,aAAO,OAAO;YACR;AACN,YAAM,SAAS,YAAY,WAAW,MAAM;OAC3C,MAAM,MAAM;OACZ,OAAO,MAAM;OACb,MAAM,MAAM;OACZ,UAAU,MAAM,YAAY;OAC5B,QAAQ,MAAM,UAAU;OACxB,YAAY,MAAM,cAAc;OAChC,cAAc,MAAM;OACpB,YAAY,MAAM;OAClB,QAAQ,MAAM;OACd,SAAS,MAAM;OACf,CAAC;AACF,aAAO,OAAO;;AAGhB;;AAID,WAAO,YAAY;AACnB,WAAO,OAAO,WAAW,WAAW,OAAO;AAC3C;;AAID,SAAM,SAAS,iBAAiB;IAC/B,MAAM,WAAW;IACjB,OAAO,WAAW;IAClB,eAAe,WAAW;IAC1B,aAAa,WAAW;IACxB,MAAM,WAAW;IACjB,UAAU,WAAW,YAAY,EAAE;IACnC,QAAQ;IACR,YAAY,WAAW;IACvB,iBAAiB,WAAW;IAC5B,CAAC;AACF,UAAO,YAAY;AAGnB,QAAK,MAAM,SAAS,WAAW,QAAQ;AACtC,UAAM,SAAS,YAAY,WAAW,MAAM;KAC3C,MAAM,MAAM;KACZ,OAAO,MAAM;KACb,MAAM,MAAM;KACZ,UAAU,MAAM,YAAY;KAC5B,QAAQ,MAAM,UAAU;KACxB,YAAY,MAAM,cAAc;KAChC,cAAc,MAAM;KACpB,YAAY,MAAM;KAClB,QAAQ,MAAM;KACd,SAAS,MAAM;KACf,CAAC;AACF,WAAO,OAAO;;;;AAMjB,KAAI,KAAK,WACR,MAAK,MAAM,YAAY,KAAK,YAAY;EAEvC,MAAM,cAAc,MAAM,GACxB,WAAW,wBAAwB,CACnC,WAAW,CACX,MAAM,QAAQ,KAAK,SAAS,KAAK,CACjC,kBAAkB;AAEpB,MAAI,aAAa;AAChB,OAAI,eAAe,QAClB,OAAM,IAAI,MAAM,uBAAuB,SAAS,KAAK,kBAAkB;AAExE,OAAI,eAAe,SAClB,OAAM,GACJ,YAAY,wBAAwB,CACpC,IAAI;IACJ,OAAO,SAAS;IAChB,gBAAgB,SAAS,iBAAiB;IAC1C,cAAc,SAAS,eAAe,IAAI;IAC1C,aAAa,KAAK,UAAU,SAAS,YAAY;IACjD,CAAC,CACD,MAAM,MAAM,KAAK,YAAY,GAAG,CAChC,SAAS;SAIN;AAEN,SAAM,GACJ,WAAW,wBAAwB,CACnC,OAAO;IACP,IAAI,MAAM;IACV,MAAM,SAAS;IACf,OAAO,SAAS;IAChB,gBAAgB,SAAS,iBAAiB;IAC1C,cAAc,SAAS,eAAe,IAAI;IAC1C,aAAa,KAAK,UAAU,SAAS,YAAY;IACjD,CAAC,CACD,SAAS;AACX,UAAO,WAAW;;AAInB,MAAI,SAAS,SAAS,SAAS,MAAM,SAAS,GAAG;GAChD,MAAM,WAAW,IAAI,mBAAmB,GAAG;AAG3C,OAAI,SAAS,aACZ,OAAM,uBAAuB,UAAU,SAAS,MAAM,SAAS,OAAO,QAAQ,WAAW;OAGzF,MAAK,MAAM,QAAQ,SAAS,OAAO;IAClC,MAAM,WAAW,MAAM,SAAS,WAAW,SAAS,MAAM,KAAK,KAAK;AACpE,QAAI,UAAU;AACb,SAAI,eAAe,QAClB,OAAM,IAAI,MACT,4BAA4B,KAAK,KAAK,QAAQ,SAAS,KAAK,kBAC5D;AAEF,SAAI,eAAe,UAAU;AAC5B,YAAM,SAAS,OAAO,SAAS,IAAI;OAClC,OAAO,KAAK;OACZ,MAAM,KAAK,cAAc,EAAE,aAAa,KAAK,aAAa,GAAG,EAAE;OAC/D,CAAC;AACF,aAAO,WAAW;;WAGb;AACN,WAAM,SAAS,OAAO;MACrB,MAAM,SAAS;MACf,MAAM,KAAK;MACX,OAAO,KAAK;MACZ,MAAM,KAAK,cAAc,EAAE,aAAa,KAAK,aAAa,GAAG;MAC7D,CAAC;AACF,YAAO,WAAW;;;;;AASxB,KAAI,KAAK,SAAS;EACjB,MAAM,aAAa,IAAI,iBAAiB,GAAG;AAC3C,OAAK,MAAM,UAAU,KAAK,SAAS;GAClC,MAAM,WAAW,MAAM,WAAW,WAAW,OAAO,KAAK;AACzD,OAAI,UAAU;AACb,QAAI,eAAe,QAClB,OAAM,IAAI,MAAM,qBAAqB,OAAO,KAAK,kBAAkB;AAGpE,QAAI,eAAe,UAAU;AAC5B,WAAM,WAAW,OAAO,SAAS,IAAI;MACpC,aAAa,OAAO;MACpB,KAAK,OAAO,OAAO;MACnB,YAAY,OAAO,cAAc;MACjC,SAAS,OAAO;MAChB,CAAC;AACF,qBAAgB,IAAI,OAAO,IAAI,SAAS,GAAG;AAC3C,YAAO,QAAQ;AACf;;AAID,oBAAgB,IAAI,OAAO,IAAI,SAAS,GAAG;AAC3C,WAAO,QAAQ;AACf;;GAGD,MAAM,UAAU,MAAM,WAAW,OAAO;IACvC,MAAM,OAAO;IACb,aAAa,OAAO;IACpB,KAAK,OAAO,OAAO;IACnB,YAAY,OAAO,cAAc;IACjC,SAAS,OAAO;IAChB,CAAC;AACF,mBAAgB,IAAI,OAAO,IAAI,QAAQ,GAAG;AAC1C,UAAO,QAAQ;;;AAKjB,KAAI,kBAAkB,KAAK,SAAS;EACnC,MAAM,cAAc,IAAI,kBAAkB,GAAG;EAC7C,MAAM,aAAa,IAAI,iBAAiB,GAAG;AAG3C,OAAK,MAAM,CAAC,gBAAgB,YAAY,OAAO,QAAQ,KAAK,QAAQ,CACnE,MAAK,MAAM,SAAS,SAAS;GAE5B,MAAM,WAAW,MAAM,YAAY,WAAW,gBAAgB,MAAM,MAAM,MAAM,OAAO;AAEvF,OAAI,UAAU;AACb,QAAI,eAAe,QAClB,OAAM,IAAI,MACT,sBAAsB,MAAM,KAAK,QAAQ,eAAe,kBACxD;AAGF,QAAI,eAAe,UAAU;KAE5B,MAAM,eAAe,MAAM,kBAC1B,MAAM,MACN,WACA,cACA,OACA;KAED,MAAM,SAAS,MAAM,UAAU;AAC/B,WAAM,YAAY,OAAO,gBAAgB,SAAS,IAAI;MACrD;MACA,MAAM;MACN,CAAC;AAEF,eAAU,IAAI,MAAM,IAAI,SAAS,GAAG;AACpC,YAAO,QAAQ;AAGf,WAAM,oBACL,YACA,gBACA,SAAS,IACT,OACA,iBACA,KACA;AACD,WAAM,uBAAuB,IAAI,gBAAgB,SAAS,IAAI,OAAO,KAAK;AAC1E;;AAID,WAAO,QAAQ;AACf,cAAU,IAAI,MAAM,IAAI,SAAS,GAAG;AACpC;;GAID,MAAM,eAAe,MAAM,kBAAkB,MAAM,MAAM,WAAW,cAAc,OAAO;GAGzF,IAAI;AACJ,OAAI,MAAM,eAAe;IACxB,MAAM,WAAW,UAAU,IAAI,MAAM,cAAc;AACnD,QAAI,CAAC,SACJ,SAAQ,KACP,WAAW,eAAe,mBAAmB,MAAM,cAAc,sEACjE;QAED,iBAAgB;;GAKlB,MAAM,SAAS,MAAM,UAAU;GAC/B,MAAM,UAAU,MAAM,YAAY,OAAO;IACxC,MAAM;IACN,MAAM,MAAM;IACZ;IACA,MAAM;IACN,QAAQ,MAAM;IACd;IAEA,aAAa,WAAW,+BAAc,IAAI,MAAM,EAAC,aAAa,GAAG;IACjE,CAAC;AAEF,aAAU,IAAI,MAAM,IAAI,QAAQ,GAAG;AACnC,UAAO,QAAQ;AAEf,SAAM,oBAAoB,YAAY,gBAAgB,QAAQ,IAAI,OAAO,gBAAgB;AACzF,SAAM,uBAAuB,IAAI,gBAAgB,QAAQ,IAAI,OAAO,MAAM;;;AAM7E,KAAI,KAAK,MACR,MAAK,MAAM,QAAQ,KAAK,OAAO;EAE9B,MAAM,eAAe,MAAM,GACzB,WAAW,gBAAgB,CAC3B,WAAW,CACX,MAAM,QAAQ,KAAK,KAAK,KAAK,CAC7B,kBAAkB;EAEpB,IAAI;AAEJ,MAAI,cAAc;AACjB,YAAS,aAAa;AAEtB,SAAM,GAAG,WAAW,qBAAqB,CAAC,MAAM,WAAW,KAAK,OAAO,CAAC,SAAS;SAC3E;AAEN,YAAS,MAAM;AACf,SAAM,GACJ,WAAW,gBAAgB,CAC3B,OAAO;IACP,IAAI;IACJ,MAAM,KAAK;IACX,OAAO,KAAK;IACZ,6BAAY,IAAI,MAAM,EAAC,aAAa;IACpC,6BAAY,IAAI,MAAM,EAAC,aAAa;IACpC,CAAC,CACD,SAAS;AACX,UAAO,MAAM;;EAId,MAAM,YAAY,MAAM,eACvB,IACA,QACA,KAAK,OACL,MACA,GACA,UACA;AACD,SAAO,MAAM,SAAS;;AAKxB,KAAI,KAAK,WAAW;EACnB,MAAM,eAAe,IAAI,mBAAmB,GAAG;AAE/C,OAAK,MAAM,YAAY,KAAK,WAAW;GACtC,MAAM,WAAW,MAAM,aAAa,aAAa,SAAS,OAAO;AACjE,OAAI,UAAU;AACb,QAAI,eAAe,QAClB,OAAM,IAAI,MAAM,uBAAuB,SAAS,OAAO,kBAAkB;AAG1E,QAAI,eAAe,UAAU;AAC5B,WAAM,aAAa,OAAO,SAAS,IAAI;MACtC,aAAa,SAAS;MACtB,MAAM,SAAS;MACf,SAAS,SAAS;MAClB,WAAW,SAAS;MACpB,CAAC;AACF,YAAO,UAAU;AACjB;;AAID,WAAO,UAAU;AACjB;;AAGD,SAAM,aAAa,OAAO;IACzB,QAAQ,SAAS;IACjB,aAAa,SAAS;IACtB,MAAM,SAAS;IACf,SAAS,SAAS;IAClB,WAAW,SAAS;IACpB,CAAC;AACF,UAAO,UAAU;;;AAKnB,KAAI,KAAK,YACR,MAAK,MAAM,QAAQ,KAAK,aAAa;EAEpC,MAAM,eAAe,MAAM,GACzB,WAAW,uBAAuB,CAClC,WAAW,CACX,MAAM,QAAQ,KAAK,KAAK,KAAK,CAC7B,kBAAkB;EAEpB,IAAI;AAEJ,MAAI,cAAc;AACjB,YAAS,aAAa;AAEtB,SAAM,GAAG,WAAW,kBAAkB,CAAC,MAAM,WAAW,KAAK,OAAO,CAAC,SAAS;SACxE;AAEN,YAAS,MAAM;AACf,SAAM,GACJ,WAAW,uBAAuB,CAClC,OAAO;IACP,IAAI;IACJ,MAAM,KAAK;IACX,OAAO,KAAK;IACZ,aAAa,KAAK,eAAe;IACjC,CAAC,CACD,SAAS;AACX,UAAO,YAAY;;AAIpB,OAAK,IAAI,IAAI,GAAG,IAAI,KAAK,QAAQ,QAAQ,KAAK;GAC7C,MAAM,SAAS,KAAK,QAAQ;AAC5B,SAAM,YAAY,IAAI,QAAQ,QAAQ,EAAE;AACxC,UAAO,YAAY;;;AAMtB,KAAI,KAAK,SACR,MAAK,MAAM,WAAW,KAAK,UAAU;EAEpC,MAAM,WAAW,MAAM,GACrB,WAAW,mBAAmB,CAC9B,OAAO,KAAK,CACZ,MAAM,QAAQ,KAAK,QAAQ,KAAK,CAChC,kBAAkB;AAEpB,MAAI,UAAU;AACb,OAAI,eAAe,QAClB,OAAM,IAAI,MAAM,sBAAsB,QAAQ,KAAK,kBAAkB;AAGtE,OAAI,eAAe,UAAU;AAC5B,UAAM,GACJ,YAAY,mBAAmB,CAC/B,IAAI;KACJ,OAAO,QAAQ;KACf,aAAa,QAAQ,eAAe;KACpC,UAAU,QAAQ,WAAW,KAAK,UAAU,QAAQ,SAAS,GAAG;KAChE,SAAS,KAAK,UAAU,QAAQ,QAAQ;KACxC,QAAQ,QAAQ,UAAU;KAC1B,6BAAY,IAAI,MAAM,EAAC,aAAa;KACpC,CAAC,CACD,MAAM,MAAM,KAAK,SAAS,GAAG,CAC7B,SAAS;AACX,WAAO,SAAS;AAChB;;AAID,UAAO,SAAS;AAChB;;EAGD,MAAM,KAAK,MAAM;EACjB,MAAM,uBAAM,IAAI,MAAM,EAAC,aAAa;AAEpC,QAAM,GACJ,WAAW,mBAAmB,CAC9B,OAAO;GACP;GACA,MAAM,QAAQ;GACd,OAAO,QAAQ;GACf,aAAa,QAAQ,eAAe;GACpC,UAAU,QAAQ,WAAW,KAAK,UAAU,QAAQ,SAAS,GAAG;GAChE,SAAS,KAAK,UAAU,QAAQ,QAAQ;GACxC,kBAAkB;GAClB,QAAQ,QAAQ,UAAU;GAC1B,UAAU,QAAQ,WAAW,UAAU,QAAQ,OAAO;GACtD,YAAY;GACZ,YAAY;GACZ,CAAC,CACD,SAAS;AAEX,SAAO,SAAS;;AAKlB,KAAI,KAAK,aAAa;EACrB,MAAM,aAAa,IAAI,WAAW,GAAG;AAErC,OAAK,MAAM,cAAc,KAAK,YAC7B,KAAI,WAAW,UAAU,SAAS,SAAS,EAG1C;QADyB,MAAM,WAAW,oBAAoB,WAAW,KAAK,EACzD,SAAS,EAC7B,KAAI;AACH,UAAM,WAAW,aAAa,WAAW,KAAK;YACtC,KAAK;AAEb,YAAQ,KAAK,+BAA+B,WAAW,KAAK,IAAI,IAAI;;;;AAOzE,QAAO;;;;;AAMR,eAAe,uBACd,UACA,cACA,OACA,QACA,aAA0C,QAC1B;CAEhB,MAAM,2BAAW,IAAI,KAAqB;CAG1C,IAAI,YAAY,CAAC,GAAG,MAAM;CAC1B,IAAI,YAAY;AAEhB,QAAO,UAAU,SAAS,KAAK,YAAY,GAAG;EAC7C,MAAM,oBAA8B,EAAE;AAEtC,OAAK,MAAM,QAAQ,UAElB,KAAI,CAAC,KAAK,UAAU,SAAS,IAAI,KAAK,OAAO,EAAE;GAC9C,MAAM,WAAW,KAAK,SAAS,SAAS,IAAI,KAAK,OAAO,GAAG;GAE3D,MAAM,WAAW,MAAM,SAAS,WAAW,cAAc,KAAK,KAAK;AACnE,OAAI,UAAU;AACb,QAAI,eAAe,QAClB,OAAM,IAAI,MACT,4BAA4B,KAAK,KAAK,QAAQ,aAAa,kBAC3D;AAEF,QAAI,eAAe,UAAU;AAC5B,WAAM,SAAS,OAAO,SAAS,IAAI;MAClC,OAAO,KAAK;MACZ;MACA,MAAM,KAAK,cAAc,EAAE,aAAa,KAAK,aAAa,GAAG,EAAE;MAC/D,CAAC;AACF,YAAO,WAAW;;AAEnB,aAAS,IAAI,KAAK,MAAM,SAAS,GAAG;UAC9B;IACN,MAAM,UAAU,MAAM,SAAS,OAAO;KACrC,MAAM;KACN,MAAM,KAAK;KACX,OAAO,KAAK;KACZ;KACA,MAAM,KAAK,cAAc,EAAE,aAAa,KAAK,aAAa,GAAG;KAC7D,CAAC;AACF,aAAS,IAAI,KAAK,MAAM,QAAQ,GAAG;AACnC,WAAO,WAAW;;AAGnB,qBAAkB,KAAK,KAAK,KAAK;;AAKnC,cAAY,UAAU,QAAQ,MAAM,CAAC,kBAAkB,SAAS,EAAE,KAAK,CAAC;AACxE;;AAGD,KAAI,UAAU,SAAS,EACtB,SAAQ,KAAK,qBAAqB,UAAU,OAAO,+BAA+B;;;;;;AAQpF,eAAe,oBACd,YACA,gBACA,WACA,OACA,iBACA,WAAW,OACK;AAChB,KAAI,CAAC,MAAM,WAAW,MAAM,QAAQ,WAAW,GAAG;AAEjD,MAAI,SACH,OAAM,WAAW,kBAAkB,gBAAgB,WAAW,EAAE,CAAC;AAElE;;CAGD,MAAM,UAAU,MAAM,QACpB,KAAK,WAAW;EAChB,MAAM,WAAW,gBAAgB,IAAI,OAAO,OAAO;AACnD,MAAI,CAAC,SAAU,QAAO;AACtB,SAAO;GACN;GACA,WAAW,OAAO,aAAa;GAC/B;GACA,CACD,QAAQ,WAAqE,QAAQ,OAAO,CAAC;AAE/F,KAAI,QAAQ,WAAW,MAAM,QAAQ,OACpC,SAAQ,KACP,WAAW,eAAe,GAAG,MAAM,KAAK,iDACxC;AAMF,KAAI,QAAQ,SAAS,KAAK,SACzB,OAAM,WAAW,kBAAkB,gBAAgB,WAAW,QAAQ;;;;;;AAQxE,eAAe,uBACd,IACA,gBACA,WACA,OACA,UACgB;AAEhB,KAAI,SACH,OAAM,GACJ,WAAW,qBAAqB,CAChC,MAAM,cAAc,KAAK,eAAe,CACxC,MAAM,YAAY,KAAK,UAAU,CACjC,SAAS;AAGZ,KAAI,CAAC,MAAM,WAAY;AAEvB,MAAK,MAAM,CAAC,cAAc,cAAc,OAAO,QAAQ,MAAM,WAAW,EAAE;EACzE,MAAM,WAAW,IAAI,mBAAmB,GAAG;AAE3C,OAAK,MAAM,YAAY,WAAW;GACjC,MAAM,OAAO,MAAM,SAAS,WAAW,cAAc,SAAS;AAC9D,OAAI,KACH,OAAM,SAAS,cAAc,gBAAgB,WAAW,KAAK,GAAG;;;;;;;AASpE,eAAe,eACd,IACA,QACA,OACA,UACA,YACA,WACkB;CAClB,IAAI,QAAQ;CACZ,IAAI,QAAQ;AAEZ,MAAK,MAAM,QAAQ,OAAO;EACzB,MAAM,SAAS,MAAM;EAGrB,IAAI,cAA6B;EACjC,IAAI,sBAAqC;AAEzC,MAAI,KAAK,SAAS,UAAU,KAAK,SAAS,QAEzC;OAAI,KAAK,OAAO,UAAU,IAAI,KAAK,IAAI,EAAE;AACxC,kBAAc,UAAU,IAAI,KAAK,IAAI;AAErC,0BAAsB,KAAK,cAAc,GAAG,KAAK,KAAK;;;AAMxD,QAAM,GACJ,WAAW,qBAAqB,CAChC,OAAO;GACP,IAAI;GACJ,SAAS;GACT,WAAW;GACX,YAAY;GACZ,MAAM,KAAK;GACX,sBAAsB;GACtB,cAAc;GACd,YAAY,KAAK,OAAO;GACxB,OAAO,KAAK,SAAS;GACrB,YAAY,KAAK,aAAa;GAC9B,QAAQ,KAAK,UAAU;GACvB,aAAa,KAAK,cAAc;GAChC,6BAAY,IAAI,MAAM,EAAC,aAAa;GACpC,CAAC,CACD,SAAS;AAEX;AACA;AAGA,MAAI,KAAK,YAAY,KAAK,SAAS,SAAS,GAAG;GAC9C,MAAM,aAAa,MAAM,eAAe,IAAI,QAAQ,KAAK,UAAU,QAAQ,GAAG,UAAU;AACxF,YAAS;;;AAIX,QAAO;;;;;AAMR,eAAe,YACd,IACA,QACA,QACA,WACgB;AAChB,OAAM,GACJ,WAAW,kBAAkB,CAC7B,OAAO;EACP,IAAI,MAAM;EACV,SAAS;EACT,YAAY;EACZ,MAAM,OAAO;EACb,OAAO,OAAO,SAAS;EACvB,SAAS,OAAO,UAAU,KAAK,UAAU,OAAO,QAAQ,GAAG;EAC3D,WAAW,OAAO,YAAY;EAC9B,cAAc,OAAO,eAAe;EACpC,iBAAiB,OAAO,QAAQ,KAAK,UAAU,OAAO,MAAM,GAAG;EAC/D,CAAC,CACD,SAAS;;;;;AAgBZ,SAAS,qBAAqB,OAA6C;AAC1E,KAAI,OAAO,UAAU,YAAY,UAAU,QAAQ,EAAE,YAAY,OAChE,QAAO;CAER,MAAM,QAAS,MAAkC;AACjD,QACC,OAAO,UAAU,YACjB,UAAU,QACV,SAAS,SACT,OAAQ,MAAkC,QAAQ;;;;;AAOpD,eAAe,kBACd,MACA,WACA,cACA,QACmC;CACnC,MAAM,WAAoC,EAAE;AAE5C,MAAK,MAAM,CAAC,KAAK,UAAU,OAAO,QAAQ,KAAK,CAC9C,UAAS,OAAO,MAAM,aAAa,OAAO,WAAW,cAAc,OAAO;AAG3E,QAAO;;;;;AAMR,eAAe,aACd,OACA,WACA,cACA,QACmB;AAEnB,KAAI,OAAO,UAAU,YAAY,MAAM,WAAW,QAAQ,EAAE;EAC3D,MAAM,SAAS,MAAM,MAAM,EAAE;AAC7B,SAAO,UAAU,IAAI,OAAO,IAAI;;AAIjC,KAAI,qBAAqB,MAAM,CAC9B,QAAO,aAAa,OAAO,cAAc,OAAO;AAIjD,KAAI,MAAM,QAAQ,MAAM,CACvB,QAAO,QAAQ,IAAI,MAAM,KAAK,SAAS,aAAa,MAAM,WAAW,cAAc,OAAO,CAAC,CAAC;AAI7F,KAAI,OAAO,UAAU,YAAY,UAAU,MAAM;EAChD,MAAM,WAAoC,EAAE;AAC5C,OAAK,MAAM,CAAC,GAAG,MAAM,OAAO,QAAQ,MAAM,CACzC,UAAS,KAAK,MAAM,aAAa,GAAG,WAAW,cAAc,OAAO;AAErE,SAAO;;AAGR,QAAO;;;;;AAMR,eAAe,aACd,KACA,KACA,QAC6B;CAC7B,MAAM,EAAE,KAAK,KAAK,UAAU,YAAY,IAAI;CAG5C,MAAM,SAAS,IAAI,WAAW,IAAI,IAAI;AACtC,KAAI,QAAQ;AACX,SAAO,MAAM;AACb,SAAO;GAAE,GAAG;GAAQ,KAAK,OAAO,OAAO;GAAK;;AAK7C,KAAI,IAAI,mBAAmB;EAC1B,MAAM,aAAyB;GAC9B,UAAU;GACV,IAAI,MAAM;GACV,KAAK;GACL,KAAK,OAAO;GACZ,UAAU,YAAY;GACtB;AACD,MAAI,WAAW,IAAI,KAAK,WAAW;AACnC,SAAO,MAAM;AACb,SAAO;;AAIR,KAAI,CAAC,IAAI,SAAS;AACjB,UAAQ,KAAK,sDAAsD,MAAM;AACzE,SAAO,MAAM;AACb,SAAO;;AAGR,KAAI;AAEH,sBAAoB,IAAI;AAGxB,UAAQ,IAAI,qBAAqB,MAAM;EACvC,MAAM,WAAW,MAAM,cAAc,KAAK,EACzC,SAAS,EAER,cAAc,kBACd,EACD,CAAC;AAEF,MAAI,CAAC,SAAS,IAAI;AACjB,WAAQ,KAAK,2BAA2B,IAAI,IAAI,SAAS,SAAS;AAClE,UAAO,MAAM;AACb,UAAO;;EAIR,MAAM,cAAc,SAAS,QAAQ,IAAI,eAAe,IAAI;EAC5D,MAAM,MAAM,4BAA4B,YAAY,IAAI,oBAAoB,IAAI,IAAI;EAGpF,MAAM,KAAK,MAAM;EACjB,MAAM,gBAAgB,YAAY,iBAAiB,KAAK,IAAI;EAC5D,MAAM,aAAa,GAAG,KAAK;EAG3B,MAAM,cAAc,MAAM,SAAS,aAAa;EAChD,MAAM,OAAO,IAAI,WAAW,YAAY;EAGxC,IAAI;EACJ,IAAI;AACJ,MAAI,YAAY,WAAW,SAAS,EAAE;GACrC,MAAM,aAAa,mBAAmB,KAAK;AAC3C,WAAQ,YAAY;AACpB,YAAS,YAAY;;AAItB,QAAM,IAAI,QAAQ,OAAO;GACxB,KAAK;GACL;GACA;GACA,CAAC;AAIF,QADkB,IAAI,gBAAgB,IAAI,GAAG,CAC7B,OAAO;GACtB,UAAU;GACV,UAAU;GACV,MAAM,KAAK;GACX;GACA;GACA;GACA;GACA;GACA,QAAQ;GACR,CAAC;EAGF,MAAM,aAAyB;GAC9B,UAAU;GACV;GACA,KAAK,OAAO;GACZ;GACA;GACA,UAAU;GACV,UAAU;GACV,MAAM,EAAE,YAAY;GACpB;AAGD,MAAI,WAAW,IAAI,KAAK,WAAW;AACnC,SAAO,MAAM;AAEb,UAAQ,IAAI,iBAAiB,gBAAgB;AAC7C,SAAO;UACC,OAAO;AACf,UAAQ,KACP,gCAAgC,IAAI,IACpC,iBAAiB,QAAQ,MAAM,UAAU,MACzC;AACD,SAAO,MAAM;AACb,SAAO;;;;;;AAOT,SAAS,4BAA4B,aAAoC;CAExE,MAAM,WAAW,YAAY,MAAM,IAAI,CAAC,GAAG,MAAM;CACjD,MAAM,MAAM,KAAK,aAAa,SAAS;AACvC,QAAO,MAAM,IAAI,QAAQ;;;;;AAM1B,SAAS,oBAAoB,KAA4B;AACxD,KAAI;EAEH,MAAM,QADW,IAAI,IAAI,IAAI,CAAC,SACP,MAAM,uBAAuB;AACpD,SAAO,QAAQ,IAAI,MAAM,OAAO;SACzB;AACP,SAAO;;;;;;AAOT,SAAS,iBAAiB,KAAa,KAAqB;AAC3D,KAAI;AAOH,SAAO,IANU,IAAI,IAAI,IAAI,CAAC,SACJ,MAAM,IAAI,CAAC,KAAK,IAAI,SAExB,QAAQ,mBAAmB,GAAG,CAAC,QAAQ,qBAAqB,GAAG,CAE9D,QAAQ,kBAAkB,IAAI,CAAC,QAAQ,0BAA0B,IAAI,IACrE,UAAU;SAC1B;AACP,SAAO,QAAQ;;;;;;;AAQjB,SAAS,mBAAmB,QAA8D;AACzF,KAAI;EACH,MAAM,SAAS,UAAU,OAAO;AAChC,MAAI,OAAO,SAAS,QAAQ,OAAO,UAAU,KAC5C,QAAO;GAAE,OAAO,OAAO;GAAO,QAAQ,OAAO;GAAQ;AAEtD,SAAO;SACA;AACP,SAAO"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"byline-CL847F26.mjs","names":[],"sources":["../src/database/repositories/byline.ts"],"sourcesContent":["import { sql, type Kysely, type Selectable } from \"kysely\";\nimport { ulid } from \"ulidx\";\n\nimport { listTablesLike } from \"../dialect-helpers.js\";\nimport type { BylineTable, Database } from \"../types.js\";\nimport { validateIdentifier } from \"../validate.js\";\nimport {\n\tdecodeCursor,\n\tencodeCursor,\n\ttype BylineSummary,\n\ttype ContentBylineCredit,\n\ttype FindManyResult,\n} from \"./types.js\";\n\ntype BylineRow = Selectable<BylineTable>;\n\nexport interface CreateBylineInput {\n\tslug: string;\n\tdisplayName: string;\n\tbio?: string | null;\n\tavatarMediaId?: string | null;\n\twebsiteUrl?: string | null;\n\tuserId?: string | null;\n\tisGuest?: boolean;\n}\n\nexport interface UpdateBylineInput {\n\tslug?: string;\n\tdisplayName?: string;\n\tbio?: string | null;\n\tavatarMediaId?: string | null;\n\twebsiteUrl?: string | null;\n\tuserId?: string | null;\n\tisGuest?: boolean;\n}\n\nexport interface ContentBylineInput {\n\tbylineId: string;\n\troleLabel?: string | null;\n}\n\nfunction rowToByline(row: BylineRow): BylineSummary {\n\treturn {\n\t\tid: row.id,\n\t\tslug: row.slug,\n\t\tdisplayName: row.display_name,\n\t\tbio: row.bio,\n\t\tavatarMediaId: row.avatar_media_id,\n\t\twebsiteUrl: row.website_url,\n\t\tuserId: row.user_id,\n\t\tisGuest: row.is_guest === 1,\n\t\tcreatedAt: row.created_at,\n\t\tupdatedAt: row.updated_at,\n\t};\n}\n\nexport class BylineRepository {\n\tconstructor(private db: Kysely<Database>) {}\n\n\tasync findById(id: string): Promise<BylineSummary | null> {\n\t\tconst row = await this.db\n\t\t\t.selectFrom(\"_emdash_bylines\")\n\t\t\t.selectAll()\n\t\t\t.where(\"id\", \"=\", id)\n\t\t\t.executeTakeFirst();\n\t\treturn row ? rowToByline(row) : null;\n\t}\n\n\tasync findBySlug(slug: string): Promise<BylineSummary | null> {\n\t\tconst row = await this.db\n\t\t\t.selectFrom(\"_emdash_bylines\")\n\t\t\t.selectAll()\n\t\t\t.where(\"slug\", \"=\", slug)\n\t\t\t.executeTakeFirst();\n\t\treturn row ? rowToByline(row) : null;\n\t}\n\n\tasync findByUserId(userId: string): Promise<BylineSummary | null> {\n\t\tconst row = await this.db\n\t\t\t.selectFrom(\"_emdash_bylines\")\n\t\t\t.selectAll()\n\t\t\t.where(\"user_id\", \"=\", userId)\n\t\t\t.executeTakeFirst();\n\t\treturn row ? rowToByline(row) : null;\n\t}\n\n\tasync findMany(options?: {\n\t\tsearch?: string;\n\t\tisGuest?: boolean;\n\t\tuserId?: string;\n\t\tcursor?: string;\n\t\tlimit?: number;\n\t}): Promise<FindManyResult<BylineSummary>> {\n\t\tconst limit = Math.min(Math.max(options?.limit ?? 50, 1), 100);\n\n\t\tlet query = this.db\n\t\t\t.selectFrom(\"_emdash_bylines\")\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 (options?.search) {\n\t\t\tconst escaped = options.search\n\t\t\t\t.replaceAll(\"\\\\\", \"\\\\\\\\\")\n\t\t\t\t.replaceAll(\"%\", \"\\\\%\")\n\t\t\t\t.replaceAll(\"_\", \"\\\\_\");\n\t\t\tconst term = `%${escaped}%`;\n\t\t\tquery = query.where((eb) =>\n\t\t\t\teb.or([eb(\"display_name\", \"like\", term), eb(\"slug\", \"like\", term)]),\n\t\t\t);\n\t\t}\n\n\t\tif (options?.isGuest !== undefined) {\n\t\t\tquery = query.where(\"is_guest\", \"=\", options.isGuest ? 1 : 0);\n\t\t}\n\n\t\tif (options?.userId !== undefined) {\n\t\t\tquery = query.where(\"user_id\", \"=\", options.userId);\n\t\t}\n\n\t\tif (options?.cursor) {\n\t\t\tconst decoded = decodeCursor(options.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(rowToByline);\n\t\tconst result: FindManyResult<BylineSummary> = { items };\n\n\t\tif (rows.length > limit) {\n\t\t\tconst last = items.at(-1);\n\t\t\tif (last) {\n\t\t\t\tresult.nextCursor = encodeCursor(last.createdAt, last.id);\n\t\t\t}\n\t\t}\n\n\t\treturn result;\n\t}\n\n\tasync create(input: CreateBylineInput): Promise<BylineSummary> {\n\t\tconst id = ulid();\n\t\tconst now = new Date().toISOString();\n\n\t\tawait this.db\n\t\t\t.insertInto(\"_emdash_bylines\")\n\t\t\t.values({\n\t\t\t\tid,\n\t\t\t\tslug: input.slug,\n\t\t\t\tdisplay_name: input.displayName,\n\t\t\t\tbio: input.bio ?? null,\n\t\t\t\tavatar_media_id: input.avatarMediaId ?? null,\n\t\t\t\twebsite_url: input.websiteUrl ?? null,\n\t\t\t\tuser_id: input.userId ?? null,\n\t\t\t\tis_guest: input.isGuest ? 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\tconst byline = await this.findById(id);\n\t\tif (!byline) {\n\t\t\tthrow new Error(\"Failed to create byline\");\n\t\t}\n\t\treturn byline;\n\t}\n\n\tasync update(id: string, input: UpdateBylineInput): Promise<BylineSummary | null> {\n\t\tconst existing = await this.findById(id);\n\t\tif (!existing) return null;\n\n\t\tconst updates: Record<string, unknown> = {\n\t\t\tupdated_at: new Date().toISOString(),\n\t\t};\n\n\t\tif (input.slug !== undefined) updates.slug = input.slug;\n\t\tif (input.displayName !== undefined) updates.display_name = input.displayName;\n\t\tif (input.bio !== undefined) updates.bio = input.bio;\n\t\tif (input.avatarMediaId !== undefined) updates.avatar_media_id = input.avatarMediaId;\n\t\tif (input.websiteUrl !== undefined) updates.website_url = input.websiteUrl;\n\t\tif (input.userId !== undefined) updates.user_id = input.userId;\n\t\tif (input.isGuest !== undefined) updates.is_guest = input.isGuest ? 1 : 0;\n\n\t\tawait this.db.updateTable(\"_emdash_bylines\").set(updates).where(\"id\", \"=\", id).execute();\n\t\treturn await this.findById(id);\n\t}\n\n\tasync delete(id: string): Promise<boolean> {\n\t\tconst existing = await this.findById(id);\n\t\tif (!existing) return false;\n\n\t\tawait this.db.transaction().execute(async (trx) => {\n\t\t\tawait trx.deleteFrom(\"_emdash_content_bylines\").where(\"byline_id\", \"=\", id).execute();\n\n\t\t\tawait trx.deleteFrom(\"_emdash_bylines\").where(\"id\", \"=\", id).execute();\n\n\t\t\tconst tableNames = await listTablesLike(trx, \"ec_%\");\n\t\t\tfor (const tableName of tableNames) {\n\t\t\t\tvalidateIdentifier(tableName, \"content table\");\n\t\t\t\tawait sql`\n\t\t\t\t\tUPDATE ${sql.ref(tableName)}\n\t\t\t\t\tSET primary_byline_id = NULL\n\t\t\t\t\tWHERE primary_byline_id = ${id}\n\t\t\t\t`.execute(trx);\n\t\t\t}\n\t\t});\n\n\t\treturn true;\n\t}\n\n\tasync getContentBylines(\n\t\tcollectionSlug: string,\n\t\tcontentId: string,\n\t): Promise<ContentBylineCredit[]> {\n\t\tconst rows = await this.db\n\t\t\t.selectFrom(\"_emdash_content_bylines as cb\")\n\t\t\t.innerJoin(\"_emdash_bylines as b\", \"b.id\", \"cb.byline_id\")\n\t\t\t.select([\n\t\t\t\t\"cb.sort_order as sort_order\",\n\t\t\t\t\"cb.role_label as role_label\",\n\t\t\t\t\"b.id as id\",\n\t\t\t\t\"b.slug as slug\",\n\t\t\t\t\"b.display_name as display_name\",\n\t\t\t\t\"b.bio as bio\",\n\t\t\t\t\"b.avatar_media_id as avatar_media_id\",\n\t\t\t\t\"b.website_url as website_url\",\n\t\t\t\t\"b.user_id as user_id\",\n\t\t\t\t\"b.is_guest as is_guest\",\n\t\t\t\t\"b.created_at as created_at\",\n\t\t\t\t\"b.updated_at as updated_at\",\n\t\t\t])\n\t\t\t.where(\"cb.collection_slug\", \"=\", collectionSlug)\n\t\t\t.where(\"cb.content_id\", \"=\", contentId)\n\t\t\t.orderBy(\"cb.sort_order\", \"asc\")\n\t\t\t.execute();\n\n\t\treturn rows.map((row) => ({\n\t\t\tbyline: rowToByline(row),\n\t\t\tsortOrder: row.sort_order,\n\t\t\troleLabel: row.role_label,\n\t\t}));\n\t}\n\n\t/**\n\t * Batch-fetch byline credits for multiple content items in a single query.\n\t * Returns a Map keyed by contentId.\n\t */\n\tasync getContentBylinesMany(\n\t\tcollectionSlug: string,\n\t\tcontentIds: string[],\n\t): Promise<Map<string, ContentBylineCredit[]>> {\n\t\tconst result = new Map<string, ContentBylineCredit[]>();\n\t\tif (contentIds.length === 0) return result;\n\n\t\tconst rows = await this.db\n\t\t\t.selectFrom(\"_emdash_content_bylines as cb\")\n\t\t\t.innerJoin(\"_emdash_bylines as b\", \"b.id\", \"cb.byline_id\")\n\t\t\t.select([\n\t\t\t\t\"cb.content_id as content_id\",\n\t\t\t\t\"cb.sort_order as sort_order\",\n\t\t\t\t\"cb.role_label as role_label\",\n\t\t\t\t\"b.id as id\",\n\t\t\t\t\"b.slug as slug\",\n\t\t\t\t\"b.display_name as display_name\",\n\t\t\t\t\"b.bio as bio\",\n\t\t\t\t\"b.avatar_media_id as avatar_media_id\",\n\t\t\t\t\"b.website_url as website_url\",\n\t\t\t\t\"b.user_id as user_id\",\n\t\t\t\t\"b.is_guest as is_guest\",\n\t\t\t\t\"b.created_at as created_at\",\n\t\t\t\t\"b.updated_at as updated_at\",\n\t\t\t])\n\t\t\t.where(\"cb.collection_slug\", \"=\", collectionSlug)\n\t\t\t.where(\"cb.content_id\", \"in\", contentIds)\n\t\t\t.orderBy(\"cb.sort_order\", \"asc\")\n\t\t\t.execute();\n\n\t\tfor (const row of rows) {\n\t\t\tconst contentId = row.content_id;\n\t\t\tconst credit: ContentBylineCredit = {\n\t\t\t\tbyline: rowToByline(row),\n\t\t\t\tsortOrder: row.sort_order,\n\t\t\t\troleLabel: row.role_label,\n\t\t\t};\n\t\t\tconst existing = result.get(contentId);\n\t\t\tif (existing) {\n\t\t\t\texisting.push(credit);\n\t\t\t} else {\n\t\t\t\tresult.set(contentId, [credit]);\n\t\t\t}\n\t\t}\n\n\t\treturn result;\n\t}\n\n\t/**\n\t * Batch-fetch byline profiles linked to user IDs in a single query.\n\t * Returns a Map keyed by userId.\n\t */\n\tasync findByUserIds(userIds: string[]): Promise<Map<string, BylineSummary>> {\n\t\tconst result = new Map<string, BylineSummary>();\n\t\tif (userIds.length === 0) return result;\n\n\t\tconst rows = await this.db\n\t\t\t.selectFrom(\"_emdash_bylines\")\n\t\t\t.selectAll()\n\t\t\t.where(\"user_id\", \"in\", userIds)\n\t\t\t.execute();\n\n\t\tfor (const row of rows) {\n\t\t\tif (row.user_id) {\n\t\t\t\tresult.set(row.user_id, rowToByline(row));\n\t\t\t}\n\t\t}\n\t\treturn result;\n\t}\n\n\tasync setContentBylines(\n\t\tcollectionSlug: string,\n\t\tcontentId: string,\n\t\tinputBylines: ContentBylineInput[],\n\t): Promise<ContentBylineCredit[]> {\n\t\tvalidateIdentifier(collectionSlug, \"collection slug\");\n\t\tconst tableName = `ec_${collectionSlug}`;\n\t\tvalidateIdentifier(tableName, \"content table\");\n\n\t\tconst seen = new Set<string>();\n\t\tconst bylines = inputBylines.filter((item) => {\n\t\t\tif (seen.has(item.bylineId)) return false;\n\t\t\tseen.add(item.bylineId);\n\t\t\treturn true;\n\t\t});\n\n\t\t// This method is expected to be called within a transaction context\n\t\t// (content handlers wrap in withTransaction, seed applies sequentially).\n\t\t// All operations use this.db directly -- callers are responsible for\n\t\t// wrapping in a transaction when atomicity is required.\n\t\tif (bylines.length > 0) {\n\t\t\tconst ids = bylines.map((item) => item.bylineId);\n\t\t\tconst rows = await this.db\n\t\t\t\t.selectFrom(\"_emdash_bylines\")\n\t\t\t\t.select(\"id\")\n\t\t\t\t.where(\"id\", \"in\", ids)\n\t\t\t\t.execute();\n\t\t\tif (rows.length !== ids.length) {\n\t\t\t\tthrow new Error(\"One or more byline IDs do not exist\");\n\t\t\t}\n\t\t}\n\n\t\tawait this.db\n\t\t\t.deleteFrom(\"_emdash_content_bylines\")\n\t\t\t.where(\"collection_slug\", \"=\", collectionSlug)\n\t\t\t.where(\"content_id\", \"=\", contentId)\n\t\t\t.execute();\n\n\t\tfor (let i = 0; i < bylines.length; i++) {\n\t\t\tconst item = bylines[i];\n\t\t\tawait this.db\n\t\t\t\t.insertInto(\"_emdash_content_bylines\")\n\t\t\t\t.values({\n\t\t\t\t\tid: ulid(),\n\t\t\t\t\tcollection_slug: collectionSlug,\n\t\t\t\t\tcontent_id: contentId,\n\t\t\t\t\tbyline_id: item.bylineId,\n\t\t\t\t\tsort_order: i,\n\t\t\t\t\trole_label: item.roleLabel ?? null,\n\t\t\t\t\tcreated_at: new Date().toISOString(),\n\t\t\t\t})\n\t\t\t\t.execute();\n\t\t}\n\n\t\tawait sql`\n\t\t\tUPDATE ${sql.ref(tableName)}\n\t\t\tSET primary_byline_id = ${bylines[0]?.bylineId ?? null}\n\t\t\tWHERE id = ${contentId}\n\t\t`.execute(this.db);\n\n\t\treturn await this.getContentBylines(collectionSlug, contentId);\n\t}\n}\n"],"mappings":"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"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"content-D6C2WsZC.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} = 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\tnow,\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/**\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-CLBc4gw-.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":"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"}