@sonicjs-cms/core 2.18.1 → 3.0.0-beta.2

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 (225) hide show
  1. package/README.md +4 -3
  2. package/dist/admin-documents-form.template-KN7JF66Q.cjs +19 -0
  3. package/dist/{admin-layout-catalyst.template-UMTIN66R.js.map → admin-documents-form.template-KN7JF66Q.cjs.map} +1 -1
  4. package/dist/admin-documents-form.template-NLSI6Z42.js +6 -0
  5. package/dist/{admin-layout-catalyst.template-HFD37TY5.cjs.map → admin-documents-form.template-NLSI6Z42.js.map} +1 -1
  6. package/dist/admin-layout-catalyst.template-WHJGSWWD.js +7 -0
  7. package/dist/admin-layout-catalyst.template-WHJGSWWD.js.map +1 -0
  8. package/dist/admin-layout-catalyst.template-ZK5HD545.cjs +17 -0
  9. package/dist/admin-layout-catalyst.template-ZK5HD545.cjs.map +1 -0
  10. package/dist/app-Bo0X1OWX.d.ts +1268 -0
  11. package/dist/app-Do66yCcV.d.cts +1268 -0
  12. package/dist/cache-DDARE4QE.js +4 -0
  13. package/dist/cache-DDARE4QE.js.map +1 -0
  14. package/dist/cache-LVYS4BPL.cjs +33 -0
  15. package/dist/cache-LVYS4BPL.cjs.map +1 -0
  16. package/dist/chunk-2CB4KY7I.cjs +771 -0
  17. package/dist/chunk-2CB4KY7I.cjs.map +1 -0
  18. package/dist/{chunk-55RDMDOP.js → chunk-3TB6AT6X.js} +148 -55
  19. package/dist/chunk-3TB6AT6X.js.map +1 -0
  20. package/dist/{chunk-ON5ZMSU4.js → chunk-6JQOUUOB.js} +3 -3
  21. package/dist/chunk-6JQOUUOB.js.map +1 -0
  22. package/dist/chunk-6OUHGKFD.js +387 -0
  23. package/dist/chunk-6OUHGKFD.js.map +1 -0
  24. package/dist/{chunk-DSUJ5YQH.cjs → chunk-AAWNRBRB.cjs} +537 -92
  25. package/dist/chunk-AAWNRBRB.cjs.map +1 -0
  26. package/dist/chunk-AI663NBO.js +821 -0
  27. package/dist/chunk-AI663NBO.js.map +1 -0
  28. package/dist/chunk-BDDABDAB.cjs +1149 -0
  29. package/dist/chunk-BDDABDAB.cjs.map +1 -0
  30. package/dist/chunk-BLMTL57B.js +767 -0
  31. package/dist/chunk-BLMTL57B.js.map +1 -0
  32. package/dist/chunk-DNQCEKUK.cjs +327 -0
  33. package/dist/chunk-DNQCEKUK.cjs.map +1 -0
  34. package/dist/chunk-DSA4UX5B.cjs +276 -0
  35. package/dist/chunk-DSA4UX5B.cjs.map +1 -0
  36. package/dist/chunk-EF2NQUIQ.js +323 -0
  37. package/dist/chunk-EF2NQUIQ.js.map +1 -0
  38. package/dist/chunk-GCDZZNIN.js +192 -0
  39. package/dist/chunk-GCDZZNIN.js.map +1 -0
  40. package/dist/{chunk-ABB34XUS.cjs → chunk-H2AXVCLS.cjs} +667 -19
  41. package/dist/chunk-H2AXVCLS.cjs.map +1 -0
  42. package/dist/{chunk-XWIA3HVX.js → chunk-HDWE5FRJ.js} +6 -1249
  43. package/dist/chunk-HDWE5FRJ.js.map +1 -0
  44. package/dist/chunk-HIKBY7MS.cjs +70 -0
  45. package/dist/chunk-HIKBY7MS.cjs.map +1 -0
  46. package/dist/chunk-IESEVHXL.js +66 -0
  47. package/dist/chunk-IESEVHXL.js.map +1 -0
  48. package/dist/chunk-IVPRUGTY.js +242 -0
  49. package/dist/chunk-IVPRUGTY.js.map +1 -0
  50. package/dist/{chunk-SQ6FNXU2.cjs → chunk-IXUHXTHW.cjs} +2 -151
  51. package/dist/chunk-IXUHXTHW.cjs.map +1 -0
  52. package/dist/chunk-J6JTWD2A.cjs +100 -0
  53. package/dist/chunk-J6JTWD2A.cjs.map +1 -0
  54. package/dist/chunk-JEQ7FLOD.cjs +199 -0
  55. package/dist/chunk-JEQ7FLOD.cjs.map +1 -0
  56. package/dist/chunk-K25XHMM3.js +566 -0
  57. package/dist/chunk-K25XHMM3.js.map +1 -0
  58. package/dist/chunk-LRZIAW7U.cjs +158 -0
  59. package/dist/chunk-LRZIAW7U.cjs.map +1 -0
  60. package/dist/{chunk-OHYBNCVL.cjs → chunk-MVIZJOO5.cjs} +10 -1256
  61. package/dist/chunk-MVIZJOO5.cjs.map +1 -0
  62. package/dist/{chunk-UYJ6TJHX.cjs → chunk-NAVPFIG5.cjs} +148 -55
  63. package/dist/chunk-NAVPFIG5.cjs.map +1 -0
  64. package/dist/chunk-NLJVSER2.js +273 -0
  65. package/dist/chunk-NLJVSER2.js.map +1 -0
  66. package/dist/chunk-NMPEMSU4.js +154 -0
  67. package/dist/chunk-NMPEMSU4.js.map +1 -0
  68. package/dist/chunk-NUKJ54GA.cjs +245 -0
  69. package/dist/chunk-NUKJ54GA.cjs.map +1 -0
  70. package/dist/{chunk-T3Q5V33G.cjs → chunk-QAYFOER6.cjs} +621 -829
  71. package/dist/chunk-QAYFOER6.cjs.map +1 -0
  72. package/dist/{chunk-MGFRZO24.js → chunk-QZGABF2M.js} +3 -149
  73. package/dist/chunk-QZGABF2M.js.map +1 -0
  74. package/dist/chunk-RNZFGN4R.js +88 -0
  75. package/dist/chunk-RNZFGN4R.js.map +1 -0
  76. package/dist/chunk-RZ6H7OZK.js +1134 -0
  77. package/dist/chunk-RZ6H7OZK.js.map +1 -0
  78. package/dist/{chunk-XXDFQERJ.js → chunk-VD2EA3WT.js} +7192 -9806
  79. package/dist/chunk-VD2EA3WT.js.map +1 -0
  80. package/dist/{chunk-SXXTQETM.cjs → chunk-VXE42MYF.cjs} +8722 -11323
  81. package/dist/chunk-VXE42MYF.cjs.map +1 -0
  82. package/dist/{chunk-4ZSNJDLS.cjs → chunk-WULONYGB.cjs} +9 -9
  83. package/dist/chunk-WULONYGB.cjs.map +1 -0
  84. package/dist/chunk-XW56B23A.cjs +408 -0
  85. package/dist/chunk-XW56B23A.cjs.map +1 -0
  86. package/dist/chunk-YA3TJ65D.cjs +575 -0
  87. package/dist/chunk-YA3TJ65D.cjs.map +1 -0
  88. package/dist/{chunk-TFNTM3OA.js → chunk-YHSQVQXX.js} +645 -15
  89. package/dist/chunk-YHSQVQXX.js.map +1 -0
  90. package/dist/chunk-YP7GW2G5.cjs +866 -0
  91. package/dist/chunk-YP7GW2G5.cjs.map +1 -0
  92. package/dist/{chunk-QFWHAFEO.js → chunk-ZEZ245PW.js} +148 -858
  93. package/dist/chunk-ZEZ245PW.js.map +1 -0
  94. package/dist/{chunk-EW5NOBVU.js → chunk-ZGGXCFR6.js} +611 -817
  95. package/dist/chunk-ZGGXCFR6.js.map +1 -0
  96. package/dist/{collection-config-B4PG-AaF.d.cts → collection-config-JgHOpFCG.d.cts} +30 -2
  97. package/dist/{collection-config-B4PG-AaF.d.ts → collection-config-JgHOpFCG.d.ts} +30 -2
  98. package/dist/config-HFXANXCC.js +6 -0
  99. package/dist/config-HFXANXCC.js.map +1 -0
  100. package/dist/config-ON6FNMYX.cjs +19 -0
  101. package/dist/config-ON6FNMYX.cjs.map +1 -0
  102. package/dist/define-plugin-BzNHc1ZI.d.ts +1321 -0
  103. package/dist/define-plugin-IWDKYaVm.d.cts +1321 -0
  104. package/dist/document-projection-TDWRJX3Z.cjs +13 -0
  105. package/dist/document-projection-TDWRJX3Z.cjs.map +1 -0
  106. package/dist/document-projection-YYMC6I4U.js +4 -0
  107. package/dist/document-projection-YYMC6I4U.js.map +1 -0
  108. package/dist/index.cjs +13735 -4329
  109. package/dist/index.cjs.map +1 -1
  110. package/dist/index.d.cts +329 -492
  111. package/dist/index.d.ts +329 -492
  112. package/dist/index.js +13386 -3999
  113. package/dist/index.js.map +1 -1
  114. package/dist/middleware.cjs +36 -32
  115. package/dist/middleware.d.cts +69 -7
  116. package/dist/middleware.d.ts +69 -7
  117. package/dist/middleware.js +7 -3
  118. package/dist/migrations-NJJWQUKK.cjs +13 -0
  119. package/dist/{migrations-IYNTWDC6.cjs.map → migrations-NJJWQUKK.cjs.map} +1 -1
  120. package/dist/migrations-WCAVBD7C.js +4 -0
  121. package/dist/{migrations-R337UD46.js.map → migrations-WCAVBD7C.js.map} +1 -1
  122. package/dist/{plugin-bootstrap-DfVerYV4.d.cts → plugin-bootstrap-B8ThJU21.d.cts} +4315 -1661
  123. package/dist/{plugin-bootstrap-P_ciLp_C.d.ts → plugin-bootstrap-qu8hJgUt.d.ts} +4315 -1661
  124. package/dist/plugins.cjs +171 -12
  125. package/dist/plugins.d.cts +36 -2
  126. package/dist/plugins.d.ts +36 -2
  127. package/dist/plugins.js +5 -2
  128. package/dist/rbac-O73MFKDA.js +5 -0
  129. package/dist/rbac-O73MFKDA.js.map +1 -0
  130. package/dist/rbac-VONLJJKB.cjs +14 -0
  131. package/dist/rbac-VONLJJKB.cjs.map +1 -0
  132. package/dist/routes.cjs +41 -45
  133. package/dist/routes.d.cts +56 -146
  134. package/dist/routes.d.ts +56 -146
  135. package/dist/routes.js +17 -9
  136. package/dist/services.cjs +39 -72
  137. package/dist/services.d.cts +79 -54
  138. package/dist/services.d.ts +79 -54
  139. package/dist/services.js +6 -3
  140. package/dist/templates.cjs +17 -29
  141. package/dist/templates.d.cts +1 -66
  142. package/dist/templates.d.ts +1 -66
  143. package/dist/templates.js +3 -3
  144. package/dist/types-Dea1eNxU.d.cts +286 -0
  145. package/dist/types-Dea1eNxU.d.ts +286 -0
  146. package/dist/types.d.cts +1 -1
  147. package/dist/types.d.ts +1 -1
  148. package/dist/utils.cjs +18 -17
  149. package/dist/utils.d.cts +1 -1
  150. package/dist/utils.d.ts +1 -1
  151. package/dist/utils.js +2 -1
  152. package/migrations/0001_core.sql +184 -0
  153. package/migrations/0002_documents.sql +163 -0
  154. package/package.json +12 -7
  155. package/dist/admin-layout-catalyst.template-HFD37TY5.cjs +0 -17
  156. package/dist/admin-layout-catalyst.template-UMTIN66R.js +0 -7
  157. package/dist/app-C9esKLmh.d.cts +0 -112
  158. package/dist/app-C9esKLmh.d.ts +0 -112
  159. package/dist/chunk-4R3NOOL3.js +0 -2217
  160. package/dist/chunk-4R3NOOL3.js.map +0 -1
  161. package/dist/chunk-4ZSNJDLS.cjs.map +0 -1
  162. package/dist/chunk-55RDMDOP.js.map +0 -1
  163. package/dist/chunk-635JAMSE.cjs +0 -653
  164. package/dist/chunk-635JAMSE.cjs.map +0 -1
  165. package/dist/chunk-ABB34XUS.cjs.map +0 -1
  166. package/dist/chunk-C54YUA23.cjs +0 -2219
  167. package/dist/chunk-C54YUA23.cjs.map +0 -1
  168. package/dist/chunk-DSUJ5YQH.cjs.map +0 -1
  169. package/dist/chunk-EW5NOBVU.js.map +0 -1
  170. package/dist/chunk-EXNEW5US.js +0 -648
  171. package/dist/chunk-EXNEW5US.js.map +0 -1
  172. package/dist/chunk-I2H5NGJQ.js +0 -692
  173. package/dist/chunk-I2H5NGJQ.js.map +0 -1
  174. package/dist/chunk-MGFRZO24.js.map +0 -1
  175. package/dist/chunk-OHYBNCVL.cjs.map +0 -1
  176. package/dist/chunk-ON5ZMSU4.js.map +0 -1
  177. package/dist/chunk-QFWHAFEO.js.map +0 -1
  178. package/dist/chunk-SQ6FNXU2.cjs.map +0 -1
  179. package/dist/chunk-SXXTQETM.cjs.map +0 -1
  180. package/dist/chunk-T3Q5V33G.cjs.map +0 -1
  181. package/dist/chunk-TFNTM3OA.js.map +0 -1
  182. package/dist/chunk-UYJ6TJHX.cjs.map +0 -1
  183. package/dist/chunk-WAEQXGCX.cjs +0 -1898
  184. package/dist/chunk-WAEQXGCX.cjs.map +0 -1
  185. package/dist/chunk-XWIA3HVX.js.map +0 -1
  186. package/dist/chunk-XXDFQERJ.js.map +0 -1
  187. package/dist/migrations-IYNTWDC6.cjs +0 -13
  188. package/dist/migrations-R337UD46.js +0 -4
  189. package/dist/plugin-manager-BoM3Q7o7.d.cts +0 -328
  190. package/dist/plugin-manager-Efx9RyDX.d.ts +0 -328
  191. package/migrations/001_initial_schema.sql +0 -170
  192. package/migrations/002_faq_plugin.sql +0 -86
  193. package/migrations/003_stage5_enhancements.sql +0 -121
  194. package/migrations/004_stage6_user_management.sql +0 -183
  195. package/migrations/005_stage7_workflow_automation.sql +0 -294
  196. package/migrations/006_plugin_system.sql +0 -155
  197. package/migrations/007_demo_login_plugin.sql +0 -23
  198. package/migrations/008_fix_slug_validation.sql +0 -22
  199. package/migrations/009_system_logging.sql +0 -57
  200. package/migrations/011_config_managed_collections.sql +0 -15
  201. package/migrations/012_testimonials_plugin.sql +0 -80
  202. package/migrations/013_code_examples_plugin.sql +0 -177
  203. package/migrations/014_fix_plugin_registry.sql +0 -88
  204. package/migrations/015_add_remaining_plugins.sql +0 -89
  205. package/migrations/016_remove_duplicate_cache_plugin.sql +0 -17
  206. package/migrations/017_auth_configurable_fields.sql +0 -49
  207. package/migrations/018_settings_table.sql +0 -23
  208. package/migrations/019_remove_blog_posts_collection.sql +0 -15
  209. package/migrations/020_add_email_plugin.sql +0 -22
  210. package/migrations/021_add_magic_link_auth_plugin.sql +0 -42
  211. package/migrations/022_add_tinymce_plugin.sql +0 -25
  212. package/migrations/023_add_easy_mdx_plugin.sql +0 -25
  213. package/migrations/024_add_quill_editor_plugin.sql +0 -25
  214. package/migrations/025_add_easymde_plugin.sql +0 -25
  215. package/migrations/026_add_otp_login.sql +0 -42
  216. package/migrations/027_fix_slug_field_type.sql +0 -18
  217. package/migrations/028_fix_slug_field_type_in_schemas.sql +0 -30
  218. package/migrations/029_add_forms_system.sql +0 -184
  219. package/migrations/030_add_turnstile_to_forms.sql +0 -14
  220. package/migrations/031_ai_search_plugin.sql +0 -45
  221. package/migrations/032_user_profiles.sql +0 -37
  222. package/migrations/033_form_content_integration.sql +0 -19
  223. package/migrations/034_security_audit_plugin.sql +0 -27
  224. package/migrations/035_user_profiles_data_column.sql +0 -16
  225. package/migrations/036_analytics_events.sql +0 -22
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/services/documents.ts","../src/services/rbac.ts"],"names":[],"mappings":"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","file":"chunk-BLMTL57B.js","sourcesContent":["import { D1Database } from '@cloudflare/workers-types'\nimport { nanoid } from 'nanoid'\nimport type {\n Document,\n DocumentRow,\n CreateDocumentInput,\n UpdateDocumentInput,\n QueryableField,\n} from '../schemas/document'\nimport { DocumentProjection } from './document-projection'\n\nconst DEFAULT_MAX_VERSIONS = 50\n\n/**\n * D29: documents store `created_at`/`updated_at` in SECONDS (see `create`/`saveDraft`), but the legacy\n * `content` table — and therefore the public/CRUD `/api/content` contract — used MILLISECONDS. Any code\n * that shapes a document row into the content response must convert so `new Date(item.created_at)` keeps\n * working for API consumers. Null/undefined pass through unchanged.\n */\nexport function documentSecondsToMs(ts: number | null | undefined): number | null {\n return ts == null ? null : ts * 1000\n}\n\nfunction rowToDocument(row: DocumentRow): Document {\n return {\n id: row.id,\n rootId: row.root_id,\n typeId: row.type_id,\n typeVersion: row.type_version,\n versionOfId: row.version_of_id,\n versionNumber: row.version_number,\n isCurrentDraft: row.is_current_draft === 1,\n isPublished: row.is_published === 1,\n status: row.status,\n parentRootId: row.parent_root_id,\n slug: row.slug,\n path: row.path,\n title: row.title,\n zone: row.zone,\n sortOrder: row.sort_order,\n visible: row.visible === 1,\n publishedAt: row.published_at,\n scheduledAt: row.scheduled_at,\n expiresAt: row.expires_at,\n deletedAt: row.deleted_at,\n tenantId: row.tenant_id,\n locale: row.locale,\n translationGroupId: row.translation_group_id,\n data: JSON.parse(row.data),\n metadata: JSON.parse(row.metadata),\n ownerId: row.owner_id,\n createdBy: row.created_by,\n updatedBy: row.updated_by,\n createdAt: row.created_at,\n updatedAt: row.updated_at,\n }\n}\n\nexport interface DocumentsServiceOptions {\n queryableFields?: QueryableField[]\n typeSchemaVersion?: number\n maxVersionsPerRoot?: number\n /** Tenant this service operates within. Every root-keyed lookup is scoped to it (R3). POC default: 'default'. */\n tenantId?: string\n /** Retain version history (new row per saveDraft, supersede-as-history). Default false (in-place). */\n versioning?: boolean\n}\n\nexport class DocumentsService {\n private projection: DocumentProjection\n private tenantId: string\n private versioning: boolean\n\n constructor(\n private db: D1Database,\n private opts: DocumentsServiceOptions = {},\n ) {\n this.projection = new DocumentProjection(db)\n this.tenantId = opts.tenantId ?? 'default'\n this.versioning = opts.versioning ?? false\n }\n\n // ─── Create ───────────────────────────────────────────────────────────────\n\n async create(input: CreateDocumentInput, createdBy?: string): Promise<Document> {\n // D23: document timestamps are stored in SECONDS (legacy `content` rows use milliseconds). Any\n // Date() rendering of a document timestamp must multiply by 1000.\n const now = Math.floor(Date.now() / 1000)\n const id = nanoid()\n const publish = input.publishOnCreate ?? false\n // D34: backfill may carry the source row's original timestamps; normal creates default to now.\n const createdAt = input.createdAt ?? now\n const updatedAt = input.updatedAt ?? now\n\n const doc: Document = {\n id,\n rootId: id,\n typeId: input.typeId,\n typeVersion: this.opts.typeSchemaVersion ?? 1,\n versionOfId: null,\n versionNumber: 1,\n isCurrentDraft: true,\n isPublished: publish,\n status: publish ? 'published' : 'draft',\n parentRootId: input.parentRootId ?? '',\n slug: input.slug ?? null,\n path: null,\n title: input.title ?? null,\n zone: input.zone ?? null,\n sortOrder: input.sortOrder ?? 0,\n visible: input.visible ?? true,\n publishedAt: publish ? createdAt : null,\n scheduledAt: input.scheduledAt ?? null,\n expiresAt: input.expiresAt ?? null,\n deletedAt: null,\n // Tenant comes from the service scope unless the caller passes one explicitly. Never trust a\n // request-body tenant: route handlers must override with the resolved request-context tenant.\n tenantId: input.tenantId ?? this.tenantId,\n locale: input.locale ?? 'default',\n translationGroupId: '',\n data: input.data ?? {},\n metadata: input.metadata ?? {},\n ownerId: input.ownerId ?? null,\n createdBy: createdBy ?? null,\n updatedBy: createdBy ?? null,\n createdAt,\n updatedAt,\n }\n\n const insertDoc = this.db.prepare(\n `INSERT INTO documents (id, root_id, type_id, type_version, version_of_id, version_number,\n is_current_draft, is_published, status, parent_root_id, slug, path, title, zone,\n sort_order, visible, published_at, scheduled_at, expires_at, deleted_at,\n tenant_id, locale, translation_group_id, data, metadata,\n owner_id, created_by, updated_by, created_at, updated_at)\n VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)`,\n ).bind(\n doc.id, doc.rootId, doc.typeId, doc.typeVersion, null, 1,\n 1, publish ? 1 : 0, doc.status, doc.parentRootId, doc.slug, null, doc.title, doc.zone,\n doc.sortOrder, doc.visible ? 1 : 0, doc.publishedAt, doc.scheduledAt, doc.expiresAt, null,\n doc.tenantId, doc.locale, '', JSON.stringify(doc.data), JSON.stringify(doc.metadata),\n doc.ownerId, doc.createdBy, doc.updatedBy, createdAt, updatedAt,\n )\n\n const derivedInserts = this.projection.buildDerivedInsertStatements(doc, this.opts.queryableFields ?? [], now)\n\n await this.db.batch([insertDoc, ...derivedInserts])\n return doc\n }\n\n // ─── Save new draft ───────────────────────────────────────────────────────\n // Atomically: demote previous draft → delete its derived rows (if not published) →\n // insert new draft → materialize derived rows → prune excess versions.\n\n async saveDraft(rootId: string, input: UpdateDocumentInput, updatedBy?: string): Promise<Document> {\n const now = Math.floor(Date.now() / 1000)\n const newId = nanoid()\n\n // Fetch current state synchronously before starting the batch. Tenant-scoped (R3): a service\n // for tenant B must not find or mutate tenant A's root.\n const prevDraftRow = await this.db\n .prepare('SELECT * FROM documents WHERE root_id = ? AND tenant_id = ? AND is_current_draft = 1')\n .bind(rootId, this.tenantId)\n .first<DocumentRow>()\n\n if (!prevDraftRow) throw new Error(`No current draft found for root ${rootId}`)\n\n const prevDraft = rowToDocument(prevDraftRow)\n\n const mergedData = { ...prevDraft.data, ...(input.data ?? {}) }\n const mergedMeta = { ...prevDraft.metadata, ...(input.metadata ?? {}) }\n\n const newDoc: Document = {\n ...prevDraft,\n id: newId,\n rootId,\n typeVersion: this.opts.typeSchemaVersion ?? prevDraft.typeVersion,\n versionOfId: prevDraft.id,\n versionNumber: 0, // computed by SQL below\n isCurrentDraft: true,\n isPublished: false,\n status: 'draft',\n slug: input.slug !== undefined ? input.slug ?? null : prevDraft.slug,\n title: input.title !== undefined ? input.title ?? null : prevDraft.title,\n zone: input.zone !== undefined ? input.zone ?? null : prevDraft.zone,\n sortOrder: input.sortOrder ?? prevDraft.sortOrder,\n visible: input.visible ?? prevDraft.visible,\n scheduledAt: input.scheduledAt !== undefined ? input.scheduledAt : prevDraft.scheduledAt,\n expiresAt: input.expiresAt !== undefined ? input.expiresAt : prevDraft.expiresAt,\n data: mergedData,\n metadata: mergedMeta,\n updatedBy: updatedBy ?? prevDraft.updatedBy,\n updatedAt: now,\n createdAt: now,\n }\n\n const prevIsPublished = prevDraftRow.is_published === 1\n\n // Versioning off + the working draft is a pure draft (not the live published row):\n // update it in place. No new row, no history accumulation. (R7: rebuild derived rows.)\n if (!this.versioning && !prevIsPublished) {\n return this.updateInPlace(prevDraft, input, now, updatedBy)\n }\n\n const statements: D1PreparedStatement[] = [\n // 1. Demote previous current draft FIRST (unique index: never two current drafts mid-batch).\n this.db.prepare('UPDATE documents SET is_current_draft = 0, updated_at = ? WHERE id = ? AND tenant_id = ?')\n .bind(now, prevDraft.id, this.tenantId),\n\n // 2. If the previous draft was not also the published row, delete its derived rows.\n ...(!prevIsPublished ? this.projection.buildDerivedDeleteStatements(prevDraft.id) : []),\n\n // 3. Insert new draft. version_number derived in SQL (COALESCE(MAX)+1 from existing rows).\n // R5 arithmetic — keep balanced: 30 columns = 5 leading '?' + 1 version_number subquery\n // + 3 literals (1,0,'draft') + 21 trailing '?'. Total placeholders: 5 + 1 (subquery\n // root_id) + 21 = 27, which MUST equal the 27 .bind() args below. Do not change one side\n // without recounting the other.\n this.db.prepare(\n `INSERT INTO documents (id, root_id, type_id, type_version, version_of_id, version_number,\n is_current_draft, is_published, status, parent_root_id, slug, path, title, zone,\n sort_order, visible, published_at, scheduled_at, expires_at, deleted_at,\n tenant_id, locale, translation_group_id, data, metadata,\n owner_id, created_by, updated_by, created_at, updated_at)\n SELECT ?,?,?,?,?,\n (SELECT COALESCE(MAX(version_number), 0) + 1 FROM documents WHERE root_id = ?),\n 1,0,'draft',?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?\n WHERE 1=1`,\n ).bind(\n newId, rootId, newDoc.typeId, newDoc.typeVersion, prevDraft.id,\n rootId,\n newDoc.parentRootId, newDoc.slug, null, newDoc.title, newDoc.zone,\n newDoc.sortOrder, newDoc.visible ? 1 : 0, null, newDoc.scheduledAt, newDoc.expiresAt, null,\n newDoc.tenantId, newDoc.locale, newDoc.translationGroupId,\n JSON.stringify(newDoc.data), JSON.stringify(newDoc.metadata),\n newDoc.ownerId, newDoc.createdBy, newDoc.updatedBy, now, now,\n ),\n\n // 4. Materialize derived rows for new draft.\n ...this.projection.buildDerivedInsertStatements(newDoc, this.opts.queryableFields ?? [], now),\n ]\n\n // 5. Prune excess versions (beyond maxVersionsPerRoot), never the published or current-draft row,\n // and never a version still referenced as version_of_id by another row (FK RESTRICT).\n const maxVersions = this.opts.maxVersionsPerRoot ?? DEFAULT_MAX_VERSIONS\n statements.push(\n this.db.prepare(\n `DELETE FROM documents WHERE root_id = ? AND tenant_id = ? AND is_current_draft = 0 AND is_published = 0\n AND id NOT IN (\n SELECT id FROM documents WHERE root_id = ? AND tenant_id = ? AND is_current_draft = 0 AND is_published = 0\n ORDER BY version_number DESC LIMIT ?\n )\n AND id NOT IN (SELECT version_of_id FROM documents WHERE version_of_id IS NOT NULL AND root_id = ? AND tenant_id = ?)`,\n ).bind(rootId, this.tenantId, rootId, this.tenantId, maxVersions, rootId, this.tenantId),\n )\n\n await this.db.batch(statements)\n\n // Fetch the saved row to get the SQL-computed version_number.\n const saved = await this.db\n .prepare('SELECT * FROM documents WHERE id = ?')\n .bind(newId)\n .first<DocumentRow>()\n return rowToDocument(saved!)\n }\n\n // In-place draft update (versioning off). Mutates the existing draft row; preserves id/root_id/\n // version_number/version_of_id and the is_current_draft/is_published flags. Rebuilds derived rows.\n private async updateInPlace(\n prevDraft: Document,\n input: UpdateDocumentInput,\n now: number,\n updatedBy?: string,\n ): Promise<Document> {\n const mergedData = { ...prevDraft.data, ...(input.data ?? {}) }\n const mergedMeta = { ...prevDraft.metadata, ...(input.metadata ?? {}) }\n\n const updated: Document = {\n ...prevDraft,\n slug: input.slug !== undefined ? input.slug ?? null : prevDraft.slug,\n title: input.title !== undefined ? input.title ?? null : prevDraft.title,\n zone: input.zone !== undefined ? input.zone ?? null : prevDraft.zone,\n sortOrder: input.sortOrder ?? prevDraft.sortOrder,\n visible: input.visible ?? prevDraft.visible,\n scheduledAt: input.scheduledAt !== undefined ? input.scheduledAt : prevDraft.scheduledAt,\n expiresAt: input.expiresAt !== undefined ? input.expiresAt : prevDraft.expiresAt,\n data: mergedData,\n metadata: mergedMeta,\n updatedBy: updatedBy ?? prevDraft.updatedBy,\n updatedAt: now,\n }\n\n const statements: D1PreparedStatement[] = [\n // R5: 11 SET '?' + 2 WHERE '?' (id, tenant_id) = 13 binds, matching .bind() below.\n this.db.prepare(\n `UPDATE documents SET\n slug = ?, title = ?, zone = ?, sort_order = ?, visible = ?,\n scheduled_at = ?, expires_at = ?, data = ?, metadata = ?, updated_by = ?, updated_at = ?\n WHERE id = ? AND tenant_id = ?`,\n ).bind(\n updated.slug, updated.title, updated.zone, updated.sortOrder, updated.visible ? 1 : 0,\n updated.scheduledAt, updated.expiresAt, JSON.stringify(updated.data), JSON.stringify(updated.metadata),\n updated.updatedBy, now,\n updated.id, this.tenantId,\n ),\n // R7: derived rows track the new data — delete then reinsert for this row.\n ...this.projection.buildDerivedDeleteStatements(updated.id),\n ...this.projection.buildDerivedInsertStatements(updated, this.opts.queryableFields ?? [], now),\n ]\n\n await this.db.batch(statements)\n\n const saved = await this.db.prepare('SELECT * FROM documents WHERE id = ?').bind(updated.id).first<DocumentRow>()\n return rowToDocument(saved!)\n }\n\n // ─── Publish ──────────────────────────────────────────────────────────────\n\n async publish(documentId: string, publishedBy?: string): Promise<Document> {\n const now = Math.floor(Date.now() / 1000)\n\n const targetRow = await this.db\n .prepare('SELECT * FROM documents WHERE id = ? AND tenant_id = ?')\n .bind(documentId, this.tenantId)\n .first<DocumentRow>()\n\n if (!targetRow) throw new Error(`Document ${documentId} not found`)\n\n const prevPublishedRow = await this.db\n .prepare('SELECT * FROM documents WHERE root_id = ? AND tenant_id = ? AND is_published = 1 AND id != ?')\n .bind(targetRow.root_id, this.tenantId, documentId)\n .first<DocumentRow>()\n\n const statements: D1PreparedStatement[] = []\n\n if (prevPublishedRow) {\n if (!this.versioning && prevPublishedRow.is_current_draft !== 1) {\n // Versioning off: old published row is pure history — remove it + its derived rows.\n // First null any version_of_id pointing at it (the target draft may chain off it) so the\n // delete can't trip the FK RESTRICT on documents.version_of_id (plan risk #1; the chain is\n // unused when versioning is off). Tenant-scoped (R3).\n statements.push(this.db.prepare('UPDATE documents SET version_of_id = NULL WHERE version_of_id = ? AND tenant_id = ?')\n .bind(prevPublishedRow.id, this.tenantId))\n statements.push(...this.projection.buildDerivedDeleteStatements(prevPublishedRow.id))\n statements.push(this.db.prepare('DELETE FROM documents WHERE id = ? AND tenant_id = ?')\n .bind(prevPublishedRow.id, this.tenantId))\n } else {\n // existing behavior: clear is_published, drop derived rows if not the current draft\n statements.push(\n this.db.prepare('UPDATE documents SET is_published = 0, updated_at = ? WHERE id = ?')\n .bind(now, prevPublishedRow.id),\n )\n if (prevPublishedRow.is_current_draft !== 1) {\n statements.push(...this.projection.buildDerivedDeleteStatements(prevPublishedRow.id))\n }\n }\n }\n\n // Set published on target row.\n statements.push(\n this.db.prepare(\n `UPDATE documents SET is_published = 1, status = 'published', published_at = ?, updated_at = ?, updated_by = ? WHERE id = ?`,\n ).bind(now, now, publishedBy ?? null, documentId),\n )\n\n // Ensure derived rows exist for the target (they do if it was current draft; materialize if not).\n if (targetRow.is_current_draft !== 1) {\n const targetDoc = rowToDocument(targetRow)\n statements.push(...this.projection.buildDerivedInsertStatements(targetDoc, this.opts.queryableFields ?? [], now))\n }\n\n await this.db.batch(statements)\n\n const saved = await this.db.prepare('SELECT * FROM documents WHERE id = ?').bind(documentId).first<DocumentRow>()\n return rowToDocument(saved!)\n }\n\n // ─── Unpublish ────────────────────────────────────────────────────────────\n\n async unpublish(documentId: string): Promise<Document> {\n const now = Math.floor(Date.now() / 1000)\n\n const row = await this.db\n .prepare('SELECT * FROM documents WHERE id = ? AND tenant_id = ?')\n .bind(documentId, this.tenantId)\n .first<DocumentRow>()\n\n if (!row) throw new Error(`Document ${documentId} not found`)\n if (!row.is_published) throw new Error(`Document ${documentId} is not published`)\n\n const statements: D1PreparedStatement[] = [\n this.db.prepare(`UPDATE documents SET is_published = 0, status = 'draft', updated_at = ? WHERE id = ?`)\n .bind(now, documentId),\n ]\n\n // If the unpublished row is not the current draft, remove its derived rows.\n if (row.is_current_draft !== 1) {\n statements.push(...this.projection.buildDerivedDeleteStatements(documentId))\n }\n\n await this.db.batch(statements)\n\n const saved = await this.db.prepare('SELECT * FROM documents WHERE id = ?').bind(documentId).first<DocumentRow>()\n return rowToDocument(saved!)\n }\n\n // ─── Soft delete ──────────────────────────────────────────────────────────\n\n async softDelete(documentId: string): Promise<void> {\n const now = Math.floor(Date.now() / 1000)\n await this.db\n .prepare('UPDATE documents SET deleted_at = ?, updated_at = ? WHERE id = ? AND tenant_id = ?')\n .bind(now, now, documentId, this.tenantId)\n .run()\n }\n\n // ─── Hard erase (PII types) ───────────────────────────────────────────────\n // Deletes every version row for a root plus all derived data, in dependency order.\n\n async erase(rootId: string, tenantId: string): Promise<void> {\n // Get all document IDs for this root.\n const result = await this.db\n .prepare('SELECT id FROM documents WHERE root_id = ? AND tenant_id = ?')\n .bind(rootId, tenantId)\n .all<{ id: string }>()\n\n const docIds = (result.results ?? []).map(r => r.id)\n if (docIds.length === 0) return\n\n const statements: D1PreparedStatement[] = []\n\n // Delete derived tables first (explicit; don't rely on FK cascade).\n for (const id of docIds) {\n statements.push(this.db.prepare('DELETE FROM document_facets WHERE document_id = ?').bind(id))\n statements.push(this.db.prepare('DELETE FROM document_references WHERE from_document_id = ?').bind(id))\n }\n\n statements.push(this.db.prepare('DELETE FROM document_permissions WHERE root_id = ? AND tenant_id = ?').bind(rootId, tenantId))\n\n // Delete all version rows.\n for (const id of docIds) {\n statements.push(this.db.prepare('DELETE FROM documents WHERE id = ?').bind(id))\n }\n\n await this.db.batch(statements)\n }\n}\n","/**\n * Dynamic RBAC service — document-backed.\n *\n * Roles, verbs, and user-role assignments are stored as `is_auth` documents\n * (slug-addressed) instead of relational tables:\n * rbac_role slug = roleId, data = { name, displayName, description, isSystem, grants:[{resource,verb,scope}] }\n * rbac_verb slug = verbId, data = { name, description, isSystem, sortOrder }\n * rbac_user_roles slug = userId, data = { roleIds:[] }\n * Grants are embedded in the role document (no separate join type); user-role\n * assignments are embedded in a per-user document. Resources are still computed:\n * a fixed set of system resources plus one `document_type:<name>` per type.\n *\n * Wildcards: resource '*' / 'document_type:*', verb '*' / 'manage' (implies all).\n * Scope: 'any' beats 'own' beats 'none'.\n *\n * The public API is unchanged from the relational implementation, so callers\n * (admin-rbac routes, permission checks) need no changes.\n */\nimport { DocumentsService } from './documents'\n\nexport interface RbacRole {\n id: string\n name: string\n display_name: string\n description: string | null\n is_system: number\n}\nexport interface RbacVerb {\n id: string\n name: string\n description: string | null\n is_system: number\n sort_order: number\n}\nexport interface RbacResource {\n key: string // e.g. 'content' or 'collection:blog_posts'\n label: string\n group: 'system' | 'document_type'\n}\nexport type PermissionScope = 'none' | 'own' | 'any'\nexport interface Grant {\n role_id: string\n resource: string\n verb: string\n scope: Exclude<PermissionScope, 'none'>\n}\n\ninterface GrantData { resource: string; verb: string; scope?: PermissionScope }\ninterface RoleData { name: string; displayName: string; description?: string | null; isSystem?: boolean; grants?: GrantData[] }\ninterface VerbData { name: string; description?: string | null; isSystem?: boolean; sortOrder?: number }\ninterface UserRolesData { roleIds?: string[] }\ninterface DocRow { id: string; root_id: string; slug: string | null; data: string }\n\nconst TENANT = 'default'\nconst T_ROLE = 'rbac_role'\nconst T_VERB = 'rbac_verb'\nconst T_USER_ROLES = 'rbac_user_roles'\n\nconst SYSTEM_RESOURCES: RbacResource[] = [\n { key: '*', label: 'All resources', group: 'system' },\n { key: 'portal', label: 'Admin Portal', group: 'system' },\n { key: 'dashboard', label: 'Dashboard', group: 'system' },\n { key: 'rbac', label: 'Roles & Permissions', group: 'system' },\n { key: 'documents', label: 'Documents', group: 'system' as const },\n { key: 'document_types', label: 'Document Types', group: 'system' as const },\n { key: 'email', label: 'Email Management', group: 'system' },\n { key: 'users', label: 'Users', group: 'system' },\n { key: 'settings', label: 'Settings', group: 'system' },\n { key: 'logs', label: 'Logs', group: 'system' },\n]\n\nexport class RbacService {\n // Precedence for projecting the user's RBAC roles back onto the legacy\n // users.role compat column (highest privilege first). Only `admin` is\n // hardcoded as a seeded role — `editor` is listed here purely so that if an\n // administrator chooses to recreate a role named `editor`, legacy code that\n // still gates on the `editor` label keeps working.\n private static readonly LEGACY_ROLE_PRECEDENCE = ['admin', 'editor']\n\n private _docs?: DocumentsService\n\n constructor(private db: D1Database, private kv?: KVNamespace) {}\n\n // ── Document access helpers ──────────────────────────────────────────────────\n\n private docs(): DocumentsService {\n if (!this._docs) {\n this._docs = new DocumentsService(this.db, { tenantId: TENANT, maxVersionsPerRoot: 1, queryableFields: [] })\n }\n return this._docs\n }\n\n private parse<T>(row: DocRow): { id: string; rootId: string; slug: string; data: T } {\n let data: T\n try { data = JSON.parse(row.data) as T } catch { data = {} as T }\n return { id: row.id, rootId: row.root_id, slug: row.slug ?? '', data }\n }\n\n private async listDocs<T>(typeId: string): Promise<Array<{ id: string; rootId: string; slug: string; data: T }>> {\n const res = await this.db\n .prepare(\n `SELECT id, root_id, slug, data FROM documents\n WHERE type_id = ? AND tenant_id = ? AND is_current_draft = 1 AND deleted_at IS NULL`,\n )\n .bind(typeId, TENANT)\n .all<DocRow>()\n return (res.results ?? []).map((r) => this.parse<T>(r))\n }\n\n private async getDoc<T>(typeId: string, slug: string): Promise<{ id: string; rootId: string; data: T } | null> {\n const row = await this.db\n .prepare(\n `SELECT id, root_id, slug, data FROM documents\n WHERE type_id = ? AND tenant_id = ? AND slug = ? AND is_current_draft = 1 AND deleted_at IS NULL`,\n )\n .bind(typeId, TENANT, slug)\n .first<DocRow>()\n return row ? this.parse<T>(row) : null\n }\n\n private async upsertDoc(typeId: string, slug: string, data: unknown, title: string | null): Promise<void> {\n const existing = await this.db\n .prepare(\n `SELECT root_id FROM documents\n WHERE type_id = ? AND tenant_id = ? AND slug = ? AND is_current_draft = 1 AND deleted_at IS NULL`,\n )\n .bind(typeId, TENANT, slug)\n .first<{ root_id: string }>()\n const payload = data as Record<string, unknown>\n if (existing?.root_id) {\n await this.docs().saveDraft(existing.root_id, { data: payload, title })\n } else {\n await this.docs().create({\n typeId,\n tenantId: TENANT,\n locale: 'default',\n parentRootId: '',\n slug,\n title,\n sortOrder: 0,\n visible: true,\n data: payload,\n metadata: {},\n ownerId: null,\n publishOnCreate: false,\n })\n }\n }\n\n private async deleteDoc(typeId: string, slug: string): Promise<void> {\n const doc = await this.getDoc(typeId, slug)\n if (doc) await this.docs().softDelete(doc.id)\n }\n\n private roleToRow(d: { slug: string; data: RoleData }): RbacRole {\n return {\n id: d.slug,\n name: d.data.name,\n display_name: d.data.displayName,\n description: d.data.description ?? null,\n is_system: d.data.isSystem ? 1 : 0,\n }\n }\n\n // ── Reads ────────────────────────────────────────────────────────────────────\n\n async getRoles(): Promise<RbacRole[]> {\n const docs = await this.listDocs<RoleData>(T_ROLE)\n return docs\n .map((d) => this.roleToRow(d))\n .sort((a, b) => b.is_system - a.is_system || a.name.localeCompare(b.name))\n }\n\n async getVerbs(): Promise<RbacVerb[]> {\n const docs = await this.listDocs<VerbData>(T_VERB)\n return docs\n .map((d) => ({\n id: d.slug,\n name: d.data.name,\n description: d.data.description ?? null,\n is_system: d.data.isSystem ? 1 : 0,\n sort_order: d.data.sortOrder ?? 100,\n }))\n .sort((a, b) => a.sort_order - b.sort_order || a.name.localeCompare(b.name))\n }\n\n /** System resources + one `document_type:<name>` per active document type. */\n async getResources(): Promise<RbacResource[]> {\n const types = (\n await this.db\n .prepare('SELECT name, display_name FROM document_types WHERE is_active = 1 ORDER BY name')\n .all<{ name: string; display_name: string }>()\n ).results as Array<{ name: string; display_name: string }>\n const documentTypeResources: RbacResource[] = [\n { key: 'document_type:*', label: 'All document types', group: 'document_type' },\n ...types.map((t) => ({\n key: `document_type:${t.name}`,\n label: t.display_name || t.name,\n group: 'document_type' as const,\n })),\n ]\n return [...SYSTEM_RESOURCES, ...documentTypeResources]\n }\n\n async getGrants(): Promise<Grant[]> {\n const roles = await this.listDocs<RoleData>(T_ROLE)\n const out: Grant[] = []\n for (const r of roles) {\n for (const g of r.data.grants ?? []) {\n out.push({ role_id: r.slug, resource: g.resource, verb: g.verb, scope: g.scope === 'own' ? 'own' : 'any' })\n }\n }\n return out\n }\n\n async getRolesForUser(userId: string): Promise<RbacRole[]> {\n const ur = await this.getDoc<UserRolesData>(T_USER_ROLES, userId)\n const roleIds = new Set(ur?.data.roleIds ?? [])\n if (roleIds.size === 0) return []\n const roles = await this.listDocs<RoleData>(T_ROLE)\n return roles.filter((r) => roleIds.has(r.slug)).map((d) => this.roleToRow(d))\n }\n\n /** Grants attached to a set of role ids (from the embedded role grants). */\n private async grantsForRoleIds(roleIds: string[]): Promise<Array<{ resource: string; verb: string; scope: PermissionScope }>> {\n if (roleIds.length === 0) return []\n const want = new Set(roleIds)\n const roles = await this.listDocs<RoleData>(T_ROLE)\n const out: Array<{ resource: string; verb: string; scope: PermissionScope }> = []\n for (const r of roles) {\n if (!want.has(r.slug)) continue\n for (const g of r.data.grants ?? []) {\n out.push({ resource: g.resource, verb: g.verb, scope: g.scope === 'own' ? 'own' : 'any' })\n }\n }\n return out\n }\n\n /** Does a single grant row satisfy the requested (resource, verb)? */\n private grantMatches(g: { resource: string; verb: string }, resource: string, verb: string): boolean {\n const resourceOk =\n g.resource === '*' ||\n g.resource === resource ||\n (g.resource === 'document_type:*' && resource.startsWith('document_type:'))\n if (!resourceOk) return false\n return g.verb === '*' || g.verb === verb || g.verb === 'manage'\n }\n\n private strongestScope(scopes: PermissionScope[]): PermissionScope {\n if (scopes.includes('any')) return 'any'\n if (scopes.includes('own')) return 'own'\n return 'none'\n }\n\n /** Can the user perform `verb` on `resource`? Reads the live grant matrix. */\n async can(userId: string, resource: string, verb: string): Promise<boolean> {\n return (await this.getPermissionScope(userId, resource, verb)) !== 'none'\n }\n\n /** Highest scope granted to the user for `resource:verb`. */\n async getPermissionScope(userId: string, resource: string, verb: string): Promise<PermissionScope> {\n const ur = await this.getDoc<UserRolesData>(T_USER_ROLES, userId)\n const grants = await this.grantsForRoleIds(ur?.data.roleIds ?? [])\n return this.strongestScope(\n grants.filter((g) => this.grantMatches(g, resource, verb)).map((g) => (g.scope === 'own' ? 'own' : 'any')),\n )\n }\n\n /** Flattened, human-readable permission list for a user. Cached in KV for 60 s. */\n async permissionsForUser(userId: string): Promise<string[]> {\n if (this.kv) {\n const cached = await this.kv.get(`rbac:perms:${userId}`)\n if (cached !== null) return JSON.parse(cached) as string[]\n }\n const ur = await this.getDoc<UserRolesData>(T_USER_ROLES, userId)\n const roleIds = ur?.data.roleIds ?? []\n if (roleIds.length === 0) return []\n const grants = await this.grantsForRoleIds(roleIds)\n const resources = await this.getResources()\n const verbs = await this.getVerbs()\n const out = new Set<string>()\n for (const r of resources) {\n for (const v of verbs) {\n if (grants.some((g) => this.grantMatches(g, r.key, v.name))) out.add(`${r.key}:${v.name}`)\n }\n }\n const result = [...out].sort()\n if (this.kv) {\n await this.kv.put(`rbac:perms:${userId}`, JSON.stringify(result), { expirationTtl: 60 })\n }\n return result\n }\n\n // ── Mutations ──────────────────────────────────────────────────────────────\n\n async createRole(name: string, displayName: string, description = ''): Promise<void> {\n const slug = name.toLowerCase().replace(/[^a-z0-9]+/g, '-')\n const id = `role-${slug}`\n await this.upsertDoc(\n T_ROLE,\n id,\n { name: name.toLowerCase(), displayName, description, isSystem: false, grants: [] } satisfies RoleData,\n displayName,\n )\n }\n\n async deleteRole(roleId: string): Promise<void> {\n const role = await this.getDoc<RoleData>(T_ROLE, roleId)\n if (!role || role.data.isSystem) return // System roles cannot be deleted.\n await this.deleteDoc(T_ROLE, roleId)\n }\n\n /**\n * Update a role's display name and description. The `name` (slug) can only be\n * changed for custom roles — system role names are referenced by the legacy\n * mapping, so they stay fixed.\n */\n async updateRole(roleId: string, displayName: string, description = '', name?: string): Promise<void> {\n const role = await this.getDoc<RoleData>(T_ROLE, roleId)\n if (!role) return\n const next: RoleData = { ...role.data, displayName, description }\n if (!role.data.isSystem && name) {\n next.name = name.toLowerCase().replace(/[^a-z0-9]+/g, '-')\n }\n await this.upsertDoc(T_ROLE, roleId, next, displayName)\n }\n\n /** Update displayName + portal access in a single write to avoid double-saveDraft FK issues. */\n async updateRoleAndPortalAccess(\n roleId: string,\n displayName: string,\n name: string | undefined,\n portalEnabled: boolean,\n description?: string,\n ): Promise<void> {\n const role = await this.getDoc<RoleData>(T_ROLE, roleId)\n if (!role) return\n const next: RoleData = { ...role.data, displayName, description: description ?? role.data.description ?? '' }\n if (!role.data.isSystem && name) {\n next.name = name.toLowerCase().replace(/[^a-z0-9]+/g, '-')\n }\n const grants = (next.grants ?? []).filter((g) => !(g.resource === 'portal' && g.verb === 'access'))\n if (portalEnabled) grants.push({ resource: 'portal', verb: 'access', scope: 'any' })\n next.grants = grants\n await this.upsertDoc(T_ROLE, roleId, next, displayName)\n }\n\n async createVerb(name: string, description = ''): Promise<void> {\n const slug = name.toLowerCase().replace(/[^a-z0-9]+/g, '-')\n const id = `verb-${slug}`\n await this.upsertDoc(\n T_VERB,\n id,\n { name: name.toLowerCase(), description, isSystem: false, sortOrder: 100 } satisfies VerbData,\n name,\n )\n }\n\n async deleteVerb(verbId: string): Promise<void> {\n const verb = await this.getDoc<VerbData>(T_VERB, verbId)\n if (!verb || verb.data.isSystem) return\n await this.deleteDoc(T_VERB, verbId)\n }\n\n /** Replace all grants for one role with the supplied (resource, verb, scope) rows. */\n async setRoleGrants(\n roleId: string,\n pairs: Array<{ resource: string; verb: string; scope?: Exclude<PermissionScope, 'none'> }>,\n ): Promise<void> {\n const role = await this.getDoc<RoleData>(T_ROLE, roleId)\n if (!role) return\n const grants: GrantData[] = pairs.map((p) => ({ resource: p.resource, verb: p.verb, scope: p.scope === 'own' ? 'own' : 'any' }))\n await this.upsertDoc(T_ROLE, roleId, { ...role.data, grants } satisfies RoleData, role.data.displayName)\n }\n\n /**\n * Count active users (optionally excluding one) who hold BOTH an effective\n * portal:access grant and an effective rbac:manage grant — the users who could\n * recover from a permission lockout. Powers the self-lockout guard.\n */\n async countPortalAdmins(excludeUserId?: string): Promise<number> {\n const active = (\n await this.db.prepare('SELECT id FROM auth_user WHERE is_active = 1').all<{ id: string }>()\n ).results as Array<{ id: string }>\n const activeIds = new Set(active.map((u) => u.id))\n\n // role id -> its grants\n const roles = await this.listDocs<RoleData>(T_ROLE)\n const grantsByRole = new Map<string, GrantData[]>(roles.map((r) => [r.slug, r.data.grants ?? []]))\n\n const userRoles = await this.listDocs<UserRolesData>(T_USER_ROLES)\n let count = 0\n for (const ur of userRoles) {\n const userId = ur.slug\n if (!activeIds.has(userId)) continue\n if (excludeUserId && userId === excludeUserId) continue\n let portal = false\n let rbac = false\n for (const rid of ur.data.roleIds ?? []) {\n for (const g of grantsByRole.get(rid) ?? []) {\n if (this.grantMatches(g, 'portal', 'access')) portal = true\n if (this.grantMatches(g, 'rbac', 'manage')) rbac = true\n }\n }\n if (portal && rbac) count++\n }\n return count\n }\n\n /**\n * Replace a user's RBAC role assignments. The `rbac_user_roles` document is the\n * single source of truth for authorization; the legacy `auth_user.role` column\n * is kept as a derived projection (highest-precedence system role, else\n * 'viewer') so the two never diverge.\n */\n async setUserRoles(userId: string, roleIds: string[]): Promise<void> {\n const allRoles = await this.listDocs<RoleData>(T_ROLE)\n const byId = new Map(allRoles.map((r) => [r.slug, r.data]))\n const names = roleIds.map((id) => byId.get(id)?.name).filter((n): n is string => !!n)\n const primaryRole = RbacService.LEGACY_ROLE_PRECEDENCE.find((r) => names.includes(r)) || 'viewer'\n\n // Self-lockout guard: never leave zero active users who can BOTH enter the\n // portal and manage RBAC (the minimum needed to recover).\n const newGrants: GrantData[] = []\n for (const id of roleIds) for (const g of byId.get(id)?.grants ?? []) newGrants.push(g)\n const userWillBeAdmin =\n newGrants.some((g) => this.grantMatches(g, 'portal', 'access')) &&\n newGrants.some((g) => this.grantMatches(g, 'rbac', 'manage'))\n if (!userWillBeAdmin && (await this.countPortalAdmins(userId)) === 0) {\n throw new Error(\n 'Refusing to update roles: this would leave no user able to manage Roles & Permissions and access the portal. Grant another user portal access + Roles & Permissions first.',\n )\n }\n\n await this.upsertDoc(T_USER_ROLES, userId, { roleIds } satisfies UserRolesData, null)\n // Keep the legacy auth_user.role column in lockstep as a projection of RBAC.\n await this.db.prepare('UPDATE auth_user SET role = ?, updated_at = ? WHERE id = ?').bind(primaryRole, Date.now(), userId).run()\n if (this.kv) await this.kv.delete(`rbac:perms:${userId}`)\n }\n\n async setRolePortalAccess(roleId: string, enabled: boolean): Promise<void> {\n const role = await this.getDoc<RoleData>(T_ROLE, roleId)\n if (!role) return\n const grants = (role.data.grants ?? []).filter((g) => !(g.resource === 'portal' && g.verb === 'access'))\n if (enabled) grants.push({ resource: 'portal', verb: 'access', scope: 'any' })\n await this.upsertDoc(T_ROLE, roleId, { ...role.data, grants } satisfies RoleData, role.data.displayName)\n }\n\n // ── Bootstrap helpers ────────────────────────────────────────────────────────\n\n /**\n * Seed the system roles, verbs, and their grants as documents. Idempotent —\n * existing roles/verbs (by slug) are left untouched. Replaces the INSERT OR\n * IGNORE seeds that lived in migration 0001. Call at bootstrap, after the rbac\n * document types are registered.\n */\n async ensureSystemRbacSeed(): Promise<void> {\n // `admin` is the only hardcoded SYSTEM role (locked, undeletable). `editor`\n // is seeded as a non-system example so a fresh install has a usable second\n // role out of the box, but an administrator can edit, rename, or delete it.\n const roles: Array<RoleData & { id: string }> = [\n { id: 'role-admin', name: 'admin', displayName: 'Administrator', description: 'Full access to everything', isSystem: true,\n grants: [\n { resource: '*', verb: 'manage' }, { resource: 'portal', verb: 'access' }, { resource: 'rbac', verb: 'manage' },\n { resource: 'document_types', verb: 'manage' }, { resource: 'email', verb: 'manage' }, { resource: 'users', verb: 'manage' },\n ] },\n { id: 'role-editor', name: 'editor', displayName: 'Editor', description: 'Manage documents across all types', isSystem: false,\n grants: [\n { resource: 'portal', verb: 'access' },\n { resource: 'documents', verb: 'manage' },\n { resource: 'document_type:*', verb: 'read' },\n { resource: 'document_type:*', verb: 'create' },\n { resource: 'document_type:*', verb: 'update' },\n { resource: 'document_type:*', verb: 'delete' },\n { resource: 'settings', verb: 'read' },\n ] },\n ]\n const verbs: Array<VerbData & { id: string }> = [\n { id: 'verb-access', name: 'access', description: 'Enter or use a portal/resource', isSystem: true, sortOrder: 5 },\n { id: 'verb-read', name: 'read', description: 'View a resource', isSystem: true, sortOrder: 10 },\n { id: 'verb-create', name: 'create', description: 'Create a resource', isSystem: true, sortOrder: 20 },\n { id: 'verb-update', name: 'update', description: 'Edit a resource', isSystem: true, sortOrder: 30 },\n { id: 'verb-delete', name: 'delete', description: 'Remove a resource', isSystem: true, sortOrder: 40 },\n { id: 'verb-manage', name: 'manage', description: 'Full control (implies all verbs)', isSystem: true, sortOrder: 50 },\n ]\n\n for (const r of roles) {\n if (await this.getDoc(T_ROLE, r.id)) continue\n const { id, ...data } = r\n await this.upsertDoc(T_ROLE, id, data, r.displayName)\n }\n for (const v of verbs) {\n if (await this.getDoc(T_VERB, v.id)) continue\n const { id, ...data } = v\n await this.upsertDoc(T_VERB, id, data, v.name)\n }\n }\n\n /** Assign a role to a user by role name (e.g. 'admin'), preserving existing roles. */\n async addUserRoleByName(userId: string, roleName: string): Promise<void> {\n const roles = await this.listDocs<RoleData>(T_ROLE)\n const role = roles.find((r) => r.data.name === roleName.toLowerCase())\n if (!role) return\n const ur = await this.getDoc<UserRolesData>(T_USER_ROLES, userId)\n const roleIds = new Set(ur?.data.roleIds ?? [])\n if (roleIds.has(role.slug)) return\n roleIds.add(role.slug)\n await this.setUserRoles(userId, [...roleIds])\n }\n}\n"]}
@@ -0,0 +1,327 @@
1
+ 'use strict';
2
+
3
+ var chunkNAVPFIG5_cjs = require('./chunk-NAVPFIG5.cjs');
4
+ var chunkMNWKYY5E_cjs = require('./chunk-MNWKYY5E.cjs');
5
+
6
+ // src/templates/pages/admin-documents-form.template.ts
7
+ chunkNAVPFIG5_cjs.init_admin_layout_catalyst_template();
8
+
9
+ // src/templates/components/alert.template.ts
10
+ function renderAlert(data) {
11
+ const typeClasses = {
12
+ success: "bg-green-50 dark:bg-green-500/10 border border-green-600/20 dark:border-green-500/20",
13
+ error: "bg-error/10 border border-red-600/20 dark:border-red-500/20",
14
+ warning: "bg-amber-50 dark:bg-amber-500/10 border border-amber-600/20 dark:border-amber-500/20",
15
+ info: "bg-blue-50 dark:bg-blue-500/10 border border-blue-600/20 dark:border-blue-500/20"
16
+ };
17
+ const iconClasses = {
18
+ success: "text-green-600 dark:text-green-400",
19
+ error: "text-red-600 dark:text-red-400",
20
+ warning: "text-amber-600 dark:text-amber-400",
21
+ info: "text-blue-600 dark:text-blue-400"
22
+ };
23
+ const textClasses = {
24
+ success: "text-green-900 dark:text-green-300",
25
+ error: "text-red-900 dark:text-red-300",
26
+ warning: "text-amber-900 dark:text-amber-300",
27
+ info: "text-blue-900 dark:text-blue-300"
28
+ };
29
+ const messageTextClasses = {
30
+ success: "text-green-700 dark:text-green-400",
31
+ error: "text-red-700 dark:text-red-400",
32
+ warning: "text-amber-700 dark:text-amber-400",
33
+ info: "text-blue-700 dark:text-blue-400"
34
+ };
35
+ const icons = {
36
+ success: `<path fill-rule="evenodd" d="M10 18a8 8 0 100-16 8 8 0 000 16zm3.707-9.293a1 1 0 00-1.414-1.414L9 10.586 7.707 9.293a1 1 0 00-1.414 1.414l2 2a1 1 0 001.414 0l4-4z" clip-rule="evenodd" />`,
37
+ error: `<path fill-rule="evenodd" d="M10 18a8 8 0 100-16 8 8 0 000 16zM8.707 7.293a1 1 0 00-1.414 1.414L8.586 10l-1.293 1.293a1 1 0 101.414 1.414L10 11.414l1.293 1.293a1 1 0 001.414-1.414L11.414 10l1.293-1.293a1 1 0 00-1.414-1.414L10 8.586 8.707 7.293z" clip-rule="evenodd" />`,
38
+ warning: `<path fill-rule="evenodd" d="M8.257 3.099c.765-1.36 2.722-1.36 3.486 0l5.58 9.92c.75 1.334-.213 2.98-1.742 2.98H4.42c-1.53 0-2.493-1.646-1.743-2.98l5.58-9.92zM11 13a1 1 0 11-2 0 1 1 0 012 0zm-1-8a1 1 0 00-1 1v3a1 1 0 002 0V6a1 1 0 00-1-1z" clip-rule="evenodd" />`,
39
+ info: `<path fill-rule="evenodd" d="M18 10a8 8 0 11-16 0 8 8 0 0116 0zm-7-4a1 1 0 11-2 0 1 1 0 012 0zM9 9a1 1 0 000 2v3a1 1 0 001 1h1a1 1 0 100-2v-3a1 1 0 00-1-1H9z" clip-rule="evenodd" />`
40
+ };
41
+ return `
42
+ <div class="rounded-lg p-4 ${typeClasses[data.type]} ${data.className || ""}" ${data.dismissible ? 'id="dismissible-alert"' : ""}>
43
+ <div class="flex">
44
+ ${data.icon !== false ? `
45
+ <div class="flex-shrink-0">
46
+ <svg class="h-5 w-5 ${iconClasses[data.type]}" viewBox="0 0 20 20" fill="currentColor">
47
+ ${icons[data.type]}
48
+ </svg>
49
+ </div>
50
+ ` : ""}
51
+ <div class="${data.icon !== false ? "ml-3" : ""}">
52
+ ${data.title ? `
53
+ <h3 class="text-sm font-semibold ${textClasses[data.type]}">
54
+ ${chunkMNWKYY5E_cjs.escapeHtml(data.title)}
55
+ </h3>
56
+ ` : ""}
57
+ <div class="${data.title ? "mt-1 text-sm" : "text-sm"} ${messageTextClasses[data.type]}">
58
+ <p>${chunkMNWKYY5E_cjs.escapeHtml(data.message)}</p>
59
+ </div>
60
+ </div>
61
+ ${data.dismissible ? `
62
+ <div class="ml-auto pl-3">
63
+ <div class="-mx-1.5 -my-1.5">
64
+ <button
65
+ type="button"
66
+ class="inline-flex rounded-md p-1.5 ${iconClasses[data.type]} hover:bg-opacity-20 focus:outline-none focus:ring-2 focus:ring-offset-2"
67
+ onclick="document.getElementById('dismissible-alert').remove()"
68
+ >
69
+ <span class="sr-only">Dismiss</span>
70
+ <svg class="h-5 w-5" viewBox="0 0 20 20" fill="currentColor">
71
+ <path fill-rule="evenodd" d="M4.293 4.293a1 1 0 011.414 0L10 8.586l4.293-4.293a1 1 0 111.414 1.414L11.414 10l4.293 4.293a1 1 0 01-1.414 1.414L10 11.414l-4.293 4.293a1 1 0 01-1.414-1.414L8.586 10 4.293 5.707a1 1 0 010-1.414z" clip-rule="evenodd" />
72
+ </svg>
73
+ </button>
74
+ </div>
75
+ </div>
76
+ ` : ""}
77
+ </div>
78
+ </div>
79
+ `;
80
+ }
81
+
82
+ // src/templates/pages/admin-documents-form.template.ts
83
+ function inputClass(error) {
84
+ const base = "block w-full rounded-lg border bg-white dark:bg-zinc-800 px-3 py-2 text-sm text-zinc-950 dark:text-white placeholder:text-zinc-400 focus:outline-none focus:ring-2 focus:ring-blue-500 transition-colors";
85
+ return error ? `${base} border-red-400 dark:border-red-500` : `${base} border-zinc-300 dark:border-zinc-700`;
86
+ }
87
+ function renderFieldInput(field, value, error) {
88
+ const id = `data_${field.name}`;
89
+ const name = `data[${field.name}]`;
90
+ const label = field.name.replace(/([A-Z])/g, " $1").replace(/^./, (s) => s.toUpperCase());
91
+ const strVal = value != null ? String(value) : "";
92
+ let input;
93
+ if (field.type === "integer" || field.type === "number") {
94
+ input = `<input type="number" id="${id}" name="${name}" value="${chunkMNWKYY5E_cjs.escapeHtml(strVal)}"
95
+ step="${field.type === "integer" ? "1" : "any"}"
96
+ class="${inputClass(error)}">`;
97
+ } else if (field.type === "boolean") {
98
+ input = `<div class="flex items-center gap-2">
99
+ <input type="hidden" name="${name}" value="false">
100
+ <input type="checkbox" id="${id}" name="${name}" value="true" ${strVal === "true" ? "checked" : ""}
101
+ class="h-4 w-4 rounded border-zinc-300 dark:border-zinc-600 text-blue-600 focus:ring-blue-500">
102
+ <span class="text-sm text-zinc-700 dark:text-zinc-300">${label}</span>
103
+ </div>`;
104
+ return `
105
+ <div>
106
+ ${input}
107
+ ${error ? `<p class="mt-1 text-xs text-red-500">${chunkMNWKYY5E_cjs.escapeHtml(error)}</p>` : ""}
108
+ </div>`;
109
+ } else if (field.kind === "facet") {
110
+ const arrVal = Array.isArray(value) ? value.join(", ") : strVal;
111
+ input = `<input type="text" id="${id}" name="${name}" value="${chunkMNWKYY5E_cjs.escapeHtml(arrVal)}"
112
+ placeholder="Comma-separated values"
113
+ class="${inputClass(error)}">`;
114
+ } else {
115
+ input = `<input type="text" id="${id}" name="${name}" value="${chunkMNWKYY5E_cjs.escapeHtml(strVal)}"
116
+ class="${inputClass(error)}">`;
117
+ }
118
+ return `
119
+ <div>
120
+ <label for="${id}" class="block text-sm font-medium text-zinc-700 dark:text-zinc-300 mb-1">
121
+ ${label}
122
+ </label>
123
+ ${input}
124
+ ${error ? `<p class="mt-1 text-xs text-red-500">${chunkMNWKYY5E_cjs.escapeHtml(error)}</p>` : ""}
125
+ </div>`;
126
+ }
127
+ function renderRemainingFields(allData, queryableFields, errors) {
128
+ const knownNames = new Set(queryableFields.map((f) => f.name));
129
+ const remainingKeys = Object.keys(allData).filter((k) => !knownNames.has(k));
130
+ if (remainingKeys.length === 0) return "";
131
+ const inputs = remainingKeys.map((key) => {
132
+ const val = allData[key];
133
+ const id = `data_${key}`;
134
+ const name = `data[${key}]`;
135
+ const label = key.replace(/([A-Z])/g, " $1").replace(/^./, (s) => s.toUpperCase());
136
+ const strVal = typeof val === "object" ? JSON.stringify(val, null, 2) : String(val ?? "");
137
+ const isMultiline = strVal.includes("\n") || strVal.length > 100;
138
+ return `
139
+ <div>
140
+ <label for="${id}" class="block text-sm font-medium text-zinc-700 dark:text-zinc-300 mb-1">${chunkMNWKYY5E_cjs.escapeHtml(label)}</label>
141
+ ${isMultiline ? `<textarea id="${id}" name="${name}" rows="4" class="${inputClass(errors[key])}">${chunkMNWKYY5E_cjs.escapeHtml(strVal)}</textarea>` : `<input type="text" id="${id}" name="${name}" value="${chunkMNWKYY5E_cjs.escapeHtml(strVal)}" class="${inputClass(errors[key])}">`}
142
+ ${errors[key] ? `<p class="mt-1 text-xs text-red-500">${chunkMNWKYY5E_cjs.escapeHtml(errors[key])}</p>` : ""}
143
+ </div>`;
144
+ }).join("");
145
+ return `
146
+ <div class="border-t border-zinc-200 dark:border-zinc-700 pt-6">
147
+ <h3 class="text-sm font-medium text-zinc-500 dark:text-zinc-400 mb-4">Additional Fields</h3>
148
+ <div class="grid grid-cols-1 gap-4 sm:grid-cols-2">${inputs}</div>
149
+ </div>`;
150
+ }
151
+ function renderDocumentFormPage(data) {
152
+ const { docType, doc, publishedDoc, isEdit, errors = {} } = data;
153
+ const queryableFields = docType.queryableFields ?? [];
154
+ const docData = doc?.data ?? {};
155
+ const isAdmin = data.user?.role === "admin";
156
+ const isEditor = isAdmin || data.user?.role === "editor";
157
+ const hasNewerDraft = isEdit && doc && !doc.isPublished && publishedDoc;
158
+ const isPublishedAndDraft = isEdit && doc?.isPublished && doc?.isCurrentDraft;
159
+ const formAction = isEdit ? `/admin/content/documents/${chunkMNWKYY5E_cjs.escapeHtml(docType.id)}/${chunkMNWKYY5E_cjs.escapeHtml(doc.rootId)}` : `/admin/content/documents/${chunkMNWKYY5E_cjs.escapeHtml(docType.id)}/new`;
160
+ const publishBannerHtml = (() => {
161
+ if (!isEdit || !doc) return "";
162
+ if (isPublishedAndDraft) {
163
+ return renderAlert({
164
+ type: "success",
165
+ message: 'This document is live. Saving creates a new draft. Use "Publish" to push changes live.'
166
+ });
167
+ }
168
+ if (hasNewerDraft) {
169
+ return renderAlert({
170
+ type: "info",
171
+ message: `A published version (v${publishedDoc.versionNumber}) is still live. This is an unpublished draft (v${doc.versionNumber}).`
172
+ });
173
+ }
174
+ return "";
175
+ })();
176
+ const queryableInputs = queryableFields.filter((f) => f.kind !== "reference").map((f) => renderFieldInput(f, docData[f.name], errors[`data.${f.name}`])).join("");
177
+ const remainingHtml = renderRemainingFields(docData, queryableFields, errors);
178
+ const content = `
179
+ <div class="w-full px-4 sm:px-6 lg:px-8 py-6 space-y-6">
180
+ <!-- Header -->
181
+ <div class="flex flex-col sm:flex-row sm:items-center sm:justify-between">
182
+ <div>
183
+ <div class="flex items-center gap-2 text-sm text-zinc-500 dark:text-zinc-400 mb-1">
184
+ <a href="/admin/content" class="hover:text-zinc-950 dark:hover:text-white">Content</a>
185
+ <svg class="h-4 w-4" viewBox="0 0 20 20" fill="currentColor"><path fill-rule="evenodd" d="M8.22 5.22a.75.75 0 0 1 1.06 0l4.25 4.25a.75.75 0 0 1 0 1.06l-4.25 4.25a.75.75 0 0 1-1.06-1.06L11.94 10 8.22 6.28a.75.75 0 0 1 0-1.06Z" clip-rule="evenodd"/></svg>
186
+ <a href="/admin/content?model=doc:${chunkMNWKYY5E_cjs.escapeHtml(docType.id)}" class="hover:text-zinc-950 dark:hover:text-white">${chunkMNWKYY5E_cjs.escapeHtml(docType.displayName)}</a>
187
+ <svg class="h-4 w-4" viewBox="0 0 20 20" fill="currentColor"><path fill-rule="evenodd" d="M8.22 5.22a.75.75 0 0 1 1.06 0l4.25 4.25a.75.75 0 0 1 0 1.06l-4.25 4.25a.75.75 0 0 1-1.06-1.06L11.94 10 8.22 6.28a.75.75 0 0 1 0-1.06Z" clip-rule="evenodd"/></svg>
188
+ <span class="text-zinc-950 dark:text-white font-medium">${isEdit ? "Edit" : "New"}</span>
189
+ </div>
190
+ <h1 class="text-2xl/8 font-semibold text-zinc-950 dark:text-white sm:text-xl/8">
191
+ ${isEdit ? `Edit ${chunkMNWKYY5E_cjs.escapeHtml(docType.displayName)}` : `New ${chunkMNWKYY5E_cjs.escapeHtml(docType.displayName)}`}
192
+ </h1>
193
+ ${isEdit && doc ? `<p class="mt-1 text-xs text-zinc-500 dark:text-zinc-400">v${doc.versionNumber} \xB7 root: <code class="font-mono">${chunkMNWKYY5E_cjs.escapeHtml(doc.rootId)}</code></p>` : ""}
194
+ </div>
195
+
196
+ <!-- Publish controls (edit mode, versioning types only) -->
197
+ ${isEdit && doc && isEditor && data.versioningEnabled ? `
198
+ <div class="mt-4 sm:mt-0 flex gap-2">
199
+ ${!doc.isPublished ? `
200
+ <form method="POST" action="/admin/content/documents/${chunkMNWKYY5E_cjs.escapeHtml(docType.id)}/${chunkMNWKYY5E_cjs.escapeHtml(doc.id)}/publish">
201
+ <button type="submit"
202
+ class="inline-flex items-center rounded-lg bg-green-600 px-3.5 py-2.5 text-sm font-semibold text-white hover:bg-green-500 transition-colors shadow-sm">
203
+ Publish
204
+ </button>
205
+ </form>` : `
206
+ <form method="POST" action="/admin/content/documents/${chunkMNWKYY5E_cjs.escapeHtml(docType.id)}/${chunkMNWKYY5E_cjs.escapeHtml(doc.id)}/unpublish">
207
+ <button type="submit"
208
+ class="inline-flex items-center rounded-lg bg-amber-500 px-3.5 py-2.5 text-sm font-semibold text-white hover:bg-amber-400 transition-colors shadow-sm">
209
+ Unpublish
210
+ </button>
211
+ </form>`}
212
+ </div>` : ""}
213
+ </div>
214
+
215
+ ${publishBannerHtml}
216
+ ${data.message ? renderAlert({ type: data.messageType ?? "info", message: data.message, dismissible: true }) : ""}
217
+
218
+ <!-- Form -->
219
+ <form method="POST" action="${formAction}">
220
+ ${isEdit ? `<input type="hidden" name="_method" value="PUT">` : ""}
221
+
222
+ <div class="relative rounded-xl">
223
+ <div class="absolute inset-0 bg-gradient-to-br from-blue-500/5 to-purple-500/5 dark:from-blue-400/10 dark:to-purple-400/10 rounded-xl"></div>
224
+ <div class="relative bg-white/80 dark:bg-zinc-900/80 backdrop-blur-xl shadow-sm ring-1 ring-zinc-950/5 dark:ring-white/10 rounded-xl p-6 space-y-6">
225
+
226
+ <!-- Standard fields -->
227
+ <div>
228
+ <h3 class="text-sm font-semibold text-zinc-700 dark:text-zinc-200 mb-4">Document</h3>
229
+ <div class="grid grid-cols-1 gap-4 sm:grid-cols-2">
230
+ <div>
231
+ <label for="title" class="block text-sm font-medium text-zinc-700 dark:text-zinc-300 mb-1">Title</label>
232
+ <input type="text" id="title" name="title" value="${chunkMNWKYY5E_cjs.escapeHtml(doc?.title ?? "")}"
233
+ class="${inputClass(errors.title)}">
234
+ ${errors.title ? `<p class="mt-1 text-xs text-red-500">${chunkMNWKYY5E_cjs.escapeHtml(errors.title)}</p>` : ""}
235
+ </div>
236
+ <div>
237
+ <label for="slug" class="block text-sm font-medium text-zinc-700 dark:text-zinc-300 mb-1">Slug</label>
238
+ <input type="text" id="slug" name="slug" value="${chunkMNWKYY5E_cjs.escapeHtml(doc?.slug ?? "")}"
239
+ placeholder="auto-generated-if-empty"
240
+ class="${inputClass(errors.slug)}">
241
+ ${errors.slug ? `<p class="mt-1 text-xs text-red-500">${chunkMNWKYY5E_cjs.escapeHtml(errors.slug)}</p>` : ""}
242
+ </div>
243
+ </div>
244
+ </div>
245
+
246
+ <!-- Queryable data fields -->
247
+ ${queryableFields.length > 0 ? `
248
+ <div class="border-t border-zinc-200 dark:border-zinc-700 pt-6">
249
+ <h3 class="text-sm font-semibold text-zinc-700 dark:text-zinc-200 mb-4">Content</h3>
250
+ <div class="grid grid-cols-1 gap-4 sm:grid-cols-2">
251
+ ${queryableInputs}
252
+ </div>
253
+ </div>` : ""}
254
+
255
+ <!-- Remaining data fields not in queryable fields -->
256
+ ${remainingHtml}
257
+
258
+ <!-- Actions -->
259
+ <div class="border-t border-zinc-200 dark:border-zinc-700 pt-6 flex items-center justify-between">
260
+ <a href="/admin/content?model=doc:${chunkMNWKYY5E_cjs.escapeHtml(docType.id)}"
261
+ class="inline-flex items-center rounded-lg bg-white dark:bg-zinc-800 px-3.5 py-2.5 text-sm font-semibold text-zinc-700 dark:text-zinc-200 ring-1 ring-inset ring-zinc-300 dark:ring-zinc-700 hover:bg-zinc-50 dark:hover:bg-zinc-700 transition-colors">
262
+ Cancel
263
+ </a>
264
+ <div class="flex gap-3">
265
+ <button type="submit"
266
+ class="inline-flex items-center rounded-lg bg-zinc-950 dark:bg-white px-3.5 py-2.5 text-sm font-semibold text-white dark:text-zinc-950 hover:bg-zinc-800 dark:hover:bg-zinc-100 transition-colors shadow-sm">
267
+ ${isEdit ? data.versioningEnabled ? "Save Draft" : "Update" : "Create"}
268
+ </button>
269
+ </div>
270
+ </div>
271
+ </div>
272
+ </div>
273
+ </form>
274
+
275
+ <!-- Version history (edit mode, versioning opt-in only) -->
276
+ ${isEdit && doc && data.versioningEnabled ? `
277
+ <details class="group">
278
+ <summary class="cursor-pointer text-sm text-zinc-500 dark:text-zinc-400 hover:text-zinc-950 dark:hover:text-white flex items-center gap-2 py-2">
279
+ <svg class="h-4 w-4 transition-transform group-open:rotate-90" viewBox="0 0 20 20" fill="currentColor">
280
+ <path fill-rule="evenodd" d="M8.22 5.22a.75.75 0 0 1 1.06 0l4.25 4.25a.75.75 0 0 1 0 1.06l-4.25 4.25a.75.75 0 0 1-1.06-1.06L11.94 10 8.22 6.28a.75.75 0 0 1 0-1.06Z" clip-rule="evenodd"/>
281
+ </svg>
282
+ Version history
283
+ </summary>
284
+ <div class="mt-3 rounded-xl bg-white dark:bg-zinc-900 ring-1 ring-zinc-950/5 dark:ring-white/10 overflow-hidden">
285
+ <div id="version-history-placeholder" class="px-6 py-4 text-sm text-zinc-500 dark:text-zinc-400"
286
+ hx-get="/admin/versioning/${chunkMNWKYY5E_cjs.escapeHtml(doc.rootId)}"
287
+ hx-trigger="revealed"
288
+ hx-swap="outerHTML">
289
+ Loading version history\u2026
290
+ </div>
291
+ </div>
292
+ </details>` : ""}
293
+ </div>
294
+ `;
295
+ return chunkNAVPFIG5_cjs.renderAdminLayoutCatalyst({
296
+ title: `${isEdit ? "Edit" : "New"} ${docType.displayName} \u2014 Documents`,
297
+ currentPath: "/admin/content",
298
+ user: data.user,
299
+ version: data.version,
300
+ content
301
+ });
302
+ }
303
+ function renderVersionHistoryFragment(data) {
304
+ if (data.versions.length === 0) {
305
+ return `<div class="px-6 py-4 text-sm text-zinc-500 dark:text-zinc-400">No versions found.</div>`;
306
+ }
307
+ const rows = data.versions.map((v) => `
308
+ <div class="flex items-center justify-between px-6 py-3 border-b border-zinc-100 dark:border-zinc-800 last:border-0">
309
+ <div class="flex items-center gap-3">
310
+ <span class="text-sm font-medium text-zinc-950 dark:text-white">v${v.versionNumber}</span>
311
+ ${v.isPublished ? `<span class="inline-flex items-center rounded-md bg-green-50 dark:bg-green-500/10 px-1.5 py-0.5 text-xs font-medium text-green-700 dark:text-green-400">live</span>` : ""}
312
+ ${v.isCurrentDraft ? `<span class="inline-flex items-center rounded-md bg-blue-50 dark:bg-blue-500/10 px-1.5 py-0.5 text-xs font-medium text-blue-700 dark:text-blue-400">draft</span>` : ""}
313
+ </div>
314
+ <div class="flex items-center gap-4 text-xs text-zinc-500 dark:text-zinc-400">
315
+ <span>${v.createdBy ?? "\u2014"}</span>
316
+ <span>${new Date(v.updatedAt * 1e3).toLocaleString("en-US", { dateStyle: "short", timeStyle: "short" })}</span>
317
+ </div>
318
+ </div>
319
+ `).join("");
320
+ return `<div>${rows}</div>`;
321
+ }
322
+
323
+ exports.renderAlert = renderAlert;
324
+ exports.renderDocumentFormPage = renderDocumentFormPage;
325
+ exports.renderVersionHistoryFragment = renderVersionHistoryFragment;
326
+ //# sourceMappingURL=chunk-DNQCEKUK.cjs.map
327
+ //# sourceMappingURL=chunk-DNQCEKUK.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/templates/pages/admin-documents-form.template.ts","../src/templates/components/alert.template.ts"],"names":["init_admin_layout_catalyst_template","escapeHtml","renderAdminLayoutCatalyst"],"mappings":"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","file":"chunk-DNQCEKUK.cjs","sourcesContent":["import { renderAdminLayoutCatalyst } from '../layouts/admin-layout-catalyst.template'\nimport { renderAlert } from '../components/alert.template'\nimport { escapeHtml } from '../../utils/sanitize'\nimport type { Document, DocumentType, QueryableField } from '../../schemas/document'\n\nexport interface DocumentFormData {\n docType: DocumentType\n doc?: Document\n publishedDoc?: Document | null // Published revision when different from current draft\n isEdit: boolean\n errors?: Record<string, string>\n message?: string\n messageType?: 'success' | 'error' | 'warning' | 'info'\n user?: { name: string; email: string; role: string }\n version?: string\n versioningEnabled?: boolean // Whether versioning is opt-in for this document type\n}\n\nfunction inputClass(error?: string): string {\n const base = 'block w-full rounded-lg border bg-white dark:bg-zinc-800 px-3 py-2 text-sm text-zinc-950 dark:text-white placeholder:text-zinc-400 focus:outline-none focus:ring-2 focus:ring-blue-500 transition-colors'\n return error\n ? `${base} border-red-400 dark:border-red-500`\n : `${base} border-zinc-300 dark:border-zinc-700`\n}\n\nfunction renderFieldInput(field: QueryableField, value: unknown, error?: string): string {\n const id = `data_${field.name}`\n const name = `data[${field.name}]`\n const label = field.name.replace(/([A-Z])/g, ' $1').replace(/^./, s => s.toUpperCase())\n const strVal = value != null ? String(value) : ''\n\n let input: string\n if (field.type === 'integer' || field.type === 'number') {\n input = `<input type=\"number\" id=\"${id}\" name=\"${name}\" value=\"${escapeHtml(strVal)}\"\n step=\"${field.type === 'integer' ? '1' : 'any'}\"\n class=\"${inputClass(error)}\">`\n } else if (field.type === 'boolean') {\n // Hidden 'false' before the checkbox: an unchecked checkbox submits nothing, so without this a\n // boolean could never be set back to false (D15). When checked, the checkbox value wins.\n input = `<div class=\"flex items-center gap-2\">\n <input type=\"hidden\" name=\"${name}\" value=\"false\">\n <input type=\"checkbox\" id=\"${id}\" name=\"${name}\" value=\"true\" ${strVal === 'true' ? 'checked' : ''}\n class=\"h-4 w-4 rounded border-zinc-300 dark:border-zinc-600 text-blue-600 focus:ring-blue-500\">\n <span class=\"text-sm text-zinc-700 dark:text-zinc-300\">${label}</span>\n </div>`\n return `\n <div>\n ${input}\n ${error ? `<p class=\"mt-1 text-xs text-red-500\">${escapeHtml(error)}</p>` : ''}\n </div>`\n } else if (field.kind === 'facet') {\n // Multi-value: comma-separated list\n const arrVal = Array.isArray(value) ? (value as string[]).join(', ') : strVal\n input = `<input type=\"text\" id=\"${id}\" name=\"${name}\" value=\"${escapeHtml(arrVal)}\"\n placeholder=\"Comma-separated values\"\n class=\"${inputClass(error)}\">`\n } else {\n input = `<input type=\"text\" id=\"${id}\" name=\"${name}\" value=\"${escapeHtml(strVal)}\"\n class=\"${inputClass(error)}\">`\n }\n\n return `\n <div>\n <label for=\"${id}\" class=\"block text-sm font-medium text-zinc-700 dark:text-zinc-300 mb-1\">\n ${label}\n </label>\n ${input}\n ${error ? `<p class=\"mt-1 text-xs text-red-500\">${escapeHtml(error)}</p>` : ''}\n </div>`\n}\n\nfunction renderRemainingFields(\n allData: Record<string, unknown>,\n queryableFields: QueryableField[],\n errors: Record<string, string>,\n): string {\n const knownNames = new Set(queryableFields.map(f => f.name))\n const remainingKeys = Object.keys(allData).filter(k => !knownNames.has(k))\n if (remainingKeys.length === 0) return ''\n\n const inputs = remainingKeys.map(key => {\n const val = allData[key]\n const id = `data_${key}`\n const name = `data[${key}]`\n const label = key.replace(/([A-Z])/g, ' $1').replace(/^./, s => s.toUpperCase())\n const strVal = typeof val === 'object' ? JSON.stringify(val, null, 2) : String(val ?? '')\n const isMultiline = strVal.includes('\\n') || strVal.length > 100\n\n return `\n <div>\n <label for=\"${id}\" class=\"block text-sm font-medium text-zinc-700 dark:text-zinc-300 mb-1\">${escapeHtml(label)}</label>\n ${isMultiline\n ? `<textarea id=\"${id}\" name=\"${name}\" rows=\"4\" class=\"${inputClass(errors[key])}\">${escapeHtml(strVal)}</textarea>`\n : `<input type=\"text\" id=\"${id}\" name=\"${name}\" value=\"${escapeHtml(strVal)}\" class=\"${inputClass(errors[key])}\">`\n }\n ${errors[key] ? `<p class=\"mt-1 text-xs text-red-500\">${escapeHtml(errors[key])}</p>` : ''}\n </div>`\n }).join('')\n\n return `\n <div class=\"border-t border-zinc-200 dark:border-zinc-700 pt-6\">\n <h3 class=\"text-sm font-medium text-zinc-500 dark:text-zinc-400 mb-4\">Additional Fields</h3>\n <div class=\"grid grid-cols-1 gap-4 sm:grid-cols-2\">${inputs}</div>\n </div>`\n}\n\nexport function renderDocumentFormPage(data: DocumentFormData): string {\n const { docType, doc, publishedDoc, isEdit, errors = {} } = data\n const queryableFields = docType.queryableFields ?? []\n const docData = (doc?.data ?? {}) as Record<string, unknown>\n\n const isAdmin = data.user?.role === 'admin'\n const isEditor = isAdmin || data.user?.role === 'editor'\n\n const hasNewerDraft = isEdit && doc && !doc.isPublished && publishedDoc\n const isPublishedAndDraft = isEdit && doc?.isPublished && doc?.isCurrentDraft\n\n // Real document CRUD lives under /admin/content/documents/:typeId/... (admin-content.ts), NOT\n // /admin/documents/ui (those are GET redirects only). Edit/save POSTs to :rootId; create to /new.\n const formAction = isEdit\n ? `/admin/content/documents/${escapeHtml(docType.id)}/${escapeHtml(doc!.rootId)}`\n : `/admin/content/documents/${escapeHtml(docType.id)}/new`\n\n const publishBannerHtml = (() => {\n if (!isEdit || !doc) return ''\n if (isPublishedAndDraft) {\n return renderAlert({\n type: 'success',\n message: 'This document is live. Saving creates a new draft. Use \"Publish\" to push changes live.',\n })\n }\n if (hasNewerDraft) {\n return renderAlert({\n type: 'info',\n message: `A published version (v${publishedDoc!.versionNumber}) is still live. This is an unpublished draft (v${doc.versionNumber}).`,\n })\n }\n return ''\n })()\n\n // Reference-kind fields are intentionally not rendered yet (D27) — fine for FAQ/testimonial, which\n // have none. When media references land (Phase 6), render a root-id picker here.\n const queryableInputs = queryableFields\n .filter(f => f.kind !== 'reference')\n .map(f => renderFieldInput(f, docData[f.name], errors[`data.${f.name}`]))\n .join('')\n\n const remainingHtml = renderRemainingFields(docData, queryableFields, errors)\n\n const content = `\n <div class=\"w-full px-4 sm:px-6 lg:px-8 py-6 space-y-6\">\n <!-- Header -->\n <div class=\"flex flex-col sm:flex-row sm:items-center sm:justify-between\">\n <div>\n <div class=\"flex items-center gap-2 text-sm text-zinc-500 dark:text-zinc-400 mb-1\">\n <a href=\"/admin/content\" class=\"hover:text-zinc-950 dark:hover:text-white\">Content</a>\n <svg class=\"h-4 w-4\" viewBox=\"0 0 20 20\" fill=\"currentColor\"><path fill-rule=\"evenodd\" d=\"M8.22 5.22a.75.75 0 0 1 1.06 0l4.25 4.25a.75.75 0 0 1 0 1.06l-4.25 4.25a.75.75 0 0 1-1.06-1.06L11.94 10 8.22 6.28a.75.75 0 0 1 0-1.06Z\" clip-rule=\"evenodd\"/></svg>\n <a href=\"/admin/content?model=doc:${escapeHtml(docType.id)}\" class=\"hover:text-zinc-950 dark:hover:text-white\">${escapeHtml(docType.displayName)}</a>\n <svg class=\"h-4 w-4\" viewBox=\"0 0 20 20\" fill=\"currentColor\"><path fill-rule=\"evenodd\" d=\"M8.22 5.22a.75.75 0 0 1 1.06 0l4.25 4.25a.75.75 0 0 1 0 1.06l-4.25 4.25a.75.75 0 0 1-1.06-1.06L11.94 10 8.22 6.28a.75.75 0 0 1 0-1.06Z\" clip-rule=\"evenodd\"/></svg>\n <span class=\"text-zinc-950 dark:text-white font-medium\">${isEdit ? 'Edit' : 'New'}</span>\n </div>\n <h1 class=\"text-2xl/8 font-semibold text-zinc-950 dark:text-white sm:text-xl/8\">\n ${isEdit ? `Edit ${escapeHtml(docType.displayName)}` : `New ${escapeHtml(docType.displayName)}`}\n </h1>\n ${isEdit && doc ? `<p class=\"mt-1 text-xs text-zinc-500 dark:text-zinc-400\">v${doc.versionNumber} · root: <code class=\"font-mono\">${escapeHtml(doc.rootId)}</code></p>` : ''}\n </div>\n\n <!-- Publish controls (edit mode, versioning types only) -->\n ${isEdit && doc && isEditor && data.versioningEnabled ? `\n <div class=\"mt-4 sm:mt-0 flex gap-2\">\n ${!doc.isPublished ? `\n <form method=\"POST\" action=\"/admin/content/documents/${escapeHtml(docType.id)}/${escapeHtml(doc.id)}/publish\">\n <button type=\"submit\"\n class=\"inline-flex items-center rounded-lg bg-green-600 px-3.5 py-2.5 text-sm font-semibold text-white hover:bg-green-500 transition-colors shadow-sm\">\n Publish\n </button>\n </form>` : `\n <form method=\"POST\" action=\"/admin/content/documents/${escapeHtml(docType.id)}/${escapeHtml(doc.id)}/unpublish\">\n <button type=\"submit\"\n class=\"inline-flex items-center rounded-lg bg-amber-500 px-3.5 py-2.5 text-sm font-semibold text-white hover:bg-amber-400 transition-colors shadow-sm\">\n Unpublish\n </button>\n </form>`}\n </div>` : ''}\n </div>\n\n ${publishBannerHtml}\n ${data.message ? renderAlert({ type: data.messageType ?? 'info', message: data.message, dismissible: true }) : ''}\n\n <!-- Form -->\n <form method=\"POST\" action=\"${formAction}\">\n ${isEdit ? `<input type=\"hidden\" name=\"_method\" value=\"PUT\">` : ''}\n\n <div class=\"relative rounded-xl\">\n <div class=\"absolute inset-0 bg-gradient-to-br from-blue-500/5 to-purple-500/5 dark:from-blue-400/10 dark:to-purple-400/10 rounded-xl\"></div>\n <div class=\"relative bg-white/80 dark:bg-zinc-900/80 backdrop-blur-xl shadow-sm ring-1 ring-zinc-950/5 dark:ring-white/10 rounded-xl p-6 space-y-6\">\n\n <!-- Standard fields -->\n <div>\n <h3 class=\"text-sm font-semibold text-zinc-700 dark:text-zinc-200 mb-4\">Document</h3>\n <div class=\"grid grid-cols-1 gap-4 sm:grid-cols-2\">\n <div>\n <label for=\"title\" class=\"block text-sm font-medium text-zinc-700 dark:text-zinc-300 mb-1\">Title</label>\n <input type=\"text\" id=\"title\" name=\"title\" value=\"${escapeHtml(doc?.title ?? '')}\"\n class=\"${inputClass(errors.title)}\">\n ${errors.title ? `<p class=\"mt-1 text-xs text-red-500\">${escapeHtml(errors.title)}</p>` : ''}\n </div>\n <div>\n <label for=\"slug\" class=\"block text-sm font-medium text-zinc-700 dark:text-zinc-300 mb-1\">Slug</label>\n <input type=\"text\" id=\"slug\" name=\"slug\" value=\"${escapeHtml(doc?.slug ?? '')}\"\n placeholder=\"auto-generated-if-empty\"\n class=\"${inputClass(errors.slug)}\">\n ${errors.slug ? `<p class=\"mt-1 text-xs text-red-500\">${escapeHtml(errors.slug)}</p>` : ''}\n </div>\n </div>\n </div>\n\n <!-- Queryable data fields -->\n ${queryableFields.length > 0 ? `\n <div class=\"border-t border-zinc-200 dark:border-zinc-700 pt-6\">\n <h3 class=\"text-sm font-semibold text-zinc-700 dark:text-zinc-200 mb-4\">Content</h3>\n <div class=\"grid grid-cols-1 gap-4 sm:grid-cols-2\">\n ${queryableInputs}\n </div>\n </div>` : ''}\n\n <!-- Remaining data fields not in queryable fields -->\n ${remainingHtml}\n\n <!-- Actions -->\n <div class=\"border-t border-zinc-200 dark:border-zinc-700 pt-6 flex items-center justify-between\">\n <a href=\"/admin/content?model=doc:${escapeHtml(docType.id)}\"\n class=\"inline-flex items-center rounded-lg bg-white dark:bg-zinc-800 px-3.5 py-2.5 text-sm font-semibold text-zinc-700 dark:text-zinc-200 ring-1 ring-inset ring-zinc-300 dark:ring-zinc-700 hover:bg-zinc-50 dark:hover:bg-zinc-700 transition-colors\">\n Cancel\n </a>\n <div class=\"flex gap-3\">\n <button type=\"submit\"\n class=\"inline-flex items-center rounded-lg bg-zinc-950 dark:bg-white px-3.5 py-2.5 text-sm font-semibold text-white dark:text-zinc-950 hover:bg-zinc-800 dark:hover:bg-zinc-100 transition-colors shadow-sm\">\n ${isEdit ? (data.versioningEnabled ? 'Save Draft' : 'Update') : 'Create'}\n </button>\n </div>\n </div>\n </div>\n </div>\n </form>\n\n <!-- Version history (edit mode, versioning opt-in only) -->\n ${isEdit && doc && data.versioningEnabled ? `\n <details class=\"group\">\n <summary class=\"cursor-pointer text-sm text-zinc-500 dark:text-zinc-400 hover:text-zinc-950 dark:hover:text-white flex items-center gap-2 py-2\">\n <svg class=\"h-4 w-4 transition-transform group-open:rotate-90\" viewBox=\"0 0 20 20\" fill=\"currentColor\">\n <path fill-rule=\"evenodd\" d=\"M8.22 5.22a.75.75 0 0 1 1.06 0l4.25 4.25a.75.75 0 0 1 0 1.06l-4.25 4.25a.75.75 0 0 1-1.06-1.06L11.94 10 8.22 6.28a.75.75 0 0 1 0-1.06Z\" clip-rule=\"evenodd\"/>\n </svg>\n Version history\n </summary>\n <div class=\"mt-3 rounded-xl bg-white dark:bg-zinc-900 ring-1 ring-zinc-950/5 dark:ring-white/10 overflow-hidden\">\n <div id=\"version-history-placeholder\" class=\"px-6 py-4 text-sm text-zinc-500 dark:text-zinc-400\"\n hx-get=\"/admin/versioning/${escapeHtml(doc.rootId)}\"\n hx-trigger=\"revealed\"\n hx-swap=\"outerHTML\">\n Loading version history…\n </div>\n </div>\n </details>` : ''}\n </div>\n `\n\n return renderAdminLayoutCatalyst({\n title: `${isEdit ? 'Edit' : 'New'} ${docType.displayName} — Documents`,\n currentPath: '/admin/content',\n user: data.user,\n version: data.version,\n content,\n })\n}\n\n// ─── Version history fragment (HTMX target) ──────────────────────────────────\n\nexport interface VersionHistoryData {\n versions: Array<{\n id: string\n versionNumber: number\n isCurrentDraft: boolean\n isPublished: boolean\n status: string\n updatedAt: number\n createdBy: string | null\n }>\n docType: DocumentType\n rootId: string\n}\n\nexport function renderVersionHistoryFragment(data: VersionHistoryData): string {\n if (data.versions.length === 0) {\n return `<div class=\"px-6 py-4 text-sm text-zinc-500 dark:text-zinc-400\">No versions found.</div>`\n }\n\n const rows = data.versions.map(v => `\n <div class=\"flex items-center justify-between px-6 py-3 border-b border-zinc-100 dark:border-zinc-800 last:border-0\">\n <div class=\"flex items-center gap-3\">\n <span class=\"text-sm font-medium text-zinc-950 dark:text-white\">v${v.versionNumber}</span>\n ${v.isPublished ? `<span class=\"inline-flex items-center rounded-md bg-green-50 dark:bg-green-500/10 px-1.5 py-0.5 text-xs font-medium text-green-700 dark:text-green-400\">live</span>` : ''}\n ${v.isCurrentDraft ? `<span class=\"inline-flex items-center rounded-md bg-blue-50 dark:bg-blue-500/10 px-1.5 py-0.5 text-xs font-medium text-blue-700 dark:text-blue-400\">draft</span>` : ''}\n </div>\n <div class=\"flex items-center gap-4 text-xs text-zinc-500 dark:text-zinc-400\">\n <span>${v.createdBy ?? '—'}</span>\n <span>${new Date(v.updatedAt * 1000).toLocaleString('en-US', { dateStyle: 'short', timeStyle: 'short' })}</span>\n </div>\n </div>\n `).join('')\n\n return `<div>${rows}</div>`\n}\n","import { escapeHtml } from '../../utils/sanitize'\n\nexport type AlertType = 'success' | 'error' | 'warning' | 'info'\n\nexport interface AlertData {\n type: AlertType\n title?: string\n message: string\n dismissible?: boolean\n className?: string\n icon?: boolean\n}\n\nexport function renderAlert(data: AlertData): string {\n const typeClasses = {\n success: 'bg-green-50 dark:bg-green-500/10 border border-green-600/20 dark:border-green-500/20',\n error: 'bg-error/10 border border-red-600/20 dark:border-red-500/20',\n warning: 'bg-amber-50 dark:bg-amber-500/10 border border-amber-600/20 dark:border-amber-500/20',\n info: 'bg-blue-50 dark:bg-blue-500/10 border border-blue-600/20 dark:border-blue-500/20'\n }\n\n const iconClasses = {\n success: 'text-green-600 dark:text-green-400',\n error: 'text-red-600 dark:text-red-400',\n warning: 'text-amber-600 dark:text-amber-400',\n info: 'text-blue-600 dark:text-blue-400'\n }\n\n const textClasses = {\n success: 'text-green-900 dark:text-green-300',\n error: 'text-red-900 dark:text-red-300',\n warning: 'text-amber-900 dark:text-amber-300',\n info: 'text-blue-900 dark:text-blue-300'\n }\n\n const messageTextClasses = {\n success: 'text-green-700 dark:text-green-400',\n error: 'text-red-700 dark:text-red-400',\n warning: 'text-amber-700 dark:text-amber-400',\n info: 'text-blue-700 dark:text-blue-400'\n }\n\n const icons = {\n success: `<path fill-rule=\"evenodd\" d=\"M10 18a8 8 0 100-16 8 8 0 000 16zm3.707-9.293a1 1 0 00-1.414-1.414L9 10.586 7.707 9.293a1 1 0 00-1.414 1.414l2 2a1 1 0 001.414 0l4-4z\" clip-rule=\"evenodd\" />`,\n error: `<path fill-rule=\"evenodd\" d=\"M10 18a8 8 0 100-16 8 8 0 000 16zM8.707 7.293a1 1 0 00-1.414 1.414L8.586 10l-1.293 1.293a1 1 0 101.414 1.414L10 11.414l1.293 1.293a1 1 0 001.414-1.414L11.414 10l1.293-1.293a1 1 0 00-1.414-1.414L10 8.586 8.707 7.293z\" clip-rule=\"evenodd\" />`,\n warning: `<path fill-rule=\"evenodd\" d=\"M8.257 3.099c.765-1.36 2.722-1.36 3.486 0l5.58 9.92c.75 1.334-.213 2.98-1.742 2.98H4.42c-1.53 0-2.493-1.646-1.743-2.98l5.58-9.92zM11 13a1 1 0 11-2 0 1 1 0 012 0zm-1-8a1 1 0 00-1 1v3a1 1 0 002 0V6a1 1 0 00-1-1z\" clip-rule=\"evenodd\" />`,\n info: `<path fill-rule=\"evenodd\" d=\"M18 10a8 8 0 11-16 0 8 8 0 0116 0zm-7-4a1 1 0 11-2 0 1 1 0 012 0zM9 9a1 1 0 000 2v3a1 1 0 001 1h1a1 1 0 100-2v-3a1 1 0 00-1-1H9z\" clip-rule=\"evenodd\" />`\n }\n\n return `\n <div class=\"rounded-lg p-4 ${typeClasses[data.type]} ${data.className || ''}\" ${data.dismissible ? 'id=\"dismissible-alert\"' : ''}>\n <div class=\"flex\">\n ${data.icon !== false ? `\n <div class=\"flex-shrink-0\">\n <svg class=\"h-5 w-5 ${iconClasses[data.type]}\" viewBox=\"0 0 20 20\" fill=\"currentColor\">\n ${icons[data.type]}\n </svg>\n </div>\n ` : ''}\n <div class=\"${data.icon !== false ? 'ml-3' : ''}\">\n ${data.title ? `\n <h3 class=\"text-sm font-semibold ${textClasses[data.type]}\">\n ${escapeHtml(data.title)}\n </h3>\n ` : ''}\n <div class=\"${data.title ? 'mt-1 text-sm' : 'text-sm'} ${messageTextClasses[data.type]}\">\n <p>${escapeHtml(data.message)}</p>\n </div>\n </div>\n ${data.dismissible ? `\n <div class=\"ml-auto pl-3\">\n <div class=\"-mx-1.5 -my-1.5\">\n <button\n type=\"button\"\n class=\"inline-flex rounded-md p-1.5 ${iconClasses[data.type]} hover:bg-opacity-20 focus:outline-none focus:ring-2 focus:ring-offset-2\"\n onclick=\"document.getElementById('dismissible-alert').remove()\"\n >\n <span class=\"sr-only\">Dismiss</span>\n <svg class=\"h-5 w-5\" viewBox=\"0 0 20 20\" fill=\"currentColor\">\n <path fill-rule=\"evenodd\" d=\"M4.293 4.293a1 1 0 011.414 0L10 8.586l4.293-4.293a1 1 0 111.414 1.414L11.414 10l4.293 4.293a1 1 0 01-1.414 1.414L10 11.414l-4.293 4.293a1 1 0 01-1.414-1.414L8.586 10 4.293 5.707a1 1 0 010-1.414z\" clip-rule=\"evenodd\" />\n </svg>\n </button>\n </div>\n </div>\n ` : ''}\n </div>\n </div>\n `\n}\n\nexport function renderSuccessAlert(message: string, title?: string): string {\n return renderAlert({ type: 'success', message, title })\n}\n\nexport function renderErrorAlert(message: string, title?: string): string {\n return renderAlert({ type: 'error', message, title })\n}\n\nexport function renderWarningAlert(message: string, title?: string): string {\n return renderAlert({ type: 'warning', message, title })\n}\n\nexport function renderInfoAlert(message: string, title?: string): string {\n return renderAlert({ type: 'info', message, title })\n}\n"]}