kempo 4.8.0 → 4.9.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +7 -3
- package/bin/cli.js +23 -1
- package/dist/admin/components/Updates.js +117 -0
- package/dist/admin/components/Updates.js.map +1 -0
- package/dist/admin/nav.fragment.html +6 -0
- package/dist/admin/updates/index.page.html +14 -0
- package/dist/kempo/api/updates/GET.js +2 -0
- package/dist/kempo/api/updates/GET.js.map +1 -0
- package/dist/kempo/api/updates/apply/POST.js +2 -0
- package/dist/kempo/api/updates/apply/POST.js.map +1 -0
- package/dist/kempo/api/updates/check/POST.js +2 -0
- package/dist/kempo/api/updates/check/POST.js.map +1 -0
- package/dist/kempo/api/updates/discard/POST.js +2 -0
- package/dist/kempo/api/updates/discard/POST.js.map +1 -0
- package/dist/kempo/api/updates/prepare/POST.js +2 -0
- package/dist/kempo/api/updates/prepare/POST.js.map +1 -0
- package/dist/kempo/api/updates/rollback/POST.js +2 -0
- package/dist/kempo/api/updates/rollback/POST.js.map +1 -0
- package/dist/kempo/fetch.js +1 -1
- package/dist/kempo/fetch.js.map +1 -1
- package/dist/kempo/sdk.js +1 -1
- package/dist/kempo/sdk.js.map +1 -1
- package/docker/.dockerignore +9 -0
- package/docker/Dockerfile +25 -0
- package/docker/docker-compose.prod.yml +39 -0
- package/docker/entrypoint.mjs +96 -0
- package/middleware/kempo.js +53 -3
- package/package.json +3 -1
- package/server/db/schema.js +12 -0
- package/server/db/upgrades/README.md +20 -0
- package/server/sdk.js +3 -0
- package/server/utils/extensions/checkExtensionUpdate.js +9 -36
- package/server/utils/extensions/reconcileExtensions.js +90 -0
- package/server/utils/extensions/updateExtension.js +14 -153
- package/server/utils/extensions/upgradeExtension.js +117 -0
- package/server/utils/extensions/writeSiteFile.js +66 -0
- package/server/utils/settings/systemSettings.js +1 -0
- package/server/utils/setup/runUpgrades.js +70 -0
- package/server/utils/setup/seedDatabase.js +1 -1
- package/server/utils/setup/seedIfNew.js +21 -0
- package/server/utils/setup/syncCoreSchema.js +130 -0
- package/server/utils/setup/systemPermissions.js +2 -0
- package/server/utils/updates/applyStagedUpdate.js +95 -0
- package/server/utils/updates/applyUpdate.js +76 -0
- package/server/utils/updates/backupDatabase.js +35 -0
- package/server/utils/updates/discardUpdate.js +11 -0
- package/server/utils/updates/extensionTargets.js +101 -0
- package/server/utils/updates/fetchManifest.js +26 -0
- package/server/utils/updates/getExtensionUpdates.js +70 -0
- package/server/utils/updates/getInstallInfo.js +25 -0
- package/server/utils/updates/getUpdateStatus.js +57 -0
- package/server/utils/updates/helpers.js +30 -0
- package/server/utils/updates/notifySchemaAttention.js +35 -0
- package/server/utils/updates/npm.js +41 -0
- package/server/utils/updates/prepareUpdate.js +109 -0
- package/server/utils/updates/releaseStatus.js +23 -0
- package/server/utils/updates/restart.js +64 -0
- package/server/utils/updates/rollbackUpdate.js +56 -0
- package/server/utils/updates/runUpdateCheck.js +52 -0
- package/server/utils/updates/runtime.js +15 -0
- package/server/utils/updates/siteLayout.js +200 -0
- package/server/utils/updates/starterFiles.js +118 -0
package/dist/kempo/sdk.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"src\\kempo\\sdk.js","names":["get","post","put","patch","del","API_BASE","register","async","email","password","name","login","logout","getSession","forgotPassword","resetPassword","token","logoutAll","newPassword","changePassword","currentPassword","verifyEmail","currentUserHasPermission","permission","currentUserHasAllPermissions","permissions","currentUserHasSomePermissions","getAllCurrentUserPermissions","userHasPermission","userid","userHasAllPermissions","userHasSomePermissions","getAllUserPermissions","getUsers","limit","offset","searchUsers","q","inGroup","notInGroup","createUser","emailVerified","deleteUsers","ids","updateUser","id","createdAt","getUser","getUserSessions","deleteUserSession","sessionToken","deleteExpiredUserSessions","getUserGroups","addUserToGroup","groupName","removeUserFromGroup","listGroups","owner","createGroup","description","updateGroup","newName","deleteGroups","names","getGroup","encodeURIComponent","getGroupMembers","addMemberToGroup","userId","removeMemberFromGroup","getGroupPermissions","addPermissionToGroup","permissionName","removePermissionFromGroup","listPermissions","createPermissions","updatePermission","deletePermissions","getSetting","listSettings","setSetting","data","deleteSetting","listEmails","status","type","search","getEmail","retryEmail","sendTestEmail","to","listPages","showHidden","rescanPages","listTemplates","listDirectories","getPage","file","createPage","directory","template","updatePage","title","author","contents","extraMetadata","deletePages","files","disablePage","enablePage","movePage","newFile","searchPagesByMetadata","query","JSON","stringify","setPageLocked","locked","getTemplate","createTemplate","copyFrom","updateTemplate","markup","deleteTemplates","listEmailTemplates","getEmailTemplate","saveEmailTemplate","source","resetEmailTemplate","disableTemplate","enableTemplate","moveTemplate","setTemplateLocked","listFragments","getFragment","createFragment","updateFragment","deleteFragments","moveFragment","disableFragment","enableFragment","setFragmentLocked","listGlobalContent","getGlobalContent","createGlobalContent","location","priority","updateGlobalContent","deleteGlobalContent","disableGlobalContent","enableGlobalContent","setGlobalContentLocked","listMenus","saveMenu","deleteMenu","assignMenuLocation","menuId","saveMenuItem","navItem","label","href","icon","newTab","deleteMenuItems","setMenuItemEnabled","enabled","reorderMenuItems","adoptMenuItem","menuName","listExtensions","listAvailableExtensions","listKnownExtensions","sort","getKnownExtension","rateExtension","rating","getDashboardWidgets","getNotifications","unreadOnly","getUnreadNotificationCount","markNotificationRead","markNotificationHandled","markAllNotificationsRead","dismissNotification","listRealtimeConnections","installExtension","withDependencies","uninstallExtension","purgeData","cascade","enableExtension","getExtensionRequirements","disableExtension","getExtensionDependents","includeDisabled","undefined","listAdminGlobalContent","getAdminGlobalContent","createAdminGlobalContent","updateAdminGlobalContent","deleteAdminGlobalContent","enableAdminGlobalContent","disableAdminGlobalContent"],"sources":["0"],"sourcesContent":["import { get, post, put, patch, del } from './fetch.js';\nconst API_BASE = '/kempo/api';\n\nexport const register = async ({ email, password, name }) =>\n post(`${API_BASE}/auth/register/email`, { email, password, name });\n\nexport const login = async ({ email, password }) =>\n post(`${API_BASE}/auth/login/email`, { email, password });\n\nexport const logout = async () => post(`${API_BASE}/auth/logout`, {});\n\nexport const getSession = async () => get(`${API_BASE}/auth/session`);\n\nexport const forgotPassword = async ({ email }) =>\n post(`${API_BASE}/forgot-password`, { email });\n\nexport const resetPassword = async ({ token, password, logoutAll = false }) =>\n post(`${API_BASE}/auth/reset-password`, { token, newPassword: password, logoutAll });\n \nexport const changePassword = async ({ currentPassword, newPassword, logoutAll }) => \n post(`${API_BASE}/auth/change-password`, { currentPassword, newPassword, logoutAll });\n\nexport const verifyEmail = async ({ token }) =>\n post(`${API_BASE}/auth/verify-email`, { token });\n\nexport const currentUserHasPermission = async ({ permission }) =>\n get(`${API_BASE}/user/current/permissions`, { permission });\n\nexport const currentUserHasAllPermissions = async ({ permissions }) =>\n get(`${API_BASE}/user/current/permissions/all`, { permissions });\n\nexport const currentUserHasSomePermissions = async ({ permissions }) =>\n get(`${API_BASE}/user/current/permissions/some`, { permissions });\n\nexport const getAllCurrentUserPermissions = async () =>\n get(`${API_BASE}/user/current/permissions/list`);\n\nexport const userHasPermission = async ({ userid, permission }) =>\n get(`${API_BASE}/user/${userid}/permissions`, { permission });\n\nexport const userHasAllPermissions = async ({ userid, permissions }) =>\n get(`${API_BASE}/user/${userid}/permissions/all`, { permissions });\n\nexport const userHasSomePermissions = async ({ userid, permissions }) =>\n get(`${API_BASE}/user/${userid}/permissions/some`, { permissions });\n\nexport const getAllUserPermissions = async ({ userid }) =>\n get(`${API_BASE}/user/${userid}/permissions/list`);\n\nexport const getUsers = async ({ limit, offset } = {}) =>\n get(`${API_BASE}/user`, { limit, offset });\n\nexport const searchUsers = async ({ q, limit, offset, inGroup, notInGroup } = {}) =>\n get(`${API_BASE}/user/search`, { q, limit, offset, inGroup, notInGroup });\n\nexport const createUser = async ({ name, email, password, emailVerified }) =>\n post(`${API_BASE}/user/create`, { name, email, password, emailVerified });\n\nexport const deleteUsers = async (ids) =>\n del(`${API_BASE}/user`, { ids });\n\nexport const updateUser = async ({ id, name, email, emailVerified, createdAt }) =>\n patch(`${API_BASE}/user`, { id, name, email, emailVerified, createdAt });\n\nexport const getUser = async (userid) =>\n get(`${API_BASE}/user/${userid}`);\n\nexport const getUserSessions = async (userid, { limit, offset } = {}) =>\n get(`${API_BASE}/user/${userid}/sessions`, { limit, offset });\n\nexport const deleteUserSession = async (userid, sessionToken) =>\n del(`${API_BASE}/user/${userid}/sessions`, { sessionToken });\n\nexport const deleteExpiredUserSessions = async (userid) =>\n del(`${API_BASE}/user/${userid}/sessions/expired`);\n\nexport const getUserGroups = async (userid, { limit, offset } = {}) =>\n get(`${API_BASE}/user/${userid}/groups`, { limit, offset });\n\nexport const addUserToGroup = async (userid, groupName) =>\n post(`${API_BASE}/user/${userid}/groups`, { groupName });\n\nexport const removeUserFromGroup = async (userid, groupName) =>\n del(`${API_BASE}/user/${userid}/groups`, { groupName });\n\nexport const listGroups = async ({ limit, offset, owner } = {}) =>\n get(`${API_BASE}/groups`, { limit, offset, owner });\n\nexport const createGroup = async ({ name, description }) =>\n post(`${API_BASE}/groups`, { name, description });\n\nexport const updateGroup = async ({ name, newName, description }) =>\n patch(`${API_BASE}/groups`, { name, newName, description });\n\nexport const deleteGroups = async (names) =>\n del(`${API_BASE}/groups`, { names });\n\nexport const getGroup = async (name) =>\n get(`${API_BASE}/groups/${encodeURIComponent(name)}`);\n\nexport const getGroupMembers = async (name, { limit, offset } = {}) =>\n get(`${API_BASE}/groups/${encodeURIComponent(name)}/members`, { limit, offset });\n\nexport const addMemberToGroup = async (name, userId) =>\n post(`${API_BASE}/groups/${encodeURIComponent(name)}/members`, { userId });\n\nexport const removeMemberFromGroup = async (name, userId) =>\n del(`${API_BASE}/groups/${encodeURIComponent(name)}/members`, { userId });\n\nexport const getGroupPermissions = async (name) =>\n get(`${API_BASE}/groups/${encodeURIComponent(name)}/permissions`);\n\nexport const addPermissionToGroup = async (name, permissionName) =>\n post(`${API_BASE}/groups/${encodeURIComponent(name)}/permissions`, { permissionName });\n\nexport const removePermissionFromGroup = async (name, permissionName) =>\n del(`${API_BASE}/groups/${encodeURIComponent(name)}/permissions`, { permissionName });\n\nexport const listPermissions = async ({ limit, offset, owner } = {}) =>\n get(`${API_BASE}/permissions`, { limit, offset, owner });\n\nexport const createPermissions = async (permissions) =>\n post(`${API_BASE}/permissions`, { permissions });\n\nexport const updatePermission = async ({ name, description }) =>\n patch(`${API_BASE}/permissions`, { name, description });\n\nexport const deletePermissions = async (names) =>\n del(`${API_BASE}/permissions`, { names });\n\nexport const getSetting = async (owner, name) =>\n get(`${API_BASE}/settings/${encodeURIComponent(owner)}/${encodeURIComponent(name)}`);\n\nexport const listSettings = async ({ owner, limit, offset } = {}) =>\n get(`${API_BASE}/settings/${encodeURIComponent(owner)}`, { limit, offset });\n\nexport const setSetting = async (owner, name, data) =>\n post(`${API_BASE}/settings/${encodeURIComponent(owner)}/${encodeURIComponent(name)}`, data);\n\nexport const deleteSetting = async (owner, name) =>\n del(`${API_BASE}/settings/${encodeURIComponent(owner)}/${encodeURIComponent(name)}`);\n\n/*\n Emails\n*/\nexport const listEmails = async ({ status, type, search, limit, offset } = {}) =>\n get(`${API_BASE}/emails`, { status, type, search, limit, offset });\n\nexport const getEmail = async (id) =>\n get(`${API_BASE}/emails/${encodeURIComponent(id)}`);\n\nexport const retryEmail = async (id) =>\n post(`${API_BASE}/emails/${encodeURIComponent(id)}/retry`, {});\n\nexport const sendTestEmail = async (to) =>\n post(`${API_BASE}/emails/test`, { to });\n\n/*\n Pages\n*/\n\nexport const listPages = async ({ owner, showHidden, offset, limit } = {}) =>\n get(`${API_BASE}/pages`, { owner, showHidden, offset, limit });\n\nexport const rescanPages = async () =>\n post(`${API_BASE}/pages/rescan`, {});\n\nexport const listTemplates = async () =>\n get(`${API_BASE}/templates`);\n\nexport const listDirectories = async () =>\n get(`${API_BASE}/pages/directories`);\n\nexport const getPage = async (file) =>\n get(`${API_BASE}/pages/file`, { file });\n\nexport const createPage = async ({ directory, name, template }) =>\n post(`${API_BASE}/pages`, { directory, name, template });\n\nexport const updatePage = async ({ file, name, title, description, author, template, contents, extraMetadata }) =>\n put(`${API_BASE}/pages/file`, { file, name, title, description, author, template, contents, extraMetadata });\n\nexport const deletePages = async (files) =>\n del(`${API_BASE}/pages`, { files });\n\nexport const disablePage = async (file) =>\n put(`${API_BASE}/pages/disable`, { file });\n\nexport const enablePage = async (file) =>\n put(`${API_BASE}/pages/enable`, { file });\n\nexport const movePage = async ({ file, newFile }) =>\n patch(`${API_BASE}/pages/file`, { file, newFile });\n\nexport const searchPagesByMetadata = async (query) =>\n get(`${API_BASE}/pages/search`, { query: JSON.stringify(query) });\n\nexport const setPageLocked = async ({ file, locked }) =>\n put(`${API_BASE}/pages/lock`, { file, locked });\n\n/*\n Templates\n*/\n\nexport const getTemplate = async (file) =>\n get(`${API_BASE}/templates/file`, { file });\n\nexport const createTemplate = async ({ directory, name, copyFrom }) =>\n post(`${API_BASE}/templates`, { directory, name, copyFrom });\n\nexport const updateTemplate = async ({ file, name, author, markup }) =>\n put(`${API_BASE}/templates/file`, { file, name, author, markup });\n\nexport const deleteTemplates = async (files) =>\n del(`${API_BASE}/templates`, { files });\n\nexport const listEmailTemplates = async (owner) =>\n get(`${API_BASE}/email-templates`, owner ? { owner } : {});\n\nexport const getEmailTemplate = async (template) =>\n get(`${API_BASE}/email-templates/file`, { template });\n\nexport const saveEmailTemplate = async ({ template, source }) =>\n put(`${API_BASE}/email-templates/file`, { template, source });\n\nexport const resetEmailTemplate = async (template) =>\n del(`${API_BASE}/email-templates/file`, { template });\n\nexport const disableTemplate = async (file) =>\n put(`${API_BASE}/templates/disable`, { file });\n\nexport const enableTemplate = async (file) =>\n put(`${API_BASE}/templates/enable`, { file });\n\nexport const moveTemplate = async ({ file, newFile }) =>\n patch(`${API_BASE}/templates/file`, { file, newFile });\n\nexport const setTemplateLocked = async ({ file, locked }) =>\n put(`${API_BASE}/templates/lock`, { file, locked });\n\n/*\n Fragments\n*/\n\nexport const listFragments = async () =>\n get(`${API_BASE}/fragments`);\n\nexport const getFragment = async (file) =>\n get(`${API_BASE}/fragments/file`, { file });\n\nexport const createFragment = async ({ directory, name }) =>\n post(`${API_BASE}/fragments`, { directory, name });\n\nexport const updateFragment = async ({ file, author, markup }) =>\n put(`${API_BASE}/fragments/file`, { file, author, markup });\n\nexport const deleteFragments = async (files) =>\n del(`${API_BASE}/fragments`, { files });\n\nexport const moveFragment = async ({ file, newFile }) =>\n patch(`${API_BASE}/fragments/file`, { file, newFile });\n\nexport const disableFragment = async (file) =>\n put(`${API_BASE}/fragments/disable`, { file });\n\nexport const enableFragment = async (file) =>\n put(`${API_BASE}/fragments/enable`, { file });\n\nexport const setFragmentLocked = async ({ file, locked }) =>\n put(`${API_BASE}/fragments/lock`, { file, locked });\n\n/*\n Global Content\n*/\n\nexport const listGlobalContent = async () =>\n get(`${API_BASE}/globals`);\n\nexport const getGlobalContent = async (id) =>\n get(`${API_BASE}/globals/entry`, { id });\n\nexport const createGlobalContent = async ({ name, location, priority }) =>\n post(`${API_BASE}/globals`, { name, location, priority });\n\nexport const updateGlobalContent = async ({ id, name, location, priority, markup }) =>\n put(`${API_BASE}/globals/entry`, { id, name, location, priority, markup });\n\nexport const deleteGlobalContent = async (ids) =>\n del(`${API_BASE}/globals`, { ids });\n\nexport const disableGlobalContent = async (id) =>\n put(`${API_BASE}/globals/disable`, { id });\n\nexport const enableGlobalContent = async (id) =>\n put(`${API_BASE}/globals/enable`, { id });\n\nexport const setGlobalContentLocked = async ({ id, locked }) =>\n put(`${API_BASE}/globals/lock`, { id, locked });\n\n/*\n Menus\n*/\n\nexport const listMenus = async () =>\n get(`${API_BASE}/menus`);\n\nexport const saveMenu = async ({ id, name }) =>\n post(`${API_BASE}/menus`, { id, name });\n\nexport const deleteMenu = async (id) =>\n del(`${API_BASE}/menus`, { id });\n\nexport const assignMenuLocation = async ({ location, menuId }) =>\n put(`${API_BASE}/menus/location`, { location, menuId });\n\nexport const saveMenuItem = async ({ id, menuId, location, navItem, label, href, icon, newTab }) =>\n post(`${API_BASE}/menus/items`, { id, menuId, location, navItem, label, href, icon, newTab });\n\nexport const deleteMenuItems = async (ids) =>\n del(`${API_BASE}/menus/items`, { ids });\n\nexport const setMenuItemEnabled = async ({ id, enabled }) =>\n put(`${API_BASE}/menus/items/enabled`, { id, enabled });\n\nexport const reorderMenuItems = async ({ menuId, ids }) =>\n put(`${API_BASE}/menus/items/order`, { menuId, ids });\n\nexport const adoptMenuItem = async ({ id, menuId, menuName }) =>\n put(`${API_BASE}/menus/adopt`, { id, menuId, menuName });\n\n/*\n Extensions\n*/\n\nexport const listExtensions = async ({ limit, offset } = {}) =>\n get(`${API_BASE}/extensions`, { limit, offset });\n\nexport const listAvailableExtensions = async () =>\n get(`${API_BASE}/extensions/available`);\n\nexport const listKnownExtensions = async ({ search, sort, limit, offset } = {}) =>\n get(`${API_BASE}/extensions/known`, { search, sort, limit, offset });\n\nexport const getKnownExtension = async (name) =>\n get(`${API_BASE}/extensions/known`, { name });\n\nexport const rateExtension = async (name, rating) =>\n put(`${API_BASE}/extensions/rating`, { name, rating });\n\n/*\n Dashboard\n*/\n\nexport const getDashboardWidgets = async () =>\n get(`${API_BASE}/dashboard/widgets`);\n\n/*\n Notifications\n*/\n\nexport const getNotifications = async ({ unreadOnly = false, limit, offset } = {}) =>\n get(`${API_BASE}/notifications`, { unreadOnly, limit, offset });\n\nexport const getUnreadNotificationCount = async () =>\n get(`${API_BASE}/notifications/count`);\n\nexport const markNotificationRead = async (id) =>\n post(`${API_BASE}/notifications/${encodeURIComponent(id)}/read`, {});\n\nexport const markNotificationHandled = async (id) =>\n post(`${API_BASE}/notifications/${encodeURIComponent(id)}/handled`, {});\n\nexport const markAllNotificationsRead = async () =>\n post(`${API_BASE}/notifications/read-all`, {});\n\nexport const dismissNotification = async (id) =>\n del(`${API_BASE}/notifications/${encodeURIComponent(id)}`);\n\nexport const listRealtimeConnections = async () =>\n get(`${API_BASE}/realtime/connections`);\n\nexport const installExtension = async (name, { withDependencies = false } = {}) =>\n post(`${API_BASE}/extensions`, { name, withDependencies });\n\nexport const uninstallExtension = async (name, purgeData = false, { cascade = false } = {}) =>\n del(`${API_BASE}/extensions`, { name, purgeData, cascade });\n\nexport const enableExtension = async (name, { cascade = false } = {}) =>\n post(`${API_BASE}/extensions/${encodeURIComponent(name)}/enable`, { cascade });\n\nexport const getExtensionRequirements = async (name) =>\n get(`${API_BASE}/extensions/${encodeURIComponent(name)}/requirements`);\n\nexport const disableExtension = async (name, { cascade = false } = {}) =>\n post(`${API_BASE}/extensions/${encodeURIComponent(name)}/disable`, { cascade });\n\nexport const getExtensionDependents = async (name, { includeDisabled = false } = {}) =>\n get(`${API_BASE}/extensions/${encodeURIComponent(name)}/dependents`, { includeDisabled: includeDisabled ? 'true' : undefined });\n\n/*\n Admin Global Content\n*/\n\nexport const listAdminGlobalContent = async () =>\n get(`${API_BASE}/admin-globals`);\n\nexport const getAdminGlobalContent = async (id) =>\n get(`${API_BASE}/admin-globals/${encodeURIComponent(id)}`);\n\nexport const createAdminGlobalContent = async ({ name, location, priority, owner, markup }) =>\n post(`${API_BASE}/admin-globals`, { name, location, priority, owner, markup });\n\nexport const updateAdminGlobalContent = async (id, { name, location, priority, markup }) =>\n put(`${API_BASE}/admin-globals/${encodeURIComponent(id)}`, { name, location, priority, markup });\n\nexport const deleteAdminGlobalContent = async (ids) =>\n del(`${API_BASE}/admin-globals`, { ids });\n\nexport const enableAdminGlobalContent = async (id) =>\n put(`${API_BASE}/admin-globals/${encodeURIComponent(id)}/enable`, {});\n\nexport const disableAdminGlobalContent = async (id) =>\n put(`${API_BASE}/admin-globals/${encodeURIComponent(id)}/disable`, {});\n\n"],"mappings":"cAASA,UAAKC,SAAMC,WAAKC,SAAOC,MAAW,aAC3C,MAAMC,EAAW,oBAEV,MAAMC,SAAWC,OAASC,QAAOC,WAAUC,UAChDT,EAAK,GAAGI,wBAAgC,CAAEG,QAAOC,WAAUC,gBAEtD,MAAMC,MAAQJ,OAASC,QAAOC,cACnCR,EAAK,GAAGI,qBAA6B,CAAEG,QAAOC,oBAEzC,MAAMG,OAASL,SAAYN,EAAK,GAAGI,gBAAwB,CAAC,UAE5D,MAAMQ,WAAaN,SAAYP,EAAI,GAAGK,yBAEtC,MAAMS,eAAiBP,OAASC,WACrCP,EAAK,GAAGI,oBAA4B,CAAEG,iBAEjC,MAAMO,cAAgBR,OAASS,QAAOP,WAAUQ,aAAY,KACjEhB,EAAK,GAAGI,wBAAgC,CAAEW,QAAOE,YAAaT,EAAUQ,qBAEnE,MAAME,eAAiBZ,OAASa,kBAAiBF,cAAaD,eACnEhB,EAAK,GAAGI,yBAAiC,CAAEe,kBAAiBF,cAAaD,qBAEpE,MAAMI,YAAcd,OAASS,WAClCf,EAAK,GAAGI,sBAA8B,CAAEW,iBAEnC,MAAMM,yBAA2Bf,OAASgB,gBAC/CvB,EAAI,GAAGK,6BAAqC,CAAEkB,sBAEzC,MAAMC,6BAA+BjB,OAASkB,iBACnDzB,EAAI,GAAGK,iCAAyC,CAAEoB,uBAE7C,MAAMC,8BAAgCnB,OAASkB,iBACpDzB,EAAI,GAAGK,kCAA0C,CAAEoB,uBAE9C,MAAME,6BAA+BpB,SAC1CP,EAAI,GAAGK,0CAEF,MAAMuB,kBAAoBrB,OAASsB,SAAQN,gBAChDvB,EAAI,GAAGK,UAAiBwB,gBAAsB,CAAEN,sBAE3C,MAAMO,sBAAwBvB,OAASsB,SAAQJ,iBACpDzB,EAAI,GAAGK,UAAiBwB,oBAA0B,CAAEJ,uBAE/C,MAAMM,uBAAyBxB,OAASsB,SAAQJ,iBACrDzB,EAAI,GAAGK,UAAiBwB,qBAA2B,CAAEJ,uBAEhD,MAAMO,sBAAwBzB,OAASsB,YAC5C7B,EAAI,GAAGK,UAAiBwB,6BAEnB,MAAMI,SAAW1B,OAAS2B,QAAOC,UAAW,CAAC,IAClDnC,EAAI,GAAGK,SAAiB,CAAE6B,QAAOC,kBAE5B,MAAMC,YAAc7B,OAAS8B,IAAGH,QAAOC,SAAQG,UAASC,cAAe,CAAC,IAC7EvC,EAAI,GAAGK,gBAAwB,CAAEgC,IAAGH,QAAOC,SAAQG,UAASC,sBAEvD,MAAMC,WAAajC,OAASG,OAAMF,QAAOC,WAAUgC,mBACxDxC,EAAK,GAAGI,gBAAwB,CAAEK,OAAMF,QAAOC,WAAUgC,yBAEpD,MAAMC,YAAcnC,MAAOoC,GAChCvC,EAAI,GAAGC,SAAiB,CAAEsC,eAErB,MAAMC,WAAarC,OAASsC,KAAInC,OAAMF,QAAOiC,gBAAeK,eACjE3C,EAAM,GAAGE,SAAiB,CAAEwC,KAAInC,OAAMF,QAAOiC,gBAAeK,qBAEvD,MAAMC,QAAUxC,MAAOsB,GAC5B7B,EAAI,GAAGK,UAAiBwB,YAEnB,MAAMmB,gBAAkBzC,MAAOsB,GAAUK,QAAOC,UAAW,CAAC,IACjEnC,EAAI,GAAGK,UAAiBwB,aAAmB,CAAEK,QAAOC,kBAE/C,MAAMc,kBAAoB1C,MAAOsB,EAAQqB,IAC9C9C,EAAI,GAAGC,UAAiBwB,aAAmB,CAAEqB,wBAExC,MAAMC,0BAA4B5C,MAAOsB,GAC9CzB,EAAI,GAAGC,UAAiBwB,6BAEnB,MAAMuB,cAAgB7C,MAAOsB,GAAUK,QAAOC,UAAW,CAAC,IAC/DnC,EAAI,GAAGK,UAAiBwB,WAAiB,CAAEK,QAAOC,kBAE7C,MAAMkB,eAAiB9C,MAAOsB,EAAQyB,IAC3CrD,EAAK,GAAGI,UAAiBwB,WAAiB,CAAEyB,qBAEvC,MAAMC,oBAAsBhD,MAAOsB,EAAQyB,IAChDlD,EAAI,GAAGC,UAAiBwB,WAAiB,CAAEyB,qBAEtC,MAAME,WAAajD,OAAS2B,QAAOC,SAAQsB,SAAU,CAAC,IAC3DzD,EAAI,GAAGK,WAAmB,CAAE6B,QAAOC,SAAQsB,iBAEtC,MAAMC,YAAcnD,OAASG,OAAMiD,iBACxC1D,EAAK,GAAGI,WAAmB,CAAEK,OAAMiD,uBAE9B,MAAMC,YAAcrD,OAASG,OAAMmD,UAASF,iBACjDxD,EAAM,GAAGE,WAAmB,CAAEK,OAAMmD,UAASF,uBAExC,MAAMG,aAAevD,MAAOwD,GACjC3D,EAAI,GAAGC,WAAmB,CAAE0D,iBAEvB,MAAMC,SAAWzD,MAAOG,GAC7BV,EAAI,GAAGK,YAAmB4D,mBAAmBvD,aAExC,MAAMwD,gBAAkB3D,MAAOG,GAAQwB,QAAOC,UAAW,CAAC,IAC/DnC,EAAI,GAAGK,YAAmB4D,mBAAmBvD,aAAiB,CAAEwB,QAAOC,kBAElE,MAAMgC,iBAAmB5D,MAAOG,EAAM0D,IAC3CnE,EAAK,GAAGI,YAAmB4D,mBAAmBvD,aAAiB,CAAE0D,kBAE5D,MAAMC,sBAAwB9D,MAAOG,EAAM0D,IAChDhE,EAAI,GAAGC,YAAmB4D,mBAAmBvD,aAAiB,CAAE0D,kBAE3D,MAAME,oBAAsB/D,MAAOG,GACxCV,EAAI,GAAGK,YAAmB4D,mBAAmBvD,yBAExC,MAAM6D,qBAAuBhE,MAAOG,EAAM8D,IAC/CvE,EAAK,GAAGI,YAAmB4D,mBAAmBvD,iBAAqB,CAAE8D,0BAEhE,MAAMC,0BAA4BlE,MAAOG,EAAM8D,IACpDpE,EAAI,GAAGC,YAAmB4D,mBAAmBvD,iBAAqB,CAAE8D,0BAE/D,MAAME,gBAAkBnE,OAAS2B,QAAOC,SAAQsB,SAAU,CAAC,IAChEzD,EAAI,GAAGK,gBAAwB,CAAE6B,QAAOC,SAAQsB,iBAE3C,MAAMkB,kBAAoBpE,MAAOkB,GACtCxB,EAAK,GAAGI,gBAAwB,CAAEoB,uBAE7B,MAAMmD,iBAAmBrE,OAASG,OAAMiD,iBAC7CxD,EAAM,GAAGE,gBAAwB,CAAEK,OAAMiD,uBAEpC,MAAMkB,kBAAoBtE,MAAOwD,GACtC3D,EAAI,GAAGC,gBAAwB,CAAE0D,iBAE5B,MAAMe,WAAavE,MAAOkD,EAAO/C,IACtCV,EAAI,GAAGK,cAAqB4D,mBAAmBR,MAAUQ,mBAAmBvD,aAEvE,MAAMqE,aAAexE,OAASkD,QAAOvB,QAAOC,UAAW,CAAC,IAC7DnC,EAAI,GAAGK,cAAqB4D,mBAAmBR,KAAU,CAAEvB,QAAOC,kBAE7D,MAAM6C,WAAazE,MAAOkD,EAAO/C,EAAMuE,IAC5ChF,EAAK,GAAGI,cAAqB4D,mBAAmBR,MAAUQ,mBAAmBvD,KAASuE,UAEjF,MAAMC,cAAgB3E,MAAOkD,EAAO/C,IACzCN,EAAI,GAAGC,cAAqB4D,mBAAmBR,MAAUQ,mBAAmBvD,aAKvE,MAAMyE,WAAa5E,OAAS6E,SAAQC,OAAMC,SAAQpD,QAAOC,UAAW,CAAC,IAC1EnC,EAAI,GAAGK,WAAmB,CAAE+E,SAAQC,OAAMC,SAAQpD,QAAOC,kBAEpD,MAAMoD,SAAWhF,MAAOsC,GAC7B7C,EAAI,GAAGK,YAAmB4D,mBAAmBpB,aAExC,MAAM2C,WAAajF,MAAOsC,GAC/B5C,EAAK,GAAGI,YAAmB4D,mBAAmBpB,WAAa,CAAC,UAEvD,MAAM4C,cAAgBlF,MAAOmF,GAClCzF,EAAK,GAAGI,gBAAwB,CAAEqF,cAM7B,MAAMC,UAAYpF,OAASkD,QAAOmC,aAAYzD,SAAQD,SAAU,CAAC,IACtElC,EAAI,GAAGK,UAAkB,CAAEoD,QAAOmC,aAAYzD,SAAQD,iBAEjD,MAAM2D,YAActF,SACzBN,EAAK,GAAGI,iBAAyB,CAAC,UAE7B,MAAMyF,cAAgBvF,SAC3BP,EAAI,GAAGK,sBAEF,MAAM0F,gBAAkBxF,SAC7BP,EAAI,GAAGK,8BAEF,MAAM2F,QAAUzF,MAAO0F,GAC5BjG,EAAI,GAAGK,eAAuB,CAAE4F,gBAE3B,MAAMC,WAAa3F,OAAS4F,YAAWzF,OAAM0F,cAClDnG,EAAK,GAAGI,UAAkB,CAAE8F,YAAWzF,OAAM0F,oBAExC,MAAMC,WAAa9F,OAAS0F,OAAMvF,OAAM4F,QAAO3C,cAAa4C,SAAQH,WAAUI,WAAUC,mBAC7FvG,EAAI,GAAGG,eAAuB,CAAE4F,OAAMvF,OAAM4F,QAAO3C,cAAa4C,SAAQH,WAAUI,WAAUC,yBAEvF,MAAMC,YAAcnG,MAAOoG,GAChCvG,EAAI,GAAGC,UAAkB,CAAEsG,iBAEtB,MAAMC,YAAcrG,MAAO0F,GAChC/F,EAAI,GAAGG,kBAA0B,CAAE4F,gBAE9B,MAAMY,WAAatG,MAAO0F,GAC/B/F,EAAI,GAAGG,iBAAyB,CAAE4F,gBAE7B,MAAMa,SAAWvG,OAAS0F,OAAMc,aACrC5G,EAAM,GAAGE,eAAuB,CAAE4F,OAAMc,mBAEnC,MAAMC,sBAAwBzG,MAAO0G,GAC1CjH,EAAI,GAAGK,iBAAyB,CAAE4G,MAAOC,KAAKC,UAAUF,YAEnD,MAAMG,cAAgB7G,OAAS0F,OAAMoB,YAC1CnH,EAAI,GAAGG,eAAuB,CAAE4F,OAAMoB,kBAMjC,MAAMC,YAAc/G,MAAO0F,GAChCjG,EAAI,GAAGK,mBAA2B,CAAE4F,gBAE/B,MAAMsB,eAAiBhH,OAAS4F,YAAWzF,OAAM8G,cACtDvH,EAAK,GAAGI,cAAsB,CAAE8F,YAAWzF,OAAM8G,oBAE5C,MAAMC,eAAiBlH,OAAS0F,OAAMvF,OAAM6F,SAAQmB,YACzDxH,EAAI,GAAGG,mBAA2B,CAAE4F,OAAMvF,OAAM6F,SAAQmB,kBAEnD,MAAMC,gBAAkBpH,MAAOoG,GACpCvG,EAAI,GAAGC,cAAsB,CAAEsG,iBAE1B,MAAMiB,mBAAqBrH,MAAOkD,GACvCzD,EAAI,GAAGK,oBAA4BoD,EAAQ,CAAEA,SAAU,CAAC,UAEnD,MAAMoE,iBAAmBtH,MAAO6F,GACrCpG,EAAI,GAAGK,yBAAiC,CAAE+F,oBAErC,MAAM0B,kBAAoBvH,OAAS6F,WAAU2B,YAClD7H,EAAI,GAAGG,yBAAiC,CAAE+F,WAAU2B,kBAE/C,MAAMC,mBAAqBzH,MAAO6F,GACvChG,EAAI,GAAGC,yBAAiC,CAAE+F,oBAErC,MAAM6B,gBAAkB1H,MAAO0F,GACpC/F,EAAI,GAAGG,sBAA8B,CAAE4F,gBAElC,MAAMiC,eAAiB3H,MAAO0F,GACnC/F,EAAI,GAAGG,qBAA6B,CAAE4F,gBAEjC,MAAMkC,aAAe5H,OAAS0F,OAAMc,aACzC5G,EAAM,GAAGE,mBAA2B,CAAE4F,OAAMc,mBAEvC,MAAMqB,kBAAoB7H,OAAS0F,OAAMoB,YAC9CnH,EAAI,GAAGG,mBAA2B,CAAE4F,OAAMoB,kBAMrC,MAAMgB,cAAgB9H,SAC3BP,EAAI,GAAGK,sBAEF,MAAMiI,YAAc/H,MAAO0F,GAChCjG,EAAI,GAAGK,mBAA2B,CAAE4F,gBAE/B,MAAMsC,eAAiBhI,OAAS4F,YAAWzF,UAChDT,EAAK,GAAGI,cAAsB,CAAE8F,YAAWzF,gBAEtC,MAAM8H,eAAiBjI,OAAS0F,OAAMM,SAAQmB,YACnDxH,EAAI,GAAGG,mBAA2B,CAAE4F,OAAMM,SAAQmB,kBAE7C,MAAMe,gBAAkBlI,MAAOoG,GACpCvG,EAAI,GAAGC,cAAsB,CAAEsG,iBAE1B,MAAM+B,aAAenI,OAAS0F,OAAMc,aACzC5G,EAAM,GAAGE,mBAA2B,CAAE4F,OAAMc,mBAEvC,MAAM4B,gBAAkBpI,MAAO0F,GACpC/F,EAAI,GAAGG,sBAA8B,CAAE4F,gBAElC,MAAM2C,eAAiBrI,MAAO0F,GACnC/F,EAAI,GAAGG,qBAA6B,CAAE4F,gBAEjC,MAAM4C,kBAAoBtI,OAAS0F,OAAMoB,YAC9CnH,EAAI,GAAGG,mBAA2B,CAAE4F,OAAMoB,kBAMrC,MAAMyB,kBAAoBvI,SAC/BP,EAAI,GAAGK,oBAEF,MAAM0I,iBAAmBxI,MAAOsC,GACrC7C,EAAI,GAAGK,kBAA0B,CAAEwC,cAE9B,MAAMmG,oBAAsBzI,OAASG,OAAMuI,WAAUC,cAC1DjJ,EAAK,GAAGI,YAAoB,CAAEK,OAAMuI,WAAUC,oBAEzC,MAAMC,oBAAsB5I,OAASsC,KAAInC,OAAMuI,WAAUC,WAAUxB,YACxExH,EAAI,GAAGG,kBAA0B,CAAEwC,KAAInC,OAAMuI,WAAUC,WAAUxB,kBAE5D,MAAM0B,oBAAsB7I,MAAOoC,GACxCvC,EAAI,GAAGC,YAAoB,CAAEsC,eAExB,MAAM0G,qBAAuB9I,MAAOsC,GACzC3C,EAAI,GAAGG,oBAA4B,CAAEwC,cAEhC,MAAMyG,oBAAsB/I,MAAOsC,GACxC3C,EAAI,GAAGG,mBAA2B,CAAEwC,cAE/B,MAAM0G,uBAAyBhJ,OAASsC,KAAIwE,YACjDnH,EAAI,GAAGG,iBAAyB,CAAEwC,KAAIwE,kBAMjC,MAAMmC,UAAYjJ,SACvBP,EAAI,GAAGK,kBAEF,MAAMoJ,SAAWlJ,OAASsC,KAAInC,UACnCT,EAAK,GAAGI,UAAkB,CAAEwC,KAAInC,gBAE3B,MAAMgJ,WAAanJ,MAAOsC,GAC/BzC,EAAI,GAAGC,UAAkB,CAAEwC,cAEtB,MAAM8G,mBAAqBpJ,OAAS0I,WAAUW,YACnD1J,EAAI,GAAGG,mBAA2B,CAAE4I,WAAUW,kBAEzC,MAAMC,aAAetJ,OAASsC,KAAI+G,SAAQX,WAAUa,UAASC,QAAOC,OAAMC,OAAMC,YACrFjK,EAAK,GAAGI,gBAAwB,CAAEwC,KAAI+G,SAAQX,WAAUa,UAASC,QAAOC,OAAMC,OAAMC,kBAE/E,MAAMC,gBAAkB5J,MAAOoC,GACpCvC,EAAI,GAAGC,gBAAwB,CAAEsC,eAE5B,MAAMyH,mBAAqB7J,OAASsC,KAAIwH,aAC7CnK,EAAI,GAAGG,wBAAgC,CAAEwC,KAAIwH,mBAExC,MAAMC,iBAAmB/J,OAASqJ,SAAQjH,SAC/CzC,EAAI,GAAGG,sBAA8B,CAAEuJ,SAAQjH,eAE1C,MAAM4H,cAAgBhK,OAASsC,KAAI+G,SAAQY,cAChDtK,EAAI,GAAGG,gBAAwB,CAAEwC,KAAI+G,SAAQY,oBAMxC,MAAMC,eAAiBlK,OAAS2B,QAAOC,UAAW,CAAC,IACxDnC,EAAI,GAAGK,eAAuB,CAAE6B,QAAOC,kBAElC,MAAMuI,wBAA0BnK,SACrCP,EAAI,GAAGK,iCAEF,MAAMsK,oBAAsBpK,OAAS+E,SAAQsF,OAAM1I,QAAOC,UAAW,CAAC,IAC3EnC,EAAI,GAAGK,qBAA6B,CAAEiF,SAAQsF,OAAM1I,QAAOC,kBAEtD,MAAM0I,kBAAoBtK,MAAOG,GACtCV,EAAI,GAAGK,qBAA6B,CAAEK,gBAEjC,MAAMoK,cAAgBvK,MAAOG,EAAMqK,IACxC7K,EAAI,GAAGG,sBAA8B,CAAEK,OAAMqK,kBAMxC,MAAMC,oBAAsBzK,SACjCP,EAAI,GAAGK,8BAMF,MAAM4K,iBAAmB1K,OAAS2K,cAAa,EAAOhJ,QAAOC,UAAW,CAAC,IAC9EnC,EAAI,GAAGK,kBAA0B,CAAE6K,aAAYhJ,QAAOC,kBAEjD,MAAMgJ,2BAA6B5K,SACxCP,EAAI,GAAGK,gCAEF,MAAM+K,qBAAuB7K,MAAOsC,GACzC5C,EAAK,GAAGI,mBAA0B4D,mBAAmBpB,UAAY,CAAC,UAE7D,MAAMwI,wBAA0B9K,MAAOsC,GAC5C5C,EAAK,GAAGI,mBAA0B4D,mBAAmBpB,aAAe,CAAC,UAEhE,MAAMyI,yBAA2B/K,SACtCN,EAAK,GAAGI,2BAAmC,CAAC,UAEvC,MAAMkL,oBAAsBhL,MAAOsC,GACxCzC,EAAI,GAAGC,mBAA0B4D,mBAAmBpB,aAE/C,MAAM2I,wBAA0BjL,SACrCP,EAAI,GAAGK,iCAEF,MAAMoL,iBAAmBlL,MAAOG,GAAQgL,oBAAmB,GAAU,CAAC,IAC3EzL,EAAK,GAAGI,eAAuB,CAAEK,OAAMgL,4BAElC,MAAMC,mBAAqBpL,MAAOG,EAAMkL,GAAY,GAASC,WAAU,GAAU,CAAC,IACvFzL,EAAI,GAAGC,eAAuB,CAAEK,OAAMkL,YAAWC,mBAE5C,MAAMC,gBAAkBvL,MAAOG,GAAQmL,WAAU,GAAU,CAAC,IACjE5L,EAAK,GAAGI,gBAAuB4D,mBAAmBvD,YAAgB,CAAEmL,mBAE/D,MAAME,yBAA2BxL,MAAOG,GAC7CV,EAAI,GAAGK,gBAAuB4D,mBAAmBvD,0BAE5C,MAAMsL,iBAAmBzL,MAAOG,GAAQmL,WAAU,GAAU,CAAC,IAClE5L,EAAK,GAAGI,gBAAuB4D,mBAAmBvD,aAAiB,CAAEmL,mBAEhE,MAAMI,uBAAyB1L,MAAOG,GAAQwL,mBAAkB,GAAU,CAAC,IAChFlM,EAAI,GAAGK,gBAAuB4D,mBAAmBvD,gBAAoB,CAAEwL,gBAAiBA,EAAkB,YAASC,WAM9G,MAAMC,uBAAyB7L,SACpCP,EAAI,GAAGK,0BAEF,MAAMgM,sBAAwB9L,MAAOsC,GAC1C7C,EAAI,GAAGK,mBAA0B4D,mBAAmBpB,aAE/C,MAAMyJ,yBAA2B/L,OAASG,OAAMuI,WAAUC,WAAUzF,QAAOiE,YAChFzH,EAAK,GAAGI,kBAA0B,CAAEK,OAAMuI,WAAUC,WAAUzF,QAAOiE,kBAEhE,MAAM6E,yBAA2BhM,MAAOsC,GAAMnC,OAAMuI,WAAUC,WAAUxB,YAC7ExH,EAAI,GAAGG,mBAA0B4D,mBAAmBpB,KAAO,CAAEnC,OAAMuI,WAAUC,WAAUxB,kBAElF,MAAM8E,yBAA2BjM,MAAOoC,GAC7CvC,EAAI,GAAGC,kBAA0B,CAAEsC,eAE9B,MAAM8J,yBAA2BlM,MAAOsC,GAC7C3C,EAAI,GAAGG,mBAA0B4D,mBAAmBpB,YAAc,CAAC,UAE9D,MAAM6J,0BAA4BnM,MAAOsC,GAC9C3C,EAAI,GAAGG,mBAA0B4D,mBAAmBpB,aAAe,CAAC","ignoreList":[]}
|
|
1
|
+
{"version":3,"file":"src\\kempo\\sdk.js","names":["get","post","put","patch","del","API_BASE","register","async","email","password","name","login","logout","getSession","forgotPassword","resetPassword","token","logoutAll","newPassword","changePassword","currentPassword","verifyEmail","currentUserHasPermission","permission","currentUserHasAllPermissions","permissions","currentUserHasSomePermissions","getAllCurrentUserPermissions","userHasPermission","userid","userHasAllPermissions","userHasSomePermissions","getAllUserPermissions","getUsers","limit","offset","searchUsers","q","inGroup","notInGroup","createUser","emailVerified","deleteUsers","ids","updateUser","id","createdAt","getUser","getUserSessions","deleteUserSession","sessionToken","deleteExpiredUserSessions","getUserGroups","addUserToGroup","groupName","removeUserFromGroup","listGroups","owner","createGroup","description","updateGroup","newName","deleteGroups","names","getGroup","encodeURIComponent","getGroupMembers","addMemberToGroup","userId","removeMemberFromGroup","getGroupPermissions","addPermissionToGroup","permissionName","removePermissionFromGroup","listPermissions","createPermissions","updatePermission","deletePermissions","getSetting","listSettings","setSetting","data","deleteSetting","listEmails","status","type","search","getEmail","retryEmail","sendTestEmail","to","getUpdateStatus","checkForUpdate","prepareUpdate","version","extensions","applyUpdate","confirm","rollbackUpdate","discardUpdate","listPages","showHidden","rescanPages","listTemplates","listDirectories","getPage","file","createPage","directory","template","updatePage","title","author","contents","extraMetadata","deletePages","files","disablePage","enablePage","movePage","newFile","searchPagesByMetadata","query","JSON","stringify","setPageLocked","locked","getTemplate","createTemplate","copyFrom","updateTemplate","markup","deleteTemplates","listEmailTemplates","getEmailTemplate","saveEmailTemplate","source","resetEmailTemplate","disableTemplate","enableTemplate","moveTemplate","setTemplateLocked","listFragments","getFragment","createFragment","updateFragment","deleteFragments","moveFragment","disableFragment","enableFragment","setFragmentLocked","listGlobalContent","getGlobalContent","createGlobalContent","location","priority","updateGlobalContent","deleteGlobalContent","disableGlobalContent","enableGlobalContent","setGlobalContentLocked","listMenus","saveMenu","deleteMenu","assignMenuLocation","menuId","saveMenuItem","navItem","label","href","icon","newTab","deleteMenuItems","setMenuItemEnabled","enabled","reorderMenuItems","adoptMenuItem","menuName","listExtensions","listAvailableExtensions","listKnownExtensions","sort","getKnownExtension","rateExtension","rating","getDashboardWidgets","getNotifications","unreadOnly","getUnreadNotificationCount","markNotificationRead","markNotificationHandled","markAllNotificationsRead","dismissNotification","listRealtimeConnections","installExtension","withDependencies","uninstallExtension","purgeData","cascade","enableExtension","getExtensionRequirements","disableExtension","getExtensionDependents","includeDisabled","undefined","listAdminGlobalContent","getAdminGlobalContent","createAdminGlobalContent","updateAdminGlobalContent","deleteAdminGlobalContent","enableAdminGlobalContent","disableAdminGlobalContent"],"sources":["0"],"sourcesContent":["import { get, post, put, patch, del } from './fetch.js';\r\nconst API_BASE = '/kempo/api';\r\n\r\nexport const register = async ({ email, password, name }) =>\r\n post(`${API_BASE}/auth/register/email`, { email, password, name });\r\n\r\nexport const login = async ({ email, password }) =>\r\n post(`${API_BASE}/auth/login/email`, { email, password });\r\n\r\nexport const logout = async () => post(`${API_BASE}/auth/logout`, {});\r\n\r\nexport const getSession = async () => get(`${API_BASE}/auth/session`);\r\n\r\nexport const forgotPassword = async ({ email }) =>\r\n post(`${API_BASE}/forgot-password`, { email });\r\n\r\nexport const resetPassword = async ({ token, password, logoutAll = false }) =>\r\n post(`${API_BASE}/auth/reset-password`, { token, newPassword: password, logoutAll });\r\n \r\nexport const changePassword = async ({ currentPassword, newPassword, logoutAll }) => \r\n post(`${API_BASE}/auth/change-password`, { currentPassword, newPassword, logoutAll });\r\n\r\nexport const verifyEmail = async ({ token }) =>\r\n post(`${API_BASE}/auth/verify-email`, { token });\r\n\r\nexport const currentUserHasPermission = async ({ permission }) =>\r\n get(`${API_BASE}/user/current/permissions`, { permission });\r\n\r\nexport const currentUserHasAllPermissions = async ({ permissions }) =>\r\n get(`${API_BASE}/user/current/permissions/all`, { permissions });\r\n\r\nexport const currentUserHasSomePermissions = async ({ permissions }) =>\r\n get(`${API_BASE}/user/current/permissions/some`, { permissions });\r\n\r\nexport const getAllCurrentUserPermissions = async () =>\r\n get(`${API_BASE}/user/current/permissions/list`);\r\n\r\nexport const userHasPermission = async ({ userid, permission }) =>\r\n get(`${API_BASE}/user/${userid}/permissions`, { permission });\r\n\r\nexport const userHasAllPermissions = async ({ userid, permissions }) =>\r\n get(`${API_BASE}/user/${userid}/permissions/all`, { permissions });\r\n\r\nexport const userHasSomePermissions = async ({ userid, permissions }) =>\r\n get(`${API_BASE}/user/${userid}/permissions/some`, { permissions });\r\n\r\nexport const getAllUserPermissions = async ({ userid }) =>\r\n get(`${API_BASE}/user/${userid}/permissions/list`);\r\n\r\nexport const getUsers = async ({ limit, offset } = {}) =>\r\n get(`${API_BASE}/user`, { limit, offset });\r\n\r\nexport const searchUsers = async ({ q, limit, offset, inGroup, notInGroup } = {}) =>\r\n get(`${API_BASE}/user/search`, { q, limit, offset, inGroup, notInGroup });\r\n\r\nexport const createUser = async ({ name, email, password, emailVerified }) =>\r\n post(`${API_BASE}/user/create`, { name, email, password, emailVerified });\r\n\r\nexport const deleteUsers = async (ids) =>\r\n del(`${API_BASE}/user`, { ids });\r\n\r\nexport const updateUser = async ({ id, name, email, emailVerified, createdAt }) =>\r\n patch(`${API_BASE}/user`, { id, name, email, emailVerified, createdAt });\r\n\r\nexport const getUser = async (userid) =>\r\n get(`${API_BASE}/user/${userid}`);\r\n\r\nexport const getUserSessions = async (userid, { limit, offset } = {}) =>\r\n get(`${API_BASE}/user/${userid}/sessions`, { limit, offset });\r\n\r\nexport const deleteUserSession = async (userid, sessionToken) =>\r\n del(`${API_BASE}/user/${userid}/sessions`, { sessionToken });\r\n\r\nexport const deleteExpiredUserSessions = async (userid) =>\r\n del(`${API_BASE}/user/${userid}/sessions/expired`);\r\n\r\nexport const getUserGroups = async (userid, { limit, offset } = {}) =>\r\n get(`${API_BASE}/user/${userid}/groups`, { limit, offset });\r\n\r\nexport const addUserToGroup = async (userid, groupName) =>\r\n post(`${API_BASE}/user/${userid}/groups`, { groupName });\r\n\r\nexport const removeUserFromGroup = async (userid, groupName) =>\r\n del(`${API_BASE}/user/${userid}/groups`, { groupName });\r\n\r\nexport const listGroups = async ({ limit, offset, owner } = {}) =>\r\n get(`${API_BASE}/groups`, { limit, offset, owner });\r\n\r\nexport const createGroup = async ({ name, description }) =>\r\n post(`${API_BASE}/groups`, { name, description });\r\n\r\nexport const updateGroup = async ({ name, newName, description }) =>\r\n patch(`${API_BASE}/groups`, { name, newName, description });\r\n\r\nexport const deleteGroups = async (names) =>\r\n del(`${API_BASE}/groups`, { names });\r\n\r\nexport const getGroup = async (name) =>\r\n get(`${API_BASE}/groups/${encodeURIComponent(name)}`);\r\n\r\nexport const getGroupMembers = async (name, { limit, offset } = {}) =>\r\n get(`${API_BASE}/groups/${encodeURIComponent(name)}/members`, { limit, offset });\r\n\r\nexport const addMemberToGroup = async (name, userId) =>\r\n post(`${API_BASE}/groups/${encodeURIComponent(name)}/members`, { userId });\r\n\r\nexport const removeMemberFromGroup = async (name, userId) =>\r\n del(`${API_BASE}/groups/${encodeURIComponent(name)}/members`, { userId });\r\n\r\nexport const getGroupPermissions = async (name) =>\r\n get(`${API_BASE}/groups/${encodeURIComponent(name)}/permissions`);\r\n\r\nexport const addPermissionToGroup = async (name, permissionName) =>\r\n post(`${API_BASE}/groups/${encodeURIComponent(name)}/permissions`, { permissionName });\r\n\r\nexport const removePermissionFromGroup = async (name, permissionName) =>\r\n del(`${API_BASE}/groups/${encodeURIComponent(name)}/permissions`, { permissionName });\r\n\r\nexport const listPermissions = async ({ limit, offset, owner } = {}) =>\r\n get(`${API_BASE}/permissions`, { limit, offset, owner });\r\n\r\nexport const createPermissions = async (permissions) =>\r\n post(`${API_BASE}/permissions`, { permissions });\r\n\r\nexport const updatePermission = async ({ name, description }) =>\r\n patch(`${API_BASE}/permissions`, { name, description });\r\n\r\nexport const deletePermissions = async (names) =>\r\n del(`${API_BASE}/permissions`, { names });\r\n\r\nexport const getSetting = async (owner, name) =>\r\n get(`${API_BASE}/settings/${encodeURIComponent(owner)}/${encodeURIComponent(name)}`);\r\n\r\nexport const listSettings = async ({ owner, limit, offset } = {}) =>\r\n get(`${API_BASE}/settings/${encodeURIComponent(owner)}`, { limit, offset });\r\n\r\nexport const setSetting = async (owner, name, data) =>\r\n post(`${API_BASE}/settings/${encodeURIComponent(owner)}/${encodeURIComponent(name)}`, data);\r\n\r\nexport const deleteSetting = async (owner, name) =>\r\n del(`${API_BASE}/settings/${encodeURIComponent(owner)}/${encodeURIComponent(name)}`);\r\n\r\n/*\r\n Emails\r\n*/\r\nexport const listEmails = async ({ status, type, search, limit, offset } = {}) =>\r\n get(`${API_BASE}/emails`, { status, type, search, limit, offset });\r\n\r\nexport const getEmail = async (id) =>\r\n get(`${API_BASE}/emails/${encodeURIComponent(id)}`);\r\n\r\nexport const retryEmail = async (id) =>\r\n post(`${API_BASE}/emails/${encodeURIComponent(id)}/retry`, {});\r\n\r\nexport const sendTestEmail = async (to) =>\r\n post(`${API_BASE}/emails/test`, { to });\r\n\r\n/*\r\n Updates\r\n*/\r\nexport const getUpdateStatus = async () =>\r\n get(`${API_BASE}/updates`);\r\n\r\nexport const checkForUpdate = async () =>\r\n post(`${API_BASE}/updates/check`, {});\r\n\r\nexport const prepareUpdate = async ({ version, extensions } = {}) =>\r\n post(`${API_BASE}/updates/prepare`, { version, extensions });\r\n\r\nexport const applyUpdate = async ({ version, extensions, confirm } = {}) =>\r\n post(`${API_BASE}/updates/apply`, { version, extensions, confirm });\r\n\r\nexport const rollbackUpdate = async (confirm) =>\r\n post(`${API_BASE}/updates/rollback`, { confirm });\r\n\r\nexport const discardUpdate = async () =>\r\n post(`${API_BASE}/updates/discard`, {});\r\n\r\n/*\r\n Pages\r\n*/\r\n\r\nexport const listPages = async ({ owner, showHidden, offset, limit } = {}) =>\r\n get(`${API_BASE}/pages`, { owner, showHidden, offset, limit });\r\n\r\nexport const rescanPages = async () =>\r\n post(`${API_BASE}/pages/rescan`, {});\r\n\r\nexport const listTemplates = async () =>\r\n get(`${API_BASE}/templates`);\r\n\r\nexport const listDirectories = async () =>\r\n get(`${API_BASE}/pages/directories`);\r\n\r\nexport const getPage = async (file) =>\r\n get(`${API_BASE}/pages/file`, { file });\r\n\r\nexport const createPage = async ({ directory, name, template }) =>\r\n post(`${API_BASE}/pages`, { directory, name, template });\r\n\r\nexport const updatePage = async ({ file, name, title, description, author, template, contents, extraMetadata }) =>\r\n put(`${API_BASE}/pages/file`, { file, name, title, description, author, template, contents, extraMetadata });\r\n\r\nexport const deletePages = async (files) =>\r\n del(`${API_BASE}/pages`, { files });\r\n\r\nexport const disablePage = async (file) =>\r\n put(`${API_BASE}/pages/disable`, { file });\r\n\r\nexport const enablePage = async (file) =>\r\n put(`${API_BASE}/pages/enable`, { file });\r\n\r\nexport const movePage = async ({ file, newFile }) =>\r\n patch(`${API_BASE}/pages/file`, { file, newFile });\r\n\r\nexport const searchPagesByMetadata = async (query) =>\r\n get(`${API_BASE}/pages/search`, { query: JSON.stringify(query) });\r\n\r\nexport const setPageLocked = async ({ file, locked }) =>\r\n put(`${API_BASE}/pages/lock`, { file, locked });\r\n\r\n/*\r\n Templates\r\n*/\r\n\r\nexport const getTemplate = async (file) =>\r\n get(`${API_BASE}/templates/file`, { file });\r\n\r\nexport const createTemplate = async ({ directory, name, copyFrom }) =>\r\n post(`${API_BASE}/templates`, { directory, name, copyFrom });\r\n\r\nexport const updateTemplate = async ({ file, name, author, markup }) =>\r\n put(`${API_BASE}/templates/file`, { file, name, author, markup });\r\n\r\nexport const deleteTemplates = async (files) =>\r\n del(`${API_BASE}/templates`, { files });\r\n\r\nexport const listEmailTemplates = async (owner) =>\r\n get(`${API_BASE}/email-templates`, owner ? { owner } : {});\r\n\r\nexport const getEmailTemplate = async (template) =>\r\n get(`${API_BASE}/email-templates/file`, { template });\r\n\r\nexport const saveEmailTemplate = async ({ template, source }) =>\r\n put(`${API_BASE}/email-templates/file`, { template, source });\r\n\r\nexport const resetEmailTemplate = async (template) =>\r\n del(`${API_BASE}/email-templates/file`, { template });\r\n\r\nexport const disableTemplate = async (file) =>\r\n put(`${API_BASE}/templates/disable`, { file });\r\n\r\nexport const enableTemplate = async (file) =>\r\n put(`${API_BASE}/templates/enable`, { file });\r\n\r\nexport const moveTemplate = async ({ file, newFile }) =>\r\n patch(`${API_BASE}/templates/file`, { file, newFile });\r\n\r\nexport const setTemplateLocked = async ({ file, locked }) =>\r\n put(`${API_BASE}/templates/lock`, { file, locked });\r\n\r\n/*\r\n Fragments\r\n*/\r\n\r\nexport const listFragments = async () =>\r\n get(`${API_BASE}/fragments`);\r\n\r\nexport const getFragment = async (file) =>\r\n get(`${API_BASE}/fragments/file`, { file });\r\n\r\nexport const createFragment = async ({ directory, name }) =>\r\n post(`${API_BASE}/fragments`, { directory, name });\r\n\r\nexport const updateFragment = async ({ file, author, markup }) =>\r\n put(`${API_BASE}/fragments/file`, { file, author, markup });\r\n\r\nexport const deleteFragments = async (files) =>\r\n del(`${API_BASE}/fragments`, { files });\r\n\r\nexport const moveFragment = async ({ file, newFile }) =>\r\n patch(`${API_BASE}/fragments/file`, { file, newFile });\r\n\r\nexport const disableFragment = async (file) =>\r\n put(`${API_BASE}/fragments/disable`, { file });\r\n\r\nexport const enableFragment = async (file) =>\r\n put(`${API_BASE}/fragments/enable`, { file });\r\n\r\nexport const setFragmentLocked = async ({ file, locked }) =>\r\n put(`${API_BASE}/fragments/lock`, { file, locked });\r\n\r\n/*\r\n Global Content\r\n*/\r\n\r\nexport const listGlobalContent = async () =>\r\n get(`${API_BASE}/globals`);\r\n\r\nexport const getGlobalContent = async (id) =>\r\n get(`${API_BASE}/globals/entry`, { id });\r\n\r\nexport const createGlobalContent = async ({ name, location, priority }) =>\r\n post(`${API_BASE}/globals`, { name, location, priority });\r\n\r\nexport const updateGlobalContent = async ({ id, name, location, priority, markup }) =>\r\n put(`${API_BASE}/globals/entry`, { id, name, location, priority, markup });\r\n\r\nexport const deleteGlobalContent = async (ids) =>\r\n del(`${API_BASE}/globals`, { ids });\r\n\r\nexport const disableGlobalContent = async (id) =>\r\n put(`${API_BASE}/globals/disable`, { id });\r\n\r\nexport const enableGlobalContent = async (id) =>\r\n put(`${API_BASE}/globals/enable`, { id });\r\n\r\nexport const setGlobalContentLocked = async ({ id, locked }) =>\r\n put(`${API_BASE}/globals/lock`, { id, locked });\r\n\r\n/*\r\n Menus\r\n*/\r\n\r\nexport const listMenus = async () =>\r\n get(`${API_BASE}/menus`);\r\n\r\nexport const saveMenu = async ({ id, name }) =>\r\n post(`${API_BASE}/menus`, { id, name });\r\n\r\nexport const deleteMenu = async (id) =>\r\n del(`${API_BASE}/menus`, { id });\r\n\r\nexport const assignMenuLocation = async ({ location, menuId }) =>\r\n put(`${API_BASE}/menus/location`, { location, menuId });\r\n\r\nexport const saveMenuItem = async ({ id, menuId, location, navItem, label, href, icon, newTab }) =>\r\n post(`${API_BASE}/menus/items`, { id, menuId, location, navItem, label, href, icon, newTab });\r\n\r\nexport const deleteMenuItems = async (ids) =>\r\n del(`${API_BASE}/menus/items`, { ids });\r\n\r\nexport const setMenuItemEnabled = async ({ id, enabled }) =>\r\n put(`${API_BASE}/menus/items/enabled`, { id, enabled });\r\n\r\nexport const reorderMenuItems = async ({ menuId, ids }) =>\r\n put(`${API_BASE}/menus/items/order`, { menuId, ids });\r\n\r\nexport const adoptMenuItem = async ({ id, menuId, menuName }) =>\r\n put(`${API_BASE}/menus/adopt`, { id, menuId, menuName });\r\n\r\n/*\r\n Extensions\r\n*/\r\n\r\nexport const listExtensions = async ({ limit, offset } = {}) =>\r\n get(`${API_BASE}/extensions`, { limit, offset });\r\n\r\nexport const listAvailableExtensions = async () =>\r\n get(`${API_BASE}/extensions/available`);\r\n\r\nexport const listKnownExtensions = async ({ search, sort, limit, offset } = {}) =>\r\n get(`${API_BASE}/extensions/known`, { search, sort, limit, offset });\r\n\r\nexport const getKnownExtension = async (name) =>\r\n get(`${API_BASE}/extensions/known`, { name });\r\n\r\nexport const rateExtension = async (name, rating) =>\r\n put(`${API_BASE}/extensions/rating`, { name, rating });\r\n\r\n/*\r\n Dashboard\r\n*/\r\n\r\nexport const getDashboardWidgets = async () =>\r\n get(`${API_BASE}/dashboard/widgets`);\r\n\r\n/*\r\n Notifications\r\n*/\r\n\r\nexport const getNotifications = async ({ unreadOnly = false, limit, offset } = {}) =>\r\n get(`${API_BASE}/notifications`, { unreadOnly, limit, offset });\r\n\r\nexport const getUnreadNotificationCount = async () =>\r\n get(`${API_BASE}/notifications/count`);\r\n\r\nexport const markNotificationRead = async (id) =>\r\n post(`${API_BASE}/notifications/${encodeURIComponent(id)}/read`, {});\r\n\r\nexport const markNotificationHandled = async (id) =>\r\n post(`${API_BASE}/notifications/${encodeURIComponent(id)}/handled`, {});\r\n\r\nexport const markAllNotificationsRead = async () =>\r\n post(`${API_BASE}/notifications/read-all`, {});\r\n\r\nexport const dismissNotification = async (id) =>\r\n del(`${API_BASE}/notifications/${encodeURIComponent(id)}`);\r\n\r\nexport const listRealtimeConnections = async () =>\r\n get(`${API_BASE}/realtime/connections`);\r\n\r\nexport const installExtension = async (name, { withDependencies = false } = {}) =>\r\n post(`${API_BASE}/extensions`, { name, withDependencies });\r\n\r\nexport const uninstallExtension = async (name, purgeData = false, { cascade = false } = {}) =>\r\n del(`${API_BASE}/extensions`, { name, purgeData, cascade });\r\n\r\nexport const enableExtension = async (name, { cascade = false } = {}) =>\r\n post(`${API_BASE}/extensions/${encodeURIComponent(name)}/enable`, { cascade });\r\n\r\nexport const getExtensionRequirements = async (name) =>\r\n get(`${API_BASE}/extensions/${encodeURIComponent(name)}/requirements`);\r\n\r\nexport const disableExtension = async (name, { cascade = false } = {}) =>\r\n post(`${API_BASE}/extensions/${encodeURIComponent(name)}/disable`, { cascade });\r\n\r\nexport const getExtensionDependents = async (name, { includeDisabled = false } = {}) =>\r\n get(`${API_BASE}/extensions/${encodeURIComponent(name)}/dependents`, { includeDisabled: includeDisabled ? 'true' : undefined });\r\n\r\n/*\r\n Admin Global Content\r\n*/\r\n\r\nexport const listAdminGlobalContent = async () =>\r\n get(`${API_BASE}/admin-globals`);\r\n\r\nexport const getAdminGlobalContent = async (id) =>\r\n get(`${API_BASE}/admin-globals/${encodeURIComponent(id)}`);\r\n\r\nexport const createAdminGlobalContent = async ({ name, location, priority, owner, markup }) =>\r\n post(`${API_BASE}/admin-globals`, { name, location, priority, owner, markup });\r\n\r\nexport const updateAdminGlobalContent = async (id, { name, location, priority, markup }) =>\r\n put(`${API_BASE}/admin-globals/${encodeURIComponent(id)}`, { name, location, priority, markup });\r\n\r\nexport const deleteAdminGlobalContent = async (ids) =>\r\n del(`${API_BASE}/admin-globals`, { ids });\r\n\r\nexport const enableAdminGlobalContent = async (id) =>\r\n put(`${API_BASE}/admin-globals/${encodeURIComponent(id)}/enable`, {});\r\n\r\nexport const disableAdminGlobalContent = async (id) =>\r\n put(`${API_BASE}/admin-globals/${encodeURIComponent(id)}/disable`, {});\r\n\r\n"],"mappings":"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","ignoreList":[]}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
FROM node:22-alpine
|
|
2
|
+
|
|
3
|
+
# pg_dump and psql: Kempo backs the database up before an update that changes data, and puts the backup back if that update fails.
|
|
4
|
+
RUN apk add --no-cache postgresql16-client
|
|
5
|
+
|
|
6
|
+
# The site as it is when the image is built. The first time a container starts it is copied onto the /site volume, and from
|
|
7
|
+
# then on the volume is the site (its pages, templates, uploads and the Kempo it runs), so what the admin changes, installs and
|
|
8
|
+
# updates survives rebuilding or replacing the container. Rebuild the image to change Node, not to change the site.
|
|
9
|
+
WORKDIR /seed
|
|
10
|
+
COPY package.json package-lock.json ./
|
|
11
|
+
RUN npm ci --omit=dev
|
|
12
|
+
COPY . .
|
|
13
|
+
|
|
14
|
+
# The startup script and the module it shares with the site.
|
|
15
|
+
RUN mkdir -p /opt/kempo \
|
|
16
|
+
&& cp node_modules/kempo/docker/entrypoint.mjs node_modules/kempo/server/utils/updates/siteLayout.js /opt/kempo/
|
|
17
|
+
|
|
18
|
+
ENV NODE_ENV=production \
|
|
19
|
+
KEMPO_SITE_ROOT=/site \
|
|
20
|
+
KEMPO_SEED=/seed \
|
|
21
|
+
KEMPO_RESTART=exit
|
|
22
|
+
|
|
23
|
+
VOLUME /site
|
|
24
|
+
EXPOSE 9876
|
|
25
|
+
ENTRYPOINT ["node", "/opt/kempo/entrypoint.mjs"]
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
# Runs the site and its database. Put DB_PASSWORD and SETTINGS_ENCRYPTION_KEY in a file called .env next to this one
|
|
2
|
+
# (SETTINGS_ENCRYPTION_KEY is 64 hex characters; back it up with the database, the credentials saved in the admin cannot be
|
|
3
|
+
# read without it), then: docker compose -f docker-compose.prod.yml up -d --build
|
|
4
|
+
#
|
|
5
|
+
# Everything the admin does (pages, templates, uploads, installing and updating Kempo and extensions) is kept on the `site`
|
|
6
|
+
# volume, and the data on the `db` volume. Back both up. `docker compose down -v` deletes them.
|
|
7
|
+
services:
|
|
8
|
+
app:
|
|
9
|
+
build: .
|
|
10
|
+
restart: unless-stopped
|
|
11
|
+
depends_on:
|
|
12
|
+
db:
|
|
13
|
+
condition: service_healthy
|
|
14
|
+
environment:
|
|
15
|
+
DATABASE_URL: postgresql://kempo:${DB_PASSWORD:?Put DB_PASSWORD in .env}@db:5432/kempo
|
|
16
|
+
SETTINGS_ENCRYPTION_KEY: ${SETTINGS_ENCRYPTION_KEY:?Put SETTINGS_ENCRYPTION_KEY in .env}
|
|
17
|
+
volumes:
|
|
18
|
+
- site:/site
|
|
19
|
+
ports:
|
|
20
|
+
- "9876:9876"
|
|
21
|
+
|
|
22
|
+
db:
|
|
23
|
+
image: postgres:16-alpine
|
|
24
|
+
restart: unless-stopped
|
|
25
|
+
environment:
|
|
26
|
+
POSTGRES_USER: kempo
|
|
27
|
+
POSTGRES_PASSWORD: ${DB_PASSWORD:?Put DB_PASSWORD in .env}
|
|
28
|
+
POSTGRES_DB: kempo
|
|
29
|
+
volumes:
|
|
30
|
+
- db:/var/lib/postgresql/data
|
|
31
|
+
healthcheck:
|
|
32
|
+
test: ["CMD-SHELL", "pg_isready -U kempo -d kempo"]
|
|
33
|
+
interval: 5s
|
|
34
|
+
timeout: 5s
|
|
35
|
+
retries: 12
|
|
36
|
+
|
|
37
|
+
volumes:
|
|
38
|
+
site:
|
|
39
|
+
db:
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
import { spawn, spawnSync } from 'child_process';
|
|
2
|
+
import { createReadStream, existsSync, mkdirSync, readFileSync, writeFileSync } from 'fs';
|
|
3
|
+
import { join } from 'path';
|
|
4
|
+
import { createGunzip } from 'zlib';
|
|
5
|
+
import { pipeline } from 'stream/promises';
|
|
6
|
+
import { countAttempt, paths, performSwitch, restoreFiles, rollBack, seedSite, shouldRollBack } from './siteLayout.js';
|
|
7
|
+
|
|
8
|
+
/*
|
|
9
|
+
The image's startup script. It runs before the site, as the container's main process, and does what must not be left to
|
|
10
|
+
the site itself:
|
|
11
|
+
|
|
12
|
+
1. First start: fills the volume from the image (/seed) with the site as it was built.
|
|
13
|
+
2. A new version waiting (state/switch.json asked for it): moves its code into place, while nothing is running.
|
|
14
|
+
3. A new version that has not proved itself and keeps stopping, or says it failed: puts the previous code back,
|
|
15
|
+
the files an update changed, and the database too when the update changed data (from the backup it took first).
|
|
16
|
+
4. After a change of Node version: rebuilds the compiled modules (bcrypt) the volume was built with.
|
|
17
|
+
5. Starts the site, passes signals to it and ends with its exit code, so the container's restart policy sees what
|
|
18
|
+
the site did (the site ends with 75 to ask for a restart after an update).
|
|
19
|
+
|
|
20
|
+
Environment: KEMPO_SITE_ROOT (the volume, /site), KEMPO_SEED (the site as built, /seed), KEMPO_START_COMMAND (default
|
|
21
|
+
`npm start`, or a JSON array when a path has spaces), and DATABASE_URL, which a database restore needs.
|
|
22
|
+
*/
|
|
23
|
+
const siteRoot = process.env.KEMPO_SITE_ROOT || '/site';
|
|
24
|
+
const seed = process.env.KEMPO_SEED || '/seed';
|
|
25
|
+
const { app, state } = paths(siteRoot);
|
|
26
|
+
|
|
27
|
+
const say = message => console.log(`[kempo] ${message}`);
|
|
28
|
+
|
|
29
|
+
/* Puts a backup taken before a data-changing update back: a plain-SQL dump, gzipped, with its own DROP statements. */
|
|
30
|
+
const restoreDatabase = async file => {
|
|
31
|
+
if(!file || !existsSync(file)) return false;
|
|
32
|
+
const psql = spawn('psql', ['-v', 'ON_ERROR_STOP=1', '-q', process.env.DATABASE_URL], { stdio: ['pipe', 'inherit', 'inherit'] });
|
|
33
|
+
const finished = new Promise((resolve, reject) => {
|
|
34
|
+
psql.on('error', reject);
|
|
35
|
+
psql.on('exit', code => (code === 0 ? resolve() : reject(new Error(`psql ended with ${code}`))));
|
|
36
|
+
});
|
|
37
|
+
await Promise.all([pipeline(createReadStream(file), createGunzip(), psql.stdin), finished]);
|
|
38
|
+
return true;
|
|
39
|
+
};
|
|
40
|
+
|
|
41
|
+
const goBack = async reason => {
|
|
42
|
+
say(`The new version of Kempo is not working (${reason}). Going back to the one before it.`);
|
|
43
|
+
const result = rollBack({ siteRoot, reason });
|
|
44
|
+
if(!result.ok){
|
|
45
|
+
say(result.reason);
|
|
46
|
+
return;
|
|
47
|
+
}
|
|
48
|
+
say(`Back on Kempo ${result.to}.`);
|
|
49
|
+
if(result.dbBackup){
|
|
50
|
+
try {
|
|
51
|
+
say('Restoring the database from the backup taken before the update.');
|
|
52
|
+
await restoreDatabase(result.dbBackup);
|
|
53
|
+
} catch(error) {
|
|
54
|
+
say(`The database could not be restored (${error.message}). The backup is at ${result.dbBackup}.`);
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
};
|
|
58
|
+
|
|
59
|
+
if(seedSite({ siteRoot, seed })) say('First start: the site was copied onto the volume.');
|
|
60
|
+
|
|
61
|
+
const switched = performSwitch(siteRoot);
|
|
62
|
+
if(switched){
|
|
63
|
+
say(`Kempo ${switched.from.version} -> ${switched.version}.`);
|
|
64
|
+
if(switched.kind === 'rollback'){
|
|
65
|
+
restoreFiles({ siteRoot, backup: switched.filesBackup });
|
|
66
|
+
if(switched.dbBackup){
|
|
67
|
+
try {
|
|
68
|
+
say('Restoring the database from the backup taken before the update.');
|
|
69
|
+
await restoreDatabase(switched.dbBackup);
|
|
70
|
+
} catch(error) {
|
|
71
|
+
say(`The database could not be restored (${error.message}). The backup is at ${switched.dbBackup}.`);
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
const counted = countAttempt(siteRoot);
|
|
78
|
+
if(shouldRollBack(counted)) await goBack(counted.failed ? counted.failure || 'a data migration failed' : 'it stopped too many times');
|
|
79
|
+
|
|
80
|
+
const nodeFile = join(state, 'node-version');
|
|
81
|
+
const builtWith = existsSync(nodeFile) ? readFileSync(nodeFile, 'utf8').trim() : null;
|
|
82
|
+
if(builtWith && builtWith !== process.version){
|
|
83
|
+
say(`Node changed from ${builtWith} to ${process.version}: rebuilding compiled modules.`);
|
|
84
|
+
spawnSync('npm', ['rebuild'], { cwd: app, stdio: 'inherit' });
|
|
85
|
+
}
|
|
86
|
+
mkdirSync(state, { recursive: true });
|
|
87
|
+
writeFileSync(nodeFile, process.version);
|
|
88
|
+
|
|
89
|
+
const startCommand = process.env.KEMPO_START_COMMAND || 'npm start';
|
|
90
|
+
const [command, ...args] = startCommand.startsWith('[') ? JSON.parse(startCommand) : startCommand.split(' ');
|
|
91
|
+
const site = spawn(command, args, { cwd: app, stdio: 'inherit', env: { ...process.env, KEMPO_SITE_ROOT: siteRoot } });
|
|
92
|
+
|
|
93
|
+
for(const signal of ['SIGTERM', 'SIGINT']){
|
|
94
|
+
process.on(signal, () => site.kill(signal));
|
|
95
|
+
}
|
|
96
|
+
site.on('exit', (code, signal) => process.exit(code ?? (signal ? 1 : 0)));
|
package/middleware/kempo.js
CHANGED
|
@@ -13,9 +13,16 @@ import triggerHook from '../server/utils/hooks/triggerHook.js';
|
|
|
13
13
|
import { ADMIN_GLOBALS_DIR } from '../server/utils/admin-global-content/helpers.js';
|
|
14
14
|
import { startScheduler } from '../server/utils/scheduler/scheduler.js';
|
|
15
15
|
import { ensureEncryptionKey } from '../server/utils/settings/ensureEncryptionKey.js';
|
|
16
|
+
import syncCoreSchema from '../server/utils/setup/syncCoreSchema.js';
|
|
17
|
+
import runUpgrades from '../server/utils/setup/runUpgrades.js';
|
|
18
|
+
import seedIfNew from '../server/utils/setup/seedIfNew.js';
|
|
19
|
+
import reconcileExtensions from '../server/utils/extensions/reconcileExtensions.js';
|
|
20
|
+
import { flagFailed, markHealthy } from '../server/utils/updates/siteLayout.js';
|
|
21
|
+
import notifySchemaAttention from '../server/utils/updates/notifySchemaAttention.js';
|
|
16
22
|
import { ensureSystemSettings } from '../server/utils/settings/systemSettings.js';
|
|
17
23
|
import { ensureSystemPermissions } from '../server/utils/setup/systemPermissions.js';
|
|
18
24
|
import registerJobs from '../server/utils/scheduler/registerJobs.js';
|
|
25
|
+
import '../server/utils/updates/runtime.js';
|
|
19
26
|
import { resolveAlias } from '../server/utils/extensions/aliases.js';
|
|
20
27
|
import { normalizeScopes } from '../server/utils/extensions/scopes.js';
|
|
21
28
|
|
|
@@ -187,6 +194,11 @@ const serveDir = async (dirPath, method, request, response, resolveDir, rootDir,
|
|
|
187
194
|
export default config => {
|
|
188
195
|
startScheduler();
|
|
189
196
|
|
|
197
|
+
/* A site that runs from a Docker volume has just switched to new code: once it has stayed up a minute the switch is final. */
|
|
198
|
+
if(process.env.KEMPO_SITE_ROOT && process.env.KEMPO_DB !== 'pglite'){
|
|
199
|
+
setTimeout(() => markHealthy(process.env.KEMPO_SITE_ROOT), 60000).unref();
|
|
200
|
+
}
|
|
201
|
+
|
|
190
202
|
/*
|
|
191
203
|
The key that encrypts stored credentials exists before any request needs it, generated into .env the
|
|
192
204
|
first time when the site has none. Opt out with `autoEncryptionKey: false` in the server config or
|
|
@@ -198,17 +210,55 @@ export default config => {
|
|
|
198
210
|
if(error) console.error(`[kempo] ${error.msg}`);
|
|
199
211
|
});
|
|
200
212
|
/*
|
|
201
|
-
What kempo added in a later version appears on an older site at start: its settings (so they show on the settings screen and can be
|
|
202
|
-
edited), its permissions, and its own scheduled
|
|
213
|
+
What kempo added in a later version appears on an older site at start: its tables and columns (additive only, see syncCoreSchema), its settings (so they show on the settings screen and can be
|
|
214
|
+
edited), its permissions, and its own scheduled jobs (the email retries and cleanup, and the check for a newer kempo). Only what is missing is added, and never in
|
|
203
215
|
the in-memory test database (nothing is set up there yet).
|
|
204
216
|
*/
|
|
205
217
|
const systemSettingsReady = process.env.KEMPO_DB === 'pglite'
|
|
206
218
|
? Promise.resolve()
|
|
207
219
|
: (async () => {
|
|
208
220
|
for(const [step, run] of [
|
|
221
|
+
['schema', async () => {
|
|
222
|
+
const [error, result] = await syncCoreSchema();
|
|
223
|
+
if(result?.applied.length) console.log(`[kempo] Database brought up to date: ${result.applied.join('; ')}`);
|
|
224
|
+
for(const { change, reason } of result?.failed ?? []) console.error(`[kempo] Database change failed: ${change}: ${reason}`);
|
|
225
|
+
return [error];
|
|
226
|
+
}],
|
|
227
|
+
['seed', async () => {
|
|
228
|
+
const [error, result] = await seedIfNew();
|
|
229
|
+
if(result?.seeded) console.log('[kempo] New database: its groups, permissions and settings were set up. Open /setup to create the first administrator.');
|
|
230
|
+
return [error];
|
|
231
|
+
}],
|
|
232
|
+
['upgrades', async () => {
|
|
233
|
+
const [error, result] = await runUpgrades();
|
|
234
|
+
if(result?.ran.length) console.log(`[kempo] Data migrations run: ${result.ran.join(', ')}`);
|
|
235
|
+
if(error){
|
|
236
|
+
console.error(`[kempo] ${error.msg}`);
|
|
237
|
+
if(error.breaking && process.env.KEMPO_SITE_ROOT){
|
|
238
|
+
flagFailed({ siteRoot: process.env.KEMPO_SITE_ROOT, reason: error.msg });
|
|
239
|
+
process.exit(1);
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
return [null];
|
|
243
|
+
}],
|
|
209
244
|
['settings', ensureSystemSettings],
|
|
210
245
|
['permissions', ensureSystemPermissions],
|
|
211
|
-
['
|
|
246
|
+
['extensions', async () => {
|
|
247
|
+
const [error, result] = await reconcileExtensions();
|
|
248
|
+
for(const { name, from, to } of result?.upgraded ?? []) console.log(`[kempo] Extension ${name} brought up to date: ${from} -> ${to}`);
|
|
249
|
+
for(const { name, from, to } of result?.reverted ?? []) console.log(`[kempo] Extension ${name} is back on ${to} (was ${from})`);
|
|
250
|
+
for(const { name, reason } of result?.failed ?? []) console.error(`[kempo] Extension ${name} could not be brought up to date: ${reason}`);
|
|
251
|
+
if(result?.failed.some(item => item.major) && process.env.KEMPO_SITE_ROOT){
|
|
252
|
+
flagFailed({ siteRoot: process.env.KEMPO_SITE_ROOT, reason: result.failed.filter(item => item.major).map(item => `${item.name}: ${item.reason}`).join('; ') });
|
|
253
|
+
process.exit(1);
|
|
254
|
+
}
|
|
255
|
+
return [error];
|
|
256
|
+
}],
|
|
257
|
+
['schema notice', notifySchemaAttention],
|
|
258
|
+
['jobs', () => registerJobs({ owner: 'kempo', jobs: [
|
|
259
|
+
{ name: 'email-maintenance', every: '1m', callback: './server/utils/email/maintainEmails.js' },
|
|
260
|
+
{ name: 'update-check', every: '12h', callback: './server/utils/updates/runUpdateCheck.js' },
|
|
261
|
+
] })],
|
|
212
262
|
]){
|
|
213
263
|
const [error] = await run();
|
|
214
264
|
if(error) console.error(`[kempo] System ${step}: ${error.msg}`);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "kempo",
|
|
3
|
-
"version": "4.
|
|
3
|
+
"version": "4.9.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "A fullstack CMS framework for creating websites with user authentication",
|
|
6
6
|
"scripts": {
|
|
@@ -33,6 +33,8 @@
|
|
|
33
33
|
"server/utils",
|
|
34
34
|
"server/db/index.js",
|
|
35
35
|
"server/db/schema.js",
|
|
36
|
+
"server/db/upgrades",
|
|
37
|
+
"docker",
|
|
36
38
|
"server/sdk.js",
|
|
37
39
|
"middleware/kempo.js",
|
|
38
40
|
"app-templates",
|
package/server/db/schema.js
CHANGED
|
@@ -115,6 +115,18 @@ export const extension = pgTable('extension', {
|
|
|
115
115
|
updatedAt: timestamp('updatedAt').notNull(),
|
|
116
116
|
});
|
|
117
117
|
|
|
118
|
+
/*
|
|
119
|
+
Which of kempo's own data migrations (server/db/upgrades/*.js) have run on this database. The additive changes to its
|
|
120
|
+
tables need no record, they are found by comparing; a migration that restructures data runs once and is recorded here.
|
|
121
|
+
The row with id 'baseline' marks the database as already holding what the shipped migrations produce.
|
|
122
|
+
*/
|
|
123
|
+
export const upgrade = pgTable('upgrade', {
|
|
124
|
+
id: text('id').primaryKey(),
|
|
125
|
+
description: text('description'),
|
|
126
|
+
breaking: boolean('breaking').notNull().default(false),
|
|
127
|
+
appliedAt: timestamp('appliedAt').notNull().defaultNow(),
|
|
128
|
+
});
|
|
129
|
+
|
|
118
130
|
/*
|
|
119
131
|
Scheduled jobs: recurring work an extension declares in its kempo-config.json `jobs`. A row per job
|
|
120
132
|
is the schedule and the lease: `nextRunAt` is when it is next due and `lockedUntil` is held while a
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
# Data migrations
|
|
2
|
+
|
|
3
|
+
Additive changes to kempo's tables (new tables, columns, indexes) need nothing here: they are applied when the server starts.
|
|
4
|
+
A change that restructures or moves data goes in a file in this folder, named so that they sort in the order they must run:
|
|
5
|
+
|
|
6
|
+
4.9.0-split-user-name.js
|
|
7
|
+
|
|
8
|
+
```js
|
|
9
|
+
export const meta = { description: 'Splits user.name into first and last', breaking: true };
|
|
10
|
+
|
|
11
|
+
export const up = async ({ db, sql }) => {
|
|
12
|
+
await db.execute(sql`...`);
|
|
13
|
+
};
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
- It runs once, inside a transaction, when the first server of the new version starts, and is recorded in the `upgrade` table.
|
|
17
|
+
- `breaking: true` is for anything the previous version cannot run against (data moved or removed). The Updates screen warns
|
|
18
|
+
before such an update, kempo backs the database up first, and a failure puts the previous version and that backup back.
|
|
19
|
+
- Add one only in a release whose version is higher than the first one that has this folder: a site's `upgrade` table starts with
|
|
20
|
+
every file that was here when it first started recorded as already run.
|
package/server/sdk.js
CHANGED
|
@@ -221,6 +221,9 @@ export { default as installExtension } from './utils/extensions/installExtension
|
|
|
221
221
|
export { default as listExtensions } from './utils/extensions/listExtensions.js';
|
|
222
222
|
export { default as uninstallExtension } from './utils/extensions/uninstallExtension.js';
|
|
223
223
|
export { default as updateExtension } from './utils/extensions/updateExtension.js';
|
|
224
|
+
export { default as upgradeExtension } from './utils/extensions/upgradeExtension.js';
|
|
225
|
+
export { default as reconcileExtensions } from './utils/extensions/reconcileExtensions.js';
|
|
226
|
+
export { default as writeSiteFile } from './utils/extensions/writeSiteFile.js';
|
|
224
227
|
|
|
225
228
|
/*
|
|
226
229
|
Notifications
|
|
@@ -1,23 +1,11 @@
|
|
|
1
1
|
import db from '../../db/index.js';
|
|
2
2
|
import { extension } from '../../db/schema.js';
|
|
3
3
|
import { eq } from 'drizzle-orm';
|
|
4
|
+
import { compareVersions, isVersion } from '../updates/helpers.js';
|
|
5
|
+
import fetchManifest from '../updates/fetchManifest.js';
|
|
4
6
|
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
if(!match) return null;
|
|
8
|
-
return `https://raw.githubusercontent.com/${match[1]}/${match[2]}/main/${file}`;
|
|
9
|
-
};
|
|
10
|
-
|
|
11
|
-
const semverGt = (a, b) => {
|
|
12
|
-
const parse = v => (v || '0.0.0').replace(/^v/, '').split('.').map(Number);
|
|
13
|
-
const [aMaj, aMin, aPatch] = parse(a);
|
|
14
|
-
const [bMaj, bMin, bPatch] = parse(b);
|
|
15
|
-
if(aMaj !== bMaj) return aMaj > bMaj;
|
|
16
|
-
if(aMin !== bMin) return aMin > bMin;
|
|
17
|
-
return aPatch > bPatch;
|
|
18
|
-
};
|
|
19
|
-
|
|
20
|
-
export default async ({ name }) => {
|
|
7
|
+
/* Whether npm has a newer version of one installed extension than the one recorded for it. */
|
|
8
|
+
export default async ({ name, fetcher }) => {
|
|
21
9
|
if(!name){
|
|
22
10
|
return [{ code: 400, msg: 'Extension name is required' }, null];
|
|
23
11
|
}
|
|
@@ -32,25 +20,10 @@ export default async ({ name }) => {
|
|
|
32
20
|
return [{ code: 500, msg: 'Failed to find extension' }, null];
|
|
33
21
|
}
|
|
34
22
|
|
|
35
|
-
const
|
|
36
|
-
if(
|
|
37
|
-
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
const rawUrl = toRawUrl(gitUrl);
|
|
41
|
-
if(!rawUrl){
|
|
42
|
-
return [null, { hasUpdate: false, reason: 'Unsupported git URL format' }];
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
let remotePkg;
|
|
46
|
-
try {
|
|
47
|
-
const res = await fetch(rawUrl);
|
|
48
|
-
if(!res.ok) return [null, { hasUpdate: false, reason: 'Failed to fetch remote package.json' }];
|
|
49
|
-
remotePkg = await res.json();
|
|
50
|
-
} catch(error){
|
|
51
|
-
return [{ code: 502, msg: 'Failed to reach remote repository' }, null];
|
|
52
|
-
}
|
|
23
|
+
const [error, manifest] = await fetchManifest({ name, fetcher });
|
|
24
|
+
if(error?.code === 404) return [null, { hasUpdate: false, reason: 'This extension is not on npm' }];
|
|
25
|
+
if(error) return [error, null];
|
|
53
26
|
|
|
54
|
-
const hasUpdate =
|
|
55
|
-
return [null, { hasUpdate, currentVersion: record.version, latestVersion:
|
|
27
|
+
const hasUpdate = isVersion(record.version) && compareVersions(manifest.version, record.version) > 0;
|
|
28
|
+
return [null, { hasUpdate, currentVersion: record.version, latestVersion: manifest.version }];
|
|
56
29
|
};
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
import { and, eq } from 'drizzle-orm';
|
|
2
|
+
import { join } from 'path';
|
|
3
|
+
import db from '../../db/index.js';
|
|
4
|
+
import { extension } from '../../db/schema.js';
|
|
5
|
+
import readKempoConfig from './readKempoConfig.js';
|
|
6
|
+
import upgradeExtension from './upgradeExtension.js';
|
|
7
|
+
import { compareVersions, isBreakingBump, isVersion } from '../updates/helpers.js';
|
|
8
|
+
|
|
9
|
+
/*
|
|
10
|
+
Brings every installed extension's database in step with the version on disk. Run when the server starts, so it is the one
|
|
11
|
+
place an update of an extension takes effect, whichever way the new version got there (the Updates screen, a switch of the
|
|
12
|
+
site's code, npm run by hand, an image that was rebuilt). It is what a deploy script would otherwise have to do.
|
|
13
|
+
|
|
14
|
+
on disk is newer than the row upgradeExtension: its tables, update.js and whatever it newly declares
|
|
15
|
+
on disk is older than the row the site went back: the row says so, and no script runs, so going back is safe
|
|
16
|
+
the same, or not installed nothing
|
|
17
|
+
|
|
18
|
+
The row is claimed first (its version moved to the new one only if it still holds the old), so of several servers starting
|
|
19
|
+
together exactly one upgrades an extension. A failed upgrade gives the row its old version back, so it is tried again at
|
|
20
|
+
the next start, and it is reported rather than stopping the server.
|
|
21
|
+
|
|
22
|
+
Extensions are taken in dependency order (what each declares in `dependencies`, in the new version's kempo-config.json), so
|
|
23
|
+
an extension's update script finds the ones it builds on already up to date: kempo-media after kempo-files and kempo-thumbs,
|
|
24
|
+
kempo-commerce after kempo-products and kempo-payments.
|
|
25
|
+
*/
|
|
26
|
+
let lastRun = { ran: false, upgraded: [], reverted: [], failed: [] };
|
|
27
|
+
|
|
28
|
+
export const getReconcileResult = () => lastRun;
|
|
29
|
+
|
|
30
|
+
const isBreaking = (from, to) => isVersion(from) && isVersion(to) && isBreakingBump(from, to);
|
|
31
|
+
|
|
32
|
+
const newer = (installed, recorded) => (isVersion(installed) && isVersion(recorded) ? compareVersions(installed, recorded) : (installed === recorded ? 0 : 1));
|
|
33
|
+
|
|
34
|
+
export default async ({ executor = db, root = process.cwd(), upgrade = upgradeExtension } = {}) => {
|
|
35
|
+
const result = { upgraded: [], reverted: [], failed: [] };
|
|
36
|
+
|
|
37
|
+
try {
|
|
38
|
+
const found = [];
|
|
39
|
+
for(const row of await executor.select().from(extension)){
|
|
40
|
+
const extRoot = join(root, 'node_modules', row.name);
|
|
41
|
+
try {
|
|
42
|
+
const { pkg, kempo } = await readKempoConfig(extRoot);
|
|
43
|
+
found.push({ row, extRoot, installed: pkg.version, requires: kempo.dependencies ?? row.kempo?.dependencies ?? [] });
|
|
44
|
+
} catch {
|
|
45
|
+
continue;
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
const ordered = [];
|
|
50
|
+
const placed = new Set();
|
|
51
|
+
const place = item => {
|
|
52
|
+
if(placed.has(item.row.name)) return;
|
|
53
|
+
placed.add(item.row.name);
|
|
54
|
+
for(const name of item.requires){
|
|
55
|
+
const dependency = found.find(other => other.row.name === name);
|
|
56
|
+
if(dependency) place(dependency);
|
|
57
|
+
}
|
|
58
|
+
ordered.push(item);
|
|
59
|
+
};
|
|
60
|
+
found.forEach(place);
|
|
61
|
+
|
|
62
|
+
for(const { row, extRoot, installed } of ordered){
|
|
63
|
+
if(!installed || installed === row.version) continue;
|
|
64
|
+
|
|
65
|
+
const direction = row.version ? newer(installed, row.version) : 1;
|
|
66
|
+
if(direction < 0){
|
|
67
|
+
await executor.update(extension).set({ version: installed, updatedAt: new Date() }).where(eq(extension.name, row.name));
|
|
68
|
+
result.reverted.push({ name: row.name, from: row.version, to: installed });
|
|
69
|
+
continue;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
const claim = and(eq(extension.name, row.name), row.version ? eq(extension.version, row.version) : undefined);
|
|
73
|
+
const [claimed] = await executor.update(extension).set({ version: installed }).where(claim).returning({ name: extension.name });
|
|
74
|
+
if(!claimed) continue;
|
|
75
|
+
|
|
76
|
+
const [error] = await upgrade({ name: row.name, record: row, extRoot });
|
|
77
|
+
if(error){
|
|
78
|
+
await executor.update(extension).set({ version: row.version }).where(eq(extension.name, row.name));
|
|
79
|
+
result.failed.push({ name: row.name, from: row.version, to: installed, major: isBreaking(row.version, installed), reason: error.msg });
|
|
80
|
+
} else {
|
|
81
|
+
result.upgraded.push({ name: row.name, from: row.version, to: installed });
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
} catch(error) {
|
|
85
|
+
return [{ code: 500, msg: `The extensions could not be brought up to date: ${String(error.cause?.message || error.message).slice(0, 300)}` }, result];
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
lastRun = { ran: true, ...result };
|
|
89
|
+
return [null, result];
|
|
90
|
+
};
|