kempo 4.9.2 → 4.9.3

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 (206) hide show
  1. package/dist/admin/component-overrides.js +1 -1
  2. package/dist/admin/components/AddGroupControl.js +1 -1
  3. package/dist/admin/components/AdminTableControl.js +1 -1
  4. package/dist/admin/components/ClearExpiredSessionsControl.js +1 -1
  5. package/dist/admin/components/Dashboard.js +1 -1
  6. package/dist/admin/components/EmailTemplates.js +1 -1
  7. package/dist/admin/components/Emails.js +1 -1
  8. package/dist/admin/components/FragmentEditor.js +1 -1
  9. package/dist/admin/components/GlobalContentEditor.js +1 -1
  10. package/dist/admin/components/GroupDeleteSelected.js +1 -1
  11. package/dist/admin/components/GroupRemoveRecord.js +1 -1
  12. package/dist/admin/components/Menus.js +1 -1
  13. package/dist/admin/components/Monaco.js +1 -1
  14. package/dist/admin/components/PageEditor.js +1 -1
  15. package/dist/admin/components/TableRowDelete.js +1 -1
  16. package/dist/admin/components/TableRowLink.js +1 -1
  17. package/dist/admin/components/TemplateEditor.js +1 -1
  18. package/dist/admin/components/Updates.js +10 -9
  19. package/dist/admin/components/Updates.js.map +1 -1
  20. package/dist/admin/components/ValueEditor.js +1 -1
  21. package/dist/admin/components/dashboardLayout.js +1 -1
  22. package/dist/admin/components/settings/AdminSettings.js +1 -1
  23. package/dist/admin/components/settings/BooleanSetting.js +1 -1
  24. package/dist/admin/components/settings/JsonSetting.js +1 -1
  25. package/dist/admin/components/settings/NumberSetting.js +1 -1
  26. package/dist/admin/components/settings/SecretSetting.js +1 -1
  27. package/dist/admin/components/settings/Setting.js +1 -1
  28. package/dist/admin/components/settings/SettingEditor.js +1 -1
  29. package/dist/admin/components/settings/SettingsPanel.js +1 -1
  30. package/dist/admin/components/settings/StringSetting.js +1 -1
  31. package/dist/admin/components/settings/humanize.js +1 -1
  32. package/dist/admin/components/tableControls/AddMember.js +1 -1
  33. package/dist/admin/components/tableControls/AddPermission.js +1 -1
  34. package/dist/admin/components/tableControls/ExtensionDetails.js +1 -1
  35. package/dist/admin/components/tableControls/InstallExtension.js +1 -1
  36. package/dist/admin/components/tableControls/ToggleExtension.js +1 -1
  37. package/dist/admin/components/tableControls/UninstallExtension.js +1 -1
  38. package/dist/admin/components/widgets/Content.js +1 -1
  39. package/dist/admin/components/widgets/Extensions.js +1 -1
  40. package/dist/admin/components/widgets/Notifications.js +1 -1
  41. package/dist/admin/components/widgets/Pages.js +1 -1
  42. package/dist/admin/components/widgets/Users.js +1 -1
  43. package/dist/admin/init.js +1 -1
  44. package/dist/kempo/api/admin-globals/DELETE.js +1 -1
  45. package/dist/kempo/api/admin-globals/GET.js +1 -1
  46. package/dist/kempo/api/admin-globals/POST.js +1 -1
  47. package/dist/kempo/api/admin-globals/[id]/GET.js +1 -1
  48. package/dist/kempo/api/admin-globals/[id]/PUT.js +1 -1
  49. package/dist/kempo/api/admin-globals/[id]/disable/PUT.js +1 -1
  50. package/dist/kempo/api/admin-globals/[id]/enable/PUT.js +1 -1
  51. package/dist/kempo/api/auth/change-password/POST.js +1 -1
  52. package/dist/kempo/api/auth/login/email/POST.js +1 -1
  53. package/dist/kempo/api/auth/logout/POST.js +1 -1
  54. package/dist/kempo/api/auth/register/email/POST.js +1 -1
  55. package/dist/kempo/api/auth/reset-password/POST.js +1 -1
  56. package/dist/kempo/api/auth/session/GET.js +1 -1
  57. package/dist/kempo/api/auth/verify-email/POST.js +1 -1
  58. package/dist/kempo/api/dashboard/widgets/GET.js +1 -1
  59. package/dist/kempo/api/email-templates/GET.js +1 -1
  60. package/dist/kempo/api/email-templates/file/DELETE.js +1 -1
  61. package/dist/kempo/api/email-templates/file/GET.js +1 -1
  62. package/dist/kempo/api/email-templates/file/PUT.js +1 -1
  63. package/dist/kempo/api/email-templates/preview/GET.js +1 -1
  64. package/dist/kempo/api/emails/GET.js +1 -1
  65. package/dist/kempo/api/emails/[id]/GET.js +1 -1
  66. package/dist/kempo/api/emails/[id]/retry/POST.js +1 -1
  67. package/dist/kempo/api/emails/test/POST.js +1 -1
  68. package/dist/kempo/api/extensions/DELETE.js +1 -1
  69. package/dist/kempo/api/extensions/GET.js +1 -1
  70. package/dist/kempo/api/extensions/POST.js +1 -1
  71. package/dist/kempo/api/extensions/[name]/dependents/GET.js +1 -1
  72. package/dist/kempo/api/extensions/[name]/disable/POST.js +1 -1
  73. package/dist/kempo/api/extensions/[name]/enable/POST.js +1 -1
  74. package/dist/kempo/api/extensions/[name]/requirements/GET.js +1 -1
  75. package/dist/kempo/api/extensions/[name]/update/POST.js +1 -1
  76. package/dist/kempo/api/extensions/[name]/update-check/GET.js +1 -1
  77. package/dist/kempo/api/extensions/available/GET.js +1 -1
  78. package/dist/kempo/api/extensions/known/GET.js +1 -1
  79. package/dist/kempo/api/extensions/rating/PUT.js +1 -1
  80. package/dist/kempo/api/forgot-password/POST.js +1 -1
  81. package/dist/kempo/api/fragments/DELETE.js +1 -1
  82. package/dist/kempo/api/fragments/GET.js +1 -1
  83. package/dist/kempo/api/fragments/POST.js +1 -1
  84. package/dist/kempo/api/fragments/disable/PUT.js +1 -1
  85. package/dist/kempo/api/fragments/enable/PUT.js +1 -1
  86. package/dist/kempo/api/fragments/file/GET.js +1 -1
  87. package/dist/kempo/api/fragments/file/PATCH.js +1 -1
  88. package/dist/kempo/api/fragments/file/PUT.js +1 -1
  89. package/dist/kempo/api/fragments/lock/PUT.js +1 -1
  90. package/dist/kempo/api/globals/DELETE.js +1 -1
  91. package/dist/kempo/api/globals/GET.js +1 -1
  92. package/dist/kempo/api/globals/POST.js +1 -1
  93. package/dist/kempo/api/globals/disable/PUT.js +1 -1
  94. package/dist/kempo/api/globals/enable/PUT.js +1 -1
  95. package/dist/kempo/api/globals/entry/GET.js +1 -1
  96. package/dist/kempo/api/globals/entry/PUT.js +1 -1
  97. package/dist/kempo/api/globals/lock/PUT.js +1 -1
  98. package/dist/kempo/api/groups/DELETE.js +1 -1
  99. package/dist/kempo/api/groups/GET.js +1 -1
  100. package/dist/kempo/api/groups/PATCH.js +1 -1
  101. package/dist/kempo/api/groups/POST.js +1 -1
  102. package/dist/kempo/api/groups/[name]/GET.js +1 -1
  103. package/dist/kempo/api/groups/[name]/members/DELETE.js +1 -1
  104. package/dist/kempo/api/groups/[name]/members/GET.js +1 -1
  105. package/dist/kempo/api/groups/[name]/members/POST.js +1 -1
  106. package/dist/kempo/api/groups/[name]/permissions/DELETE.js +1 -1
  107. package/dist/kempo/api/groups/[name]/permissions/GET.js +1 -1
  108. package/dist/kempo/api/groups/[name]/permissions/POST.js +1 -1
  109. package/dist/kempo/api/menus/DELETE.js +1 -1
  110. package/dist/kempo/api/menus/GET.js +1 -1
  111. package/dist/kempo/api/menus/POST.js +1 -1
  112. package/dist/kempo/api/menus/adopt/PUT.js +1 -1
  113. package/dist/kempo/api/menus/items/DELETE.js +1 -1
  114. package/dist/kempo/api/menus/items/POST.js +1 -1
  115. package/dist/kempo/api/menus/items/enabled/PUT.js +1 -1
  116. package/dist/kempo/api/menus/items/order/PUT.js +1 -1
  117. package/dist/kempo/api/menus/location/PUT.js +1 -1
  118. package/dist/kempo/api/notifications/GET.js +1 -1
  119. package/dist/kempo/api/notifications/[id]/DELETE.js +1 -1
  120. package/dist/kempo/api/notifications/[id]/handled/POST.js +1 -1
  121. package/dist/kempo/api/notifications/[id]/read/POST.js +1 -1
  122. package/dist/kempo/api/notifications/count/GET.js +1 -1
  123. package/dist/kempo/api/notifications/read-all/POST.js +1 -1
  124. package/dist/kempo/api/pages/DELETE.js +1 -1
  125. package/dist/kempo/api/pages/GET.js +1 -1
  126. package/dist/kempo/api/pages/POST.js +1 -1
  127. package/dist/kempo/api/pages/directories/GET.js +1 -1
  128. package/dist/kempo/api/pages/disable/PUT.js +1 -1
  129. package/dist/kempo/api/pages/enable/PUT.js +1 -1
  130. package/dist/kempo/api/pages/file/GET.js +1 -1
  131. package/dist/kempo/api/pages/file/PATCH.js +1 -1
  132. package/dist/kempo/api/pages/file/PUT.js +1 -1
  133. package/dist/kempo/api/pages/lock/PUT.js +1 -1
  134. package/dist/kempo/api/pages/rescan/POST.js +1 -1
  135. package/dist/kempo/api/pages/search/GET.js +1 -1
  136. package/dist/kempo/api/pages/templates/GET.js +1 -1
  137. package/dist/kempo/api/permissions/DELETE.js +1 -1
  138. package/dist/kempo/api/permissions/GET.js +1 -1
  139. package/dist/kempo/api/permissions/PATCH.js +1 -1
  140. package/dist/kempo/api/permissions/POST.js +1 -1
  141. package/dist/kempo/api/realtime/WS.js +1 -1
  142. package/dist/kempo/api/realtime/connections/GET.js +1 -1
  143. package/dist/kempo/api/settings/[owner]/GET.js +1 -1
  144. package/dist/kempo/api/settings/[owner]/[name]/DELETE.js +1 -1
  145. package/dist/kempo/api/settings/[owner]/[name]/GET.js +1 -1
  146. package/dist/kempo/api/settings/[owner]/[name]/POST.js +1 -1
  147. package/dist/kempo/api/settings/public/GET.js +1 -1
  148. package/dist/kempo/api/templates/DELETE.js +1 -1
  149. package/dist/kempo/api/templates/GET.js +1 -1
  150. package/dist/kempo/api/templates/POST.js +1 -1
  151. package/dist/kempo/api/templates/disable/PUT.js +1 -1
  152. package/dist/kempo/api/templates/enable/PUT.js +1 -1
  153. package/dist/kempo/api/templates/file/GET.js +1 -1
  154. package/dist/kempo/api/templates/file/PATCH.js +1 -1
  155. package/dist/kempo/api/templates/file/PUT.js +1 -1
  156. package/dist/kempo/api/templates/lock/PUT.js +1 -1
  157. package/dist/kempo/api/updates/GET.js +1 -1
  158. package/dist/kempo/api/updates/apply/POST.js +1 -1
  159. package/dist/kempo/api/updates/check/POST.js +1 -1
  160. package/dist/kempo/api/updates/discard/POST.js +1 -1
  161. package/dist/kempo/api/updates/prepare/POST.js +1 -1
  162. package/dist/kempo/api/updates/rollback/POST.js +1 -1
  163. package/dist/kempo/api/user/DELETE.js +1 -1
  164. package/dist/kempo/api/user/GET.js +1 -1
  165. package/dist/kempo/api/user/PATCH.js +1 -1
  166. package/dist/kempo/api/user/[userid]/GET.js +1 -1
  167. package/dist/kempo/api/user/[userid]/groups/DELETE.js +1 -1
  168. package/dist/kempo/api/user/[userid]/groups/GET.js +1 -1
  169. package/dist/kempo/api/user/[userid]/groups/POST.js +1 -1
  170. package/dist/kempo/api/user/[userid]/name/GET.js +1 -1
  171. package/dist/kempo/api/user/[userid]/permissions/GET.js +1 -1
  172. package/dist/kempo/api/user/[userid]/permissions/all/GET.js +1 -1
  173. package/dist/kempo/api/user/[userid]/permissions/list/GET.js +1 -1
  174. package/dist/kempo/api/user/[userid]/permissions/some/GET.js +1 -1
  175. package/dist/kempo/api/user/[userid]/sessions/DELETE.js +1 -1
  176. package/dist/kempo/api/user/[userid]/sessions/GET.js +1 -1
  177. package/dist/kempo/api/user/[userid]/sessions/expired/DELETE.js +1 -1
  178. package/dist/kempo/api/user/create/POST.js +1 -1
  179. package/dist/kempo/api/user/search/GET.js +1 -1
  180. package/dist/kempo/components/AdminNavFooter.js +1 -1
  181. package/dist/kempo/components/DashboardWidget.js +1 -1
  182. package/dist/kempo/components/Login.js +1 -1
  183. package/dist/kempo/components/LogoutBtn.js +1 -1
  184. package/dist/kempo/components/Menu.js +1 -1
  185. package/dist/kempo/components/NotificationBell.js +1 -1
  186. package/dist/kempo/components/NotificationList.js +1 -1
  187. package/dist/kempo/components/Permission.js +1 -1
  188. package/dist/kempo/components/PermissionTarget.js +1 -1
  189. package/dist/kempo/components/Register.js +1 -1
  190. package/dist/kempo/components/Role.js +1 -1
  191. package/dist/kempo/components/UserCreatedAt.js +1 -1
  192. package/dist/kempo/components/UserDisplayName.js +1 -1
  193. package/dist/kempo/components/UserEmail.js +1 -1
  194. package/dist/kempo/components/UserEmailVerified.js +1 -1
  195. package/dist/kempo/components/UserName.js +1 -1
  196. package/dist/kempo/fetch.js +1 -1
  197. package/dist/kempo/realtime.js +1 -1
  198. package/dist/kempo/sdk.js +1 -1
  199. package/dist/kempo/utils/safeNext.js +1 -1
  200. package/package.json +1 -1
  201. package/server/utils/updates/applyStagedUpdate.js +8 -3
  202. package/server/utils/updates/goBackPlan.js +34 -0
  203. package/server/utils/updates/prepareUpdate.js +1 -1
  204. package/server/utils/updates/releaseStatus.js +8 -5
  205. package/server/utils/updates/rollbackUpdate.js +14 -21
  206. package/server/utils/updates/siteLayout.js +17 -2
package/dist/kempo/sdk.js CHANGED
@@ -1,2 +1,2 @@
1
1
  import{get as e,post as s,put as t,patch as n,del as o}from"./fetch.js";const a="/kempo/api";export const register=async({email:e,password:t,name:n})=>s(`${a}/auth/register/email`,{email:e,password:t,name:n});export const login=async({email:e,password:t})=>s(`${a}/auth/login/email`,{email:e,password:t});export const logout=async()=>s(`${a}/auth/logout`,{});export const getSession=async()=>e(`${a}/auth/session`);export const forgotPassword=async({email:e})=>s(`${a}/forgot-password`,{email:e});export const resetPassword=async({token:e,password:t,logoutAll:n=!1})=>s(`${a}/auth/reset-password`,{token:e,newPassword:t,logoutAll:n});export const changePassword=async({currentPassword:e,newPassword:t,logoutAll:n})=>s(`${a}/auth/change-password`,{currentPassword:e,newPassword:t,logoutAll:n});export const verifyEmail=async({token:e})=>s(`${a}/auth/verify-email`,{token:e});export const currentUserHasPermission=async({permission:s})=>e(`${a}/user/current/permissions`,{permission:s});export const currentUserHasAllPermissions=async({permissions:s})=>e(`${a}/user/current/permissions/all`,{permissions:s});export const currentUserHasSomePermissions=async({permissions:s})=>e(`${a}/user/current/permissions/some`,{permissions:s});export const getAllCurrentUserPermissions=async()=>e(`${a}/user/current/permissions/list`);export const userHasPermission=async({userid:s,permission:t})=>e(`${a}/user/${s}/permissions`,{permission:t});export const userHasAllPermissions=async({userid:s,permissions:t})=>e(`${a}/user/${s}/permissions/all`,{permissions:t});export const userHasSomePermissions=async({userid:s,permissions:t})=>e(`${a}/user/${s}/permissions/some`,{permissions:t});export const getAllUserPermissions=async({userid:s})=>e(`${a}/user/${s}/permissions/list`);export const getUsers=async({limit:s,offset:t}={})=>e(`${a}/user`,{limit:s,offset:t});export const searchUsers=async({q:s,limit:t,offset:n,inGroup:o,notInGroup:i}={})=>e(`${a}/user/search`,{q:s,limit:t,offset:n,inGroup:o,notInGroup:i});export const createUser=async({name:e,email:t,password:n,emailVerified:o})=>s(`${a}/user/create`,{name:e,email:t,password:n,emailVerified:o});export const deleteUsers=async e=>o(`${a}/user`,{ids:e});export const updateUser=async({id:e,name:s,email:t,emailVerified:o,createdAt:i})=>n(`${a}/user`,{id:e,name:s,email:t,emailVerified:o,createdAt:i});export const getUser=async s=>e(`${a}/user/${s}`);export const getUserSessions=async(s,{limit:t,offset:n}={})=>e(`${a}/user/${s}/sessions`,{limit:t,offset:n});export const deleteUserSession=async(e,s)=>o(`${a}/user/${e}/sessions`,{sessionToken:s});export const deleteExpiredUserSessions=async e=>o(`${a}/user/${e}/sessions/expired`);export const getUserGroups=async(s,{limit:t,offset:n}={})=>e(`${a}/user/${s}/groups`,{limit:t,offset:n});export const addUserToGroup=async(e,t)=>s(`${a}/user/${e}/groups`,{groupName:t});export const removeUserFromGroup=async(e,s)=>o(`${a}/user/${e}/groups`,{groupName:s});export const listGroups=async({limit:s,offset:t,owner:n}={})=>e(`${a}/groups`,{limit:s,offset:t,owner:n});export const createGroup=async({name:e,description:t})=>s(`${a}/groups`,{name:e,description:t});export const updateGroup=async({name:e,newName:s,description:t})=>n(`${a}/groups`,{name:e,newName:s,description:t});export const deleteGroups=async e=>o(`${a}/groups`,{names:e});export const getGroup=async s=>e(`${a}/groups/${encodeURIComponent(s)}`);export const getGroupMembers=async(s,{limit:t,offset:n}={})=>e(`${a}/groups/${encodeURIComponent(s)}/members`,{limit:t,offset:n});export const addMemberToGroup=async(e,t)=>s(`${a}/groups/${encodeURIComponent(e)}/members`,{userId:t});export const removeMemberFromGroup=async(e,s)=>o(`${a}/groups/${encodeURIComponent(e)}/members`,{userId:s});export const getGroupPermissions=async s=>e(`${a}/groups/${encodeURIComponent(s)}/permissions`);export const addPermissionToGroup=async(e,t)=>s(`${a}/groups/${encodeURIComponent(e)}/permissions`,{permissionName:t});export const removePermissionFromGroup=async(e,s)=>o(`${a}/groups/${encodeURIComponent(e)}/permissions`,{permissionName:s});export const listPermissions=async({limit:s,offset:t,owner:n}={})=>e(`${a}/permissions`,{limit:s,offset:t,owner:n});export const createPermissions=async e=>s(`${a}/permissions`,{permissions:e});export const updatePermission=async({name:e,description:s})=>n(`${a}/permissions`,{name:e,description:s});export const deletePermissions=async e=>o(`${a}/permissions`,{names:e});export const getSetting=async(s,t)=>e(`${a}/settings/${encodeURIComponent(s)}/${encodeURIComponent(t)}`);export const listSettings=async({owner:s,limit:t,offset:n}={})=>e(`${a}/settings/${encodeURIComponent(s)}`,{limit:t,offset:n});export const setSetting=async(e,t,n)=>s(`${a}/settings/${encodeURIComponent(e)}/${encodeURIComponent(t)}`,n);export const deleteSetting=async(e,s)=>o(`${a}/settings/${encodeURIComponent(e)}/${encodeURIComponent(s)}`);export const listEmails=async({status:s,type:t,search:n,limit:o,offset:i}={})=>e(`${a}/emails`,{status:s,type:t,search:n,limit:o,offset:i});export const getEmail=async s=>e(`${a}/emails/${encodeURIComponent(s)}`);export const retryEmail=async e=>s(`${a}/emails/${encodeURIComponent(e)}/retry`,{});export const sendTestEmail=async e=>s(`${a}/emails/test`,{to:e});export const getUpdateStatus=async()=>e(`${a}/updates`);export const checkForUpdate=async()=>s(`${a}/updates/check`,{});export const prepareUpdate=async({version:e,extensions:t}={})=>s(`${a}/updates/prepare`,{version:e,extensions:t});export const applyUpdate=async({version:e,extensions:t,confirm:n}={})=>s(`${a}/updates/apply`,{version:e,extensions:t,confirm:n});export const rollbackUpdate=async e=>s(`${a}/updates/rollback`,{confirm:e});export const discardUpdate=async()=>s(`${a}/updates/discard`,{});export const listPages=async({owner:s,showHidden:t,offset:n,limit:o}={})=>e(`${a}/pages`,{owner:s,showHidden:t,offset:n,limit:o});export const rescanPages=async()=>s(`${a}/pages/rescan`,{});export const listTemplates=async()=>e(`${a}/templates`);export const listDirectories=async()=>e(`${a}/pages/directories`);export const getPage=async s=>e(`${a}/pages/file`,{file:s});export const createPage=async({directory:e,name:t,template:n})=>s(`${a}/pages`,{directory:e,name:t,template:n});export const updatePage=async({file:e,name:s,title:n,description:o,author:i,template:r,contents:c,extraMetadata:p})=>t(`${a}/pages/file`,{file:e,name:s,title:n,description:o,author:i,template:r,contents:c,extraMetadata:p});export const deletePages=async e=>o(`${a}/pages`,{files:e});export const disablePage=async e=>t(`${a}/pages/disable`,{file:e});export const enablePage=async e=>t(`${a}/pages/enable`,{file:e});export const movePage=async({file:e,newFile:s})=>n(`${a}/pages/file`,{file:e,newFile:s});export const searchPagesByMetadata=async s=>e(`${a}/pages/search`,{query:JSON.stringify(s)});export const setPageLocked=async({file:e,locked:s})=>t(`${a}/pages/lock`,{file:e,locked:s});export const getTemplate=async s=>e(`${a}/templates/file`,{file:s});export const createTemplate=async({directory:e,name:t,copyFrom:n})=>s(`${a}/templates`,{directory:e,name:t,copyFrom:n});export const updateTemplate=async({file:e,name:s,author:n,markup:o})=>t(`${a}/templates/file`,{file:e,name:s,author:n,markup:o});export const deleteTemplates=async e=>o(`${a}/templates`,{files:e});export const listEmailTemplates=async s=>e(`${a}/email-templates`,s?{owner:s}:{});export const getEmailTemplate=async s=>e(`${a}/email-templates/file`,{template:s});export const saveEmailTemplate=async({template:e,source:s})=>t(`${a}/email-templates/file`,{template:e,source:s});export const resetEmailTemplate=async e=>o(`${a}/email-templates/file`,{template:e});export const disableTemplate=async e=>t(`${a}/templates/disable`,{file:e});export const enableTemplate=async e=>t(`${a}/templates/enable`,{file:e});export const moveTemplate=async({file:e,newFile:s})=>n(`${a}/templates/file`,{file:e,newFile:s});export const setTemplateLocked=async({file:e,locked:s})=>t(`${a}/templates/lock`,{file:e,locked:s});export const listFragments=async()=>e(`${a}/fragments`);export const getFragment=async s=>e(`${a}/fragments/file`,{file:s});export const createFragment=async({directory:e,name:t})=>s(`${a}/fragments`,{directory:e,name:t});export const updateFragment=async({file:e,author:s,markup:n})=>t(`${a}/fragments/file`,{file:e,author:s,markup:n});export const deleteFragments=async e=>o(`${a}/fragments`,{files:e});export const moveFragment=async({file:e,newFile:s})=>n(`${a}/fragments/file`,{file:e,newFile:s});export const disableFragment=async e=>t(`${a}/fragments/disable`,{file:e});export const enableFragment=async e=>t(`${a}/fragments/enable`,{file:e});export const setFragmentLocked=async({file:e,locked:s})=>t(`${a}/fragments/lock`,{file:e,locked:s});export const listGlobalContent=async()=>e(`${a}/globals`);export const getGlobalContent=async s=>e(`${a}/globals/entry`,{id:s});export const createGlobalContent=async({name:e,location:t,priority:n})=>s(`${a}/globals`,{name:e,location:t,priority:n});export const updateGlobalContent=async({id:e,name:s,location:n,priority:o,markup:i})=>t(`${a}/globals/entry`,{id:e,name:s,location:n,priority:o,markup:i});export const deleteGlobalContent=async e=>o(`${a}/globals`,{ids:e});export const disableGlobalContent=async e=>t(`${a}/globals/disable`,{id:e});export const enableGlobalContent=async e=>t(`${a}/globals/enable`,{id:e});export const setGlobalContentLocked=async({id:e,locked:s})=>t(`${a}/globals/lock`,{id:e,locked:s});export const listMenus=async()=>e(`${a}/menus`);export const saveMenu=async({id:e,name:t})=>s(`${a}/menus`,{id:e,name:t});export const deleteMenu=async e=>o(`${a}/menus`,{id:e});export const assignMenuLocation=async({location:e,menuId:s})=>t(`${a}/menus/location`,{location:e,menuId:s});export const saveMenuItem=async({id:e,menuId:t,location:n,navItem:o,label:i,href:r,icon:c,newTab:p})=>s(`${a}/menus/items`,{id:e,menuId:t,location:n,navItem:o,label:i,href:r,icon:c,newTab:p});export const deleteMenuItems=async e=>o(`${a}/menus/items`,{ids:e});export const setMenuItemEnabled=async({id:e,enabled:s})=>t(`${a}/menus/items/enabled`,{id:e,enabled:s});export const reorderMenuItems=async({menuId:e,ids:s})=>t(`${a}/menus/items/order`,{menuId:e,ids:s});export const adoptMenuItem=async({id:e,menuId:s,menuName:n})=>t(`${a}/menus/adopt`,{id:e,menuId:s,menuName:n});export const listExtensions=async({limit:s,offset:t}={})=>e(`${a}/extensions`,{limit:s,offset:t});export const listAvailableExtensions=async()=>e(`${a}/extensions/available`);export const listKnownExtensions=async({search:s,sort:t,limit:n,offset:o}={})=>e(`${a}/extensions/known`,{search:s,sort:t,limit:n,offset:o});export const getKnownExtension=async s=>e(`${a}/extensions/known`,{name:s});export const rateExtension=async(e,s)=>t(`${a}/extensions/rating`,{name:e,rating:s});export const getDashboardWidgets=async()=>e(`${a}/dashboard/widgets`);export const getNotifications=async({unreadOnly:s=!1,limit:t,offset:n}={})=>e(`${a}/notifications`,{unreadOnly:s,limit:t,offset:n});export const getUnreadNotificationCount=async()=>e(`${a}/notifications/count`);export const markNotificationRead=async e=>s(`${a}/notifications/${encodeURIComponent(e)}/read`,{});export const markNotificationHandled=async e=>s(`${a}/notifications/${encodeURIComponent(e)}/handled`,{});export const markAllNotificationsRead=async()=>s(`${a}/notifications/read-all`,{});export const dismissNotification=async e=>o(`${a}/notifications/${encodeURIComponent(e)}`);export const listRealtimeConnections=async()=>e(`${a}/realtime/connections`);export const installExtension=async(e,{withDependencies:t=!1}={})=>s(`${a}/extensions`,{name:e,withDependencies:t});export const uninstallExtension=async(e,s=!1,{cascade:t=!1}={})=>o(`${a}/extensions`,{name:e,purgeData:s,cascade:t});export const enableExtension=async(e,{cascade:t=!1}={})=>s(`${a}/extensions/${encodeURIComponent(e)}/enable`,{cascade:t});export const getExtensionRequirements=async s=>e(`${a}/extensions/${encodeURIComponent(s)}/requirements`);export const disableExtension=async(e,{cascade:t=!1}={})=>s(`${a}/extensions/${encodeURIComponent(e)}/disable`,{cascade:t});export const getExtensionDependents=async(s,{includeDisabled:t=!1}={})=>e(`${a}/extensions/${encodeURIComponent(s)}/dependents`,{includeDisabled:t?"true":void 0});export const listAdminGlobalContent=async()=>e(`${a}/admin-globals`);export const getAdminGlobalContent=async s=>e(`${a}/admin-globals/${encodeURIComponent(s)}`);export const createAdminGlobalContent=async({name:e,location:t,priority:n,owner:o,markup:i})=>s(`${a}/admin-globals`,{name:e,location:t,priority:n,owner:o,markup:i});export const updateAdminGlobalContent=async(e,{name:s,location:n,priority:o,markup:i})=>t(`${a}/admin-globals/${encodeURIComponent(e)}`,{name:s,location:n,priority:o,markup:i});export const deleteAdminGlobalContent=async e=>o(`${a}/admin-globals`,{ids:e});export const enableAdminGlobalContent=async e=>t(`${a}/admin-globals/${encodeURIComponent(e)}/enable`,{});export const disableAdminGlobalContent=async e=>t(`${a}/admin-globals/${encodeURIComponent(e)}/disable`,{});
2
- //# sourceMappingURL=c:\Users\dusti\dev\kempo\dist\kempo\sdk.js.map
2
+ //# sourceMappingURL=C:\Users\dusti\dev\kempo\dist\kempo\sdk.js.map
@@ -1,2 +1,2 @@
1
1
  export default t=>"string"!=typeof t||t.length>2048||!t.startsWith("/")||t.startsWith("//")||/[\\\u0000-\u001f\u007f]/.test(t)?"":t;
2
- //# sourceMappingURL=c:\Users\dusti\dev\kempo\dist\kempo\utils\safeNext.js.map
2
+ //# sourceMappingURL=C:\Users\dusti\dev\kempo\dist\kempo\utils\safeNext.js.map
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "kempo",
3
- "version": "4.9.2",
3
+ "version": "4.9.3",
4
4
  "type": "module",
5
5
  "description": "A fullstack CMS framework for creating websites with user authentication",
6
6
  "scripts": {
@@ -1,4 +1,4 @@
1
- import { existsSync } from 'fs';
1
+ import { existsSync, rmSync } from 'fs';
2
2
  import { join } from 'path';
3
3
  import { and, eq, like } from 'drizzle-orm';
4
4
  import db from '../../db/index.js';
@@ -6,7 +6,7 @@ import { notification } from '../../db/schema.js';
6
6
  import { RUNNING_VERSION } from './runtime.js';
7
7
  import backupDatabase from './backupDatabase.js';
8
8
  import { restartMode, scheduleRestart } from './restart.js';
9
- import { clearState, paths, readState, requestSwitch } from './siteLayout.js';
9
+ import { basisOf, clearState, paths, readState, requestSwitch } from './siteLayout.js';
10
10
  import { applyStarterFiles } from './starterFiles.js';
11
11
  import { PACKAGE } from './helpers.js';
12
12
  import triggerHook from '../hooks/triggerHook.js';
@@ -46,7 +46,12 @@ export default async ({ confirm = {}, siteRoot = process.env.KEMPO_SITE_ROOT, cw
46
46
  return [{ code: 409, msg: 'No update is ready: prepare one first' }, null];
47
47
  }
48
48
  if(readState(siteRoot, 'switch')){
49
- return [{ code: 409, msg: 'The last switch has not finished proving itself yet' }, null];
49
+ return [{ code: 409, msg: 'The last switch is still being checked, which takes about a minute after the restart. Try again shortly.' }, null];
50
+ }
51
+ if(staged.basis && staged.basis !== basisOf(siteRoot)){
52
+ rmSync(paths(siteRoot).staging, { recursive: true, force: true });
53
+ clearState(siteRoot, 'staged');
54
+ return [{ code: 409, msg: 'The site changed after this update was downloaded (another update, or an extension was installed), so switching to it would undo that. It has been thrown away: get the update ready again.' }, null];
50
55
  }
51
56
 
52
57
  const { plan } = staged;
@@ -0,0 +1,34 @@
1
+ import { existsSync } from 'fs';
2
+ import { join } from 'path';
3
+ import { getCurrent, paths, readState } from './siteLayout.js';
4
+
5
+ /*
6
+ What "Go back" would do right now, worked out in one place so that what the Updates screen says and what the server does
7
+ cannot differ. It is not offered while a switch is still proving itself (the site is a minute old and its record of what
8
+ it came from is not final), or when there is no earlier version, or straight after a rollback (the earlier version is then
9
+ the one that was just left, and "going back" would be a confusing way to say "update again"). It restores the database
10
+ only when the update being undone changed data and its backup is still there.
11
+ */
12
+ export default siteRoot => {
13
+ const { previous, version } = getCurrent(siteRoot);
14
+ const source = previous?.id ? join(paths(siteRoot).releases, previous.id) : null;
15
+ const last = readState(siteRoot, 'last');
16
+ const plan = { available: false, reason: null, restoresData: false, previous, version, source, last };
17
+
18
+ if(readState(siteRoot, 'switch')){
19
+ plan.reason = 'The last switch is still being checked, which takes about a minute after the restart. Try again shortly.';
20
+ return plan;
21
+ }
22
+ if(!source || !existsSync(join(source, 'node_modules'))){
23
+ plan.reason = 'There is no earlier version to go back to';
24
+ return plan;
25
+ }
26
+ if(last?.kind === 'rollback'){
27
+ plan.reason = 'The site has just gone back, so there is nothing newer to go back from. To move forward again, update it.';
28
+ return plan;
29
+ }
30
+
31
+ plan.available = true;
32
+ plan.restoresData = Boolean(last?.ok && last.breaking && last.to === version && last.dbBackup && existsSync(last.dbBackup));
33
+ return plan;
34
+ };
@@ -101,7 +101,7 @@ export default async ({ version = 'latest', extensions = [], siteRoot = process.
101
101
  return [{ code: 500, msg: `What this update would change could not be worked out: ${error.message}` }, null];
102
102
  }
103
103
 
104
- writeState(siteRoot, 'staged', { id: staged.id, dir: staged.dir, version: kempoVersion, kempoUpdate: Boolean(manifest), from: RUNNING_VERSION, packages: targets, plan, preparedAt: new Date().toISOString() });
104
+ writeState(siteRoot, 'staged', { id: staged.id, dir: staged.dir, basis: staged.basis, version: kempoVersion, kempoUpdate: Boolean(manifest), from: RUNNING_VERSION, packages: targets, plan, preparedAt: new Date().toISOString() });
105
105
  return [null, { version: kempoVersion, kempoUpdate: Boolean(manifest), packages: targets, plan }];
106
106
  } finally {
107
107
  preparing = false;
@@ -1,22 +1,25 @@
1
1
  import { existsSync } from 'fs';
2
2
  import { join } from 'path';
3
- import { getCurrent, paths, readState } from './siteLayout.js';
3
+ import goBackPlan from './goBackPlan.js';
4
+ import { readState } from './siteLayout.js';
4
5
 
5
6
  /*
6
7
  The part of the update status that only a site running from a Docker volume has: whether a version is staged and what
7
- switching to it would change, whether there is an earlier version to go back to, and how the last switch ended.
8
+ switching to it would change, whether going back is possible now and what it would do (see goBackPlan), whether a switch is still proving
9
+ itself, and how the last switch ended.
8
10
  */
9
11
  export default (siteRoot = process.env.KEMPO_SITE_ROOT) => {
10
12
  if(!siteRoot) return { mode: 'in-place' };
11
13
 
12
14
  const staged = readState(siteRoot, 'staged');
13
- const { previous } = getCurrent(siteRoot);
14
15
  const last = readState(siteRoot, 'last');
16
+ const back = goBackPlan(siteRoot);
15
17
  return {
16
18
  mode: 'release',
17
19
  staged: staged && existsSync(join(staged.dir, 'node_modules')) ? { version: staged.version, kempoUpdate: Boolean(staged.kempoUpdate), packages: staged.packages ?? [], plan: staged.plan, preparedAt: staged.preparedAt } : null,
18
- canGoBack: Boolean(previous?.id && existsSync(join(paths(siteRoot).releases, previous.id, 'node_modules'))),
19
- previousVersion: previous?.version ?? null,
20
+ canGoBack: back.available,
21
+ previousVersion: back.previous?.version ?? null,
22
+ goBack: { available: back.available, reason: back.reason, restoresData: back.restoresData, packages: back.last?.ok && back.last.to === back.version ? back.last.packages ?? [] : [] },
20
23
  switching: readState(siteRoot, 'switch')?.status ?? null,
21
24
  lastUpdate: last ? { ok: last.ok, from: last.from, to: last.to, packages: last.packages ?? [], reason: last.reason ?? null, breaking: Boolean(last.breaking), at: last.at } : null
22
25
  };
@@ -1,8 +1,7 @@
1
- import { existsSync } from 'fs';
2
- import { join } from 'path';
3
1
  import { RUNNING_VERSION } from './runtime.js';
2
+ import goBackPlan from './goBackPlan.js';
4
3
  import { restartMode, scheduleRestart } from './restart.js';
5
- import { getCurrent, paths, readState, requestSwitch } from './siteLayout.js';
4
+ import { requestSwitch } from './siteLayout.js';
6
5
 
7
6
  let going = false;
8
7
 
@@ -10,7 +9,8 @@ let going = false;
10
9
  Puts a site that runs from a Docker volume back on the version it had before the last update: the code, and the
11
10
  starter files the update replaced. If that update changed data, going back also restores the database from the backup
12
11
  taken before it, which loses whatever was entered since, so that needs `confirm.data`. Otherwise (the usual case: an
13
- update only added to the database) the earlier version runs on the database as it is and nothing is lost.
12
+ update only added to the database) the earlier version runs on the database as it is and nothing is lost. What it
13
+ would do, and whether it is allowed now, is goBackPlan, the same answer the Updates screen shows.
14
14
 
15
15
  Resolves to [error, { from, to, restart, restoresData }].
16
16
  */
@@ -21,19 +21,12 @@ export default async ({ confirm = {}, siteRoot = process.env.KEMPO_SITE_ROOT, re
21
21
  if(going){
22
22
  return [{ code: 409, msg: 'A switch is already under way' }, null];
23
23
  }
24
- if(readState(siteRoot, 'switch')){
25
- return [{ code: 409, msg: 'The last switch has not finished proving itself yet' }, null];
26
- }
27
24
 
28
- const { previous, version } = getCurrent(siteRoot);
29
- const source = previous?.id ? join(paths(siteRoot).releases, previous.id) : null;
30
- if(!source || !existsSync(join(source, 'node_modules'))){
31
- return [{ code: 409, msg: 'There is no earlier version to go back to' }, null];
25
+ const plan = goBackPlan(siteRoot);
26
+ if(!plan.available){
27
+ return [{ code: 409, msg: plan.reason }, null];
32
28
  }
33
-
34
- const last = readState(siteRoot, 'last');
35
- const restoresData = Boolean(last?.ok && last.breaking && last.to === version && last.dbBackup && existsSync(last.dbBackup));
36
- if(restoresData && !confirm.data){
29
+ if(plan.restoresData && !confirm.data){
37
30
  return [{ code: 409, msg: 'Going back restores the database from before the update and loses what was entered since', details: { confirm: 'data' } }, null];
38
31
  }
39
32
 
@@ -41,15 +34,15 @@ export default async ({ confirm = {}, siteRoot = process.env.KEMPO_SITE_ROOT, re
41
34
  try {
42
35
  requestSwitch({
43
36
  siteRoot,
44
- id: previous.id,
45
- version: previous.version,
46
- source,
37
+ id: plan.previous.id,
38
+ version: plan.previous.version,
39
+ source: plan.source,
47
40
  kind: 'rollback',
48
- filesBackup: last?.ok && last.to === version ? last.filesBackup : null,
49
- dbBackup: restoresData ? last.dbBackup : null
41
+ filesBackup: plan.last?.ok && plan.last.to === plan.version ? plan.last.filesBackup : null,
42
+ dbBackup: plan.restoresData ? plan.last.dbBackup : null
50
43
  });
51
44
  restart();
52
- return [null, { from: RUNNING_VERSION, to: previous.version, restart: restartMode(), restoresData }];
45
+ return [null, { from: RUNNING_VERSION, to: plan.previous.version, restart: restartMode(), restoresData: plan.restoresData }];
53
46
  } finally {
54
47
  going = false;
55
48
  }
@@ -1,3 +1,4 @@
1
+ import { createHash } from 'crypto';
1
2
  import { cpSync, existsSync, mkdirSync, readFileSync, readdirSync, renameSync, rmSync, writeFileSync } from 'fs';
2
3
  import { dirname, join } from 'path';
3
4
 
@@ -81,9 +82,23 @@ export const seedSite = ({ siteRoot, seed }) => {
81
82
 
82
83
  export const getCurrent = siteRoot => readState(siteRoot, 'current') ?? { id: null, version: versionIn(paths(siteRoot).app), previous: null };
83
84
 
85
+ /*
86
+ A fingerprint of the code the site is running: which release it is, and the manifests that say what is installed. A
87
+ staged copy is made from this code, so it is only good while the fingerprint is the same. If the site's code changes in
88
+ between (another switch, an extension installed from the admin), switching to the copy would silently undo that change.
89
+ */
90
+ export const basisOf = siteRoot => {
91
+ const { app } = paths(siteRoot);
92
+ const hash = createHash('sha256').update(String(getCurrent(siteRoot).id));
93
+ for(const name of MANIFESTS){
94
+ if(existsSync(join(app, name))) hash.update(readFileSync(join(app, name)));
95
+ }
96
+ return hash.digest('hex');
97
+ };
98
+
84
99
  /*
85
100
  Staging a new version: a copy of the code the site has now, which the caller then installs into. The running site is
86
- not touched. Only one is kept: staging again replaces the one before.
101
+ not touched. Only one is kept: staging again replaces the one before. `basis` is the fingerprint it was made from.
87
102
  */
88
103
  export const stage = ({ siteRoot, version }) => {
89
104
  const { app, staging } = paths(siteRoot);
@@ -93,7 +108,7 @@ export const stage = ({ siteRoot, version }) => {
93
108
  mkdirSync(dir, { recursive: true });
94
109
  copyManifests(app, dir);
95
110
  cpSync(join(app, 'node_modules'), join(dir, 'node_modules'), { recursive: true, verbatimSymlinks: true });
96
- return { id, dir };
111
+ return { id, dir, basis: basisOf(siteRoot) };
97
112
  };
98
113
 
99
114
  /*