@kywi-software/core 0.14.0 → 0.15.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (633) hide show
  1. package/AGENT-PATTERNS.md +200 -17
  2. package/README.md +38 -12
  3. package/dist/admin/audience-editor.d.ts +2 -0
  4. package/dist/admin/audience-editor.d.ts.map +1 -1
  5. package/dist/admin/audience-editor.js +4 -2
  6. package/dist/admin/audience-editor.js.map +1 -1
  7. package/dist/admin/chrome.d.ts.map +1 -1
  8. package/dist/admin/chrome.js +6 -7
  9. package/dist/admin/chrome.js.map +1 -1
  10. package/dist/admin/condition-builder.d.ts.map +1 -1
  11. package/dist/admin/condition-builder.js +16 -3
  12. package/dist/admin/condition-builder.js.map +1 -1
  13. package/dist/admin/field-components.d.ts.map +1 -1
  14. package/dist/admin/field-components.js +27 -1
  15. package/dist/admin/field-components.js.map +1 -1
  16. package/dist/admin/form-helpers.d.ts.map +1 -1
  17. package/dist/admin/form-helpers.js +6 -1
  18. package/dist/admin/form-helpers.js.map +1 -1
  19. package/dist/admin/layout-editor/chrome-env.d.ts +35 -0
  20. package/dist/admin/layout-editor/chrome-env.d.ts.map +1 -0
  21. package/dist/admin/layout-editor/chrome-env.js +13 -0
  22. package/dist/admin/layout-editor/chrome-env.js.map +1 -0
  23. package/dist/admin/layout-editor/component-actions.d.ts +58 -7
  24. package/dist/admin/layout-editor/component-actions.d.ts.map +1 -1
  25. package/dist/admin/layout-editor/component-actions.js +131 -5
  26. package/dist/admin/layout-editor/component-actions.js.map +1 -1
  27. package/dist/admin/layout-editor/component-fork.d.ts +4 -4
  28. package/dist/admin/layout-editor/component-fork.d.ts.map +1 -1
  29. package/dist/admin/layout-editor/component-fork.js +76 -10
  30. package/dist/admin/layout-editor/component-fork.js.map +1 -1
  31. package/dist/admin/layout-editor/component-picker-field.d.ts +17 -3
  32. package/dist/admin/layout-editor/component-picker-field.d.ts.map +1 -1
  33. package/dist/admin/layout-editor/component-picker-field.js +5 -2
  34. package/dist/admin/layout-editor/component-picker-field.js.map +1 -1
  35. package/dist/admin/layout-editor/drag-feedback.d.ts +25 -1
  36. package/dist/admin/layout-editor/drag-feedback.d.ts.map +1 -1
  37. package/dist/admin/layout-editor/drag-feedback.js +9 -0
  38. package/dist/admin/layout-editor/drag-feedback.js.map +1 -1
  39. package/dist/admin/layout-editor/drag-utils.d.ts +103 -5
  40. package/dist/admin/layout-editor/drag-utils.d.ts.map +1 -1
  41. package/dist/admin/layout-editor/drag-utils.js +131 -4
  42. package/dist/admin/layout-editor/drag-utils.js.map +1 -1
  43. package/dist/admin/layout-editor/editor-canvas.d.ts +11 -0
  44. package/dist/admin/layout-editor/editor-canvas.d.ts.map +1 -1
  45. package/dist/admin/layout-editor/editor-canvas.js +134 -20
  46. package/dist/admin/layout-editor/editor-canvas.js.map +1 -1
  47. package/dist/admin/layout-editor/editor-dialog.d.ts +58 -3
  48. package/dist/admin/layout-editor/editor-dialog.d.ts.map +1 -1
  49. package/dist/admin/layout-editor/editor-dialog.js +71 -9
  50. package/dist/admin/layout-editor/editor-dialog.js.map +1 -1
  51. package/dist/admin/layout-editor/editor-state.d.ts +119 -0
  52. package/dist/admin/layout-editor/editor-state.d.ts.map +1 -1
  53. package/dist/admin/layout-editor/editor-state.js +188 -6
  54. package/dist/admin/layout-editor/editor-state.js.map +1 -1
  55. package/dist/admin/layout-editor/editor-toolbar.d.ts +10 -1
  56. package/dist/admin/layout-editor/editor-toolbar.d.ts.map +1 -1
  57. package/dist/admin/layout-editor/editor-toolbar.js +2 -2
  58. package/dist/admin/layout-editor/editor-toolbar.js.map +1 -1
  59. package/dist/admin/layout-editor/editor.css +216 -8
  60. package/dist/admin/layout-editor/inline-text.d.ts +15 -1
  61. package/dist/admin/layout-editor/inline-text.d.ts.map +1 -1
  62. package/dist/admin/layout-editor/inline-text.js +30 -2
  63. package/dist/admin/layout-editor/inline-text.js.map +1 -1
  64. package/dist/admin/layout-editor/layout-editor.d.ts +21 -16
  65. package/dist/admin/layout-editor/layout-editor.d.ts.map +1 -1
  66. package/dist/admin/layout-editor/layout-editor.js +40 -17
  67. package/dist/admin/layout-editor/layout-editor.js.map +1 -1
  68. package/dist/admin/layout-editor/linked-component-notes.d.ts +88 -0
  69. package/dist/admin/layout-editor/linked-component-notes.d.ts.map +1 -0
  70. package/dist/admin/layout-editor/linked-component-notes.js +88 -0
  71. package/dist/admin/layout-editor/linked-component-notes.js.map +1 -0
  72. package/dist/admin/layout-editor/module-overlay.d.ts +23 -4
  73. package/dist/admin/layout-editor/module-overlay.d.ts.map +1 -1
  74. package/dist/admin/layout-editor/module-overlay.js +56 -10
  75. package/dist/admin/layout-editor/module-overlay.js.map +1 -1
  76. package/dist/admin/layout-editor/module-variant-container-config.d.ts.map +1 -1
  77. package/dist/admin/layout-editor/module-variant-container-config.js +9 -2
  78. package/dist/admin/layout-editor/module-variant-container-config.js.map +1 -1
  79. package/dist/admin/layout-editor/module-variant-container-panel.d.ts +75 -0
  80. package/dist/admin/layout-editor/module-variant-container-panel.d.ts.map +1 -0
  81. package/dist/admin/layout-editor/module-variant-container-panel.js +29 -0
  82. package/dist/admin/layout-editor/module-variant-container-panel.js.map +1 -0
  83. package/dist/admin/layout-editor/node-lookup.d.ts.map +1 -1
  84. package/dist/admin/layout-editor/node-lookup.js +33 -3
  85. package/dist/admin/layout-editor/node-lookup.js.map +1 -1
  86. package/dist/admin/layout-editor/overlay-shell.d.ts.map +1 -1
  87. package/dist/admin/layout-editor/overlay-shell.js +19 -4
  88. package/dist/admin/layout-editor/overlay-shell.js.map +1 -1
  89. package/dist/admin/layout-editor/props-panel.d.ts +28 -11
  90. package/dist/admin/layout-editor/props-panel.d.ts.map +1 -1
  91. package/dist/admin/layout-editor/props-panel.js +75 -125
  92. package/dist/admin/layout-editor/props-panel.js.map +1 -1
  93. package/dist/admin/layout-editor/section-variant-container-config.d.ts.map +1 -1
  94. package/dist/admin/layout-editor/section-variant-container-config.js +11 -2
  95. package/dist/admin/layout-editor/section-variant-container-config.js.map +1 -1
  96. package/dist/admin/layout-editor/use-chrome-flip.d.ts +99 -11
  97. package/dist/admin/layout-editor/use-chrome-flip.d.ts.map +1 -1
  98. package/dist/admin/layout-editor/use-chrome-flip.js +268 -97
  99. package/dist/admin/layout-editor/use-chrome-flip.js.map +1 -1
  100. package/dist/admin/layout-editor/use-component-connect.d.ts +13 -0
  101. package/dist/admin/layout-editor/use-component-connect.d.ts.map +1 -1
  102. package/dist/admin/layout-editor/use-component-connect.js +116 -20
  103. package/dist/admin/layout-editor/use-component-connect.js.map +1 -1
  104. package/dist/admin/layout-editor/use-component-fork.d.ts +49 -19
  105. package/dist/admin/layout-editor/use-component-fork.d.ts.map +1 -1
  106. package/dist/admin/layout-editor/use-component-fork.js +28 -19
  107. package/dist/admin/layout-editor/use-component-fork.js.map +1 -1
  108. package/dist/admin/layout-editor/use-component-library.d.ts +4 -4
  109. package/dist/admin/layout-editor/use-component-library.d.ts.map +1 -1
  110. package/dist/admin/layout-editor/use-component-library.js +1 -1
  111. package/dist/admin/layout-editor/use-component-library.js.map +1 -1
  112. package/dist/admin/layout-editor/use-editor-dnd.d.ts +10 -0
  113. package/dist/admin/layout-editor/use-editor-dnd.d.ts.map +1 -1
  114. package/dist/admin/layout-editor/use-editor-dnd.js +234 -14
  115. package/dist/admin/layout-editor/use-editor-dnd.js.map +1 -1
  116. package/dist/admin/layout-editor/variant-container-config.d.ts.map +1 -1
  117. package/dist/admin/layout-editor/variant-container-config.js +1 -1
  118. package/dist/admin/layout-editor/variant-container-config.js.map +1 -1
  119. package/dist/admin/layout-editor/variant-editor.d.ts +16 -15
  120. package/dist/admin/layout-editor/variant-editor.d.ts.map +1 -1
  121. package/dist/admin/layout-editor/variant-editor.js +16 -5
  122. package/dist/admin/layout-editor/variant-editor.js.map +1 -1
  123. package/dist/admin/primitives.d.ts.map +1 -1
  124. package/dist/admin/primitives.js +1 -1
  125. package/dist/admin/primitives.js.map +1 -1
  126. package/dist/admin/registry.d.ts +12 -0
  127. package/dist/admin/registry.d.ts.map +1 -1
  128. package/dist/admin/registry.js +12 -0
  129. package/dist/admin/registry.js.map +1 -1
  130. package/dist/admin/rule-tester.d.ts +1 -0
  131. package/dist/admin/rule-tester.d.ts.map +1 -1
  132. package/dist/admin/rule-tester.js +7 -4
  133. package/dist/admin/rule-tester.js.map +1 -1
  134. package/dist/admin/server.d.ts +10 -1
  135. package/dist/admin/server.d.ts.map +1 -1
  136. package/dist/admin/server.js +4 -1
  137. package/dist/admin/server.js.map +1 -1
  138. package/dist/admin/signal-options.d.ts +17 -0
  139. package/dist/admin/signal-options.d.ts.map +1 -1
  140. package/dist/admin/signal-options.js +28 -0
  141. package/dist/admin/signal-options.js.map +1 -1
  142. package/dist/admin/site-switcher.d.ts +16 -3
  143. package/dist/admin/site-switcher.d.ts.map +1 -1
  144. package/dist/admin/site-switcher.js +18 -3
  145. package/dist/admin/site-switcher.js.map +1 -1
  146. package/dist/admin/styles/admin.css +0 -3
  147. package/dist/admin/surface-matcher.d.ts +6 -2
  148. package/dist/admin/surface-matcher.d.ts.map +1 -1
  149. package/dist/admin/surface-matcher.js +42 -5
  150. package/dist/admin/surface-matcher.js.map +1 -1
  151. package/dist/admin/surfaces/audiences/audiences-data.d.ts +5 -0
  152. package/dist/admin/surfaces/audiences/audiences-data.d.ts.map +1 -1
  153. package/dist/admin/surfaces/audiences/audiences-data.js +3 -0
  154. package/dist/admin/surfaces/audiences/audiences-data.js.map +1 -1
  155. package/dist/admin/surfaces/components/components-data.d.ts +31 -11
  156. package/dist/admin/surfaces/components/components-data.d.ts.map +1 -1
  157. package/dist/admin/surfaces/components/components-data.js +17 -4
  158. package/dist/admin/surfaces/components/components-data.js.map +1 -1
  159. package/dist/admin/surfaces/components/components-list.d.ts.map +1 -1
  160. package/dist/admin/surfaces/components/components-list.js +20 -7
  161. package/dist/admin/surfaces/components/components-list.js.map +1 -1
  162. package/dist/admin/surfaces/components/definition-canvas.d.ts +11 -3
  163. package/dist/admin/surfaces/components/definition-canvas.d.ts.map +1 -1
  164. package/dist/admin/surfaces/components/definition-canvas.js +138 -17
  165. package/dist/admin/surfaces/components/definition-canvas.js.map +1 -1
  166. package/dist/admin/surfaces/dashboard/dashboard-index.d.ts.map +1 -1
  167. package/dist/admin/surfaces/dashboard/dashboard-index.js +2 -2
  168. package/dist/admin/surfaces/dashboard/dashboard-index.js.map +1 -1
  169. package/dist/admin/surfaces/layouts/layout-editor-client.d.ts.map +1 -1
  170. package/dist/admin/surfaces/layouts/layout-editor-client.js +12 -11
  171. package/dist/admin/surfaces/layouts/layout-editor-client.js.map +1 -1
  172. package/dist/admin/surfaces/menus/menu-editor.d.ts.map +1 -1
  173. package/dist/admin/surfaces/menus/menu-editor.js +17 -4
  174. package/dist/admin/surfaces/menus/menu-editor.js.map +1 -1
  175. package/dist/admin/surfaces/menus/menu-tree.d.ts +18 -4
  176. package/dist/admin/surfaces/menus/menu-tree.d.ts.map +1 -1
  177. package/dist/admin/surfaces/menus/menu-tree.js +18 -3
  178. package/dist/admin/surfaces/menus/menu-tree.js.map +1 -1
  179. package/dist/admin/surfaces/menus/menus-data.d.ts +18 -0
  180. package/dist/admin/surfaces/menus/menus-data.d.ts.map +1 -1
  181. package/dist/admin/surfaces/menus/menus-data.js +4 -0
  182. package/dist/admin/surfaces/menus/menus-data.js.map +1 -1
  183. package/dist/admin/surfaces/menus/menus-list.d.ts.map +1 -1
  184. package/dist/admin/surfaces/menus/menus-list.js +2 -12
  185. package/dist/admin/surfaces/menus/menus-list.js.map +1 -1
  186. package/dist/admin/surfaces/users/users-data.d.ts +14 -0
  187. package/dist/admin/surfaces/users/users-data.d.ts.map +1 -1
  188. package/dist/admin/surfaces/users/users-data.js +19 -0
  189. package/dist/admin/surfaces/users/users-data.js.map +1 -1
  190. package/dist/admin/surfaces/users/users-detail.d.ts.map +1 -1
  191. package/dist/admin/surfaces/users/users-detail.js +40 -4
  192. package/dist/admin/surfaces/users/users-detail.js.map +1 -1
  193. package/dist/admin/surfaces/users/users-new.d.ts.map +1 -1
  194. package/dist/admin/surfaces/users/users-new.js +8 -5
  195. package/dist/admin/surfaces/users/users-new.js.map +1 -1
  196. package/dist/admin/user-form.d.ts +10 -1
  197. package/dist/admin/user-form.d.ts.map +1 -1
  198. package/dist/admin/user-form.js +2 -2
  199. package/dist/admin/user-form.js.map +1 -1
  200. package/dist/api/admin-features-routes.js +2 -2
  201. package/dist/api/admin-features-routes.js.map +1 -1
  202. package/dist/api/api-key-routes.js +2 -2
  203. package/dist/api/api-key-routes.js.map +1 -1
  204. package/dist/api/audience-preview-routes.d.ts +7 -0
  205. package/dist/api/audience-preview-routes.d.ts.map +1 -1
  206. package/dist/api/audience-preview-routes.js +4 -4
  207. package/dist/api/audience-preview-routes.js.map +1 -1
  208. package/dist/api/audience-routes.d.ts +7 -0
  209. package/dist/api/audience-routes.d.ts.map +1 -1
  210. package/dist/api/audience-routes.js +31 -19
  211. package/dist/api/audience-routes.js.map +1 -1
  212. package/dist/api/audience-runtime-routes.d.ts +23 -0
  213. package/dist/api/audience-runtime-routes.d.ts.map +1 -1
  214. package/dist/api/audience-runtime-routes.js +511 -25
  215. package/dist/api/audience-runtime-routes.js.map +1 -1
  216. package/dist/api/auth-routes.d.ts.map +1 -1
  217. package/dist/api/auth-routes.js +10 -4
  218. package/dist/api/auth-routes.js.map +1 -1
  219. package/dist/api/auth.d.ts +1 -0
  220. package/dist/api/auth.d.ts.map +1 -1
  221. package/dist/api/auth.js +43 -3
  222. package/dist/api/auth.js.map +1 -1
  223. package/dist/api/ax-routes.d.ts.map +1 -1
  224. package/dist/api/ax-routes.js +7 -3
  225. package/dist/api/ax-routes.js.map +1 -1
  226. package/dist/api/bulk-routes.d.ts.map +1 -1
  227. package/dist/api/bulk-routes.js +7 -7
  228. package/dist/api/bulk-routes.js.map +1 -1
  229. package/dist/api/category-routes.js +6 -6
  230. package/dist/api/category-routes.js.map +1 -1
  231. package/dist/api/changeset-routes.js +2 -2
  232. package/dist/api/changeset-routes.js.map +1 -1
  233. package/dist/api/comment-routes.js +12 -12
  234. package/dist/api/comment-routes.js.map +1 -1
  235. package/dist/api/component-routes.d.ts +25 -0
  236. package/dist/api/component-routes.d.ts.map +1 -1
  237. package/dist/api/component-routes.js +44 -19
  238. package/dist/api/component-routes.js.map +1 -1
  239. package/dist/api/config-routes.js +4 -4
  240. package/dist/api/config-routes.js.map +1 -1
  241. package/dist/api/content-permission-routes.js +2 -2
  242. package/dist/api/content-permission-routes.js.map +1 -1
  243. package/dist/api/content-routes.d.ts.map +1 -1
  244. package/dist/api/content-routes.js +21 -16
  245. package/dist/api/content-routes.js.map +1 -1
  246. package/dist/api/content-type-routes.js +3 -3
  247. package/dist/api/content-type-routes.js.map +1 -1
  248. package/dist/api/dashboard-routes.js +1 -1
  249. package/dist/api/dashboard-routes.js.map +1 -1
  250. package/dist/api/experiment-routes.d.ts +7 -0
  251. package/dist/api/experiment-routes.d.ts.map +1 -1
  252. package/dist/api/experiment-routes.js +10 -10
  253. package/dist/api/experiment-routes.js.map +1 -1
  254. package/dist/api/experiment-runtime-routes.d.ts +6 -0
  255. package/dist/api/experiment-runtime-routes.d.ts.map +1 -1
  256. package/dist/api/experiment-runtime-routes.js +47 -11
  257. package/dist/api/experiment-runtime-routes.js.map +1 -1
  258. package/dist/api/extension-routes.js +4 -4
  259. package/dist/api/extension-routes.js.map +1 -1
  260. package/dist/api/feed-routes.d.ts +2 -2
  261. package/dist/api/feed-routes.js +5 -5
  262. package/dist/api/feed-routes.js.map +1 -1
  263. package/dist/api/form-routes.js +6 -6
  264. package/dist/api/form-routes.js.map +1 -1
  265. package/dist/api/graphql/resolvers.d.ts +1 -1
  266. package/dist/api/graphql/resolvers.d.ts.map +1 -1
  267. package/dist/api/graphql/resolvers.js +68 -33
  268. package/dist/api/graphql/resolvers.js.map +1 -1
  269. package/dist/api/group-routes.js +9 -9
  270. package/dist/api/group-routes.js.map +1 -1
  271. package/dist/api/index.d.ts +1 -0
  272. package/dist/api/index.d.ts.map +1 -1
  273. package/dist/api/index.js +43 -7
  274. package/dist/api/index.js.map +1 -1
  275. package/dist/api/layout-routes.d.ts +19 -1
  276. package/dist/api/layout-routes.d.ts.map +1 -1
  277. package/dist/api/layout-routes.js +92 -8
  278. package/dist/api/layout-routes.js.map +1 -1
  279. package/dist/api/layout-write-guard.d.ts +3 -2
  280. package/dist/api/layout-write-guard.d.ts.map +1 -1
  281. package/dist/api/layout-write-guard.js +12 -4
  282. package/dist/api/layout-write-guard.js.map +1 -1
  283. package/dist/api/media-routes.d.ts.map +1 -1
  284. package/dist/api/media-routes.js +100 -35
  285. package/dist/api/media-routes.js.map +1 -1
  286. package/dist/api/menu-routes.d.ts +9 -1
  287. package/dist/api/menu-routes.d.ts.map +1 -1
  288. package/dist/api/menu-routes.js +46 -12
  289. package/dist/api/menu-routes.js.map +1 -1
  290. package/dist/api/nav-routes.d.ts +6 -0
  291. package/dist/api/nav-routes.d.ts.map +1 -1
  292. package/dist/api/nav-routes.js +25 -4
  293. package/dist/api/nav-routes.js.map +1 -1
  294. package/dist/api/oauth-routes.js +2 -2
  295. package/dist/api/oauth-routes.js.map +1 -1
  296. package/dist/api/openapi.d.ts.map +1 -1
  297. package/dist/api/openapi.js +82 -34
  298. package/dist/api/openapi.js.map +1 -1
  299. package/dist/api/pagination.d.ts +10 -0
  300. package/dist/api/pagination.d.ts.map +1 -1
  301. package/dist/api/pagination.js +7 -1
  302. package/dist/api/pagination.js.map +1 -1
  303. package/dist/api/response.d.ts +29 -0
  304. package/dist/api/response.d.ts.map +1 -1
  305. package/dist/api/response.js +23 -3
  306. package/dist/api/response.js.map +1 -1
  307. package/dist/api/search-routes.d.ts.map +1 -1
  308. package/dist/api/search-routes.js +19 -5
  309. package/dist/api/search-routes.js.map +1 -1
  310. package/dist/api/section-template-routes.d.ts.map +1 -1
  311. package/dist/api/section-template-routes.js +37 -20
  312. package/dist/api/section-template-routes.js.map +1 -1
  313. package/dist/api/site-admin-routes.d.ts +10 -1
  314. package/dist/api/site-admin-routes.d.ts.map +1 -1
  315. package/dist/api/site-admin-routes.js +21 -1
  316. package/dist/api/site-admin-routes.js.map +1 -1
  317. package/dist/api/site-context.d.ts +35 -5
  318. package/dist/api/site-context.d.ts.map +1 -1
  319. package/dist/api/site-context.js +21 -6
  320. package/dist/api/site-context.js.map +1 -1
  321. package/dist/api/site-routes.js +2 -2
  322. package/dist/api/site-routes.js.map +1 -1
  323. package/dist/api/tag-routes.d.ts.map +1 -1
  324. package/dist/api/tag-routes.js +5 -5
  325. package/dist/api/tag-routes.js.map +1 -1
  326. package/dist/api/translation-routes.js +5 -5
  327. package/dist/api/translation-routes.js.map +1 -1
  328. package/dist/api/user-routes.d.ts.map +1 -1
  329. package/dist/api/user-routes.js +136 -21
  330. package/dist/api/user-routes.js.map +1 -1
  331. package/dist/api/version-routes.js +2 -2
  332. package/dist/api/version-routes.js.map +1 -1
  333. package/dist/api/webhook-routes.js +8 -8
  334. package/dist/api/webhook-routes.js.map +1 -1
  335. package/dist/api/workflow-routes.d.ts.map +1 -1
  336. package/dist/api/workflow-routes.js +23 -14
  337. package/dist/api/workflow-routes.js.map +1 -1
  338. package/dist/audiences/collectors/identity.d.ts +14 -1
  339. package/dist/audiences/collectors/identity.d.ts.map +1 -1
  340. package/dist/audiences/collectors/identity.js +16 -3
  341. package/dist/audiences/collectors/identity.js.map +1 -1
  342. package/dist/audiences/collectors/index.d.ts +16 -2
  343. package/dist/audiences/collectors/index.d.ts.map +1 -1
  344. package/dist/audiences/collectors/index.js +29 -5
  345. package/dist/audiences/collectors/index.js.map +1 -1
  346. package/dist/audiences/collectors/pinned-audience.d.ts +28 -2
  347. package/dist/audiences/collectors/pinned-audience.d.ts.map +1 -1
  348. package/dist/audiences/collectors/pinned-audience.js +35 -5
  349. package/dist/audiences/collectors/pinned-audience.js.map +1 -1
  350. package/dist/audiences/collectors/selfid.d.ts +25 -0
  351. package/dist/audiences/collectors/selfid.d.ts.map +1 -0
  352. package/dist/audiences/collectors/selfid.js +46 -0
  353. package/dist/audiences/collectors/selfid.js.map +1 -0
  354. package/dist/audiences/collectors/session.d.ts +41 -0
  355. package/dist/audiences/collectors/session.d.ts.map +1 -0
  356. package/dist/audiences/collectors/session.js +50 -0
  357. package/dist/audiences/collectors/session.js.map +1 -0
  358. package/dist/audiences/collectors/utm.d.ts +15 -1
  359. package/dist/audiences/collectors/utm.d.ts.map +1 -1
  360. package/dist/audiences/collectors/utm.js +16 -2
  361. package/dist/audiences/collectors/utm.js.map +1 -1
  362. package/dist/audiences/consent-config.d.ts +21 -0
  363. package/dist/audiences/consent-config.d.ts.map +1 -0
  364. package/dist/audiences/consent-config.js +15 -0
  365. package/dist/audiences/consent-config.js.map +1 -0
  366. package/dist/audiences/consent-startup.d.ts +39 -0
  367. package/dist/audiences/consent-startup.d.ts.map +1 -0
  368. package/dist/audiences/consent-startup.js +105 -0
  369. package/dist/audiences/consent-startup.js.map +1 -0
  370. package/dist/audiences/consent.d.ts +205 -0
  371. package/dist/audiences/consent.d.ts.map +1 -0
  372. package/dist/audiences/consent.js +335 -0
  373. package/dist/audiences/consent.js.map +1 -0
  374. package/dist/audiences/cookies.d.ts +21 -0
  375. package/dist/audiences/cookies.d.ts.map +1 -1
  376. package/dist/audiences/cookies.js +26 -0
  377. package/dist/audiences/cookies.js.map +1 -1
  378. package/dist/audiences/engine.d.ts +7 -0
  379. package/dist/audiences/engine.d.ts.map +1 -1
  380. package/dist/audiences/engine.js +7 -2
  381. package/dist/audiences/engine.js.map +1 -1
  382. package/dist/audiences/entry-page.d.ts +89 -0
  383. package/dist/audiences/entry-page.d.ts.map +1 -0
  384. package/dist/audiences/entry-page.js +116 -0
  385. package/dist/audiences/entry-page.js.map +1 -0
  386. package/dist/audiences/evaluator/instant-match.d.ts.map +1 -1
  387. package/dist/audiences/evaluator/instant-match.js +7 -0
  388. package/dist/audiences/evaluator/instant-match.js.map +1 -1
  389. package/dist/audiences/index.d.ts +6 -2
  390. package/dist/audiences/index.d.ts.map +1 -1
  391. package/dist/audiences/index.js +12 -2
  392. package/dist/audiences/index.js.map +1 -1
  393. package/dist/audiences/queries.d.ts +16 -0
  394. package/dist/audiences/queries.d.ts.map +1 -1
  395. package/dist/audiences/queries.js +28 -1
  396. package/dist/audiences/queries.js.map +1 -1
  397. package/dist/audiences/schema.d.ts +17 -0
  398. package/dist/audiences/schema.d.ts.map +1 -1
  399. package/dist/audiences/schema.js +7 -0
  400. package/dist/audiences/schema.js.map +1 -1
  401. package/dist/audiences/server-eval.d.ts +32 -1
  402. package/dist/audiences/server-eval.d.ts.map +1 -1
  403. package/dist/audiences/server-eval.js +35 -3
  404. package/dist/audiences/server-eval.js.map +1 -1
  405. package/dist/audiences/ssr.d.ts +18 -1
  406. package/dist/audiences/ssr.d.ts.map +1 -1
  407. package/dist/audiences/ssr.js +18 -1
  408. package/dist/audiences/ssr.js.map +1 -1
  409. package/dist/audiences/types.d.ts +22 -1
  410. package/dist/audiences/types.d.ts.map +1 -1
  411. package/dist/audiences/types.js +1 -0
  412. package/dist/audiences/types.js.map +1 -1
  413. package/dist/audiences/utm-persistence.d.ts +20 -7
  414. package/dist/audiences/utm-persistence.d.ts.map +1 -1
  415. package/dist/audiences/utm-persistence.js +20 -7
  416. package/dist/audiences/utm-persistence.js.map +1 -1
  417. package/dist/auth/roles.d.ts +11 -0
  418. package/dist/auth/roles.d.ts.map +1 -1
  419. package/dist/auth/roles.js +13 -0
  420. package/dist/auth/roles.js.map +1 -1
  421. package/dist/auth/tokens.d.ts +7 -0
  422. package/dist/auth/tokens.d.ts.map +1 -1
  423. package/dist/auth/tokens.js +24 -2
  424. package/dist/auth/tokens.js.map +1 -1
  425. package/dist/ax/content-source.d.ts +10 -2
  426. package/dist/ax/content-source.d.ts.map +1 -1
  427. package/dist/ax/content-source.js +81 -5
  428. package/dist/ax/content-source.js.map +1 -1
  429. package/dist/ax/effective-body.d.ts +28 -0
  430. package/dist/ax/effective-body.d.ts.map +1 -0
  431. package/dist/ax/effective-body.js +47 -0
  432. package/dist/ax/effective-body.js.map +1 -0
  433. package/dist/ax/index.d.ts +3 -1
  434. package/dist/ax/index.d.ts.map +1 -1
  435. package/dist/ax/index.js +2 -0
  436. package/dist/ax/index.js.map +1 -1
  437. package/dist/ax/jsonld.d.ts +31 -1
  438. package/dist/ax/jsonld.d.ts.map +1 -1
  439. package/dist/ax/jsonld.js +35 -22
  440. package/dist/ax/jsonld.js.map +1 -1
  441. package/dist/ax/layout-to-html.d.ts +127 -0
  442. package/dist/ax/layout-to-html.d.ts.map +1 -0
  443. package/dist/ax/layout-to-html.js +545 -0
  444. package/dist/ax/layout-to-html.js.map +1 -0
  445. package/dist/ax/llms-full-txt.d.ts +3 -1
  446. package/dist/ax/llms-full-txt.d.ts.map +1 -1
  447. package/dist/ax/llms-full-txt.js +5 -2
  448. package/dist/ax/llms-full-txt.js.map +1 -1
  449. package/dist/ax/page-markdown.d.ts +10 -2
  450. package/dist/ax/page-markdown.d.ts.map +1 -1
  451. package/dist/ax/page-markdown.js +16 -3
  452. package/dist/ax/page-markdown.js.map +1 -1
  453. package/dist/ax/summary.d.ts +4 -0
  454. package/dist/ax/summary.d.ts.map +1 -1
  455. package/dist/ax/summary.js +6 -1
  456. package/dist/ax/summary.js.map +1 -1
  457. package/dist/ax/types.d.ts +24 -0
  458. package/dist/ax/types.d.ts.map +1 -1
  459. package/dist/cache/content-invalidation.d.ts.map +1 -1
  460. package/dist/cache/content-invalidation.js +11 -0
  461. package/dist/cache/content-invalidation.js.map +1 -1
  462. package/dist/config/types.d.ts +43 -0
  463. package/dist/config/types.d.ts.map +1 -1
  464. package/dist/config/types.js.map +1 -1
  465. package/dist/config/validate.d.ts.map +1 -1
  466. package/dist/config/validate.js +3 -0
  467. package/dist/config/validate.js.map +1 -1
  468. package/dist/db/apply-snapshot.d.ts +25 -0
  469. package/dist/db/apply-snapshot.d.ts.map +1 -1
  470. package/dist/db/apply-snapshot.js +48 -16
  471. package/dist/db/apply-snapshot.js.map +1 -1
  472. package/dist/db/ax-queries.d.ts +6 -0
  473. package/dist/db/ax-queries.d.ts.map +1 -1
  474. package/dist/db/ax-queries.js +6 -0
  475. package/dist/db/ax-queries.js.map +1 -1
  476. package/dist/db/component-instance-queries.d.ts +79 -19
  477. package/dist/db/component-instance-queries.d.ts.map +1 -1
  478. package/dist/db/component-instance-queries.js +266 -83
  479. package/dist/db/component-instance-queries.js.map +1 -1
  480. package/dist/db/component-queries.d.ts +1 -16
  481. package/dist/db/component-queries.d.ts.map +1 -1
  482. package/dist/db/component-queries.js +7 -56
  483. package/dist/db/component-queries.js.map +1 -1
  484. package/dist/db/content-queries.d.ts.map +1 -1
  485. package/dist/db/content-queries.js +9 -2
  486. package/dist/db/content-queries.js.map +1 -1
  487. package/dist/db/extension-queries.d.ts +2 -2
  488. package/dist/db/feed-queries.d.ts +3 -3
  489. package/dist/db/index.d.ts +1 -0
  490. package/dist/db/index.d.ts.map +1 -1
  491. package/dist/db/index.js +1 -0
  492. package/dist/db/index.js.map +1 -1
  493. package/dist/db/layout-queries.d.ts +21 -3
  494. package/dist/db/layout-queries.d.ts.map +1 -1
  495. package/dist/db/layout-queries.js +14 -6
  496. package/dist/db/layout-queries.js.map +1 -1
  497. package/dist/db/menu-queries.d.ts +69 -5
  498. package/dist/db/menu-queries.d.ts.map +1 -1
  499. package/dist/db/menu-queries.js +120 -13
  500. package/dist/db/menu-queries.js.map +1 -1
  501. package/dist/db/search-queries.d.ts.map +1 -1
  502. package/dist/db/search-queries.js +24 -1
  503. package/dist/db/search-queries.js.map +1 -1
  504. package/dist/db/section-template-queries.d.ts +62 -0
  505. package/dist/db/section-template-queries.d.ts.map +1 -0
  506. package/dist/db/section-template-queries.js +178 -0
  507. package/dist/db/section-template-queries.js.map +1 -0
  508. package/dist/db/site-plugin-queries.d.ts +2 -2
  509. package/dist/db/tree-queries.d.ts.map +1 -1
  510. package/dist/db/tree-queries.js +5 -0
  511. package/dist/db/tree-queries.js.map +1 -1
  512. package/dist/db/webhook-queries.d.ts +3 -3
  513. package/dist/db/workflow-queries.d.ts.map +1 -1
  514. package/dist/db/workflow-queries.js +5 -20
  515. package/dist/db/workflow-queries.js.map +1 -1
  516. package/dist/experiments/runtime.d.ts +21 -3
  517. package/dist/experiments/runtime.d.ts.map +1 -1
  518. package/dist/experiments/runtime.js +21 -3
  519. package/dist/experiments/runtime.js.map +1 -1
  520. package/dist/hooks/ax-invalidation.d.ts.map +1 -1
  521. package/dist/hooks/ax-invalidation.js +4 -0
  522. package/dist/hooks/ax-invalidation.js.map +1 -1
  523. package/dist/layout/component-refs.d.ts +90 -2
  524. package/dist/layout/component-refs.d.ts.map +1 -1
  525. package/dist/layout/component-refs.js +293 -16
  526. package/dist/layout/component-refs.js.map +1 -1
  527. package/dist/layout/index.d.ts +7 -4
  528. package/dist/layout/index.d.ts.map +1 -1
  529. package/dist/layout/index.js +6 -3
  530. package/dist/layout/index.js.map +1 -1
  531. package/dist/layout/legacy-variant-container.d.ts +123 -0
  532. package/dist/layout/legacy-variant-container.d.ts.map +1 -0
  533. package/dist/layout/legacy-variant-container.js +397 -0
  534. package/dist/layout/legacy-variant-container.js.map +1 -0
  535. package/dist/layout/module-permissions.d.ts.map +1 -1
  536. package/dist/layout/module-permissions.js +26 -38
  537. package/dist/layout/module-permissions.js.map +1 -1
  538. package/dist/layout/modules-extended.d.ts +28 -1
  539. package/dist/layout/modules-extended.d.ts.map +1 -1
  540. package/dist/layout/modules-extended.js +73 -1
  541. package/dist/layout/modules-extended.js.map +1 -1
  542. package/dist/layout/modules.d.ts.map +1 -1
  543. package/dist/layout/modules.js +9 -1
  544. package/dist/layout/modules.js.map +1 -1
  545. package/dist/layout/personalization.d.ts +83 -0
  546. package/dist/layout/personalization.d.ts.map +1 -1
  547. package/dist/layout/personalization.js +250 -4
  548. package/dist/layout/personalization.js.map +1 -1
  549. package/dist/layout/registry.d.ts.map +1 -1
  550. package/dist/layout/registry.js +20 -0
  551. package/dist/layout/registry.js.map +1 -1
  552. package/dist/layout/renderer.d.ts +29 -2
  553. package/dist/layout/renderer.d.ts.map +1 -1
  554. package/dist/layout/renderer.js +23 -6
  555. package/dist/layout/renderer.js.map +1 -1
  556. package/dist/layout/seed-defaults.d.ts +45 -0
  557. package/dist/layout/seed-defaults.d.ts.map +1 -0
  558. package/dist/layout/seed-defaults.js +75 -0
  559. package/dist/layout/seed-defaults.js.map +1 -0
  560. package/dist/layout/types.d.ts +17 -0
  561. package/dist/layout/types.d.ts.map +1 -1
  562. package/dist/layout/types.js +7 -0
  563. package/dist/layout/types.js.map +1 -1
  564. package/dist/layout/walk.d.ts +14 -0
  565. package/dist/layout/walk.d.ts.map +1 -0
  566. package/dist/layout/walk.js +49 -0
  567. package/dist/layout/walk.js.map +1 -0
  568. package/dist/media/index.d.ts +1 -1
  569. package/dist/media/index.d.ts.map +1 -1
  570. package/dist/media/index.js +1 -1
  571. package/dist/media/index.js.map +1 -1
  572. package/dist/media/inline-risk.d.ts +26 -0
  573. package/dist/media/inline-risk.d.ts.map +1 -0
  574. package/dist/media/inline-risk.js +142 -0
  575. package/dist/media/inline-risk.js.map +1 -0
  576. package/dist/media/upload-allowlist.d.ts +23 -0
  577. package/dist/media/upload-allowlist.d.ts.map +1 -1
  578. package/dist/media/upload-allowlist.js +29 -0
  579. package/dist/media/upload-allowlist.js.map +1 -1
  580. package/dist/nav/builder.d.ts.map +1 -1
  581. package/dist/nav/builder.js +15 -3
  582. package/dist/nav/builder.js.map +1 -1
  583. package/dist/nav/index.d.ts +1 -1
  584. package/dist/nav/index.d.ts.map +1 -1
  585. package/dist/nav/index.js +1 -1
  586. package/dist/nav/index.js.map +1 -1
  587. package/dist/nav/menu-resolver.d.ts +11 -0
  588. package/dist/nav/menu-resolver.d.ts.map +1 -1
  589. package/dist/nav/menu-resolver.js +49 -9
  590. package/dist/nav/menu-resolver.js.map +1 -1
  591. package/dist/nav/paths.d.ts +37 -0
  592. package/dist/nav/paths.d.ts.map +1 -0
  593. package/dist/nav/paths.js +48 -0
  594. package/dist/nav/paths.js.map +1 -0
  595. package/dist/nav/types.d.ts +6 -0
  596. package/dist/nav/types.d.ts.map +1 -1
  597. package/dist/nav/url-resolver.d.ts +1 -5
  598. package/dist/nav/url-resolver.d.ts.map +1 -1
  599. package/dist/nav/url-resolver.js +6 -12
  600. package/dist/nav/url-resolver.js.map +1 -1
  601. package/dist/schema/base.d.ts +24 -4
  602. package/dist/schema/base.d.ts.map +1 -1
  603. package/dist/schema/base.js +17 -4
  604. package/dist/schema/base.js.map +1 -1
  605. package/dist/schema/components.d.ts +90 -9
  606. package/dist/schema/components.d.ts.map +1 -1
  607. package/dist/schema/components.js +113 -22
  608. package/dist/schema/components.js.map +1 -1
  609. package/dist/schema/mysql-tables.d.ts +5775 -48
  610. package/dist/schema/mysql-tables.d.ts.map +1 -1
  611. package/dist/schema/mysql-tables.js +622 -46
  612. package/dist/schema/mysql-tables.js.map +1 -1
  613. package/dist/scope/jsonld.d.ts +18 -3
  614. package/dist/scope/jsonld.d.ts.map +1 -1
  615. package/dist/scope/jsonld.js +6 -4
  616. package/dist/scope/jsonld.js.map +1 -1
  617. package/dist/scope/kywi-form.d.ts +11 -0
  618. package/dist/scope/kywi-form.d.ts.map +1 -1
  619. package/dist/scope/kywi-form.js +11 -1
  620. package/dist/scope/kywi-form.js.map +1 -1
  621. package/dist/scope/kywi-wizard-form.d.ts.map +1 -1
  622. package/dist/scope/kywi-wizard-form.js +76 -2
  623. package/dist/scope/kywi-wizard-form.js.map +1 -1
  624. package/dist/scope/sticky-offset.d.ts +34 -13
  625. package/dist/scope/sticky-offset.d.ts.map +1 -1
  626. package/dist/scope/sticky-offset.js +236 -43
  627. package/dist/scope/sticky-offset.js.map +1 -1
  628. package/dist/site/styles.css +61 -15
  629. package/dist/versioning/scheduler.d.ts +28 -0
  630. package/dist/versioning/scheduler.d.ts.map +1 -1
  631. package/dist/versioning/scheduler.js +50 -3
  632. package/dist/versioning/scheduler.js.map +1 -1
  633. package/package.json +12 -2
@@ -1,5 +1,33 @@
1
1
  import { randomUUID } from 'node:crypto';
2
- import { mysqlTable, varchar, text, int, boolean, datetime, json, decimal, unique, } from 'drizzle-orm/mysql-core';
2
+ import { sql } from 'drizzle-orm';
3
+ import { mysqlTable, varchar, text, int, boolean, datetime, json, decimal, index, primaryKey, unique, check, } from 'drizzle-orm/mysql-core';
4
+ /**
5
+ * MySQL twins of every Postgres table in this package (kywi-cms#75).
6
+ *
7
+ * MySQL is a supported deployment target, not a Postgres subset: every
8
+ * `pgTable` exported from `schema/` (plus `audiences/` and `experiments/`) has
9
+ * a twin here with the same table name, columns, nullability and defaults.
10
+ * `schema/__tests__/mysql-parity.test.ts` enforces that programmatically —
11
+ * add a pgTable without a twin and it fails.
12
+ *
13
+ * Where a Postgres construct has no MySQL equivalent, the twin says so in a
14
+ * comment and takes the closest expressible shape. The recurring cases:
15
+ *
16
+ * - **`uuid` → `varchar(36)`.** MySQL has no uuid type.
17
+ * - **`timestamptz` → `datetime(3)`.** MySQL's `timestamp` is 2038-bounded and
18
+ * auto-updating; `datetime` with millisecond precision is the faithful twin.
19
+ * `defaultNow()` becomes `DEFAULT CURRENT_TIMESTAMP(3)` ({@link mysqlNow}).
20
+ * - **`jsonb` → `json`.** No jsonb operator classes, so no GIN-equivalent
21
+ * indexing, and a JSON column cannot take a *literal* DEFAULT — see
22
+ * {@link mysqlJsonDefault}.
23
+ * - **`text` → `varchar(n)` when the column is keyed, indexed or defaulted.**
24
+ * MySQL cannot use TEXT as a primary key, cannot index it without a prefix
25
+ * length, and cannot give it a DEFAULT. Every such conversion is marked.
26
+ * - **Partial (`WHERE …`) unique indexes have no MySQL equivalent.** The one
27
+ * place Kywi uses them — `kywi_content_permissions` — falls back to plain
28
+ * lookup indexes plus the app-level dedupe already in the migrate path; see
29
+ * the comment on {@link kywiContentPermissionsMysql} and docs/hosting.md.
30
+ */
3
31
  // ── Helper: UUID primary key for MySQL ──────────────────────────────────────
4
32
  function mysqlUuidPk() {
5
33
  return varchar({ length: 36 }).primaryKey().$defaultFn(() => randomUUID());
@@ -10,16 +38,42 @@ function mysqlUuid(name) {
10
38
  function mysqlTs(name) {
11
39
  return datetime(name, { fsp: 3 });
12
40
  }
41
+ /**
42
+ * The MySQL twin of Postgres `defaultNow()`.
43
+ *
44
+ * drizzle's mysql-core exposes `.defaultNow()` only on `timestamp`, and these
45
+ * twins deliberately use `datetime` (see the module doc). `DEFAULT
46
+ * CURRENT_TIMESTAMP(3)` is what `defaultNow()` compiles to for a `datetime(3)`
47
+ * column, and MySQL has accepted it on DATETIME since 5.6.5.
48
+ *
49
+ * Returns a fresh `SQL` each call so no two columns share one node.
50
+ */
51
+ function mysqlNow() {
52
+ return sql `CURRENT_TIMESTAMP(3)`;
53
+ }
54
+ /**
55
+ * The MySQL twin of a Postgres `jsonb(...).default([])`.
56
+ *
57
+ * MySQL rejects a literal DEFAULT on a JSON column outright; since 8.0.13 it
58
+ * accepts a *parenthesised expression* default instead, which is what this
59
+ * emits. On MySQL 8.0.12 and older there is no way to express the default at
60
+ * all and the column has to be written explicitly by the caller — the query
61
+ * layer already does, so the practical effect is limited to hand-written
62
+ * inserts. Documented in docs/hosting.md.
63
+ */
64
+ function mysqlJsonDefault(literal) {
65
+ return sql.raw(`('${literal.replace(/'/g, "''")}')`);
66
+ }
13
67
  // ── kywiSitesMysql ──────────────────────────────────────────────────────────
14
68
  export const kywiSitesMysql = mysqlTable('kywi_sites', {
15
69
  id: mysqlUuidPk(),
16
- slug: varchar('slug', { length: 100 }).notNull(),
70
+ slug: varchar('slug', { length: 100 }).notNull().unique(),
17
71
  name: text('name').notNull(),
18
72
  domain: text('domain').notNull(),
19
73
  defaultLocale: varchar('default_locale', { length: 10 }).notNull().default('en'),
20
74
  theme: varchar('theme', { length: 100 }).notNull().default('default'),
21
- createdAt: mysqlTs('created_at').notNull(),
22
- updatedAt: mysqlTs('updated_at').notNull(),
75
+ createdAt: mysqlTs('created_at').notNull().default(mysqlNow()),
76
+ updatedAt: mysqlTs('updated_at').notNull().default(mysqlNow()),
23
77
  });
24
78
  // ── kywiContentMysql ────────────────────────────────────────────────────────
25
79
  export const kywiContentMysql = mysqlTable('kywi_content', {
@@ -27,7 +81,9 @@ export const kywiContentMysql = mysqlTable('kywi_content', {
27
81
  id: mysqlUuidPk(),
28
82
  siteId: mysqlUuid('site_id').notNull().references(() => kywiSitesMysql.id),
29
83
  parentId: mysqlUuid('parent_id'),
30
- path: text('path').notNull(),
84
+ // pg: `text NOT NULL DEFAULT '/'`. MySQL cannot give a TEXT column a
85
+ // DEFAULT, so the twin narrows to varchar to keep the default.
86
+ path: varchar('path', { length: 1024 }).notNull().default('/'),
31
87
  depth: int('depth').notNull().default(0),
32
88
  sortOrder: int('sort_order').notNull().default(0),
33
89
  title: text('title').notNull(),
@@ -37,8 +93,8 @@ export const kywiContentMysql = mysqlTable('kywi_content', {
37
93
  baseType: varchar('base_type', { length: 50 }).notNull(),
38
94
  contentTypeName: varchar('content_type_name', { length: 100 }).notNull(),
39
95
  publishedAt: mysqlTs('published_at'),
40
- createdAt: mysqlTs('created_at').notNull(),
41
- updatedAt: mysqlTs('updated_at').notNull(),
96
+ createdAt: mysqlTs('created_at').notNull().default(mysqlNow()),
97
+ updatedAt: mysqlTs('updated_at').notNull().default(mysqlNow()),
42
98
  createdBy: mysqlUuid('created_by'),
43
99
  updatedBy: mysqlUuid('updated_by'),
44
100
  metaTitle: text('meta_title'),
@@ -56,7 +112,9 @@ export const kywiContentMysql = mysqlTable('kywi_content', {
56
112
  robotsFollow: varchar('robots_follow', { length: 10 }),
57
113
  deletedAt: mysqlTs('deleted_at'),
58
114
  featuredImageId: mysqlUuid('featured_image_id'),
59
- featureInSection: text('feature_in_section'),
115
+ // pg: `text DEFAULT 'no'` — 'no' | 'yes' | ISO date string. Narrowed to
116
+ // varchar so MySQL can carry the default (an ISO-8601 stamp is 29 chars).
117
+ featureInSection: varchar('feature_in_section', { length: 64 }).default('no'),
60
118
  expiresAt: mysqlTs('expires_at'),
61
119
  excludeFromSearch: boolean('exclude_from_search').notNull().default(false),
62
120
  internalNotes: text('internal_notes'),
@@ -105,15 +163,18 @@ export const kywiContentMysql = mysqlTable('kywi_content', {
105
163
  // ── kywiUsersMysql ──────────────────────────────────────────────────────────
106
164
  export const kywiUsersMysql = mysqlTable('kywi_users', {
107
165
  id: mysqlUuidPk(),
108
- email: text('email').notNull(),
166
+ // pg: `text NOT NULL UNIQUE`. MySQL cannot put a UNIQUE index on TEXT
167
+ // without a prefix length; 320 is the RFC 5321 maximum address length.
168
+ email: varchar('email', { length: 320 }).notNull().unique(),
109
169
  passwordHash: text('password_hash').notNull(),
110
- firstName: text('first_name').notNull(),
111
- lastName: text('last_name').notNull(),
170
+ // pg: `text NOT NULL DEFAULT ''` — narrowed so MySQL can carry the default.
171
+ firstName: varchar('first_name', { length: 255 }).notNull().default(''),
172
+ lastName: varchar('last_name', { length: 255 }).notNull().default(''),
112
173
  role: varchar('role', { length: 20 }).notNull().default('reader'),
113
174
  isActive: boolean('is_active').notNull().default(true),
114
175
  lastLoginAt: mysqlTs('last_login_at'),
115
- createdAt: mysqlTs('created_at').notNull(),
116
- updatedAt: mysqlTs('updated_at').notNull(),
176
+ createdAt: mysqlTs('created_at').notNull().default(mysqlNow()),
177
+ updatedAt: mysqlTs('updated_at').notNull().default(mysqlNow()),
117
178
  // ── Profile fields ──────────────────────────────────────────────────────────
118
179
  company: text('company'),
119
180
  jobTitle: text('job_title'),
@@ -132,7 +193,7 @@ export const kywiGroupsMysql = mysqlTable('kywi_groups', {
132
193
  name: text('name').notNull(),
133
194
  type: varchar('type', { length: 20 }).notNull().default('private'),
134
195
  defaultRole: varchar('default_role', { length: 20 }).notNull().default('reader'),
135
- createdAt: mysqlTs('created_at').notNull(),
196
+ createdAt: mysqlTs('created_at').notNull().default(mysqlNow()),
136
197
  });
137
198
  // ── kywiUserGroupsMysql ─────────────────────────────────────────────────────
138
199
  // #40: unique(userId, groupId) — see the matching note on kywiUserGroups in
@@ -149,9 +210,9 @@ export const kywiApiKeysMysql = mysqlTable('kywi_api_keys', {
149
210
  name: text('name').notNull(),
150
211
  keyHash: text('key_hash').notNull(),
151
212
  keyPrefix: varchar('key_prefix', { length: 12 }).notNull(),
152
- scopes: json('scopes').notNull(),
213
+ scopes: json('scopes').notNull().default(mysqlJsonDefault('[]')),
153
214
  lastUsedAt: mysqlTs('last_used_at'),
154
- createdAt: mysqlTs('created_at').notNull(),
215
+ createdAt: mysqlTs('created_at').notNull().default(mysqlNow()),
155
216
  });
156
217
  // ── kywiSiteMembershipsMysql ────────────────────────────────────────────────
157
218
  // #40: unique(userId, siteId) — see the matching note on kywiSiteMemberships
@@ -161,8 +222,8 @@ export const kywiApiKeysMysql = mysqlTable('kywi_api_keys', {
161
222
  export const kywiSiteMembershipsMysql = mysqlTable('kywi_site_memberships', {
162
223
  userId: mysqlUuid('user_id').notNull().references(() => kywiUsersMysql.id, { onDelete: 'cascade' }),
163
224
  siteId: mysqlUuid('site_id').notNull().references(() => kywiSitesMysql.id, { onDelete: 'cascade' }),
164
- groups: json('groups').notNull(),
165
- createdAt: mysqlTs('created_at').notNull(),
225
+ groups: json('groups').notNull().default(mysqlJsonDefault('[]')),
226
+ createdAt: mysqlTs('created_at').notNull().default(mysqlNow()),
166
227
  }, (t) => [unique().on(t.userId, t.siteId)]);
167
228
  // ── kywiMediaMysql ──────────────────────────────────────────────────────────
168
229
  export const kywiMediaMysql = mysqlTable('kywi_media', {
@@ -181,8 +242,8 @@ export const kywiMediaMysql = mysqlTable('kywi_media', {
181
242
  uploadedBy: mysqlUuid('uploaded_by'),
182
243
  storageKey: text('storage_key').notNull(),
183
244
  deletedAt: mysqlTs('deleted_at'),
184
- createdAt: mysqlTs('created_at').notNull(),
185
- updatedAt: mysqlTs('updated_at').notNull(),
245
+ createdAt: mysqlTs('created_at').notNull().default(mysqlNow()),
246
+ updatedAt: mysqlTs('updated_at').notNull().default(mysqlNow()),
186
247
  });
187
248
  // ── kywiFormSubmissionsMysql ────────────────────────────────────────────────
188
249
  export const kywiFormSubmissionsMysql = mysqlTable('kywi_form_submissions', {
@@ -190,7 +251,7 @@ export const kywiFormSubmissionsMysql = mysqlTable('kywi_form_submissions', {
190
251
  siteId: mysqlUuid('site_id').notNull().references(() => kywiSitesMysql.id),
191
252
  formContentId: mysqlUuid('form_content_id').notNull(),
192
253
  data: json('data').notNull(),
193
- submittedAt: mysqlTs('submitted_at').notNull(),
254
+ submittedAt: mysqlTs('submitted_at').notNull().default(mysqlNow()),
194
255
  ipAddress: varchar('ip_address', { length: 45 }),
195
256
  status: varchar('status', { length: 20 }).notNull().default('new'),
196
257
  });
@@ -204,7 +265,7 @@ export const kywiContentVersionsMysql = mysqlTable('kywi_content_versions', {
204
265
  changeNote: text('change_note'),
205
266
  status: varchar('status', { length: 20 }).notNull(),
206
267
  createdBy: mysqlUuid('created_by'),
207
- createdAt: mysqlTs('created_at').notNull(),
268
+ createdAt: mysqlTs('created_at').notNull().default(mysqlNow()),
208
269
  });
209
270
  // ── kywiCategoriesMysql ─────────────────────────────────────────────────────
210
271
  export const kywiCategoriesMysql = mysqlTable('kywi_categories', {
@@ -218,8 +279,8 @@ export const kywiCategoriesMysql = mysqlTable('kywi_categories', {
218
279
  isActive: boolean('is_active').notNull().default(true),
219
280
  isInterestGroup: boolean('is_interest_group').notNull().default(false),
220
281
  notes: text('notes'),
221
- createdAt: mysqlTs('created_at').notNull(),
222
- updatedAt: mysqlTs('updated_at').notNull(),
282
+ createdAt: mysqlTs('created_at').notNull().default(mysqlNow()),
283
+ updatedAt: mysqlTs('updated_at').notNull().default(mysqlNow()),
223
284
  });
224
285
  // ── kywiTagsMysql ───────────────────────────────────────────────────────────
225
286
  export const kywiTagsMysql = mysqlTable('kywi_tags', {
@@ -229,7 +290,7 @@ export const kywiTagsMysql = mysqlTable('kywi_tags', {
229
290
  label: text('label').notNull(),
230
291
  usageCount: int('usage_count').notNull().default(0),
231
292
  groupName: varchar('group_name', { length: 100 }),
232
- createdAt: mysqlTs('created_at').notNull(),
293
+ createdAt: mysqlTs('created_at').notNull().default(mysqlNow()),
233
294
  });
234
295
  // ── kywiCommentsMysql ───────────────────────────────────────────────────────
235
296
  export const kywiCommentsMysql = mysqlTable('kywi_comments', {
@@ -242,8 +303,8 @@ export const kywiCommentsMysql = mysqlTable('kywi_comments', {
242
303
  authorEmail: text('author_email'),
243
304
  body: text('body').notNull(),
244
305
  status: varchar('status', { length: 20 }).notNull().default('pending'),
245
- createdAt: mysqlTs('created_at').notNull(),
246
- updatedAt: mysqlTs('updated_at').notNull(),
306
+ createdAt: mysqlTs('created_at').notNull().default(mysqlNow()),
307
+ updatedAt: mysqlTs('updated_at').notNull().default(mysqlNow()),
247
308
  });
248
309
  // ── kywiExperimentsMysql ─────────────────────────────────────────────────────
249
310
  export const kywiExperimentsMysql = mysqlTable('kywi_experiments', {
@@ -262,9 +323,12 @@ export const kywiExperimentsMysql = mysqlTable('kywi_experiments', {
262
323
  pausedAt: mysqlTs('paused_at'),
263
324
  completedAt: mysqlTs('completed_at'),
264
325
  createdBy: mysqlUuid('created_by'),
265
- createdAt: mysqlTs('created_at').notNull(),
266
- updatedAt: mysqlTs('updated_at').notNull(),
267
- });
326
+ createdAt: mysqlTs('created_at').notNull().default(mysqlNow()),
327
+ updatedAt: mysqlTs('updated_at').notNull().default(mysqlNow()),
328
+ }, (t) => [
329
+ index('kywi_experiments_site_idx').on(t.siteId),
330
+ index('kywi_experiments_status_idx').on(t.status),
331
+ ]);
268
332
  // ── kywiExperimentVariantsMysql ──────────────────────────────────────────────
269
333
  export const kywiExperimentVariantsMysql = mysqlTable('kywi_experiment_variants', {
270
334
  id: mysqlUuidPk(),
@@ -274,18 +338,25 @@ export const kywiExperimentVariantsMysql = mysqlTable('kywi_experiment_variants'
274
338
  isControl: boolean('is_control').notNull().default(false),
275
339
  variantKey: text('variant_key'),
276
340
  sortOrder: int('sort_order').notNull().default(0),
277
- createdAt: mysqlTs('created_at').notNull(),
278
- });
341
+ createdAt: mysqlTs('created_at').notNull().default(mysqlNow()),
342
+ }, (t) => [
343
+ index('kywi_experiment_variants_experiment_idx').on(t.experimentId),
344
+ ]);
279
345
  // ── kywiExperimentAssignmentsMysql ───────────────────────────────────────────
280
346
  export const kywiExperimentAssignmentsMysql = mysqlTable('kywi_experiment_assignments', {
281
347
  id: mysqlUuidPk(),
282
348
  experimentId: mysqlUuid('experiment_id').notNull().references(() => kywiExperimentsMysql.id),
283
349
  variantId: mysqlUuid('variant_id').notNull(),
284
350
  siteId: mysqlUuid('site_id').notNull(),
285
- visitorId: text('visitor_id').notNull(),
286
- assignedAt: mysqlTs('assigned_at').notNull(),
351
+ // pg: `text`, but it is half of a UNIQUE index here — MySQL cannot index TEXT
352
+ // without a prefix length, so the twin narrows to varchar.
353
+ visitorId: varchar('visitor_id', { length: 255 }).notNull(),
354
+ assignedAt: mysqlTs('assigned_at').notNull().default(mysqlNow()),
287
355
  exposedAt: mysqlTs('exposed_at'),
288
- });
356
+ }, (t) => [
357
+ unique('kywi_experiment_assignments_exp_visitor_uniq').on(t.experimentId, t.visitorId),
358
+ index('kywi_experiment_assignments_exp_variant_idx').on(t.experimentId, t.variantId),
359
+ ]);
289
360
  // ── kywiExperimentConversionsMysql ───────────────────────────────────────────
290
361
  export const kywiExperimentConversionsMysql = mysqlTable('kywi_experiment_conversions', {
291
362
  id: mysqlUuidPk(),
@@ -295,8 +366,10 @@ export const kywiExperimentConversionsMysql = mysqlTable('kywi_experiment_conver
295
366
  visitorId: text('visitor_id').notNull(),
296
367
  goalType: text('goal_type').notNull(),
297
368
  metadata: json('metadata'),
298
- occurredAt: mysqlTs('occurred_at').notNull(),
299
- });
369
+ occurredAt: mysqlTs('occurred_at').notNull().default(mysqlNow()),
370
+ }, (t) => [
371
+ index('kywi_experiment_conversions_exp_variant_idx').on(t.experimentId, t.variantId),
372
+ ]);
300
373
  // ── kywiContentTypeFieldsMysql (hybrid schema engine — admin-added fields) ────
301
374
  export const kywiContentTypeFieldsMysql = mysqlTable('kywi_content_type_fields', {
302
375
  id: mysqlUuidPk(),
@@ -313,8 +386,8 @@ export const kywiContentTypeFieldsMysql = mysqlTable('kywi_content_type_fields',
313
386
  // 'list' fields set it.
314
387
  itemType: varchar('item_type', { length: 50 }),
315
388
  sortOrder: int('sort_order').notNull().default(0),
316
- createdAt: mysqlTs('created_at').notNull(),
317
- updatedAt: mysqlTs('updated_at').notNull(),
389
+ createdAt: mysqlTs('created_at').notNull().default(mysqlNow()),
390
+ updatedAt: mysqlTs('updated_at').notNull().default(mysqlNow()),
318
391
  }, (t) => [unique().on(t.contentTypeName, t.name)]);
319
392
  // ── kywiContentTypesMysql (visual type designer — admin-created types) ────────
320
393
  export const kywiContentTypesMysql = mysqlTable('kywi_content_types', {
@@ -326,8 +399,8 @@ export const kywiContentTypesMysql = mysqlTable('kywi_content_types', {
326
399
  // Whether the Title field is required on this type (kywi-cms#12). Defaults
327
400
  // true — back-compat with every type created before this setting existed.
328
401
  titleRequired: boolean('title_required').notNull().default(true),
329
- createdAt: mysqlTs('created_at').notNull(),
330
- updatedAt: mysqlTs('updated_at').notNull(),
402
+ createdAt: mysqlTs('created_at').notNull().default(mysqlNow()),
403
+ updatedAt: mysqlTs('updated_at').notNull().default(mysqlNow()),
331
404
  });
332
405
  // ── kywiMenusMysql (#110 — named owner-manageable navigation menus) ───────────
333
406
  export const kywiMenusMysql = mysqlTable('kywi_menus', {
@@ -335,8 +408,8 @@ export const kywiMenusMysql = mysqlTable('kywi_menus', {
335
408
  siteId: mysqlUuid('site_id').notNull().references(() => kywiSitesMysql.id),
336
409
  slug: varchar('slug', { length: 255 }).notNull(),
337
410
  name: text('name').notNull(),
338
- createdAt: mysqlTs('created_at').notNull(),
339
- updatedAt: mysqlTs('updated_at').notNull(),
411
+ createdAt: mysqlTs('created_at').notNull().default(mysqlNow()),
412
+ updatedAt: mysqlTs('updated_at').notNull().default(mysqlNow()),
340
413
  }, (t) => [unique().on(t.siteId, t.slug)]);
341
414
  // ── kywiMenuItemsMysql (#110) ────────────────────────────────────────────────
342
415
  // See the Postgres twin in base.ts for the contentId-XOR-externalUrl rule (it
@@ -347,11 +420,514 @@ export const kywiMenuItemsMysql = mysqlTable('kywi_menu_items', {
347
420
  parentId: mysqlUuid('parent_id'),
348
421
  sortOrder: int('sort_order').notNull().default(0),
349
422
  label: text('label').notNull(),
350
- contentId: mysqlUuid('content_id'),
423
+ kind: varchar('kind', { length: 20 }).notNull().default('link'),
424
+ contentId: mysqlUuid('content_id').references(() => kywiContentMysql.id, { onDelete: 'set null' }),
351
425
  externalUrl: text('external_url'),
352
426
  openInNewWindow: boolean('open_in_new_window').notNull().default(false),
353
427
  description: text('description'),
354
- createdAt: mysqlTs('created_at').notNull(),
355
- updatedAt: mysqlTs('updated_at').notNull(),
428
+ createdAt: mysqlTs('created_at').notNull().default(mysqlNow()),
429
+ updatedAt: mysqlTs('updated_at').notNull().default(mysqlNow()),
430
+ });
431
+ // ═════════════════════════════════════════════════════════════════════════════
432
+ // Twins added by the #75 parity sweep. Ordered to mirror the Postgres modules:
433
+ // base.ts, audiences/, webhooks.ts, extensions.ts, then the small per-feature
434
+ // modules. Every one is asserted against its Postgres original by
435
+ // __tests__/mysql-parity.test.ts.
436
+ // ═════════════════════════════════════════════════════════════════════════════
437
+ // ── base.ts ──────────────────────────────────────────────────────────────────
438
+ export const kywiContentDisplayIntervalsMysql = mysqlTable('kywi_content_display_intervals', {
439
+ id: mysqlUuidPk(),
440
+ contentId: mysqlUuid('content_id').notNull().references(() => kywiContentMysql.id, { onDelete: 'cascade' }),
441
+ dayOfWeek: int('day_of_week'),
442
+ startTime: text('start_time').notNull(),
443
+ endTime: text('end_time').notNull(),
444
+ startDate: mysqlTs('start_date'),
445
+ endDate: mysqlTs('end_date'),
446
+ });
447
+ export const kywiFeedsMysql = mysqlTable('kywi_feeds', {
448
+ id: mysqlUuidPk(),
449
+ siteId: mysqlUuid('site_id').notNull().references(() => kywiSitesMysql.id),
450
+ name: text('name').notNull(),
451
+ slug: varchar('slug', { length: 255 }).notNull(),
452
+ query: json('query').notNull(),
453
+ cacheTtl: int('cache_ttl'),
454
+ createdBy: mysqlUuid('created_by'),
455
+ createdAt: mysqlTs('created_at').notNull().default(mysqlNow()),
456
+ updatedAt: mysqlTs('updated_at').notNull().default(mysqlNow()),
457
+ });
458
+ export const kywiFormSubmissionDraftsMysql = mysqlTable('kywi_form_submission_drafts', {
459
+ id: mysqlUuidPk(),
460
+ formContentId: mysqlUuid('form_content_id').notNull(),
461
+ token: varchar('token', { length: 64 }).notNull().unique(),
462
+ data: json('data').notNull(),
463
+ currentStep: int('current_step').notNull().default(0),
464
+ expiresAt: mysqlTs('expires_at').notNull(),
465
+ createdAt: mysqlTs('created_at').notNull().default(mysqlNow()),
466
+ updatedAt: mysqlTs('updated_at').notNull().default(mysqlNow()),
467
+ });
468
+ export const kywiAuditLogMysql = mysqlTable('kywi_audit_log', {
469
+ id: mysqlUuidPk(),
470
+ siteId: mysqlUuid('site_id').notNull().references(() => kywiSitesMysql.id),
471
+ contentId: mysqlUuid('content_id').notNull().references(() => kywiContentMysql.id, { onDelete: 'cascade' }),
472
+ action: varchar('action', { length: 30 }).notNull(),
473
+ fromStatus: varchar('from_status', { length: 20 }),
474
+ toStatus: varchar('to_status', { length: 20 }),
475
+ changedFields: json('changed_fields'),
476
+ userId: mysqlUuid('user_id').notNull(),
477
+ userEmail: text('user_email').notNull(),
478
+ createdAt: mysqlTs('created_at').notNull().default(mysqlNow()),
479
+ });
480
+ export const kywiContentCategoriesMysql = mysqlTable('kywi_content_categories', {
481
+ contentId: mysqlUuid('content_id').notNull().references(() => kywiContentMysql.id, { onDelete: 'cascade' }),
482
+ categoryId: mysqlUuid('category_id').notNull().references(() => kywiCategoriesMysql.id, { onDelete: 'cascade' }),
483
+ isFeatured: boolean('is_featured').notNull().default(false),
484
+ featuredUntil: mysqlTs('featured_until'),
485
+ });
486
+ export const kywiContentTagsMysql = mysqlTable('kywi_content_tags', {
487
+ contentId: mysqlUuid('content_id').notNull().references(() => kywiContentMysql.id, { onDelete: 'cascade' }),
488
+ tagId: mysqlUuid('tag_id').notNull().references(() => kywiTagsMysql.id, { onDelete: 'cascade' }),
489
+ createdAt: mysqlTs('created_at').notNull().default(mysqlNow()),
490
+ }, (t) => [primaryKey({ columns: [t.contentId, t.tagId] })]);
491
+ export const kywiOAuthClientsMysql = mysqlTable('kywi_oauth_clients', {
492
+ id: mysqlUuidPk(),
493
+ clientId: varchar('client_id', { length: 64 }).notNull().unique(),
494
+ clientSecret: text('client_secret').notNull(),
495
+ name: text('name').notNull(),
496
+ scopes: json('scopes').notNull().default(mysqlJsonDefault('[]')),
497
+ redirectUris: json('redirect_uris').notNull().default(mysqlJsonDefault('[]')),
498
+ rateLimitPerMinute: int('rate_limit_per_minute').notNull().default(60),
499
+ createdBy: mysqlUuid('created_by'),
500
+ createdAt: mysqlTs('created_at').notNull().default(mysqlNow()),
501
+ updatedAt: mysqlTs('updated_at').notNull().default(mysqlNow()),
502
+ });
503
+ export const kywiLoginStrikesMysql = mysqlTable('kywi_login_strikes', {
504
+ id: mysqlUuidPk(),
505
+ userId: text('user_id').notNull(),
506
+ ip: text('ip').notNull(),
507
+ attemptedAt: mysqlTs('attempted_at').notNull().default(mysqlNow()),
508
+ });
509
+ export const kywiMfaSecretsMysql = mysqlTable('kywi_mfa_secrets', {
510
+ id: mysqlUuidPk(),
511
+ // pg: `text NOT NULL UNIQUE`, holding a kywi_users.id. MySQL cannot index
512
+ // TEXT without a prefix length, so the twin narrows to the uuid width.
513
+ userId: varchar('user_id', { length: 36 }).notNull().unique(),
514
+ secret: text('secret').notNull(),
515
+ recoveryCodes: text('recovery_codes').notNull(),
516
+ enabledAt: mysqlTs('enabled_at'),
517
+ createdAt: mysqlTs('created_at').notNull().default(mysqlNow()),
518
+ });
519
+ export const kywiMagicLinkTokensMysql = mysqlTable('kywi_magic_link_tokens', {
520
+ id: mysqlUuidPk(),
521
+ userId: text('user_id').notNull(),
522
+ tokenHash: text('token_hash').notNull(),
523
+ expiresAt: mysqlTs('expires_at').notNull(),
524
+ usedAt: mysqlTs('used_at'),
525
+ createdAt: mysqlTs('created_at').notNull().default(mysqlNow()),
526
+ });
527
+ export const kywiChangesetsMysql = mysqlTable('kywi_changesets', {
528
+ id: mysqlUuidPk(),
529
+ siteId: text('site_id').notNull(),
530
+ name: text('name').notNull(),
531
+ description: text('description'),
532
+ // pg: `text NOT NULL DEFAULT 'open'` — narrowed so MySQL can carry the default.
533
+ status: varchar('status', { length: 20 }).notNull().default('open'),
534
+ scheduledPublishAt: mysqlTs('scheduled_publish_at'),
535
+ publishedAt: mysqlTs('published_at'),
536
+ publishedBy: text('published_by'),
537
+ createdBy: text('created_by').notNull(),
538
+ createdAt: mysqlTs('created_at').notNull().default(mysqlNow()),
539
+ updatedAt: mysqlTs('updated_at').notNull().default(mysqlNow()),
540
+ });
541
+ export const kywiChangesetItemsMysql = mysqlTable('kywi_changeset_items', {
542
+ id: mysqlUuidPk(),
543
+ changesetId: text('changeset_id').notNull(),
544
+ contentId: text('content_id').notNull(),
545
+ versionId: text('version_id'),
546
+ action: text('action').notNull(),
547
+ createdAt: mysqlTs('created_at').notNull().default(mysqlNow()),
548
+ });
549
+ export const kywiChangesetAuditMysql = mysqlTable('kywi_changeset_audit', {
550
+ id: mysqlUuidPk(),
551
+ changesetId: text('changeset_id').notNull(),
552
+ siteId: text('site_id').notNull(),
553
+ action: varchar('action', { length: 20 }).notNull(),
554
+ userId: text('user_id').notNull(),
555
+ detail: json('detail'),
556
+ createdAt: mysqlTs('created_at').notNull().default(mysqlNow()),
557
+ });
558
+ export const kywiFilenameArchiveMysql = mysqlTable('kywi_filename_archive', {
559
+ id: mysqlUuidPk(),
560
+ siteId: text('site_id').notNull(),
561
+ oldPath: text('old_path').notNull(),
562
+ newPath: text('new_path').notNull(),
563
+ contentId: text('content_id').notNull(),
564
+ createdAt: mysqlTs('created_at').notNull().default(mysqlNow()),
565
+ });
566
+ export const kywiContentLocksMysql = mysqlTable('kywi_content_locks', {
567
+ // pg: `text PRIMARY KEY`. MySQL cannot use TEXT as a primary key, so the twin
568
+ // narrows to the uuid width the column actually holds.
569
+ contentId: varchar('content_id', { length: 36 }).primaryKey(),
570
+ userId: text('user_id').notNull(),
571
+ lockedAt: mysqlTs('locked_at').notNull().default(mysqlNow()),
572
+ expiresAt: mysqlTs('expires_at').notNull(),
573
+ });
574
+ export const kywiContentStatsMysql = mysqlTable('kywi_content_stats', {
575
+ // pg: `text PRIMARY KEY` — same TEXT-as-PK narrowing as kywi_content_locks.
576
+ contentId: varchar('content_id', { length: 36 }).primaryKey(),
577
+ views: int('views').notNull().default(0),
578
+ downloads: int('downloads').notNull().default(0),
579
+ commentCount: int('comment_count').notNull().default(0),
580
+ lastViewedAt: mysqlTs('last_viewed_at'),
581
+ updatedAt: mysqlTs('updated_at').notNull().default(mysqlNow()),
582
+ });
583
+ export const kywiViewLogMysql = mysqlTable('kywi_view_log', {
584
+ id: mysqlUuidPk(),
585
+ contentId: text('content_id').notNull(),
586
+ visitorId: text('visitor_id'),
587
+ viewedAt: mysqlTs('viewed_at').notNull().default(mysqlNow()),
588
+ });
589
+ export const kywiSectionTemplatesMysql = mysqlTable('kywi_section_templates', {
590
+ id: mysqlUuidPk(),
591
+ siteId: mysqlUuid('site_id').notNull().references(() => kywiSitesMysql.id),
592
+ name: text('name').notNull(),
593
+ category: varchar('category', { length: 100 }).notNull().default('general'),
594
+ definition: json('definition').notNull(),
595
+ createdBy: mysqlUuid('created_by'),
596
+ createdAt: mysqlTs('created_at').notNull().default(mysqlNow()),
597
+ updatedAt: mysqlTs('updated_at').notNull().default(mysqlNow()),
598
+ });
599
+ export const kywiApprovalChainsMysql = mysqlTable('kywi_approval_chains', {
600
+ id: mysqlUuidPk(),
601
+ siteId: text('site_id').notNull(),
602
+ name: text('name').notNull(),
603
+ steps: json('steps').notNull(),
604
+ createdAt: mysqlTs('created_at').notNull().default(mysqlNow()),
605
+ updatedAt: mysqlTs('updated_at').notNull().default(mysqlNow()),
606
+ });
607
+ export const kywiApprovalActionsMysql = mysqlTable('kywi_approval_actions', {
608
+ id: mysqlUuidPk(),
609
+ chainId: text('chain_id').notNull(),
610
+ contentId: text('content_id').notNull(),
611
+ stepIndex: int('step_index').notNull(),
612
+ action: varchar('action', { length: 20 }).notNull(),
613
+ userId: text('user_id').notNull(),
614
+ comment: text('comment'),
615
+ createdAt: mysqlTs('created_at').notNull().default(mysqlNow()),
616
+ });
617
+ export const kywiAnalyticsEventsMysql = mysqlTable('kywi_analytics_events', {
618
+ id: mysqlUuidPk(),
619
+ siteId: mysqlUuid('site_id').notNull(),
620
+ audienceId: mysqlUuid('audience_id').notNull(),
621
+ visitorId: text('visitor_id').notNull(),
622
+ // pg: `text` with an enum of 'matched' | 'impression' | 'click'. Postgres
623
+ // renders a text-with-enum column as plain text; varchar is the MySQL twin.
624
+ eventType: varchar('event_type', { length: 20 }).notNull(),
625
+ contentId: text('content_id'),
626
+ variantId: text('variant_id'),
627
+ createdAt: mysqlTs('created_at').notNull().default(mysqlNow()),
628
+ });
629
+ // ── audiences/schema.ts ──────────────────────────────────────────────────────
630
+ export const kywiAudiencesMysql = mysqlTable('kywi_audiences', {
631
+ id: mysqlUuidPk(),
632
+ siteId: mysqlUuid('site_id').notNull().references(() => kywiSitesMysql.id),
633
+ name: text('name').notNull(),
634
+ description: text('description'),
635
+ priority: int('priority').notNull(),
636
+ status: varchar('status', { length: 20 }).notNull().default('draft'),
637
+ scoreThreshold: int('score_threshold'),
638
+ // See the Postgres twin: public audience-name listing (kywi-cms#200).
639
+ isPublic: boolean('is_public').notNull().default(false),
640
+ createdAt: mysqlTs('created_at').notNull().default(mysqlNow()),
641
+ updatedAt: mysqlTs('updated_at').notNull().default(mysqlNow()),
642
+ }, (t) => [
643
+ index('kywi_audiences_site_idx').on(t.siteId),
644
+ unique('kywi_audiences_site_priority_uniq').on(t.siteId, t.priority),
645
+ ]);
646
+ export const kywiConditionGroupsMysql = mysqlTable('kywi_condition_groups', {
647
+ id: mysqlUuidPk(),
648
+ audienceId: mysqlUuid('audience_id').notNull().references(() => kywiAudiencesMysql.id, { onDelete: 'cascade' }),
649
+ sortOrder: int('sort_order').notNull().default(0),
356
650
  });
651
+ export const kywiConditionsMysql = mysqlTable('kywi_conditions', {
652
+ id: mysqlUuidPk(),
653
+ groupId: mysqlUuid('group_id').notNull().references(() => kywiConditionGroupsMysql.id, { onDelete: 'cascade' }),
654
+ type: varchar('type', { length: 20 }).notNull(),
655
+ signal: text('signal'),
656
+ operator: text('operator'),
657
+ value: json('value'),
658
+ // `trigger` is a MySQL reserved word; drizzle backtick-quotes every
659
+ // identifier it emits, so the column name needs no rename.
660
+ trigger: text('trigger'),
661
+ points: int('points'),
662
+ threshold: int('threshold'),
663
+ category: text('category'),
664
+ pattern: text('pattern'),
665
+ sortOrder: int('sort_order').notNull().default(0),
666
+ });
667
+ export const kywiSelfIdFieldsMysql = mysqlTable('kywi_selfid_fields', {
668
+ // pg: `text PRIMARY KEY` (a caller-supplied field key, not a uuid).
669
+ id: varchar('id', { length: 255 }).primaryKey(),
670
+ siteId: mysqlUuid('site_id').notNull().references(() => kywiSitesMysql.id),
671
+ label: text('label').notNull(),
672
+ picklist: json('picklist').notNull(),
673
+ required: boolean('required').notNull().default(false),
674
+ sortOrder: int('sort_order').notNull().default(0),
675
+ });
676
+ export const kywiSelfIdWidgetConfigMysql = mysqlTable('kywi_selfid_widget_config', {
677
+ id: mysqlUuidPk(),
678
+ siteId: mysqlUuid('site_id').notNull().references(() => kywiSitesMysql.id),
679
+ displayMode: varchar('display_mode', { length: 20 }).notNull().default('modal'),
680
+ trigger: json('trigger').notNull(),
681
+ headline: text('headline').notNull(),
682
+ subheadline: text('subheadline'),
683
+ fieldIds: json('field_ids').notNull(),
684
+ // pg: `text NOT NULL DEFAULT 'Submit'` — narrowed to carry the default.
685
+ submitLabel: varchar('submit_label', { length: 100 }).notNull().default('Submit'),
686
+ skipLabel: text('skip_label'),
687
+ frequency: varchar('frequency', { length: 20 }).notNull().default('once_visitor'),
688
+ });
689
+ export const kywiPreviewTokenDenylistMysql = mysqlTable('kywi_preview_token_denylist', {
690
+ // pg: `text PRIMARY KEY` — a JWT jti.
691
+ jti: varchar('jti', { length: 255 }).primaryKey(),
692
+ audienceId: mysqlUuid('audience_id').notNull(),
693
+ expiresAt: mysqlTs('expires_at').notNull(),
694
+ revokedAt: mysqlTs('revoked_at').notNull().default(mysqlNow()),
695
+ });
696
+ export const kywiAdapterIdentityStoreMysql = mysqlTable('kywi_adapter_identity_store', {
697
+ id: mysqlUuidPk(),
698
+ // pg: `text`, but both columns form a UNIQUE index — narrowed so MySQL can
699
+ // index them without a prefix length.
700
+ visitorId: varchar('visitor_id', { length: 255 }).notNull(),
701
+ adapterId: varchar('adapter_id', { length: 100 }).notNull(),
702
+ payload: json('payload').notNull(),
703
+ updatedAt: mysqlTs('updated_at').notNull().default(mysqlNow()),
704
+ }, (t) => [
705
+ unique('kywi_adapter_identity_visitor_adapter_uniq').on(t.visitorId, t.adapterId),
706
+ ]);
707
+ // ── webhooks.ts ──────────────────────────────────────────────────────────────
708
+ export const kywiWebhookEndpointsMysql = mysqlTable('kywi_webhook_endpoints', {
709
+ id: mysqlUuidPk(),
710
+ siteId: mysqlUuid('site_id').notNull().references(() => kywiSitesMysql.id),
711
+ url: text('url').notNull(),
712
+ secret: text('secret').notNull(),
713
+ events: json('events').notNull().default(mysqlJsonDefault('[]')),
714
+ isActive: boolean('is_active').notNull().default(true),
715
+ createdBy: mysqlUuid('created_by'),
716
+ createdAt: mysqlTs('created_at').notNull().default(mysqlNow()),
717
+ updatedAt: mysqlTs('updated_at').notNull().default(mysqlNow()),
718
+ });
719
+ export const kywiWebhookDeliveriesMysql = mysqlTable('kywi_webhook_deliveries', {
720
+ id: mysqlUuidPk(),
721
+ endpointId: mysqlUuid('endpoint_id').notNull().references(() => kywiWebhookEndpointsMysql.id, { onDelete: 'cascade' }),
722
+ event: varchar('event', { length: 100 }).notNull(),
723
+ payload: json('payload').notNull(),
724
+ status: varchar('status', { length: 20 }).notNull().default('pending'),
725
+ httpStatus: int('http_status'),
726
+ responseBody: text('response_body'),
727
+ attempts: int('attempts').notNull().default(0),
728
+ nextRetryAt: mysqlTs('next_retry_at'),
729
+ createdAt: mysqlTs('created_at').notNull().default(mysqlNow()),
730
+ });
731
+ // ── extensions.ts ────────────────────────────────────────────────────────────
732
+ export const kywiExtendSubtypesMysql = mysqlTable('kywi_extend_subtypes', {
733
+ id: mysqlUuidPk(),
734
+ name: varchar('name', { length: 100 }).notNull(),
735
+ baseContentType: varchar('base_content_type', { length: 100 }).notNull(),
736
+ description: text('description'),
737
+ isActive: boolean('is_active').notNull().default(true),
738
+ createdAt: mysqlTs('created_at').notNull().default(mysqlNow()),
739
+ });
740
+ export const kywiExtendSetsMysql = mysqlTable('kywi_extend_sets', {
741
+ id: mysqlUuidPk(),
742
+ subtypeId: mysqlUuid('subtype_id').notNull().references(() => kywiExtendSubtypesMysql.id, { onDelete: 'cascade' }),
743
+ name: varchar('name', { length: 100 }).notNull(),
744
+ label: varchar('label', { length: 200 }).notNull(),
745
+ sortOrder: int('sort_order').notNull().default(0),
746
+ createdAt: mysqlTs('created_at').notNull().default(mysqlNow()),
747
+ });
748
+ export const kywiExtendAttributesMysql = mysqlTable('kywi_extend_attributes', {
749
+ id: mysqlUuidPk(),
750
+ setId: mysqlUuid('set_id').notNull().references(() => kywiExtendSetsMysql.id, { onDelete: 'cascade' }),
751
+ name: varchar('name', { length: 100 }).notNull(),
752
+ label: varchar('label', { length: 200 }).notNull(),
753
+ type: varchar('type', { length: 50 }).notNull(),
754
+ defaultValue: text('default_value'),
755
+ validation: json('validation'),
756
+ sortOrder: int('sort_order').notNull().default(0),
757
+ createdAt: mysqlTs('created_at').notNull().default(mysqlNow()),
758
+ });
759
+ export const kywiExtendDataMysql = mysqlTable('kywi_extend_data', {
760
+ id: mysqlUuidPk(),
761
+ contentId: mysqlUuid('content_id').notNull().references(() => kywiContentMysql.id, { onDelete: 'cascade' }),
762
+ attributeId: mysqlUuid('attribute_id').notNull().references(() => kywiExtendAttributesMysql.id, { onDelete: 'cascade' }),
763
+ stringValue: text('string_value'),
764
+ numberValue: decimal('number_value', { precision: 20, scale: 6 }),
765
+ dateValue: mysqlTs('date_value'),
766
+ booleanValue: boolean('boolean_value'),
767
+ jsonValue: json('json_value'),
768
+ createdAt: mysqlTs('created_at').notNull().default(mysqlNow()),
769
+ updatedAt: mysqlTs('updated_at').notNull().default(mysqlNow()),
770
+ });
771
+ export const kywiExtendRelatedSetsMysql = mysqlTable('kywi_extend_related_sets', {
772
+ id: mysqlUuidPk(),
773
+ contentId: mysqlUuid('content_id').notNull().references(() => kywiContentMysql.id, { onDelete: 'cascade' }),
774
+ setId: mysqlUuid('set_id').notNull().references(() => kywiExtendSetsMysql.id, { onDelete: 'cascade' }),
775
+ data: json('data').notNull(),
776
+ sortOrder: int('sort_order').notNull().default(0),
777
+ createdAt: mysqlTs('created_at').notNull().default(mysqlNow()),
778
+ });
779
+ // ── reminders.ts ─────────────────────────────────────────────────────────────
780
+ export const kywiRemindersMysql = mysqlTable('kywi_reminders', {
781
+ id: mysqlUuidPk(),
782
+ contentId: mysqlUuid('content_id').notNull().references(() => kywiContentMysql.id, { onDelete: 'cascade' }),
783
+ userId: mysqlUuid('user_id').notNull().references(() => kywiUsersMysql.id, { onDelete: 'cascade' }),
784
+ message: text('message').notNull(),
785
+ remindAt: mysqlTs('remind_at').notNull(),
786
+ dismissed: boolean('dismissed').notNull().default(false),
787
+ createdAt: mysqlTs('created_at').notNull().default(mysqlNow()),
788
+ });
789
+ // ── components.ts ────────────────────────────────────────────────────────────
790
+ export const kywiComponentsMysql = mysqlTable('kywi_components', {
791
+ id: mysqlUuidPk(),
792
+ siteId: mysqlUuid('site_id').notNull().references(() => kywiSitesMysql.id),
793
+ name: text('name').notNull(),
794
+ description: text('description'),
795
+ // Widened with its Postgres twin (kywi-cms#170) — `'moduleVariantContainer'`
796
+ // is 22 characters and did not fit the old 20.
797
+ type: varchar('type', { length: 40 }).notNull(),
798
+ moduleType: varchar('module_type', { length: 100 }),
799
+ definition: json('definition').notNull(),
800
+ createdBy: mysqlUuid('created_by'),
801
+ createdAt: mysqlTs('created_at').notNull().default(mysqlNow()),
802
+ updatedAt: mysqlTs('updated_at').notNull().default(mysqlNow()),
803
+ });
804
+ /**
805
+ * Holder-polymorphic since kywi-cms#156 — see the Postgres table's doc.
806
+ *
807
+ * The two placement indexes are the one place the twin reads differently from
808
+ * Postgres and means the same thing. Postgres declares them PARTIAL (`WHERE
809
+ * content_id IS NOT NULL`); MySQL has no partial indexes, but it does not need
810
+ * one here: a UNIQUE index ignores rows whose indexed columns include a NULL in
811
+ * both engines, so a plain `UNIQUE (component_id, content_id, node_id)` already
812
+ * constrains exactly the content rows and lets every blueprint row (content_id
813
+ * NULL) through — which is precisely what the partial index says out loud. This
814
+ * is NOT the `kywi_content_permissions` situation, where uniqueness genuinely
815
+ * could not be expressed and fell back to the application.
816
+ *
817
+ * The one-holder CHECK — which also ties `holder_kind` to whichever id column
818
+ * is set — is expressible directly: MySQL 8.0.16+ enforces table CHECK
819
+ * constraints. Older MySQL parses and ignores it, so on those versions the
820
+ * invariant rests on the query layer, which never writes another shape.
821
+ */
822
+ export const kywiComponentInstancesMysql = mysqlTable('kywi_component_instances', {
823
+ id: mysqlUuidPk(),
824
+ componentId: mysqlUuid('component_id').notNull().references(() => kywiComponentsMysql.id, { onDelete: 'cascade' }),
825
+ siteId: mysqlUuid('site_id').notNull().references(() => kywiSitesMysql.id),
826
+ holderKind: varchar('holder_kind', { length: 20 }).notNull().default('content'),
827
+ contentId: mysqlUuid('content_id').references(() => kywiContentMysql.id, { onDelete: 'cascade' }),
828
+ blueprintId: mysqlUuid('blueprint_id').references(() => kywiSectionTemplatesMysql.id, { onDelete: 'cascade' }),
829
+ contentType: varchar('content_type', { length: 100 }).notNull(),
830
+ // pg: `text`, but it is the third column of the placement UNIQUE index —
831
+ // MySQL cannot index TEXT without a prefix length, so the twin narrows it.
832
+ nodeId: varchar('node_id', { length: 255 }).notNull(),
833
+ updatedAt: mysqlTs('updated_at').notNull().default(mysqlNow()),
834
+ }, (t) => [
835
+ unique('kywi_component_instances_placement').on(t.componentId, t.contentId, t.nodeId),
836
+ unique('kywi_component_instances_blueprint_placement').on(t.componentId, t.blueprintId, t.nodeId),
837
+ index('kywi_component_instances_by_content').on(t.contentId),
838
+ index('kywi_component_instances_by_blueprint').on(t.blueprintId),
839
+ check('kywi_component_instances_one_holder', sql `(${t.holderKind} = 'content' and ${t.contentId} is not null and ${t.blueprintId} is null)
840
+ or (${t.holderKind} = 'blueprint' and ${t.blueprintId} is not null and ${t.contentId} is null)`),
841
+ ]);
842
+ // ── comment-subscriptions.ts ─────────────────────────────────────────────────
843
+ export const kywiCommentSubscriptionsMysql = mysqlTable('kywi_comment_subscriptions', {
844
+ id: mysqlUuidPk(),
845
+ contentId: mysqlUuid('content_id').notNull().references(() => kywiContentMysql.id, { onDelete: 'cascade' }),
846
+ email: text('email').notNull(),
847
+ userId: mysqlUuid('user_id').references(() => kywiUsersMysql.id, { onDelete: 'cascade' }),
848
+ isActive: boolean('is_active').notNull().default(true),
849
+ createdAt: mysqlTs('created_at').notNull().default(mysqlNow()),
850
+ });
851
+ // ── content-permissions.ts ───────────────────────────────────────────────────
852
+ /**
853
+ * The one place a Postgres construct has **no** MySQL equivalent.
854
+ *
855
+ * The Postgres table carries two PARTIAL unique indexes — `unique(content_id,
856
+ * user_id, action) WHERE group_id IS NULL` and its group-side mirror — because
857
+ * a grant row always has exactly one of user_id/group_id set, and `NULL !=
858
+ * NULL` for uniqueness in both dialects, so a plain four-column unique cannot
859
+ * express "no duplicate grant".
860
+ *
861
+ * MySQL has no partial indexes. The twin therefore declares the same two column
862
+ * tuples as PLAIN (non-unique) indexes: they still serve the read path that
863
+ * matters — `access-control.ts`'s permission check and the permissions-tab
864
+ * listing — but uniqueness is left to the application:
865
+ *
866
+ * - `grantContentPermission` (db/content-permission-queries.ts) checks for an
867
+ * existing identical grant before inserting, and
868
+ * - `kywi migrate` runs `dedupeContentPermissionRows` for existing databases.
869
+ *
870
+ * A MySQL 8 alternative would be a unique index over generated columns
871
+ * (`COALESCE(user_id, '-')`), which drizzle's mysql-core cannot declare today;
872
+ * it is recorded as a follow-up rather than hand-written DDL here.
873
+ */
874
+ export const kywiContentPermissionsMysql = mysqlTable('kywi_content_permissions', {
875
+ id: mysqlUuidPk(),
876
+ contentId: mysqlUuid('content_id').notNull().references(() => kywiContentMysql.id, { onDelete: 'cascade' }),
877
+ userId: mysqlUuid('user_id').references(() => kywiUsersMysql.id, { onDelete: 'cascade' }),
878
+ groupId: mysqlUuid('group_id').references(() => kywiGroupsMysql.id, { onDelete: 'cascade' }),
879
+ action: varchar('action', { length: 20 }).notNull(),
880
+ createdAt: mysqlTs('created_at').notNull().default(mysqlNow()),
881
+ }, (t) => [
882
+ index('kywi_content_permissions_user_grant').on(t.contentId, t.userId, t.action),
883
+ index('kywi_content_permissions_group_grant').on(t.contentId, t.groupId, t.action),
884
+ ]);
885
+ // ── content-references.ts ────────────────────────────────────────────────────
886
+ export const kywiContentReferencesMysql = mysqlTable('kywi_content_references', {
887
+ id: mysqlUuidPk(),
888
+ sourceSiteId: mysqlUuid('source_site_id').notNull().references(() => kywiSitesMysql.id),
889
+ sourceContentId: mysqlUuid('source_content_id').notNull().references(() => kywiContentMysql.id, { onDelete: 'cascade' }),
890
+ targetSiteId: mysqlUuid('target_site_id').notNull().references(() => kywiSitesMysql.id),
891
+ targetContentId: mysqlUuid('target_content_id').notNull().references(() => kywiContentMysql.id),
892
+ createdAt: mysqlTs('created_at').notNull().default(mysqlNow()),
893
+ });
894
+ // ── relationships.ts ─────────────────────────────────────────────────────────
895
+ export const kywiContentRelationshipsMysql = mysqlTable('kywi_content_relationships', {
896
+ id: mysqlUuidPk(),
897
+ sourceId: mysqlUuid('source_id').notNull().references(() => kywiContentMysql.id, { onDelete: 'cascade' }),
898
+ targetId: mysqlUuid('target_id').notNull().references(() => kywiContentMysql.id, { onDelete: 'cascade' }),
899
+ type: varchar('type', { length: 50 }).notNull().default('related'),
900
+ sortOrder: int('sort_order').notNull().default(0),
901
+ createdAt: mysqlTs('created_at').notNull().default(mysqlNow()),
902
+ });
903
+ // ── password-reset-tokens.ts ─────────────────────────────────────────────────
904
+ export const kywiPasswordResetTokensMysql = mysqlTable('kywi_password_reset_tokens', {
905
+ id: mysqlUuidPk(),
906
+ userId: mysqlUuid('user_id').notNull().references(() => kywiUsersMysql.id, { onDelete: 'cascade' }),
907
+ tokenHash: text('token_hash').notNull(),
908
+ expiresAt: mysqlTs('expires_at').notNull(),
909
+ usedAt: mysqlTs('used_at'),
910
+ createdAt: mysqlTs('created_at').notNull().default(mysqlNow()),
911
+ });
912
+ // ── site-plugins.ts ──────────────────────────────────────────────────────────
913
+ export const kywiSitePluginsMysql = mysqlTable('kywi_site_plugins', {
914
+ id: mysqlUuidPk(),
915
+ siteId: mysqlUuid('site_id').notNull().references(() => kywiSitesMysql.id, { onDelete: 'cascade' }),
916
+ pluginPackage: varchar('plugin_package', { length: 200 }).notNull(),
917
+ isActive: boolean('is_active').notNull().default(true),
918
+ config: json('config'),
919
+ createdAt: mysqlTs('created_at').notNull().default(mysqlNow()),
920
+ updatedAt: mysqlTs('updated_at').notNull().default(mysqlNow()),
921
+ });
922
+ // ── site-settings.ts ─────────────────────────────────────────────────────────
923
+ export const kywiSiteSettingsMysql = mysqlTable('kywi_site_settings', {
924
+ id: mysqlUuidPk(),
925
+ siteId: mysqlUuid('site_id').notNull().references(() => kywiSitesMysql.id, { onDelete: 'cascade' }),
926
+ // `key` is a MySQL reserved word; drizzle backtick-quotes identifiers.
927
+ key: varchar('key', { length: 100 }).notNull(),
928
+ value: json('value').notNull(),
929
+ updatedAt: mysqlTs('updated_at').notNull().default(mysqlNow()),
930
+ }, (t) => [
931
+ unique('kywi_site_settings_site_id_key_unique').on(t.siteId, t.key),
932
+ ]);
357
933
  //# sourceMappingURL=mysql-tables.js.map