@ketvietlab/ketsuite 0.1.3 → 0.1.6

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 (359) hide show
  1. package/dist/cli.js +1 -1
  2. package/dist/deployment.d.ts.map +1 -1
  3. package/dist/deployment.js +3 -0
  4. package/dist/deployment.js.map +1 -1
  5. package/dist/index.d.ts +8 -1
  6. package/dist/index.d.ts.map +1 -1
  7. package/dist/index.js +7 -1
  8. package/dist/index.js.map +1 -1
  9. package/dist/modules/account_staff_channel/channel-routes.d.ts.map +1 -1
  10. package/dist/modules/account_staff_channel/channel-routes.js +1 -12
  11. package/dist/modules/account_staff_channel/channel-routes.js.map +1 -1
  12. package/dist/modules/attendance/channel-routes.d.ts.map +1 -1
  13. package/dist/modules/attendance/channel-routes.js +1 -12
  14. package/dist/modules/attendance/channel-routes.js.map +1 -1
  15. package/dist/modules/backend/design/HANDOFF.md +2 -2
  16. package/dist/modules/backend/design/auth.css +12 -0
  17. package/dist/modules/backend/design/client/table-selection.d.mts +3 -3
  18. package/dist/modules/backend/design/client/table-selection.d.mts.map +1 -1
  19. package/dist/modules/backend/design/client/table-selection.mjs +1 -1
  20. package/dist/modules/backend/design/client/table-selection.mjs.map +4 -4
  21. package/dist/modules/backend/design/content.css +43 -0
  22. package/dist/modules/backend/design/design-system.css +1 -1
  23. package/dist/modules/backend/design/forms.css +84 -1
  24. package/dist/modules/backend/design/lists.css +26 -18
  25. package/dist/modules/backend/design/record.css +5 -2
  26. package/dist/modules/backend/design/responsive.css +5 -6
  27. package/dist/modules/backend/design/user-workflow.css +257 -0
  28. package/dist/modules/backend/forms.d.ts +38 -1
  29. package/dist/modules/backend/forms.d.ts.map +1 -1
  30. package/dist/modules/backend/forms.js +29 -0
  31. package/dist/modules/backend/forms.js.map +1 -1
  32. package/dist/modules/backend/index.d.ts +3 -2
  33. package/dist/modules/backend/index.d.ts.map +1 -1
  34. package/dist/modules/backend/index.js +3 -2
  35. package/dist/modules/backend/index.js.map +1 -1
  36. package/dist/modules/backend/messages.d.ts.map +1 -1
  37. package/dist/modules/backend/messages.js +42 -2
  38. package/dist/modules/backend/messages.js.map +1 -1
  39. package/dist/modules/channel_api/core.d.ts +30 -0
  40. package/dist/modules/channel_api/core.d.ts.map +1 -1
  41. package/dist/modules/channel_api/core.js +28 -0
  42. package/dist/modules/channel_api/core.js.map +1 -1
  43. package/dist/modules/crm/functions.d.ts +5 -0
  44. package/dist/modules/crm/functions.d.ts.map +1 -1
  45. package/dist/modules/crm/functions.js +105 -10
  46. package/dist/modules/crm/functions.js.map +1 -1
  47. package/dist/modules/crm/jobs.d.ts.map +1 -1
  48. package/dist/modules/crm/jobs.js +1 -0
  49. package/dist/modules/crm/jobs.js.map +1 -1
  50. package/dist/modules/crm/operations.d.ts.map +1 -1
  51. package/dist/modules/crm/operations.js +2 -1
  52. package/dist/modules/crm/operations.js.map +1 -1
  53. package/dist/modules/crm_backend/index.d.ts.map +1 -1
  54. package/dist/modules/crm_backend/index.js +5 -2
  55. package/dist/modules/crm_backend/index.js.map +1 -1
  56. package/dist/modules/crm_backend/messages.d.ts +116 -0
  57. package/dist/modules/crm_backend/messages.d.ts.map +1 -1
  58. package/dist/modules/crm_backend/messages.js +122 -6
  59. package/dist/modules/crm_backend/messages.js.map +1 -1
  60. package/dist/modules/crm_backend/routes.d.ts.map +1 -1
  61. package/dist/modules/crm_backend/routes.js +434 -174
  62. package/dist/modules/crm_backend/routes.js.map +1 -1
  63. package/dist/modules/crm_backend/screens/case-create.d.ts +7 -0
  64. package/dist/modules/crm_backend/screens/case-create.d.ts.map +1 -1
  65. package/dist/modules/crm_backend/screens/case-create.js +13 -4
  66. package/dist/modules/crm_backend/screens/case-create.js.map +1 -1
  67. package/dist/modules/crm_backend/screens/case-detail.d.ts +6 -0
  68. package/dist/modules/crm_backend/screens/case-detail.d.ts.map +1 -1
  69. package/dist/modules/crm_backend/screens/case-detail.js +73 -23
  70. package/dist/modules/crm_backend/screens/case-detail.js.map +1 -1
  71. package/dist/modules/crm_backend/screens/configuration.d.ts +21 -3
  72. package/dist/modules/crm_backend/screens/configuration.d.ts.map +1 -1
  73. package/dist/modules/crm_backend/screens/configuration.js +260 -55
  74. package/dist/modules/crm_backend/screens/configuration.js.map +1 -1
  75. package/dist/modules/crm_backend/screens/index.d.ts +3 -3
  76. package/dist/modules/crm_backend/screens/index.d.ts.map +1 -1
  77. package/dist/modules/crm_backend/screens/index.js +2 -2
  78. package/dist/modules/crm_backend/screens/index.js.map +1 -1
  79. package/dist/modules/crm_staff_channel/channel-routes.d.ts.map +1 -1
  80. package/dist/modules/crm_staff_channel/channel-routes.js +1 -12
  81. package/dist/modules/crm_staff_channel/channel-routes.js.map +1 -1
  82. package/dist/modules/flow/membership.d.ts.map +1 -1
  83. package/dist/modules/flow/membership.js +7 -1
  84. package/dist/modules/flow/membership.js.map +1 -1
  85. package/dist/modules/flow/operations.d.ts +10 -4
  86. package/dist/modules/flow/operations.d.ts.map +1 -1
  87. package/dist/modules/flow/operations.js +10 -4
  88. package/dist/modules/flow/operations.js.map +1 -1
  89. package/dist/modules/flow_staff_channel/channel-routes.d.ts.map +1 -1
  90. package/dist/modules/flow_staff_channel/channel-routes.js +1 -20
  91. package/dist/modules/flow_staff_channel/channel-routes.js.map +1 -1
  92. package/dist/modules/hospitality_core/messages.d.ts.map +1 -1
  93. package/dist/modules/hospitality_core/messages.js +44 -0
  94. package/dist/modules/hospitality_core/messages.js.map +1 -1
  95. package/dist/modules/hospitality_core/night-audit.d.ts.map +1 -1
  96. package/dist/modules/hospitality_core/night-audit.js +7 -0
  97. package/dist/modules/hospitality_core/night-audit.js.map +1 -1
  98. package/dist/modules/hospitality_core/operations.d.ts.map +1 -1
  99. package/dist/modules/hospitality_core/operations.js +150 -40
  100. package/dist/modules/hospitality_core/operations.js.map +1 -1
  101. package/dist/modules/hospitality_core/routes.d.ts.map +1 -1
  102. package/dist/modules/hospitality_core/routes.js +24 -2
  103. package/dist/modules/hospitality_core/routes.js.map +1 -1
  104. package/dist/modules/hospitality_core/screens/check-out-prep.d.ts +46 -0
  105. package/dist/modules/hospitality_core/screens/check-out-prep.d.ts.map +1 -0
  106. package/dist/modules/hospitality_core/screens/check-out-prep.js +133 -0
  107. package/dist/modules/hospitality_core/screens/check-out-prep.js.map +1 -0
  108. package/dist/modules/hospitality_core/screens/folio-detail.d.ts.map +1 -1
  109. package/dist/modules/hospitality_core/screens/folio-detail.js +2 -4
  110. package/dist/modules/hospitality_core/screens/folio-detail.js.map +1 -1
  111. package/dist/modules/hospitality_core/screens/index.d.ts +2 -0
  112. package/dist/modules/hospitality_core/screens/index.d.ts.map +1 -1
  113. package/dist/modules/hospitality_core/screens/index.js +1 -0
  114. package/dist/modules/hospitality_core/screens/index.js.map +1 -1
  115. package/dist/modules/hospitality_core/screens/reservation-detail.d.ts.map +1 -1
  116. package/dist/modules/hospitality_core/screens/reservation-detail.js +8 -1
  117. package/dist/modules/hospitality_core/screens/reservation-detail.js.map +1 -1
  118. package/dist/modules/hospitality_core/screens/shared.d.ts +12 -0
  119. package/dist/modules/hospitality_core/screens/shared.d.ts.map +1 -1
  120. package/dist/modules/hospitality_core/screens/shared.js +25 -4
  121. package/dist/modules/hospitality_core/screens/shared.js.map +1 -1
  122. package/dist/modules/hospitality_core/services.d.ts +48 -0
  123. package/dist/modules/hospitality_core/services.d.ts.map +1 -1
  124. package/dist/modules/hospitality_core/services.js +70 -0
  125. package/dist/modules/hospitality_core/services.js.map +1 -1
  126. package/dist/modules/hospitality_staff_channel/channel-routes.d.ts.map +1 -1
  127. package/dist/modules/hospitality_staff_channel/channel-routes.js +1 -12
  128. package/dist/modules/hospitality_staff_channel/channel-routes.js.map +1 -1
  129. package/dist/modules/inventory_staff_channel/channel-routes.d.ts.map +1 -1
  130. package/dist/modules/inventory_staff_channel/channel-routes.js +1 -12
  131. package/dist/modules/inventory_staff_channel/channel-routes.js.map +1 -1
  132. package/dist/modules/loyalty/admin-functions.d.ts +2 -0
  133. package/dist/modules/loyalty/admin-functions.d.ts.map +1 -1
  134. package/dist/modules/loyalty/admin-functions.js +96 -20
  135. package/dist/modules/loyalty/admin-functions.js.map +1 -1
  136. package/dist/modules/loyalty/engine.d.ts +4 -1
  137. package/dist/modules/loyalty/engine.d.ts.map +1 -1
  138. package/dist/modules/loyalty/engine.js +125 -18
  139. package/dist/modules/loyalty/engine.js.map +1 -1
  140. package/dist/modules/loyalty/index.d.ts.map +1 -1
  141. package/dist/modules/loyalty/index.js +4 -3
  142. package/dist/modules/loyalty/index.js.map +1 -1
  143. package/dist/modules/loyalty/jobs.d.ts.map +1 -1
  144. package/dist/modules/loyalty/jobs.js +0 -1
  145. package/dist/modules/loyalty/jobs.js.map +1 -1
  146. package/dist/modules/loyalty/membership-functions.d.ts +5 -0
  147. package/dist/modules/loyalty/membership-functions.d.ts.map +1 -1
  148. package/dist/modules/loyalty/membership-functions.js +37 -23
  149. package/dist/modules/loyalty/membership-functions.js.map +1 -1
  150. package/dist/modules/loyalty/messages.d.ts +14 -0
  151. package/dist/modules/loyalty/messages.d.ts.map +1 -1
  152. package/dist/modules/loyalty/messages.js +14 -0
  153. package/dist/modules/loyalty/messages.js.map +1 -1
  154. package/dist/modules/loyalty/models.d.ts.map +1 -1
  155. package/dist/modules/loyalty/models.js +17 -0
  156. package/dist/modules/loyalty/models.js.map +1 -1
  157. package/dist/modules/loyalty/order-functions.d.ts.map +1 -1
  158. package/dist/modules/loyalty/order-functions.js +70 -17
  159. package/dist/modules/loyalty/order-functions.js.map +1 -1
  160. package/dist/modules/loyalty/program-design.d.ts +11 -0
  161. package/dist/modules/loyalty/program-design.d.ts.map +1 -0
  162. package/dist/modules/loyalty/program-design.js +356 -0
  163. package/dist/modules/loyalty/program-design.js.map +1 -0
  164. package/dist/modules/loyalty/stats.d.ts +0 -13
  165. package/dist/modules/loyalty/stats.d.ts.map +1 -1
  166. package/dist/modules/loyalty/stats.js +11 -6
  167. package/dist/modules/loyalty/stats.js.map +1 -1
  168. package/dist/modules/loyalty/stored-value.d.ts.map +1 -1
  169. package/dist/modules/loyalty/stored-value.js +7 -2
  170. package/dist/modules/loyalty/stored-value.js.map +1 -1
  171. package/dist/modules/loyalty/types.d.ts +1 -1
  172. package/dist/modules/loyalty/types.d.ts.map +1 -1
  173. package/dist/modules/loyalty_backend/design-messages.d.ts +221 -0
  174. package/dist/modules/loyalty_backend/design-messages.d.ts.map +1 -0
  175. package/dist/modules/loyalty_backend/design-messages.js +221 -0
  176. package/dist/modules/loyalty_backend/design-messages.js.map +1 -0
  177. package/dist/modules/loyalty_backend/index.js +224 -412
  178. package/dist/modules/loyalty_backend/index.js.map +1 -1
  179. package/dist/modules/loyalty_backend/messages.d.ts +642 -214
  180. package/dist/modules/loyalty_backend/messages.d.ts.map +1 -1
  181. package/dist/modules/loyalty_backend/messages.js +19 -13
  182. package/dist/modules/loyalty_backend/messages.js.map +1 -1
  183. package/dist/modules/loyalty_backend/program-workspace.d.ts +4 -0
  184. package/dist/modules/loyalty_backend/program-workspace.d.ts.map +1 -0
  185. package/dist/modules/loyalty_backend/program-workspace.js +600 -0
  186. package/dist/modules/loyalty_backend/program-workspace.js.map +1 -0
  187. package/dist/modules/loyalty_backend/screens/index.d.ts +12 -36
  188. package/dist/modules/loyalty_backend/screens/index.d.ts.map +1 -1
  189. package/dist/modules/loyalty_backend/screens/index.js +148 -292
  190. package/dist/modules/loyalty_backend/screens/index.js.map +1 -1
  191. package/dist/modules/loyalty_backend/screens/page-frame.d.ts.map +1 -1
  192. package/dist/modules/loyalty_backend/screens/page-frame.js +2 -2
  193. package/dist/modules/loyalty_backend/screens/page-frame.js.map +1 -1
  194. package/dist/modules/loyalty_pos/functions.d.ts.map +1 -1
  195. package/dist/modules/loyalty_pos/functions.js +1 -0
  196. package/dist/modules/loyalty_pos/functions.js.map +1 -1
  197. package/dist/modules/loyalty_pos/index.js +1 -1
  198. package/dist/modules/loyalty_pos/index.js.map +1 -1
  199. package/dist/modules/loyalty_sale/functions.d.ts +1 -0
  200. package/dist/modules/loyalty_sale/functions.d.ts.map +1 -1
  201. package/dist/modules/loyalty_sale/functions.js +1 -0
  202. package/dist/modules/loyalty_sale/functions.js.map +1 -1
  203. package/dist/modules/partner_backend/client/partner.css +3 -1
  204. package/dist/modules/partner_backend/index.d.ts.map +1 -1
  205. package/dist/modules/partner_backend/index.js +4 -0
  206. package/dist/modules/partner_backend/index.js.map +1 -1
  207. package/dist/modules/partner_backend/routes.d.ts.map +1 -1
  208. package/dist/modules/partner_backend/routes.js +6 -1
  209. package/dist/modules/partner_backend/routes.js.map +1 -1
  210. package/dist/modules/partner_backend/screens/form.d.ts +1 -0
  211. package/dist/modules/partner_backend/screens/form.d.ts.map +1 -1
  212. package/dist/modules/partner_backend/screens/form.js +1 -0
  213. package/dist/modules/partner_backend/screens/form.js.map +1 -1
  214. package/dist/modules/purchase_staff_channel/order-routes.d.ts.map +1 -1
  215. package/dist/modules/purchase_staff_channel/order-routes.js +1 -12
  216. package/dist/modules/purchase_staff_channel/order-routes.js.map +1 -1
  217. package/dist/modules/quality_staff_channel/channel-routes.d.ts.map +1 -1
  218. package/dist/modules/quality_staff_channel/channel-routes.js +1 -12
  219. package/dist/modules/quality_staff_channel/channel-routes.js.map +1 -1
  220. package/dist/modules/sale/functions.d.ts.map +1 -1
  221. package/dist/modules/sale/functions.js +27 -17
  222. package/dist/modules/sale/functions.js.map +1 -1
  223. package/dist/modules/sale_staff_channel/channel-routes.d.ts.map +1 -1
  224. package/dist/modules/sale_staff_channel/channel-routes.js +1 -12
  225. package/dist/modules/sale_staff_channel/channel-routes.js.map +1 -1
  226. package/dist/modules/sale_staff_channel/order-routes.d.ts.map +1 -1
  227. package/dist/modules/sale_staff_channel/order-routes.js +1 -12
  228. package/dist/modules/sale_staff_channel/order-routes.js.map +1 -1
  229. package/dist/modules/stock_staff_channel/operation-routes.d.ts.map +1 -1
  230. package/dist/modules/stock_staff_channel/operation-routes.js +1 -12
  231. package/dist/modules/stock_staff_channel/operation-routes.js.map +1 -1
  232. package/dist/modules/user/authorization.d.ts +64 -1
  233. package/dist/modules/user/authorization.d.ts.map +1 -1
  234. package/dist/modules/user/authorization.js +445 -53
  235. package/dist/modules/user/authorization.js.map +1 -1
  236. package/dist/modules/user/functions.d.ts.map +1 -1
  237. package/dist/modules/user/functions.js +45 -23
  238. package/dist/modules/user/functions.js.map +1 -1
  239. package/dist/modules/user/index.d.ts +2 -1
  240. package/dist/modules/user/index.d.ts.map +1 -1
  241. package/dist/modules/user/index.js +1 -1
  242. package/dist/modules/user/index.js.map +1 -1
  243. package/dist/modules/user/models.d.ts.map +1 -1
  244. package/dist/modules/user/models.js +5 -0
  245. package/dist/modules/user/models.js.map +1 -1
  246. package/dist/modules/user/roles.d.ts.map +1 -1
  247. package/dist/modules/user/roles.js +2 -1
  248. package/dist/modules/user/roles.js.map +1 -1
  249. package/dist/modules/user_backend/access-routes.d.ts +31 -0
  250. package/dist/modules/user_backend/access-routes.d.ts.map +1 -0
  251. package/dist/modules/user_backend/access-routes.js +447 -0
  252. package/dist/modules/user_backend/access-routes.js.map +1 -0
  253. package/dist/modules/user_backend/index.d.ts +1 -0
  254. package/dist/modules/user_backend/index.d.ts.map +1 -1
  255. package/dist/modules/user_backend/index.js +1 -0
  256. package/dist/modules/user_backend/index.js.map +1 -1
  257. package/dist/modules/user_backend/messages.d.ts +4 -0
  258. package/dist/modules/user_backend/messages.d.ts.map +1 -1
  259. package/dist/modules/user_backend/messages.js +4 -0
  260. package/dist/modules/user_backend/messages.js.map +1 -1
  261. package/dist/modules/user_backend/routes.d.ts.map +1 -1
  262. package/dist/modules/user_backend/routes.js +38 -3
  263. package/dist/modules/user_backend/routes.js.map +1 -1
  264. package/dist/modules/user_backend/screens/user-form.d.ts +1 -0
  265. package/dist/modules/user_backend/screens/user-form.d.ts.map +1 -1
  266. package/dist/modules/user_backend/screens/user-form.js +28 -0
  267. package/dist/modules/user_backend/screens/user-form.js.map +1 -1
  268. package/dist/modules/website/cms.d.ts.map +1 -1
  269. package/dist/modules/website/cms.js +283 -6
  270. package/dist/modules/website/cms.js.map +1 -1
  271. package/dist/modules/website/index.d.ts.map +1 -1
  272. package/dist/modules/website/index.js +12 -0
  273. package/dist/modules/website/index.js.map +1 -1
  274. package/dist/modules/website/media-usage.d.ts +38 -0
  275. package/dist/modules/website/media-usage.d.ts.map +1 -0
  276. package/dist/modules/website/media-usage.js +87 -0
  277. package/dist/modules/website/media-usage.js.map +1 -0
  278. package/dist/modules/website/paths.js +1 -1
  279. package/dist/modules/website/paths.js.map +1 -1
  280. package/dist/modules/website/sections.d.ts.map +1 -1
  281. package/dist/modules/website/sections.js +12 -1
  282. package/dist/modules/website/sections.js.map +1 -1
  283. package/dist/modules/website_backend/index.js +138 -0
  284. package/dist/modules/website_backend/index.js.map +1 -1
  285. package/dist/modules/website_backend/menus.d.ts.map +1 -1
  286. package/dist/modules/website_backend/menus.js +11 -0
  287. package/dist/modules/website_backend/menus.js.map +1 -1
  288. package/dist/modules/website_backend/routes.d.ts.map +1 -1
  289. package/dist/modules/website_backend/routes.js +414 -31
  290. package/dist/modules/website_backend/routes.js.map +1 -1
  291. package/dist/modules/website_backend/screens/index.d.ts +98 -6
  292. package/dist/modules/website_backend/screens/index.d.ts.map +1 -1
  293. package/dist/modules/website_backend/screens/index.js +600 -154
  294. package/dist/modules/website_backend/screens/index.js.map +1 -1
  295. package/dist/modules/website_backend/screens/page-frame.d.ts +3 -1
  296. package/dist/modules/website_backend/screens/page-frame.d.ts.map +1 -1
  297. package/dist/modules/website_backend/screens/page-frame.js +1 -1
  298. package/dist/modules/website_backend/screens/page-frame.js.map +1 -1
  299. package/dist/modules/website_menu/functions.d.ts.map +1 -1
  300. package/dist/modules/website_menu/functions.js +51 -0
  301. package/dist/modules/website_menu/functions.js.map +1 -1
  302. package/dist/modules/website_menu/index.js +2 -0
  303. package/dist/modules/website_menu/index.js.map +1 -1
  304. package/dist/modules/website_search/functions.d.ts.map +1 -1
  305. package/dist/modules/website_search/functions.js +10 -120
  306. package/dist/modules/website_search/functions.js.map +1 -1
  307. package/dist/modules/website_search/index.js +2 -0
  308. package/dist/modules/website_search/index.js.map +1 -1
  309. package/dist/modules/website_search/jobs.d.ts +3 -0
  310. package/dist/modules/website_search/jobs.d.ts.map +1 -0
  311. package/dist/modules/website_search/jobs.js +101 -0
  312. package/dist/modules/website_search/jobs.js.map +1 -0
  313. package/dist/modules/website_search/rebuild.d.ts +33 -0
  314. package/dist/modules/website_search/rebuild.d.ts.map +1 -0
  315. package/dist/modules/website_search/rebuild.js +125 -0
  316. package/dist/modules/website_search/rebuild.js.map +1 -0
  317. package/dist/permission-catalogue.d.ts.map +1 -1
  318. package/dist/permission-catalogue.js +21 -1
  319. package/dist/permission-catalogue.js.map +1 -1
  320. package/dist/scaffold/index.js +1 -1
  321. package/dist/ui/chrome.d.ts +8 -0
  322. package/dist/ui/chrome.d.ts.map +1 -1
  323. package/dist/ui/chrome.js +9 -1
  324. package/dist/ui/chrome.js.map +1 -1
  325. package/dist/ui/client/table-selection-view.d.ts.map +1 -1
  326. package/dist/ui/client/table-selection-view.js +161 -5
  327. package/dist/ui/client/table-selection-view.js.map +1 -1
  328. package/dist/ui/client/user-workflow.d.ts +2 -0
  329. package/dist/ui/client/user-workflow.d.ts.map +1 -0
  330. package/dist/ui/client/user-workflow.js +141 -0
  331. package/dist/ui/client/user-workflow.js.map +1 -0
  332. package/dist/ui/form.d.ts +9 -0
  333. package/dist/ui/form.d.ts.map +1 -1
  334. package/dist/ui/form.js +29 -15
  335. package/dist/ui/form.js.map +1 -1
  336. package/dist/ui/icons.d.ts.map +1 -1
  337. package/dist/ui/icons.js +2 -0
  338. package/dist/ui/icons.js.map +1 -1
  339. package/dist/ui/index.d.ts +7 -3
  340. package/dist/ui/index.d.ts.map +1 -1
  341. package/dist/ui/index.js +6 -3
  342. package/dist/ui/index.js.map +1 -1
  343. package/dist/ui/layout.d.ts.map +1 -1
  344. package/dist/ui/layout.js +14 -4
  345. package/dist/ui/layout.js.map +1 -1
  346. package/dist/ui/nav.d.ts.map +1 -1
  347. package/dist/ui/nav.js +2 -1
  348. package/dist/ui/nav.js.map +1 -1
  349. package/dist/ui/state.d.ts +20 -1
  350. package/dist/ui/state.d.ts.map +1 -1
  351. package/dist/ui/state.js +17 -0
  352. package/dist/ui/state.js.map +1 -1
  353. package/dist/ui/table.js +1 -1
  354. package/dist/ui/table.js.map +1 -1
  355. package/dist/ui/user-workflow.d.ts +72 -0
  356. package/dist/ui/user-workflow.d.ts.map +1 -0
  357. package/dist/ui/user-workflow.js +144 -0
  358. package/dist/ui/user-workflow.js.map +1 -0
  359. package/package.json +8 -4
@@ -1,9 +1,18 @@
1
1
  import { createHash, randomBytes, randomUUID } from 'node:crypto';
2
- import { asc, defineFn, deleteFrom, desc, eq, from, inArray, isNotNull, like, diffPlacements, isPlacementId, ne, placementIdErrors, validateLayout, withPlacementIds, } from '@ketvietlab/ketjs';
2
+ import { asc, defineFn, deleteFrom, desc, eq, from, inArray, isNotNull, like, likeLiteral, diffPlacements, isPlacementId, ne, partitionTokens, placementIdErrors, validateLayout, withPlacementIds, } from '@ketvietlab/ketjs';
3
3
  import { canAccessSite, canAdministerSite, canCreateEntry, canEditEntry, canManageStructure, canPublishEntry, } from './access.js';
4
4
  import { ensureCustomerRealm } from './customer.js';
5
5
  import { isReservedPath, reservedPrefixes } from './paths.js';
6
+ import { usageOf } from './media-usage.js';
6
7
  import { preflightEntry } from './renderable.js';
8
+ /**
9
+ * What a person typed in the title box, as a literal.
10
+ *
11
+ * Without the escape a `%` matched every page and a `_` matched any character,
12
+ * so the list answered nonsense to anyone searching for "50%" or "co_op" - and
13
+ * the count beside it agreed, which made it look deliberate.
14
+ */
15
+ const titlePattern = (search) => `%${likeLiteral(String(search).trim().slice(0, 100))}%`;
7
16
  const SITE_ROLES = new Set(['administrator', 'editor', 'author', 'contributor']);
8
17
  /** How many pages one unnamed preflight will read. Beyond it, the answer is "ask again by id". */
9
18
  const PREFLIGHT_SCAN_LIMIT = 1_000;
@@ -390,6 +399,14 @@ export const cmsFunctions = {
390
399
  return invalid('defaultLocale', 'website.error.invalidLocale');
391
400
  if (jsonBytes(args.tokens ?? {}) > 64 * 1024)
392
401
  return invalid('tokens', 'website.error.payloadTooLarge');
402
+ const tokens = args.tokens;
403
+ if (tokens != null && (typeof tokens !== 'object' || Array.isArray(tokens)))
404
+ return invalid('tokens', 'website.error.invalidTokens');
405
+ if (tokens) {
406
+ const { rejected } = partitionTokens(tokens);
407
+ if (rejected.length)
408
+ return invalid('tokens', 'website.error.invalidTokenValue');
409
+ }
393
410
  const duplicate = (await ctx.db.select('website.Site')).find((site) => site.id !== args.id && String(site.name).toLowerCase() === name.toLowerCase());
394
411
  if (duplicate)
395
412
  return invalid('name', 'website.error.duplicateName');
@@ -463,6 +480,28 @@ export const cmsFunctions = {
463
480
  return { ok: true, id: args.id };
464
481
  },
465
482
  }),
483
+ deleteDomain: defineFn({
484
+ input: { id: 'id' },
485
+ output: { ok: 'bool', id: 'id?', errors: 'json?' },
486
+ effects: ['read:website.SiteMember', 'read:website.SiteDomain', 'write:website.SiteDomain'],
487
+ idempotent: true,
488
+ handler: async (ctx, args) => {
489
+ const domain = (await ctx.db.select('website.SiteDomain', { id: args.id }))[0];
490
+ if (!domain)
491
+ return { ok: true, id: args.id };
492
+ if (!(await canAdministerSite(ctx, domain.siteId)))
493
+ return forbidden();
494
+ const siblings = await ctx.db.select('website.SiteDomain', { siteId: domain.siteId });
495
+ // Canonical URLs and the sitemap are built from the primary, so removing
496
+ // it while other hosts still answer for the site would publish the wrong
497
+ // address to every crawler that asks. Promote another one first.
498
+ if (domain.primary === true && siblings.length > 1)
499
+ return invalid('id', 'website.error.primaryDomainInUse');
500
+ const Domain = ctx.table('website.SiteDomain');
501
+ await ctx.db.del(deleteFrom(Domain).where(eq(Domain.id, args.id)));
502
+ return { ok: true, id: args.id };
503
+ },
504
+ }),
466
505
  listDomains: defineFn({
467
506
  input: { siteId: 'id', limit: 'int?', offset: 'int?' },
468
507
  output: {
@@ -572,10 +611,14 @@ export const cmsFunctions = {
572
611
  .orderBy(desc(Entry.updatedAt), asc(Entry.title));
573
612
  if (args.type)
574
613
  query = query.where(eq(Entry.type, args.type));
614
+ // Asked for by name or left out entirely: a list of what there is does
615
+ // not mean a list of what was thrown away.
575
616
  if (args.status)
576
617
  query = query.where(eq(Entry.status, args.status));
618
+ else
619
+ query = query.where(ne(Entry.status, 'trash'));
577
620
  if (args.search)
578
- query = query.where(like(Entry.title, `%${String(args.search).trim().slice(0, 100)}%`));
621
+ query = query.where(like(Entry.title, titlePattern(args.search), true));
579
622
  query = query.limit(paging.limit).offset(paging.offset);
580
623
  return ctx.db.all(query);
581
624
  },
@@ -591,10 +634,14 @@ export const cmsFunctions = {
591
634
  let query = from(Entry).where(eq(Entry.siteId, args.siteId));
592
635
  if (args.type)
593
636
  query = query.where(eq(Entry.type, args.type));
637
+ // The same rule as listEntries, or the pager counts rows the list will
638
+ // not show and the last page comes back empty.
594
639
  if (args.status)
595
640
  query = query.where(eq(Entry.status, args.status));
641
+ else
642
+ query = query.where(ne(Entry.status, 'trash'));
596
643
  if (args.search)
597
- query = query.where(like(Entry.title, `%${String(args.search).trim().slice(0, 100)}%`));
644
+ query = query.where(like(Entry.title, titlePattern(args.search), true));
598
645
  return { count: await ctx.db.count(query) };
599
646
  },
600
647
  }),
@@ -910,6 +957,105 @@ export const cmsFunctions = {
910
957
  return { ok: true, id: args.id, status: 'published' };
911
958
  },
912
959
  }),
960
+ /**
961
+ * Out of the way, without being gone.
962
+ *
963
+ * Every consumer in the module already honours `trash`: the public resolver
964
+ * refuses it, the sitemap and the menu validator leave it out, the search
965
+ * index skips it, preflight and the media library do not count it, and
966
+ * `preparePublication` refuses a set containing one. Nothing could produce
967
+ * it, so a page created by mistake stayed in the list for ever.
968
+ *
969
+ * Trash rather than delete because deleting is the harder question and this
970
+ * is not it: `ref:` emits no foreign key, so removing an entry would leave
971
+ * its revisions, its term assignments, its preview tokens and - across a
972
+ * module boundary `website` cannot reach - its SEO row all pointing at
973
+ * nothing. Trash keeps every row and answers the question people actually
974
+ * have, which is "get this off my list".
975
+ */
976
+ trashEntry: defineFn({
977
+ input: { id: 'id' },
978
+ output: { ok: 'bool', id: 'id?', errors: 'json?' },
979
+ effects: ['read:website.Entry', 'read:website.SiteMember', 'write:website.Entry'],
980
+ idempotent: true,
981
+ agent: true,
982
+ handler: async (ctx, args) => {
983
+ const entry = await entryById(ctx, args.id);
984
+ if (!entry || !(await canPublishEntry(ctx, entry)))
985
+ return forbidden();
986
+ if (entry.status === 'trash')
987
+ return { ok: true, id: args.id };
988
+ // The same clearing unpublishEntry does. The resolver checks the status
989
+ // too, but a pointer left behind is a pointer somebody later trusts.
990
+ await ctx.db.update('website.Entry', { id: args.id }, { status: 'trash', publishedRevisionId: null, scheduledRevisionId: null, publishAt: null });
991
+ return { ok: true, id: args.id };
992
+ },
993
+ }),
994
+ /**
995
+ * Back to a draft.
996
+ *
997
+ * `saveEntry` and `restoreRevision` both already revive a trashed entry,
998
+ * which is right - editing something means you want it back - but it is an
999
+ * implicit revival, and a screen needs a control that says what it does.
1000
+ */
1001
+ untrashEntry: defineFn({
1002
+ input: { id: 'id' },
1003
+ output: { ok: 'bool', id: 'id?', errors: 'json?' },
1004
+ effects: ['read:website.Entry', 'read:website.SiteMember', 'write:website.Entry'],
1005
+ idempotent: true,
1006
+ agent: true,
1007
+ handler: async (ctx, args) => {
1008
+ const entry = await entryById(ctx, args.id);
1009
+ if (!entry || !(await canPublishEntry(ctx, entry)))
1010
+ return forbidden();
1011
+ if (entry.status !== 'trash')
1012
+ return { ok: true, id: args.id };
1013
+ // A draft, never straight back to published: what it used to say may be
1014
+ // the reason it was thrown away.
1015
+ await ctx.db.update('website.Entry', { id: args.id }, { status: 'draft' });
1016
+ return { ok: true, id: args.id };
1017
+ },
1018
+ }),
1019
+ /**
1020
+ * The inverse of publishEntry, which never had one.
1021
+ *
1022
+ * A page could go live and never come back down: nothing set `status` back,
1023
+ * and the public resolver's per-entry fallback reads `publishedRevisionId`,
1024
+ * which nothing ever cleared. A page published by mistake, an event that is
1025
+ * over, a takedown - all of them had only `noindex`, which asks crawlers to
1026
+ * forget the page while every visitor with the address still reads it.
1027
+ *
1028
+ * This is also how a schedule is cancelled: `publishScheduled` re-reads
1029
+ * `status` before it publishes, so a scheduled page moved back to draft
1030
+ * stays there and the queued job returns without doing anything.
1031
+ *
1032
+ * What it does not do is take a page out of an *active publication*. That
1033
+ * set is frozen by design, and the way to change what it contains is to
1034
+ * prepare and activate another one.
1035
+ */
1036
+ unpublishEntry: defineFn({
1037
+ input: { id: 'id' },
1038
+ output: { ok: 'bool', id: 'id?', status: 'text?', errors: 'json?' },
1039
+ effects: ['read:website.Entry', 'read:website.SiteMember', 'write:website.Entry'],
1040
+ idempotent: true,
1041
+ agent: true,
1042
+ handler: async (ctx, args) => {
1043
+ const entry = await entryById(ctx, args.id);
1044
+ if (!entry || !(await canPublishEntry(ctx, entry)))
1045
+ return forbidden();
1046
+ if (entry.status === 'draft')
1047
+ return { ok: true, id: args.id, status: 'draft' };
1048
+ await ctx.db.update('website.Entry', { id: args.id }, {
1049
+ status: 'draft',
1050
+ publishedRevisionId: null,
1051
+ scheduledRevisionId: null,
1052
+ publishAt: null,
1053
+ });
1054
+ // publishedAt stays: it is the record of when the page was last live,
1055
+ // and clearing it would lose that to no purpose.
1056
+ return { ok: true, id: args.id, status: 'draft' };
1057
+ },
1058
+ }),
913
1059
  /**
914
1060
  * What would break if this went live now.
915
1061
  *
@@ -1106,10 +1252,29 @@ export const cmsFunctions = {
1106
1252
  return { token, expiresAt };
1107
1253
  },
1108
1254
  }),
1255
+ /**
1256
+ * The draft behind a preview link.
1257
+ *
1258
+ * Answers the same shape as `getEntryByPath`, because the storefront renders
1259
+ * whichever of the two answered and a second shape would mean a second
1260
+ * renderer. `meta` is the entry's own, not the publication's frozen copy: a
1261
+ * preview is for looking at what is about to go out.
1262
+ */
1109
1263
  previewEntry: defineFn({
1110
1264
  anonymous: true,
1111
1265
  input: { token: 'text' },
1112
- output: { entry: 'json', revision: 'json' },
1266
+ output: {
1267
+ id: 'id',
1268
+ siteId: 'id?',
1269
+ type: 'text?',
1270
+ path: 'text',
1271
+ title: 'text',
1272
+ excerpt: 'text?',
1273
+ layout: 'json',
1274
+ fields: 'json?',
1275
+ meta: 'json?',
1276
+ published: 'bool?',
1277
+ },
1113
1278
  effects: [
1114
1279
  'read:website.PreviewToken',
1115
1280
  'write:website.PreviewToken',
@@ -1133,7 +1298,18 @@ export const cmsFunctions = {
1133
1298
  if (!('dryRun' in used) && !used.matched)
1134
1299
  return null;
1135
1300
  }
1136
- return { entry, revision };
1301
+ return {
1302
+ id: entry.id,
1303
+ siteId: entry.siteId,
1304
+ type: entry.type,
1305
+ path: entry.path,
1306
+ title: revision.title,
1307
+ excerpt: revision.excerpt ?? null,
1308
+ layout: revision.layout,
1309
+ fields: revision.fields,
1310
+ meta: publicMeta(entry),
1311
+ published: entry.status === 'published',
1312
+ };
1137
1313
  },
1138
1314
  }),
1139
1315
  revokePreviewTokens: defineFn({
@@ -1311,6 +1487,64 @@ export const cmsFunctions = {
1311
1487
  return { ok: true, id: args.id };
1312
1488
  },
1313
1489
  }),
1490
+ listEntryTerms: defineFn({
1491
+ input: { entryId: 'id' },
1492
+ output: { id: 'id', termId: 'id', taxonomy: 'text', slug: 'text', name: 'text' },
1493
+ effects: [
1494
+ 'read:website.Entry',
1495
+ 'read:website.SiteMember',
1496
+ 'read:website.EntryTerm',
1497
+ 'read:website.TaxonomyTerm',
1498
+ ],
1499
+ agent: true,
1500
+ handler: async (ctx, args) => {
1501
+ const entry = await entryById(ctx, args.entryId);
1502
+ if (!entry || !(await canAccessSite(ctx, entry.siteId)))
1503
+ return [];
1504
+ const assignments = await ctx.db.select('website.EntryTerm', { entryId: args.entryId });
1505
+ if (!assignments.length)
1506
+ return [];
1507
+ const Term = ctx.table('website.TaxonomyTerm');
1508
+ const terms = await ctx.db.all(from(Term)
1509
+ .where(inArray(Term.id, assignments.map((row) => row.termId)))
1510
+ .orderBy(asc(Term.taxonomy), asc(Term.name)));
1511
+ const byId = new Map(terms.map((term) => [term.id, term]));
1512
+ // The assignment's own id, because that is what unassignTerm is given
1513
+ // and what a remove button has to carry.
1514
+ return assignments.flatMap((assignment) => {
1515
+ const term = byId.get(assignment.termId);
1516
+ return term
1517
+ ? [
1518
+ {
1519
+ id: assignment.id,
1520
+ termId: term.id,
1521
+ taxonomy: term.taxonomy,
1522
+ slug: term.slug,
1523
+ name: term.name,
1524
+ },
1525
+ ]
1526
+ : [];
1527
+ });
1528
+ },
1529
+ }),
1530
+ unassignTerm: defineFn({
1531
+ input: { entryId: 'id', termId: 'id' },
1532
+ output: { ok: 'bool', id: 'id?', errors: 'json?' },
1533
+ effects: ['read:website.Entry', 'read:website.SiteMember', 'write:website.EntryTerm'],
1534
+ idempotent: true,
1535
+ handler: async (ctx, args) => {
1536
+ const entry = await entryById(ctx, args.entryId);
1537
+ if (!entry || !(await canEditEntry(ctx, entry)))
1538
+ return forbidden();
1539
+ const EntryTerm = ctx.table('website.EntryTerm');
1540
+ // Removing a term that is not there is the state the caller asked for,
1541
+ // so this answers ok either way rather than making a retry an error.
1542
+ await ctx.db.del(deleteFrom(EntryTerm)
1543
+ .where(eq(EntryTerm.entryId, args.entryId))
1544
+ .where(eq(EntryTerm.termId, args.termId)));
1545
+ return { ok: true, id: args.entryId };
1546
+ },
1547
+ }),
1314
1548
  saveMediaMetadata: defineFn({
1315
1549
  input: {
1316
1550
  id: 'id',
@@ -1371,10 +1605,41 @@ export const cmsFunctions = {
1371
1605
  return media && (await canAccessSite(ctx, media.siteId)) ? media : null;
1372
1606
  },
1373
1607
  }),
1608
+ /**
1609
+ * Which pages draw this media item.
1610
+ *
1611
+ * The other half of the guard below: an editor about to delete an image
1612
+ * should be able to see what would break, and `deleteTerm` has shown the
1613
+ * same for taxonomy since it was written.
1614
+ */
1615
+ mediaUsage: defineFn({
1616
+ input: { id: 'id' },
1617
+ output: { used: 'bool', capped: 'bool', uses: 'json' },
1618
+ effects: [
1619
+ 'read:website.MediaMetadata',
1620
+ 'read:website.SiteMember',
1621
+ 'read:website.Entry',
1622
+ 'read:website.EntryRevision',
1623
+ ],
1624
+ agent: true,
1625
+ handler: async (ctx, args) => {
1626
+ const media = (await ctx.db.select('website.MediaMetadata', { id: args.id }))[0];
1627
+ if (!media || !(await canAccessSite(ctx, media.siteId)))
1628
+ return { used: false, capped: false, uses: [] };
1629
+ const { uses, capped } = await usageOf(ctx, media);
1630
+ return { used: uses.length > 0, capped, uses };
1631
+ },
1632
+ }),
1374
1633
  deleteMediaMetadata: defineFn({
1375
1634
  input: { id: 'id' },
1376
1635
  output: { ok: 'bool', id: 'id?', errors: 'json?' },
1377
- effects: ['read:website.MediaMetadata', 'read:website.SiteMember', 'write:website.MediaMetadata'],
1636
+ effects: [
1637
+ 'read:website.MediaMetadata',
1638
+ 'read:website.SiteMember',
1639
+ 'read:website.Entry',
1640
+ 'read:website.EntryRevision',
1641
+ 'write:website.MediaMetadata',
1642
+ ],
1378
1643
  idempotent: true,
1379
1644
  handler: async (ctx, args) => {
1380
1645
  const media = (await ctx.db.select('website.MediaMetadata', { id: args.id }))[0];
@@ -1382,6 +1647,15 @@ export const cmsFunctions = {
1382
1647
  return { ok: true, id: args.id };
1383
1648
  if (!(await canManageStructure(ctx, media.siteId)))
1384
1649
  return forbidden();
1650
+ // A page placing this would go on naming an id that no longer resolves,
1651
+ // and nothing anywhere would say why the image stopped appearing.
1652
+ const { uses, capped } = await usageOf(ctx, media);
1653
+ if (uses.length)
1654
+ return invalid('id', 'website.error.mediaInUse');
1655
+ // A scan that did not reach the whole site cannot answer "nothing uses
1656
+ // this" - the same reason a capped preflight is never ok.
1657
+ if (capped)
1658
+ return invalid('id', 'website.error.mediaUsageUnknown');
1385
1659
  const Media = ctx.table('website.MediaMetadata');
1386
1660
  await ctx.db.del(deleteFrom(Media).where(eq(Media.id, args.id)));
1387
1661
  return { ok: true, id: args.id };
@@ -1434,6 +1708,9 @@ export const cmsFunctions = {
1434
1708
  if (existing && existing.siteId !== args.siteId)
1435
1709
  return invalid('id', 'website.error.immutableOwnership');
1436
1710
  const redirects = await ctx.db.select('website.Redirect', { siteId: args.siteId });
1711
+ const taken = redirects.find((redirect) => redirect.id !== args.id && redirect.fromPath === fromPath);
1712
+ if (taken)
1713
+ return invalid('fromPath', 'website.error.duplicateRedirect');
1437
1714
  let target = toPath;
1438
1715
  for (let depth = 0; depth <= 20; depth += 1) {
1439
1716
  if (target === fromPath || depth === 20)