@shapio/cms 0.0.0-stage → 0.2.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +27 -2
- package/dist/admin/apple-touch-icon.png +0 -0
- package/dist/admin/assets/AssistError-hVUWpP3F.js +2 -0
- package/dist/admin/assets/AssistError-hVUWpP3F.js.map +1 -0
- package/dist/admin/assets/BlockMenuItems-B0g93m6M.js +6 -0
- package/dist/admin/assets/BlockMenuItems-B0g93m6M.js.map +1 -0
- package/dist/admin/assets/Body-CFQKONK4.js +2 -0
- package/dist/admin/assets/Body-CFQKONK4.js.map +1 -0
- package/dist/admin/assets/Builder-Do5KVHV9.js +2 -0
- package/dist/admin/assets/Builder-Do5KVHV9.js.map +1 -0
- package/dist/admin/assets/ConfirmDialog-D6rs75TP.js +2 -0
- package/dist/admin/assets/ConfirmDialog-D6rs75TP.js.map +1 -0
- package/dist/admin/assets/CopyButton-Bc7crFDE.js +2 -0
- package/dist/admin/assets/CopyButton-Bc7crFDE.js.map +1 -0
- package/dist/admin/assets/CursorPager-BFPD_adV.js +2 -0
- package/dist/admin/assets/CursorPager-BFPD_adV.js.map +1 -0
- package/dist/admin/assets/ExternalLink-Cdfcyyed.js +2 -0
- package/dist/admin/assets/ExternalLink-Cdfcyyed.js.map +1 -0
- package/dist/admin/assets/FormCheckboxGroup-Bicl1CBP.js +2 -0
- package/dist/admin/assets/FormCheckboxGroup-Bicl1CBP.js.map +1 -0
- package/dist/admin/assets/FormRadioGroup-34iVSV4L.js +2 -0
- package/dist/admin/assets/FormRadioGroup-34iVSV4L.js.map +1 -0
- package/dist/admin/assets/FormSelectField-Ba4fIu-8.js +2 -0
- package/dist/admin/assets/FormSelectField-Ba4fIu-8.js.map +1 -0
- package/dist/admin/assets/FormSwitchField-DN6bfPC0.js +2 -0
- package/dist/admin/assets/FormSwitchField-DN6bfPC0.js.map +1 -0
- package/dist/admin/assets/FormTextareaField-WsNjLm32.js +2 -0
- package/dist/admin/assets/FormTextareaField-WsNjLm32.js.map +1 -0
- package/dist/admin/assets/HintedLabel-jKLM0ETt.js +2 -0
- package/dist/admin/assets/HintedLabel-jKLM0ETt.js.map +1 -0
- package/dist/admin/assets/InfoHint-DBqcrmZ3.js +2 -0
- package/dist/admin/assets/InfoHint-DBqcrmZ3.js.map +1 -0
- package/dist/admin/assets/InsertMenuItem-CRKXblK5.js +2 -0
- package/dist/admin/assets/InsertMenuItem-CRKXblK5.js.map +1 -0
- package/dist/admin/assets/LinkTabs-Bn2JVqOL.js +2 -0
- package/dist/admin/assets/LinkTabs-Bn2JVqOL.js.map +1 -0
- package/dist/admin/assets/Match-DaYgKrk7.js +2 -0
- package/dist/admin/assets/Match-DaYgKrk7.js.map +1 -0
- package/dist/admin/assets/Panel-6wFe96Gr.js +2 -0
- package/dist/admin/assets/Panel-6wFe96Gr.js.map +1 -0
- package/dist/admin/assets/QueryView-DFZtm0fn.js +2 -0
- package/dist/admin/assets/QueryView-DFZtm0fn.js.map +1 -0
- package/dist/admin/assets/RadioTile-DsTyz7ml.js +2 -0
- package/dist/admin/assets/RadioTile-DsTyz7ml.js.map +1 -0
- package/dist/admin/assets/RichTextField-BGkH403g.js +144 -0
- package/dist/admin/assets/RichTextField-BGkH403g.js.map +1 -0
- package/dist/admin/assets/RowTitle-sFt6NjO4.js +2 -0
- package/dist/admin/assets/RowTitle-sFt6NjO4.js.map +1 -0
- package/dist/admin/assets/SecretReveal-Z6MOFdcL.js +2 -0
- package/dist/admin/assets/SecretReveal-Z6MOFdcL.js.map +1 -0
- package/dist/admin/assets/StepList-BTP_EMzx.js +2 -0
- package/dist/admin/assets/StepList-BTP_EMzx.js.map +1 -0
- package/dist/admin/assets/Structure-D5-hCUuF.js +2 -0
- package/dist/admin/assets/Structure-D5-hCUuF.js.map +1 -0
- package/dist/admin/assets/SubNavLink-C5oN5mzB.js +2 -0
- package/dist/admin/assets/SubNavLink-C5oN5mzB.js.map +1 -0
- package/dist/admin/assets/SuggestAltButton-BuN35BBL.js +2 -0
- package/dist/admin/assets/SuggestAltButton-BuN35BBL.js.map +1 -0
- package/dist/admin/assets/TextLink-B4a6j3r6.js +2 -0
- package/dist/admin/assets/TextLink-B4a6j3r6.js.map +1 -0
- package/dist/admin/assets/Thumbnail-u8NE5NhQ.js +2 -0
- package/dist/admin/assets/Thumbnail-u8NE5NhQ.js.map +1 -0
- package/dist/admin/assets/UnsavedChangesGuard-BYwMTDsE.js +2 -0
- package/dist/admin/assets/UnsavedChangesGuard-BYwMTDsE.js.map +1 -0
- package/dist/admin/assets/UserAvatar-D-yX0ozh.js +2 -0
- package/dist/admin/assets/UserAvatar-D-yX0ozh.js.map +1 -0
- package/dist/admin/assets/View-BLsQYPow.js +11 -0
- package/dist/admin/assets/View-BLsQYPow.js.map +1 -0
- package/dist/admin/assets/arrow-up-Ws7W9KsZ.js +2 -0
- package/dist/admin/assets/arrow-up-Ws7W9KsZ.js.map +1 -0
- package/dist/admin/assets/auth-b3_9QbtL.js +2 -0
- package/dist/admin/assets/auth-b3_9QbtL.js.map +1 -0
- package/dist/admin/assets/badge-CMox6-v3.js +2 -0
- package/dist/admin/assets/badge-CMox6-v3.js.map +1 -0
- package/dist/admin/assets/calendar-clock-9W0Lkt89.js +2 -0
- package/dist/admin/assets/calendar-clock-9W0Lkt89.js.map +1 -0
- package/dist/admin/assets/changeSets-CO7JdILW.js +2 -0
- package/dist/admin/assets/changeSets-CO7JdILW.js.map +1 -0
- package/dist/admin/assets/chevron-left-DyqYjcMB.js +2 -0
- package/dist/admin/assets/chevron-left-DyqYjcMB.js.map +1 -0
- package/dist/admin/assets/circle-check-aJ2DW5t4.js +2 -0
- package/dist/admin/assets/circle-check-aJ2DW5t4.js.map +1 -0
- package/dist/admin/assets/circle-x-BnRBht9z.js +2 -0
- package/dist/admin/assets/circle-x-BnRBht9z.js.map +1 -0
- package/dist/admin/assets/client-C8vMCv-p.js +10 -0
- package/dist/admin/assets/client-C8vMCv-p.js.map +1 -0
- package/dist/admin/assets/clock-DRtFQbTs.js +2 -0
- package/dist/admin/assets/clock-DRtFQbTs.js.map +1 -0
- package/dist/admin/assets/cn-DnXL75B0.js +2 -0
- package/dist/admin/assets/cn-DnXL75B0.js.map +1 -0
- package/dist/admin/assets/coerce-COM3rk1i.js +2 -0
- package/dist/admin/assets/coerce-COM3rk1i.js.map +1 -0
- package/dist/admin/assets/constants-CS1ziZO0.js +2 -0
- package/dist/admin/assets/constants-CS1ziZO0.js.map +1 -0
- package/dist/admin/assets/constants-DCtq_UOe.js +2 -0
- package/dist/admin/assets/constants-DCtq_UOe.js.map +1 -0
- package/dist/admin/assets/constants-DUBUgzpU.js +2 -0
- package/dist/admin/assets/constants-DUBUgzpU.js.map +1 -0
- package/dist/admin/assets/content-Dic2fof_.js +3 -0
- package/dist/admin/assets/content-Dic2fof_.js.map +1 -0
- package/dist/admin/assets/contentCounts-Ct0tYgHD.js +2 -0
- package/dist/admin/assets/contentCounts-Ct0tYgHD.js.map +1 -0
- package/dist/admin/assets/contentTypes-D4_Ax9rb.js +2 -0
- package/dist/admin/assets/contentTypes-D4_Ax9rb.js.map +1 -0
- package/dist/admin/assets/copy-B5B8RjV0.js +2 -0
- package/dist/admin/assets/copy-B5B8RjV0.js.map +1 -0
- package/dist/admin/assets/dateTimeLocal-BuBv3it2.js +2 -0
- package/dist/admin/assets/dateTimeLocal-BuBv3it2.js.map +1 -0
- package/dist/admin/assets/defineEditor-CiJc766Y.js +2 -0
- package/dist/admin/assets/defineEditor-CiJc766Y.js.map +1 -0
- package/dist/admin/assets/develop-Brnb5YPC.js +11 -0
- package/dist/admin/assets/develop-Brnb5YPC.js.map +1 -0
- package/dist/admin/assets/dropdown-menu-CW3fabv5.js +2 -0
- package/dist/admin/assets/dropdown-menu-CW3fabv5.js.map +1 -0
- package/dist/admin/assets/ellipsis-DNdmromA.js +2 -0
- package/dist/admin/assets/ellipsis-DNdmromA.js.map +1 -0
- package/dist/admin/assets/errors-DfoXUVDI.js +2 -0
- package/dist/admin/assets/errors-DfoXUVDI.js.map +1 -0
- package/dist/admin/assets/external-link-YnuWXDBk.js +2 -0
- package/dist/admin/assets/external-link-YnuWXDBk.js.map +1 -0
- package/dist/admin/assets/file-text-CB7Bc0GA.js +2 -0
- package/dist/admin/assets/file-text-CB7Bc0GA.js.map +1 -0
- package/dist/admin/assets/fileRoute-BYwireXG.js +2 -0
- package/dist/admin/assets/fileRoute-BYwireXG.js.map +1 -0
- package/dist/admin/assets/globe-Bvs3UC3V.js +2 -0
- package/dist/admin/assets/globe-Bvs3UC3V.js.map +1 -0
- package/dist/admin/assets/image-CeoxwJeM.js +2 -0
- package/dist/admin/assets/image-CeoxwJeM.js.map +1 -0
- package/dist/admin/assets/image-off-iVqYw2Zc.js +2 -0
- package/dist/admin/assets/image-off-iVqYw2Zc.js.map +1 -0
- package/dist/admin/assets/inbox-DYbEOpaQ.js +2 -0
- package/dist/admin/assets/inbox-DYbEOpaQ.js.map +1 -0
- package/dist/admin/assets/inbox-wDoqym--.js +2 -0
- package/dist/admin/assets/inbox-wDoqym--.js.map +1 -0
- package/dist/admin/assets/index-57Mn6XLO.js +4 -0
- package/dist/admin/assets/index-57Mn6XLO.js.map +1 -0
- package/dist/admin/assets/index-BLYOgCKc.css +2 -0
- package/dist/admin/assets/jsx-runtime-DREnUpxT.js +2 -0
- package/dist/admin/assets/jsx-runtime-DREnUpxT.js.map +1 -0
- package/dist/admin/assets/key-round-Bcw6qqcb.js +2 -0
- package/dist/admin/assets/key-round-Bcw6qqcb.js.map +1 -0
- package/dist/admin/assets/link-2-DhM2vi4v.js +2 -0
- package/dist/admin/assets/link-2-DhM2vi4v.js.map +1 -0
- package/dist/admin/assets/link-2-off-DpDOMsa-.js +2 -0
- package/dist/admin/assets/link-2-off-DpDOMsa-.js.map +1 -0
- package/dist/admin/assets/link-CKr_uUfb.js +2 -0
- package/dist/admin/assets/link-CKr_uUfb.js.map +1 -0
- package/dist/admin/assets/list-BElvKZw_.js +2 -0
- package/dist/admin/assets/list-BElvKZw_.js.map +1 -0
- package/dist/admin/assets/locales-Bnv3qcdZ.js +2 -0
- package/dist/admin/assets/locales-Bnv3qcdZ.js.map +1 -0
- package/dist/admin/assets/media-BfDqe_2P.js +2 -0
- package/dist/admin/assets/media-BfDqe_2P.js.map +1 -0
- package/dist/admin/assets/media-DjK3xGFN.js +2 -0
- package/dist/admin/assets/media-DjK3xGFN.js.map +1 -0
- package/dist/admin/assets/modelPermissions-DZ1lWfQZ.js +2 -0
- package/dist/admin/assets/modelPermissions-DZ1lWfQZ.js.map +1 -0
- package/dist/admin/assets/network-CAJ76ILr.js +2 -0
- package/dist/admin/assets/network-CAJ76ILr.js.map +1 -0
- package/dist/admin/assets/pencil-Zd05MDs2.js +2 -0
- package/dist/admin/assets/pencil-Zd05MDs2.js.map +1 -0
- package/dist/admin/assets/plus-B0gd63Da.js +2 -0
- package/dist/admin/assets/plus-B0gd63Da.js.map +1 -0
- package/dist/admin/assets/preload-helper-CJKHb_rG.js +2 -0
- package/dist/admin/assets/preload-helper-CJKHb_rG.js.map +1 -0
- package/dist/admin/assets/publishing-B7zv1e7j.js +2 -0
- package/dist/admin/assets/publishing-B7zv1e7j.js.map +1 -0
- package/dist/admin/assets/publishing-vCVjaSGF.js +2 -0
- package/dist/admin/assets/publishing-vCVjaSGF.js.map +1 -0
- package/dist/admin/assets/radio-group-DVR0mTpo.js +2 -0
- package/dist/admin/assets/radio-group-DVR0mTpo.js.map +1 -0
- package/dist/admin/assets/react-CQOZoUwg.js +2 -0
- package/dist/admin/assets/react-CQOZoUwg.js.map +1 -0
- package/dist/admin/assets/react-dom-pEVw9mjF.js +2 -0
- package/dist/admin/assets/react-dom-pEVw9mjF.js.map +1 -0
- package/dist/admin/assets/rolldown-runtime-Dd_uD5pT.js +1 -0
- package/dist/admin/assets/root-CDpNo7ef.js +2 -0
- package/dist/admin/assets/root-CDpNo7ef.js.map +1 -0
- package/dist/admin/assets/rotate-ccw-BOTDOdHf.js +2 -0
- package/dist/admin/assets/rotate-ccw-BOTDOdHf.js.map +1 -0
- package/dist/admin/assets/schedules-CG-ZphRK.js +2 -0
- package/dist/admin/assets/schedules-CG-ZphRK.js.map +1 -0
- package/dist/admin/assets/schema-KXXSPVJn.js +2 -0
- package/dist/admin/assets/schema-KXXSPVJn.js.map +1 -0
- package/dist/admin/assets/scroll-text-D-gHqYwR.js +2 -0
- package/dist/admin/assets/scroll-text-D-gHqYwR.js.map +1 -0
- package/dist/admin/assets/search-BcPL1qyc.js +2 -0
- package/dist/admin/assets/search-BcPL1qyc.js.map +1 -0
- package/dist/admin/assets/searchSchema-BGrRDBL_.js +2 -0
- package/dist/admin/assets/searchSchema-BGrRDBL_.js.map +1 -0
- package/dist/admin/assets/searchSchemas-ChN9hhuQ.js +2 -0
- package/dist/admin/assets/searchSchemas-ChN9hhuQ.js.map +1 -0
- package/dist/admin/assets/sections-BrGcWOnw.js +2 -0
- package/dist/admin/assets/sections-BrGcWOnw.js.map +1 -0
- package/dist/admin/assets/sections-i9TeeK-h.js +2 -0
- package/dist/admin/assets/sections-i9TeeK-h.js.map +1 -0
- package/dist/admin/assets/select--nGB4WjU.js +2 -0
- package/dist/admin/assets/select--nGB4WjU.js.map +1 -0
- package/dist/admin/assets/send-Bu3RRfdI.js +2 -0
- package/dist/admin/assets/send-Bu3RRfdI.js.map +1 -0
- package/dist/admin/assets/settings-68BAxrPM.js +2 -0
- package/dist/admin/assets/settings-68BAxrPM.js.map +1 -0
- package/dist/admin/assets/settle-LRKtTN_e.js +2 -0
- package/dist/admin/assets/settle-LRKtTN_e.js.map +1 -0
- package/dist/admin/assets/shared-react-KADNSNpb.js +1 -0
- package/dist/admin/assets/shared-react-dom-BpneAejY.js +1 -0
- package/dist/admin/assets/shared-react-dom-client-CnpZTXxo.js +1 -0
- package/dist/admin/assets/shared-react-jsx-runtime-CU_Fm1m8.js +1 -0
- package/dist/admin/assets/shared-shapio-editor-sdk-9ANIbEN0.js +1 -0
- package/dist/admin/assets/sites-C6_THCVK.js +2 -0
- package/dist/admin/assets/sites-C6_THCVK.js.map +1 -0
- package/dist/admin/assets/skeleton-DUvclBAr.js +42 -0
- package/dist/admin/assets/skeleton-DUvclBAr.js.map +1 -0
- package/dist/admin/assets/snapshots-CKjK-vkL.js +2 -0
- package/dist/admin/assets/snapshots-CKjK-vkL.js.map +1 -0
- package/dist/admin/assets/sparkles-B_NX7PAY.js +2 -0
- package/dist/admin/assets/sparkles-B_NX7PAY.js.map +1 -0
- package/dist/admin/assets/src-D6DABe5J.js +4 -0
- package/dist/admin/assets/src-D6DABe5J.js.map +1 -0
- package/dist/admin/assets/stableId-Dmr2Afn_.js +2 -0
- package/dist/admin/assets/stableId-Dmr2Afn_.js.map +1 -0
- package/dist/admin/assets/store-B5xrQ1Ex.js +2 -0
- package/dist/admin/assets/store-B5xrQ1Ex.js.map +1 -0
- package/dist/admin/assets/switch-B-FbT-l8.js +2 -0
- package/dist/admin/assets/switch-B-FbT-l8.js.map +1 -0
- package/dist/admin/assets/table-DQzCPm7J.js +56 -0
- package/dist/admin/assets/table-DQzCPm7J.js.map +1 -0
- package/dist/admin/assets/tabs-YThoOiE3.js +5 -0
- package/dist/admin/assets/tabs-YThoOiE3.js.map +1 -0
- package/dist/admin/assets/textarea-_wcx8Mn1.js +2 -0
- package/dist/admin/assets/textarea-_wcx8Mn1.js.map +1 -0
- package/dist/admin/assets/titles-DyCBLXue.js +2 -0
- package/dist/admin/assets/titles-DyCBLXue.js.map +1 -0
- package/dist/admin/assets/tokens-CqsxrApC.js +2 -0
- package/dist/admin/assets/tokens-CqsxrApC.js.map +1 -0
- package/dist/admin/assets/tooltip-BMe4HylJ.js +2 -0
- package/dist/admin/assets/tooltip-BMe4HylJ.js.map +1 -0
- package/dist/admin/assets/undo-2-DMOHOH6w.js +2 -0
- package/dist/admin/assets/undo-2-DMOHOH6w.js.map +1 -0
- package/dist/admin/assets/useAuditLabels-CSw_kwLs.js +2 -0
- package/dist/admin/assets/useAuditLabels-CSw_kwLs.js.map +1 -0
- package/dist/admin/assets/useConfirmTarget-9JmfiY2X.js +2 -0
- package/dist/admin/assets/useConfirmTarget-9JmfiY2X.js.map +1 -0
- package/dist/admin/assets/useContentSchema-CS5QQcRk.js +2 -0
- package/dist/admin/assets/useContentSchema-CS5QQcRk.js.map +1 -0
- package/dist/admin/assets/useCursorPager-Dt_axwd1.js +2 -0
- package/dist/admin/assets/useCursorPager-Dt_axwd1.js.map +1 -0
- package/dist/admin/assets/useDebouncedValue-Dqs3wwhn.js +2 -0
- package/dist/admin/assets/useDebouncedValue-Dqs3wwhn.js.map +1 -0
- package/dist/admin/assets/useDiscardGuard-7rRGpd4q.js +2 -0
- package/dist/admin/assets/useDiscardGuard-7rRGpd4q.js.map +1 -0
- package/dist/admin/assets/useMediaUploader-CBUcNW6d.js +2 -0
- package/dist/admin/assets/useMediaUploader-CBUcNW6d.js.map +1 -0
- package/dist/admin/assets/usePaletteItems-bbTIqpPu.js +2 -0
- package/dist/admin/assets/usePaletteItems-bbTIqpPu.js.map +1 -0
- package/dist/admin/assets/usePlaces-D1raoQ2s.js +2 -0
- package/dist/admin/assets/usePlaces-D1raoQ2s.js.map +1 -0
- package/dist/admin/assets/useQueries-DKGIdq6A.js +2 -0
- package/dist/admin/assets/useQueries-DKGIdq6A.js.map +1 -0
- package/dist/admin/assets/useSaveShortcut-rKtp1qK7.js +2 -0
- package/dist/admin/assets/useSaveShortcut-rKtp1qK7.js.map +1 -0
- package/dist/admin/assets/useSearchInput-1fDoEtXe.js +2 -0
- package/dist/admin/assets/useSearchInput-1fDoEtXe.js.map +1 -0
- package/dist/admin/assets/users-C1ZSee3N.js +2 -0
- package/dist/admin/assets/users-C1ZSee3N.js.map +1 -0
- package/dist/admin/assets/users-DMfQL0s4.js +2 -0
- package/dist/admin/assets/users-DMfQL0s4.js.map +1 -0
- package/dist/admin/assets/w3c-keyname-BOAvb0qz.js +2 -0
- package/dist/admin/assets/w3c-keyname-BOAvb0qz.js.map +1 -0
- package/dist/admin/assets/zod-Pf5A-ax4.js +2 -0
- package/dist/admin/assets/zod-Pf5A-ax4.js.map +1 -0
- package/dist/admin/favicon-32.png +0 -0
- package/dist/admin/favicon.svg +5 -0
- package/dist/admin/fonts/OFL-SourceSerif4.txt +93 -0
- package/dist/admin/fonts/OFL.txt +93 -0
- package/dist/admin/fonts/manrope-latin-ext-wght-normal.woff2 +0 -0
- package/dist/admin/fonts/manrope-latin-wght-normal.woff2 +0 -0
- package/dist/admin/fonts/source-serif-4-latin-ext-wght-italic.woff2 +0 -0
- package/dist/admin/fonts/source-serif-4-latin-ext-wght-normal.woff2 +0 -0
- package/dist/admin/fonts/source-serif-4-latin-wght-italic.woff2 +0 -0
- package/dist/admin/fonts/source-serif-4-latin-wght-normal.woff2 +0 -0
- package/dist/admin/index.html +89 -0
- package/dist/admin/theme-init.js +18 -0
- package/dist/cli.js +5163 -0
- package/dist/cli.js.map +1 -0
- package/dist/config.d.ts +2 -0
- package/dist/config.js +39 -0
- package/dist/config.js.map +1 -0
- package/dist/index.d.ts +1051 -0
- package/dist/index.js +3 -0
- package/dist/public-CKU0Gkfq.d.ts +1177 -0
- package/dist/worker-C-MSYr4l.js +46445 -0
- package/dist/worker-C-MSYr4l.js.map +1 -0
- package/package.json +98 -3
- package/vendor/graphiql/LICENSE.graphiql +21 -0
- package/vendor/graphiql/LICENSE.react +21 -0
- package/vendor/graphiql/LICENSE.react-dom +21 -0
- package/vendor/graphiql/graphiql.min.css +1 -0
- package/vendor/graphiql/graphiql.min.js +46 -0
- package/vendor/graphiql/react-dom.production.min.js +267 -0
- package/vendor/graphiql/react.production.min.js +31 -0
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,1051 @@
|
|
|
1
|
+
import { A as ServiceFactoryContext, C as HookEvent, D as MediaUsage, E as MediaReferenceService, F as PermissionEvaluator, I as Principal, L as DB, M as ShapioServices, N as defineConfig, O as ModelHooks, P as isHookError, R as OutboxEvents, S as HookError, T as JobHandlerContext, _ as ExtensionRoute, a as BeforeHookContext, b as ExtensionSite, c as ContentReadOptions, d as EXTENSION_CONTRACT_VERSION, f as EnqueueOptions, g as ExtensionJobService, h as ExtensionJobHandler, i as BeforeHook, j as ShapioConfig, k as ServiceFactory, l as ContentReadService, m as ExtensionHostConfig, n as AfterHookContext, o as BeforeHookEvent, p as EntryData, r as AfterHookEvent, s as ContentReadEntry, t as AfterHook, u as CustomServices, v as ExtensionRouteOptions, w as HookModel, x as HookEntry, y as ExtensionServices, z as ContentData } from "./public-CKU0Gkfq.js";
|
|
2
|
+
import { FastifyBaseLogger, FastifyInstance } from "fastify";
|
|
3
|
+
import { Kysely, Selectable, Transaction } from "kysely";
|
|
4
|
+
import { Static, Type } from "typebox";
|
|
5
|
+
import "pino";
|
|
6
|
+
import { BlockList } from "node:net";
|
|
7
|
+
//#region src/config/schema.d.ts
|
|
8
|
+
/**
|
|
9
|
+
* Every setting Shapio reads from the environment. This is the only place that knows env var names;
|
|
10
|
+
* the rest of the code receives a typed `AppConfig`. Cross-field rules live in config/index.ts.
|
|
11
|
+
*/
|
|
12
|
+
declare const configSchema: Type.TObject<{
|
|
13
|
+
NODE_ENV: Type.TEnum<["development", "production", "test"]>;
|
|
14
|
+
HOST: Type.TString;
|
|
15
|
+
PORT: Type.TInteger;
|
|
16
|
+
LOG_LEVEL: Type.TEnum<["fatal", "error", "warn", "info", "debug", "trace", "silent"]>;
|
|
17
|
+
LOG_PRETTY: Type.TBoolean;
|
|
18
|
+
/** Origin users reach Shapio at, e.g. https://cms.example.com. Required in production. */
|
|
19
|
+
PUBLIC_URL: Type.TOptional<Type.TString>;
|
|
20
|
+
/** Sub-path Shapio is served under, e.g. /cms. Prefixes every route and the admin. */
|
|
21
|
+
BASE_PATH: Type.TString;
|
|
22
|
+
/** `true`, `false`, or the number of proxy hops to trust for X-Forwarded-* headers. */
|
|
23
|
+
TRUST_PROXY: Type.TString;
|
|
24
|
+
CORS_ORIGINS: Type.TString;
|
|
25
|
+
RATE_LIMIT_MAX: Type.TInteger;
|
|
26
|
+
RATE_LIMIT_WINDOW_MS: Type.TInteger;
|
|
27
|
+
/** Requests per window and IP for public media files (`/api/media/f/*` without a signature). */
|
|
28
|
+
MEDIA_RATE_LIMIT_MAX: Type.TInteger;
|
|
29
|
+
/** HTTPS from certificate files. Both or neither. */
|
|
30
|
+
TLS_CERT_FILE: Type.TOptional<Type.TString>;
|
|
31
|
+
TLS_KEY_FILE: Type.TOptional<Type.TString>;
|
|
32
|
+
/** How often the certificate files are re-read; a changed pair is applied without a restart. */
|
|
33
|
+
TLS_RELOAD_INTERVAL_MS: Type.TInteger;
|
|
34
|
+
/** Plain-HTTP listener that redirects to HTTPS on PUBLIC_URL. Only with TLS_CERT_FILE/TLS_KEY_FILE. */
|
|
35
|
+
HTTP_PORT: Type.TOptional<Type.TInteger>;
|
|
36
|
+
DATABASE_URL: Type.TString;
|
|
37
|
+
DATABASE_POOL_MAX: Type.TInteger;
|
|
38
|
+
MIGRATE_ON_START: Type.TBoolean;
|
|
39
|
+
/**
|
|
40
|
+
* LISTEN for schema-change notifications to refresh caches early. Turn off where LISTEN does not work
|
|
41
|
+
* (e.g. PgBouncer in transaction mode); every request still checks the durable schema version.
|
|
42
|
+
*/
|
|
43
|
+
SCHEMA_LISTEN: Type.TBoolean;
|
|
44
|
+
/**
|
|
45
|
+
* The instance's general signing secret (preview tokens, private-media URLs and upload grants, app-user token
|
|
46
|
+
* keys, the key that encrypts stored webhook and deployment secrets). At least 32 characters.
|
|
47
|
+
* Optional: when unset, one is generated on first boot and stored in the database (system_settings).
|
|
48
|
+
* Admin sessions and CSRF do not use it (their secrets are server-side).
|
|
49
|
+
*/
|
|
50
|
+
SESSION_SECRET: Type.TOptional<Type.TString>;
|
|
51
|
+
/**
|
|
52
|
+
* First-run setup. `false` (default): whoever opens the Setup screen first, while no admin exists, creates
|
|
53
|
+
* the owner. `true`: setup also needs the one-time token the server logs at boot (for installs reachable by
|
|
54
|
+
* others before setup). `shapio admin create` works either way.
|
|
55
|
+
*/
|
|
56
|
+
SETUP_REQUIRE_TOKEN: Type.TBoolean;
|
|
57
|
+
WORKER_MODE: Type.TEnum<["inline", "dedicated"]>;
|
|
58
|
+
WORKER_CONCURRENCY: Type.TInteger;
|
|
59
|
+
WORKER_POLL_INTERVAL_MS: Type.TInteger;
|
|
60
|
+
JOB_LEASE_MS: Type.TInteger;
|
|
61
|
+
SHUTDOWN_TIMEOUT_MS: Type.TInteger;
|
|
62
|
+
/**
|
|
63
|
+
* Days to keep finished bookkeeping: succeeded jobs, dispatched outbox events, after-hook run records,
|
|
64
|
+
* resolved content health findings.
|
|
65
|
+
*/
|
|
66
|
+
RETENTION_DAYS: Type.TInteger;
|
|
67
|
+
/** Days after which an untouched draft (or unpublished changes) shows up in the Inbox. */
|
|
68
|
+
HEALTH_STALE_DAYS: Type.TInteger;
|
|
69
|
+
INSTANCE_ID: Type.TOptional<Type.TString>;
|
|
70
|
+
/**
|
|
71
|
+
* Media storage. `local` writes under MEDIA_PATH; `s3` uses an S3-compatible service (package G). The S3
|
|
72
|
+
* settings may be set with either driver: `shapio media migrate` copies between the two.
|
|
73
|
+
*/
|
|
74
|
+
STORAGE_DRIVER: Type.TEnum<["local", "s3"]>;
|
|
75
|
+
MEDIA_PATH: Type.TString;
|
|
76
|
+
STORAGE_S3_BUCKET: Type.TOptional<Type.TString>;
|
|
77
|
+
STORAGE_S3_REGION: Type.TOptional<Type.TString>;
|
|
78
|
+
STORAGE_S3_ENDPOINT: Type.TOptional<Type.TString>;
|
|
79
|
+
STORAGE_S3_ACCESS_KEY_ID: Type.TOptional<Type.TString>;
|
|
80
|
+
STORAGE_S3_SECRET_ACCESS_KEY: Type.TOptional<Type.TString>;
|
|
81
|
+
STORAGE_S3_FORCE_PATH_STYLE: Type.TBoolean;
|
|
82
|
+
/**
|
|
83
|
+
* Base URL public media is served from, with the object key appended: a CDN or public bucket domain in
|
|
84
|
+
* front of S3/R2, or a CDN whose origin is `{PUBLIC_URL}{BASE_PATH}/api/media/f`. Unset: Shapio serves it.
|
|
85
|
+
*/
|
|
86
|
+
MEDIA_PUBLIC_BASE_URL: Type.TOptional<Type.TString>;
|
|
87
|
+
/** Largest file an upload may be, in bytes. */
|
|
88
|
+
MEDIA_MAX_UPLOAD_BYTES: Type.TInteger;
|
|
89
|
+
/** Comma-separated MIME types or `type/*` wildcards uploads may have (checked against the file's bytes). */
|
|
90
|
+
MEDIA_ALLOWED_TYPES: Type.TString;
|
|
91
|
+
/**
|
|
92
|
+
* The project's shapio.config.{ts,mts,js,mjs} (hooks, custom routes and services, editors, jobs; ADR 0009).
|
|
93
|
+
* Default: looked up in the working directory; none means no extensions.
|
|
94
|
+
*/
|
|
95
|
+
SHAPIO_CONFIG_PATH: Type.TOptional<Type.TString>;
|
|
96
|
+
/** Outgoing email (invitations, password resets). `console` logs messages instead of sending them. */
|
|
97
|
+
EMAIL_TRANSPORT: Type.TEnum<["console", "smtp"]>;
|
|
98
|
+
/** Sender, e.g. `Shapio <cms@example.com>`. Defaults to no-reply@<PUBLIC_URL host>. */
|
|
99
|
+
EMAIL_FROM: Type.TOptional<Type.TString>;
|
|
100
|
+
SMTP_HOST: Type.TOptional<Type.TString>;
|
|
101
|
+
SMTP_PORT: Type.TInteger;
|
|
102
|
+
/** true = TLS from the first byte (port 465); false = STARTTLS when the server offers it. */
|
|
103
|
+
SMTP_SECURE: Type.TBoolean;
|
|
104
|
+
SMTP_USER: Type.TOptional<Type.TString>;
|
|
105
|
+
SMTP_PASSWORD: Type.TOptional<Type.TString>;
|
|
106
|
+
/**
|
|
107
|
+
* App users (end users of your sites and apps, package I). `true`: an app user must confirm their email
|
|
108
|
+
* before signing in (needs APP_AUTH_CONFIRM_EMAIL_URL).
|
|
109
|
+
*/
|
|
110
|
+
APP_AUTH_REQUIRE_EMAIL_CONFIRMATION: Type.TBoolean;
|
|
111
|
+
/** Lifetime of an app-user access token (JWT), in seconds. Short: blocking takes effect immediately anyway. */
|
|
112
|
+
APP_AUTH_ACCESS_TOKEN_TTL_SECONDS: Type.TInteger;
|
|
113
|
+
/** Lifetime of an app-user refresh token, in days. Each refresh issues a new one (rotation). */
|
|
114
|
+
APP_AUTH_REFRESH_TOKEN_TTL_DAYS: Type.TInteger;
|
|
115
|
+
/**
|
|
116
|
+
* Page on your site that confirms an email address: Shapio emails `<url>#token=…`, the page POSTs the token
|
|
117
|
+
* to /api/app-auth/confirm-email. Unset: no confirmation emails are sent.
|
|
118
|
+
*/
|
|
119
|
+
APP_AUTH_CONFIRM_EMAIL_URL: Type.TOptional<Type.TString>;
|
|
120
|
+
/** Page on your site that sets a new password from `<url>#token=…`. Unset: password reset is unavailable. */
|
|
121
|
+
APP_AUTH_RESET_PASSWORD_URL: Type.TOptional<Type.TString>;
|
|
122
|
+
/**
|
|
123
|
+
* Where OAuth sign-in may send the browser back to (comma-separated): exact origins
|
|
124
|
+
* (`https://www.example.com`) or custom-scheme prefixes for native apps (`myapp://auth`). Unset: the
|
|
125
|
+
* origins in CORS_ORIGINS plus PUBLIC_URL's.
|
|
126
|
+
*/
|
|
127
|
+
APP_AUTH_RETURN_URLS: Type.TOptional<Type.TString>;
|
|
128
|
+
/** Sign in with Google (OAuth client of type "Web application"; callback `{PUBLIC_URL}{BASE_PATH}/api/app-auth/oauth/google/callback`). */
|
|
129
|
+
APP_AUTH_GOOGLE_CLIENT_ID: Type.TOptional<Type.TString>;
|
|
130
|
+
APP_AUTH_GOOGLE_CLIENT_SECRET: Type.TOptional<Type.TString>;
|
|
131
|
+
/** Sign in with GitHub (OAuth app; callback `{PUBLIC_URL}{BASE_PATH}/api/app-auth/oauth/github/callback`). */
|
|
132
|
+
APP_AUTH_GITHUB_CLIENT_ID: Type.TOptional<Type.TString>;
|
|
133
|
+
APP_AUTH_GITHUB_CLIENT_SECRET: Type.TOptional<Type.TString>;
|
|
134
|
+
/**
|
|
135
|
+
* Publishing (package H). Webhooks and deploy connections never reach private, loopback or link-local
|
|
136
|
+
* addresses unless the address is in this comma-separated CIDR list AND the webhook/connection opts in.
|
|
137
|
+
*/
|
|
138
|
+
OUTBOUND_PRIVATE_NETWORK_ALLOWLIST: Type.TString;
|
|
139
|
+
/**
|
|
140
|
+
* Environment variables a deployment secret may reference as `${ENV:NAME}`, beyond those starting with
|
|
141
|
+
* SHAPIO_SECRET_ (always allowed): comma-separated names or prefixes ending in `*`, e.g. `CF_PAGES_*`.
|
|
142
|
+
*/
|
|
143
|
+
SECRET_ENV_ALLOWLIST: Type.TString;
|
|
144
|
+
OUTBOUND_TIMEOUT_MS: Type.TInteger;
|
|
145
|
+
/** Cloudflare API base for the Cloudflare Pages adapter (tests point it at a local fake). */
|
|
146
|
+
CLOUDFLARE_API_URL: Type.TString;
|
|
147
|
+
CLOUDFLARE_DASHBOARD_URL: Type.TString;
|
|
148
|
+
/** GitHub REST API base for schema write-back (GitHub Enterprise Server: https://host/api/v3). */
|
|
149
|
+
GITHUB_API_URL: Type.TString;
|
|
150
|
+
/** Vercel REST API base for the Vercel adapter's deployment status (tests point it at a local fake). */
|
|
151
|
+
VERCEL_API_URL: Type.TString;
|
|
152
|
+
/** Netlify API base for the Netlify adapter's builds and deploy status (tests point it at a local fake). */
|
|
153
|
+
NETLIFY_API_URL: Type.TString;
|
|
154
|
+
/** GraphQL at /api/graphql (package J). Shares REST's permissions, filters and page-size limits. */
|
|
155
|
+
GRAPHQL_ENABLED: Type.TBoolean;
|
|
156
|
+
GRAPHQL_MAX_DEPTH: Type.TInteger;
|
|
157
|
+
/** Estimated cost ceiling per query: each field costs 1, multiplied by enclosing page sizes and lists. */
|
|
158
|
+
GRAPHQL_MAX_COMPLEXITY: Type.TInteger;
|
|
159
|
+
/** GraphiQL for admins at /api/graphql/playground (self-hosted assets). */
|
|
160
|
+
GRAPHQL_PLAYGROUND_ENABLED: Type.TBoolean;
|
|
161
|
+
/** Let anonymous callers and app users introspect the schema. Admins and API tokens always can. */
|
|
162
|
+
GRAPHQL_PUBLIC_INTROSPECTION: Type.TBoolean;
|
|
163
|
+
/** Count which fields delivery reads use, per token (counts only, never payloads; stays on this server). */
|
|
164
|
+
USAGE_TRACKING: Type.TBoolean;
|
|
165
|
+
/** Days of field-usage counters to keep. */
|
|
166
|
+
USAGE_RETENTION_DAYS: Type.TInteger;
|
|
167
|
+
/** How often each instance writes its in-memory usage counters to the database. */
|
|
168
|
+
USAGE_FLUSH_INTERVAL_MS: Type.TInteger;
|
|
169
|
+
/**
|
|
170
|
+
* Editor assists (alt text, summaries, translation, rewrites, schema drafts) with your own model provider.
|
|
171
|
+
* Unset (the default): assist is off and nothing is ever sent to a model provider. `openai-compatible`
|
|
172
|
+
* covers Ollama, LM Studio and vLLM (set AI_BASE_URL). See documentation/assist.md.
|
|
173
|
+
*/
|
|
174
|
+
AI_PROVIDER: Type.TOptional<Type.TEnum<["anthropic", "openai", "openai-compatible"]>>;
|
|
175
|
+
/** The model name the provider expects, e.g. a model ID or `llama3.2-vision`. Required with AI_PROVIDER. */
|
|
176
|
+
AI_MODEL: Type.TOptional<Type.TString>;
|
|
177
|
+
/** The provider API key. Required for `anthropic` and `openai`; optional for `openai-compatible`. */
|
|
178
|
+
AI_API_KEY: Type.TOptional<Type.TString>;
|
|
179
|
+
/**
|
|
180
|
+
* The provider's API base including its version path, e.g. `http://127.0.0.1:11434/v1` for Ollama
|
|
181
|
+
* (Shapio appends `/chat/completions` or `/messages`). Required for `openai-compatible`; overrides the public
|
|
182
|
+
* endpoint for the others. Loopback and private addresses are allowed: this is operator configuration.
|
|
183
|
+
*/
|
|
184
|
+
AI_BASE_URL: Type.TOptional<Type.TString>;
|
|
185
|
+
/** Most tokens one model response may use. */
|
|
186
|
+
AI_MAX_TOKENS: Type.TInteger;
|
|
187
|
+
/** Timeout of each request to the model provider. */
|
|
188
|
+
AI_TIMEOUT_MS: Type.TInteger;
|
|
189
|
+
/** Assist requests per minute and admin (or admin API token). */
|
|
190
|
+
AI_RATE_LIMIT_MAX: Type.TInteger;
|
|
191
|
+
}>;
|
|
192
|
+
type RawConfig = Static<typeof configSchema>;
|
|
193
|
+
//#endregion
|
|
194
|
+
//#region src/config/assist.d.ts
|
|
195
|
+
type AiProvider = NonNullable<RawConfig['AI_PROVIDER']>;
|
|
196
|
+
/** The model provider assist talks to. Never logged: `apiKey` is a secret. */
|
|
197
|
+
type AssistProviderConfig = {
|
|
198
|
+
provider: AiProvider;
|
|
199
|
+
model: string;
|
|
200
|
+
apiKey: string | undefined;
|
|
201
|
+
/** API base including the version path, without a trailing slash. */
|
|
202
|
+
baseUrl: string;
|
|
203
|
+
maxTokens: number;
|
|
204
|
+
timeoutMs: number;
|
|
205
|
+
};
|
|
206
|
+
/** Editor assists (plan agentic-ecosystem §A0, §I). `provider` undefined = assist is off. */
|
|
207
|
+
type AssistConfig = {
|
|
208
|
+
provider: AssistProviderConfig | undefined;
|
|
209
|
+
/** Assist requests per minute and actor. */
|
|
210
|
+
rateLimitMax: number;
|
|
211
|
+
};
|
|
212
|
+
//#endregion
|
|
213
|
+
//#region src/config/graphql.d.ts
|
|
214
|
+
/** The GraphQL endpoint (package J, ADR 0006). */
|
|
215
|
+
type GraphqlConfig = {
|
|
216
|
+
/** Serve `/api/graphql`. */
|
|
217
|
+
enabled: boolean;
|
|
218
|
+
/** Deepest field nesting a query may have. */
|
|
219
|
+
maxDepth: number;
|
|
220
|
+
/** Highest estimated cost a query may have (schema/codegen/graphql/complexity.ts). */
|
|
221
|
+
maxComplexity: number;
|
|
222
|
+
/** Serve GraphiQL at `/api/graphql/playground` (admin principals only). */
|
|
223
|
+
playgroundEnabled: boolean;
|
|
224
|
+
/** Allow schema introspection for anonymous callers and app users (admins and API tokens always may). */
|
|
225
|
+
publicIntrospection: boolean;
|
|
226
|
+
};
|
|
227
|
+
//#endregion
|
|
228
|
+
//#region src/config/publishing.d.ts
|
|
229
|
+
/** Outbound requests (webhooks, deploy hooks, provider APIs) and provider endpoints (package H). */
|
|
230
|
+
type PublishingConfig = {
|
|
231
|
+
/**
|
|
232
|
+
* CIDRs (or single IPs) that webhooks and deployment connections may reach although they are private,
|
|
233
|
+
* loopback or link-local. Each webhook or connection must also opt in (`allowPrivateNetwork`).
|
|
234
|
+
*/
|
|
235
|
+
privateNetworkAllowlist: string[];
|
|
236
|
+
/** SECRET_ENV_ALLOWLIST: extra variable names or `PREFIX*` patterns `${ENV:NAME}` may name (SHAPIO_SECRET_* always). */
|
|
237
|
+
secretEnvAllowlist: string[];
|
|
238
|
+
/** Timeout for one outbound request, connect to last byte. */
|
|
239
|
+
outboundTimeoutMs: number;
|
|
240
|
+
/** Cloudflare API base (no trailing slash); the token is only ever sent here. */
|
|
241
|
+
cloudflareApiUrl: string;
|
|
242
|
+
/** Cloudflare dashboard base, for links to a deployment's build log. */
|
|
243
|
+
cloudflareDashboardUrl: string;
|
|
244
|
+
/** GitHub REST API base (no trailing slash); set it for GitHub Enterprise Server. */
|
|
245
|
+
githubApiUrl: string;
|
|
246
|
+
/** Vercel REST API base (no trailing slash); the Vercel API token is only ever sent here. */
|
|
247
|
+
vercelApiUrl: string;
|
|
248
|
+
/** Netlify API base (no trailing slash); the Netlify API token is only ever sent here. */
|
|
249
|
+
netlifyApiUrl: string;
|
|
250
|
+
};
|
|
251
|
+
//#endregion
|
|
252
|
+
//#region src/config/usage.d.ts
|
|
253
|
+
/** Field usage from delivery traffic (plan developer-face §5). */
|
|
254
|
+
type UsageConfig = {
|
|
255
|
+
/** Count delivery reads per field and principal. */
|
|
256
|
+
enabled: boolean;
|
|
257
|
+
/** Days of daily counters the retention job keeps. */
|
|
258
|
+
retentionDays: number;
|
|
259
|
+
/** How often the in-memory counters are written (one multi-row upsert per table). */
|
|
260
|
+
flushIntervalMs: number;
|
|
261
|
+
};
|
|
262
|
+
//#endregion
|
|
263
|
+
//#region src/config/index.d.ts
|
|
264
|
+
type NodeEnv = RawConfig['NODE_ENV'];
|
|
265
|
+
type WorkerMode = RawConfig['WORKER_MODE'];
|
|
266
|
+
type TlsConfig = {
|
|
267
|
+
mode: 'off';
|
|
268
|
+
} | {
|
|
269
|
+
mode: 'files';
|
|
270
|
+
certFile: string;
|
|
271
|
+
keyFile: string;
|
|
272
|
+
reloadIntervalMs: number;
|
|
273
|
+
};
|
|
274
|
+
type S3StorageConfig = {
|
|
275
|
+
bucket: string;
|
|
276
|
+
region: string | undefined;
|
|
277
|
+
endpoint: string | undefined;
|
|
278
|
+
accessKeyId: string | undefined;
|
|
279
|
+
secretAccessKey: string | undefined;
|
|
280
|
+
forcePathStyle: boolean;
|
|
281
|
+
};
|
|
282
|
+
type StorageConfig = {
|
|
283
|
+
/** Where new uploads go. Existing assets are read from the driver recorded on each asset. */
|
|
284
|
+
driver: 'local' | 's3';
|
|
285
|
+
mediaPath: string;
|
|
286
|
+
/** Set whenever STORAGE_S3_BUCKET is, whatever the driver (for `shapio media migrate`). */
|
|
287
|
+
s3: S3StorageConfig | undefined;
|
|
288
|
+
/** CDN or public bucket base for public media, without a trailing slash; undefined = served by Shapio. */
|
|
289
|
+
publicBaseUrl: string | undefined;
|
|
290
|
+
maxUploadBytes: number;
|
|
291
|
+
/** MIME types or `type/*` wildcards, lower case. */
|
|
292
|
+
allowedTypes: string[];
|
|
293
|
+
};
|
|
294
|
+
type EmailConfig = {
|
|
295
|
+
transport: 'console';
|
|
296
|
+
from: string;
|
|
297
|
+
} | {
|
|
298
|
+
transport: 'smtp';
|
|
299
|
+
from: string;
|
|
300
|
+
host: string;
|
|
301
|
+
port: number;
|
|
302
|
+
secure: boolean;
|
|
303
|
+
user: string | undefined;
|
|
304
|
+
password: string | undefined;
|
|
305
|
+
};
|
|
306
|
+
type OAuthClientConfig = {
|
|
307
|
+
clientId: string;
|
|
308
|
+
clientSecret: string;
|
|
309
|
+
};
|
|
310
|
+
type AppAuthConfig = {
|
|
311
|
+
requireEmailConfirmation: boolean;
|
|
312
|
+
accessTokenTtlSeconds: number;
|
|
313
|
+
refreshTokenTtlMs: number;
|
|
314
|
+
confirmEmailUrl: string | undefined;
|
|
315
|
+
resetPasswordUrl: string | undefined;
|
|
316
|
+
/** APP_AUTH_RETURN_URLS as listed (origins or custom-scheme prefixes); undefined = CORS_ORIGINS + PUBLIC_URL. */
|
|
317
|
+
returnUrls: string[] | undefined;
|
|
318
|
+
/** Configured OAuth providers only. */
|
|
319
|
+
oauth: {
|
|
320
|
+
google: OAuthClientConfig | undefined;
|
|
321
|
+
github: OAuthClientConfig | undefined;
|
|
322
|
+
};
|
|
323
|
+
};
|
|
324
|
+
type AppConfig = {
|
|
325
|
+
nodeEnv: NodeEnv;
|
|
326
|
+
instanceId: string;
|
|
327
|
+
server: {
|
|
328
|
+
host: string;
|
|
329
|
+
port: number;
|
|
330
|
+
/** Plain-HTTP listener that redirects to HTTPS; undefined = none. */
|
|
331
|
+
httpPort: number | undefined;
|
|
332
|
+
trustProxy: boolean | number;
|
|
333
|
+
/** Origin without a trailing slash, e.g. `https://cms.example.com`. */
|
|
334
|
+
publicUrl: string;
|
|
335
|
+
/** `''` at the root, otherwise `/cms` (leading slash, no trailing slash). */
|
|
336
|
+
basePath: string;
|
|
337
|
+
};
|
|
338
|
+
tls: TlsConfig;
|
|
339
|
+
log: {
|
|
340
|
+
level: RawConfig['LOG_LEVEL'];
|
|
341
|
+
pretty: boolean;
|
|
342
|
+
};
|
|
343
|
+
database: {
|
|
344
|
+
url: string;
|
|
345
|
+
poolMax: number;
|
|
346
|
+
migrateOnStart: boolean;
|
|
347
|
+
};
|
|
348
|
+
/** `listen`: use LISTEN/NOTIFY to refresh schema caches early (correctness never depends on it). */
|
|
349
|
+
schema: {
|
|
350
|
+
listen: boolean;
|
|
351
|
+
};
|
|
352
|
+
http: {
|
|
353
|
+
corsOrigins: string[];
|
|
354
|
+
rateLimitMax: number;
|
|
355
|
+
rateLimitWindowMs: number;
|
|
356
|
+
/** Public media files get their own, higher limit (pages load many images). */
|
|
357
|
+
mediaRateLimitMax: number;
|
|
358
|
+
};
|
|
359
|
+
sessionSecret: string | undefined;
|
|
360
|
+
/** First-run setup: `requireToken` = the endpoint also needs the one-time token logged at boot. */
|
|
361
|
+
setup: {
|
|
362
|
+
requireToken: boolean;
|
|
363
|
+
};
|
|
364
|
+
worker: {
|
|
365
|
+
mode: WorkerMode;
|
|
366
|
+
concurrency: number;
|
|
367
|
+
pollIntervalMs: number;
|
|
368
|
+
leaseMs: number;
|
|
369
|
+
};
|
|
370
|
+
shutdownTimeoutMs: number;
|
|
371
|
+
/** The daily `system.retention` job prunes finished bookkeeping older than this. */
|
|
372
|
+
retention: {
|
|
373
|
+
days: number;
|
|
374
|
+
};
|
|
375
|
+
storage: StorageConfig;
|
|
376
|
+
/** Project extensions (ADR 0009): an explicit config file, else the working directory is searched. */
|
|
377
|
+
extensions: {
|
|
378
|
+
configPath: string | undefined;
|
|
379
|
+
};
|
|
380
|
+
email: EmailConfig;
|
|
381
|
+
/** App users (end users of the user's sites and apps): sign-in, tokens, OAuth. */
|
|
382
|
+
appAuth: AppAuthConfig;
|
|
383
|
+
/** Outbound requests and provider endpoints for webhooks and deployments. */
|
|
384
|
+
publishing: PublishingConfig;
|
|
385
|
+
/** The GraphQL endpoint and its limits. */
|
|
386
|
+
graphql: GraphqlConfig;
|
|
387
|
+
/** Field usage counters from delivery traffic. */
|
|
388
|
+
usage: UsageConfig;
|
|
389
|
+
/** Content health rules (the Inbox). */
|
|
390
|
+
health: {
|
|
391
|
+
staleDays: number;
|
|
392
|
+
};
|
|
393
|
+
/** Editor assists with the operator's own model provider; off unless AI_PROVIDER is set. */
|
|
394
|
+
assist: AssistConfig;
|
|
395
|
+
};
|
|
396
|
+
type EnvSource = Record<string, string | undefined>;
|
|
397
|
+
/**
|
|
398
|
+
* Validates the environment against the config schema and the cross-field rules, and returns typed
|
|
399
|
+
* config. Throws (listing every problem) so startup fails fast.
|
|
400
|
+
*/
|
|
401
|
+
export declare const loadConfig: (env?: EnvSource) => AppConfig;
|
|
402
|
+
//#endregion
|
|
403
|
+
//#region src/appAuth/oauth/types.d.ts
|
|
404
|
+
/** OAuth providers app users can sign in with (build plan §7, decision 6). */
|
|
405
|
+
declare const OAUTH_PROVIDERS: readonly ["google", "github"];
|
|
406
|
+
type OAuthProviderId = (typeof OAUTH_PROVIDERS)[number];
|
|
407
|
+
/** Where a provider lives. Real endpoints by default; tests point them at a local fake. */
|
|
408
|
+
type OAuthEndpoints = {
|
|
409
|
+
authorize: string;
|
|
410
|
+
token: string;
|
|
411
|
+
userInfo: string;
|
|
412
|
+
/** GitHub only: the account's email addresses with their verification state. */
|
|
413
|
+
emails?: string;
|
|
414
|
+
};
|
|
415
|
+
//#endregion
|
|
416
|
+
//#region src/services/actorContext.d.ts
|
|
417
|
+
/** The site a request or job is about (sites plan §H): its stable ID and its key. */
|
|
418
|
+
type SiteRef = {
|
|
419
|
+
id: string;
|
|
420
|
+
key: string;
|
|
421
|
+
};
|
|
422
|
+
//#endregion
|
|
423
|
+
//#region ../../packages/schema/dist/index.d.ts
|
|
424
|
+
//#endregion
|
|
425
|
+
//#region src/types/dataTypes.d.ts
|
|
426
|
+
/** Every stored data type. A field's data type is separate from the editor that renders it (brief §2.5). */
|
|
427
|
+
declare const DATA_TYPES: readonly ["string", "text", "richtext", "number", "integer", "decimal", "biginteger", "boolean", "date", "datetime", "time", "enum", "json", "slug", "email", "url", "uid", "media", "relation", "component", "dynamiczone"];
|
|
428
|
+
type DataType = (typeof DATA_TYPES)[number];
|
|
429
|
+
//#endregion
|
|
430
|
+
//#region src/types/json.d.ts
|
|
431
|
+
type JsonPrimitive = string | number | boolean | null;
|
|
432
|
+
type JsonValue = JsonPrimitive | JsonValue[] | {
|
|
433
|
+
[key: string]: JsonValue;
|
|
434
|
+
};
|
|
435
|
+
declare const SETTINGS_SCHEMAS: {
|
|
436
|
+
string: Type.TObject<{
|
|
437
|
+
pattern: Type.TOptional<Type.TString>;
|
|
438
|
+
minLength: Type.TOptional<Type.TInteger>;
|
|
439
|
+
maxLength: Type.TOptional<Type.TInteger>;
|
|
440
|
+
}>;
|
|
441
|
+
text: Type.TObject<{
|
|
442
|
+
minLength: Type.TOptional<Type.TInteger>;
|
|
443
|
+
maxLength: Type.TOptional<Type.TInteger>;
|
|
444
|
+
}>;
|
|
445
|
+
richtext: Type.TObject<{
|
|
446
|
+
formatVersion: Type.TOptional<Type.TInteger>;
|
|
447
|
+
maxLength: Type.TOptional<Type.TInteger>;
|
|
448
|
+
}>;
|
|
449
|
+
number: Type.TObject<{
|
|
450
|
+
min: Type.TOptional<Type.TNumber>;
|
|
451
|
+
max: Type.TOptional<Type.TNumber>;
|
|
452
|
+
}>;
|
|
453
|
+
integer: Type.TObject<{
|
|
454
|
+
min: Type.TOptional<Type.TInteger>;
|
|
455
|
+
max: Type.TOptional<Type.TInteger>;
|
|
456
|
+
}>;
|
|
457
|
+
decimal: Type.TObject<{
|
|
458
|
+
precision: Type.TOptional<Type.TInteger>;
|
|
459
|
+
scale: Type.TOptional<Type.TInteger>;
|
|
460
|
+
min: Type.TOptional<Type.TString>;
|
|
461
|
+
max: Type.TOptional<Type.TString>;
|
|
462
|
+
}>;
|
|
463
|
+
biginteger: Type.TObject<{
|
|
464
|
+
min: Type.TOptional<Type.TString>;
|
|
465
|
+
max: Type.TOptional<Type.TString>;
|
|
466
|
+
}>;
|
|
467
|
+
boolean: Type.TObject<{}>;
|
|
468
|
+
date: Type.TObject<{
|
|
469
|
+
min: Type.TOptional<Type.TString>;
|
|
470
|
+
max: Type.TOptional<Type.TString>;
|
|
471
|
+
}>;
|
|
472
|
+
datetime: Type.TObject<{
|
|
473
|
+
min: Type.TOptional<Type.TString>;
|
|
474
|
+
max: Type.TOptional<Type.TString>;
|
|
475
|
+
}>;
|
|
476
|
+
time: Type.TObject<{
|
|
477
|
+
min: Type.TOptional<Type.TString>;
|
|
478
|
+
max: Type.TOptional<Type.TString>;
|
|
479
|
+
}>;
|
|
480
|
+
enum: Type.TObject<{
|
|
481
|
+
values: Type.TArray<Type.TObject<{
|
|
482
|
+
value: Type.TString;
|
|
483
|
+
label: Type.TString;
|
|
484
|
+
}>>;
|
|
485
|
+
multiple: Type.TOptional<Type.TBoolean>;
|
|
486
|
+
}>;
|
|
487
|
+
json: Type.TObject<{}>;
|
|
488
|
+
slug: Type.TObject<{
|
|
489
|
+
sourceFieldId: Type.TOptional<Type.TString>;
|
|
490
|
+
minLength: Type.TOptional<Type.TInteger>;
|
|
491
|
+
maxLength: Type.TOptional<Type.TInteger>;
|
|
492
|
+
}>;
|
|
493
|
+
email: Type.TObject<{}>;
|
|
494
|
+
url: Type.TObject<{
|
|
495
|
+
protocols: Type.TOptional<Type.TArray<Type.TEnum<["http", "https", "mailto", "tel"]>>>;
|
|
496
|
+
}>;
|
|
497
|
+
uid: Type.TObject<{
|
|
498
|
+
minLength: Type.TOptional<Type.TInteger>;
|
|
499
|
+
maxLength: Type.TOptional<Type.TInteger>;
|
|
500
|
+
}>;
|
|
501
|
+
media: Type.TObject<{
|
|
502
|
+
min: Type.TOptional<Type.TInteger>;
|
|
503
|
+
max: Type.TOptional<Type.TInteger>;
|
|
504
|
+
multiple: Type.TOptional<Type.TBoolean>;
|
|
505
|
+
allowedKinds: Type.TOptional<Type.TArray<Type.TEnum<["image", "video", "audio", "document", "other"]>>>;
|
|
506
|
+
}>;
|
|
507
|
+
relation: Type.TObject<{
|
|
508
|
+
min: Type.TOptional<Type.TInteger>;
|
|
509
|
+
max: Type.TOptional<Type.TInteger>;
|
|
510
|
+
target: Type.TString;
|
|
511
|
+
cardinality: Type.TEnum<["one", "many"]>;
|
|
512
|
+
}>;
|
|
513
|
+
component: Type.TObject<{
|
|
514
|
+
min: Type.TOptional<Type.TInteger>;
|
|
515
|
+
max: Type.TOptional<Type.TInteger>;
|
|
516
|
+
component: Type.TString;
|
|
517
|
+
repeatable: Type.TOptional<Type.TBoolean>;
|
|
518
|
+
}>;
|
|
519
|
+
dynamiczone: Type.TObject<{
|
|
520
|
+
min: Type.TOptional<Type.TInteger>;
|
|
521
|
+
max: Type.TOptional<Type.TInteger>;
|
|
522
|
+
components: Type.TArray<Type.TString>;
|
|
523
|
+
}>;
|
|
524
|
+
};
|
|
525
|
+
type SettingsSchemas = typeof SETTINGS_SCHEMAS;
|
|
526
|
+
/** Settings as authored (defaults may be missing). */
|
|
527
|
+
type DataTypeSettingsInput = { [T in DataType]: Static<SettingsSchemas[T]>; };
|
|
528
|
+
/** Settings after normalization: the defaulted keys are always present. */
|
|
529
|
+
type DataTypeSettings = Omit<DataTypeSettingsInput, 'richtext' | 'enum' | 'media' | 'component'> & {
|
|
530
|
+
richtext: DataTypeSettingsInput['richtext'] & {
|
|
531
|
+
formatVersion: number;
|
|
532
|
+
};
|
|
533
|
+
enum: DataTypeSettingsInput['enum'] & {
|
|
534
|
+
multiple: boolean;
|
|
535
|
+
};
|
|
536
|
+
media: DataTypeSettingsInput['media'] & {
|
|
537
|
+
multiple: boolean;
|
|
538
|
+
};
|
|
539
|
+
component: DataTypeSettingsInput['component'] & {
|
|
540
|
+
repeatable: boolean;
|
|
541
|
+
};
|
|
542
|
+
};
|
|
543
|
+
//#endregion
|
|
544
|
+
//#region src/types/definitions.d.ts
|
|
545
|
+
declare const MODEL_KINDS: readonly ["collection", "singleton"];
|
|
546
|
+
type ModelKind = (typeof MODEL_KINDS)[number];
|
|
547
|
+
declare const SORT_DIRECTIONS: readonly ["asc", "desc"];
|
|
548
|
+
type SortDirection = (typeof SORT_DIRECTIONS)[number];
|
|
549
|
+
type EditorChoice = {
|
|
550
|
+
id: string;
|
|
551
|
+
options: Record<string, JsonValue>;
|
|
552
|
+
};
|
|
553
|
+
type FieldBase = {
|
|
554
|
+
id: string;
|
|
555
|
+
apiKey: string;
|
|
556
|
+
label: string;
|
|
557
|
+
description?: string;
|
|
558
|
+
required: boolean;
|
|
559
|
+
localized: boolean;
|
|
560
|
+
public: boolean;
|
|
561
|
+
unique: boolean;
|
|
562
|
+
filterable: boolean;
|
|
563
|
+
sortable: boolean;
|
|
564
|
+
deprecated: boolean;
|
|
565
|
+
defaultValue?: JsonValue;
|
|
566
|
+
editor: EditorChoice;
|
|
567
|
+
};
|
|
568
|
+
/** A normalized field. Narrow on `type` to get typed `settings`. */
|
|
569
|
+
type FieldDefinition<T extends DataType = DataType> = { [K in T]: FieldBase & {
|
|
570
|
+
type: K;
|
|
571
|
+
settings: DataTypeSettings[K];
|
|
572
|
+
}; }[T];
|
|
573
|
+
type FieldGroup = {
|
|
574
|
+
id: string;
|
|
575
|
+
label: string;
|
|
576
|
+
fieldIds: string[];
|
|
577
|
+
};
|
|
578
|
+
type ModelDisplay = {
|
|
579
|
+
titleFieldId?: string;
|
|
580
|
+
listFieldIds?: string[];
|
|
581
|
+
defaultSort?: {
|
|
582
|
+
fieldId: string;
|
|
583
|
+
direction: SortDirection;
|
|
584
|
+
};
|
|
585
|
+
groups?: FieldGroup[];
|
|
586
|
+
canvasFieldIds?: string[];
|
|
587
|
+
coverFieldId?: string;
|
|
588
|
+
stripFieldIds?: string[];
|
|
589
|
+
};
|
|
590
|
+
type ComponentDisplay = {
|
|
591
|
+
titleFieldId?: string;
|
|
592
|
+
groups?: FieldGroup[];
|
|
593
|
+
};
|
|
594
|
+
type ModelDefinition = {
|
|
595
|
+
id: string;
|
|
596
|
+
kind: ModelKind;
|
|
597
|
+
apiKey: string;
|
|
598
|
+
/**
|
|
599
|
+
* Present on collections (filled by normalizing), absent on singletons. Read it through `routeKeyOf`,
|
|
600
|
+
* which also covers a stored definition that predates plural API IDs.
|
|
601
|
+
*/
|
|
602
|
+
pluralApiKey?: string;
|
|
603
|
+
label: string;
|
|
604
|
+
description?: string;
|
|
605
|
+
localized: boolean;
|
|
606
|
+
draftAndPublish: boolean;
|
|
607
|
+
fields: FieldDefinition[];
|
|
608
|
+
display: ModelDisplay;
|
|
609
|
+
};
|
|
610
|
+
type ComponentDefinition = {
|
|
611
|
+
id: string;
|
|
612
|
+
kind: 'component';
|
|
613
|
+
apiKey: string;
|
|
614
|
+
label: string;
|
|
615
|
+
description?: string;
|
|
616
|
+
category?: string;
|
|
617
|
+
icon?: string;
|
|
618
|
+
fields: FieldDefinition[];
|
|
619
|
+
display: ComponentDisplay;
|
|
620
|
+
};
|
|
621
|
+
//#endregion
|
|
622
|
+
//#region src/diff/types.d.ts
|
|
623
|
+
declare const CHANGE_KINDS: readonly ["definition.added", "definition.removed", "definition.apiKey", "definition.pluralApiKey", "definition.metadata", "model.kind", "model.localized", "model.draftAndPublish", "field.added", "field.removed", "field.order", "field.apiKey", "field.metadata", "field.editor", "field.type", "field.required", "field.localized", "field.public", "field.deprecated", "field.unique", "field.filterable", "field.sortable", "field.settings"];
|
|
624
|
+
type ChangeKind = (typeof CHANGE_KINDS)[number];
|
|
625
|
+
/**
|
|
626
|
+
* One difference between two versions of a definition. `property` names the changed property for
|
|
627
|
+
* `*.metadata` (`label`, `description`, ...) and `field.settings` (the settings key); `from`/`to` hold the
|
|
628
|
+
* old and new values (absent when the side does not exist).
|
|
629
|
+
*/
|
|
630
|
+
type SchemaChange = {
|
|
631
|
+
kind: ChangeKind;
|
|
632
|
+
definitionId: string;
|
|
633
|
+
fieldId?: string;
|
|
634
|
+
property?: string;
|
|
635
|
+
from?: JsonValue;
|
|
636
|
+
to?: JsonValue;
|
|
637
|
+
};
|
|
638
|
+
//#endregion
|
|
639
|
+
//#region src/content/model.d.ts
|
|
640
|
+
/** A collection or singleton resolved from a pinned snapshot, with what writes need to know about it. */
|
|
641
|
+
type ContentModel = {
|
|
642
|
+
definition: ModelDefinition;
|
|
643
|
+
/** Per-model version at the pinned snapshot (re-checked at commit). */
|
|
644
|
+
version: number;
|
|
645
|
+
revisionId: string;
|
|
646
|
+
/** Components reachable from the model (directly or through other components), with their versions. */
|
|
647
|
+
components: ReadonlyMap<string, {
|
|
648
|
+
definition: ComponentDefinition;
|
|
649
|
+
version: number;
|
|
650
|
+
}>;
|
|
651
|
+
};
|
|
652
|
+
//#endregion
|
|
653
|
+
//#region src/content/hooks.d.ts
|
|
654
|
+
/**
|
|
655
|
+
* Lifecycle hook points (ADR 0009). The content services call every hook point inside the owning
|
|
656
|
+
* transaction; a hook that throws aborts the write. This registry is the engine only: the extension
|
|
657
|
+
* runtime (extensions/hooks.ts) registers project hooks on it, running `before*` hooks right here in the
|
|
658
|
+
* transaction and turning `after*` hook points into an outbox event, so project `after*` hooks run after
|
|
659
|
+
* commit as jobs and can never roll the write back.
|
|
660
|
+
*/
|
|
661
|
+
declare const BEFORE_EVENTS: readonly ["beforeCreate", "beforeUpdate", "beforePublish", "beforeDelete"];
|
|
662
|
+
declare const AFTER_EVENTS: readonly ["afterCreate", "afterUpdate", "afterPublish", "afterDelete"];
|
|
663
|
+
type BeforeEvent = (typeof BEFORE_EVENTS)[number];
|
|
664
|
+
type AfterEvent = (typeof AFTER_EVENTS)[number];
|
|
665
|
+
type LifecycleEvent = BeforeEvent | AfterEvent;
|
|
666
|
+
type LifecycleContext = {
|
|
667
|
+
trx: Transaction<DB>;
|
|
668
|
+
/** The site the entry belongs to (sites plan §H; ADR 0009 note). */
|
|
669
|
+
site: SiteRef;
|
|
670
|
+
model: ContentModel;
|
|
671
|
+
entryId: string;
|
|
672
|
+
locale: string | null;
|
|
673
|
+
/** The document in storage form (keyed by field IDs); absent for deletes. */
|
|
674
|
+
data?: Readonly<ContentData>;
|
|
675
|
+
/** The document before the change (the previous draft, or the live version being replaced). */
|
|
676
|
+
before?: Readonly<ContentData>;
|
|
677
|
+
actor: Principal;
|
|
678
|
+
};
|
|
679
|
+
type LifecycleHook = (context: LifecycleContext) => Promise<void> | void;
|
|
680
|
+
type ContentHooks = {
|
|
681
|
+
on: (event: LifecycleEvent, hook: LifecycleHook) => () => void;
|
|
682
|
+
run: (event: LifecycleEvent, context: LifecycleContext) => Promise<void>;
|
|
683
|
+
};
|
|
684
|
+
//#endregion
|
|
685
|
+
//#region src/db/index.d.ts
|
|
686
|
+
type Database = Kysely<DB>;
|
|
687
|
+
//#endregion
|
|
688
|
+
//#region src/extensions/editorManifest.d.ts
|
|
689
|
+
/**
|
|
690
|
+
* The custom field editors a project installs (ADR 0009): built ES modules in `extensions/editors/*.js`,
|
|
691
|
+
* listed by file name in the project's `shapio.config` (`editors: [...]`, loaded by extensions/loader.ts).
|
|
692
|
+
* Read once at startup, so installing an editor is a file copy plus a restart, never a rebuild of the
|
|
693
|
+
* admin. The admin imports each module at runtime through its import map.
|
|
694
|
+
*/
|
|
695
|
+
type EditorManifestEntry = {
|
|
696
|
+
/** File name inside `extensions/editors/`. */
|
|
697
|
+
file: string;
|
|
698
|
+
/** Absolute path on disk. */
|
|
699
|
+
path: string;
|
|
700
|
+
/** SHA-256 of the file (hex, shortened): the module URL changes whenever the file does. */
|
|
701
|
+
hash: string;
|
|
702
|
+
};
|
|
703
|
+
type EditorManifest = {
|
|
704
|
+
entries: EditorManifestEntry[];
|
|
705
|
+
};
|
|
706
|
+
//#endregion
|
|
707
|
+
//#region src/repositories/outboxEvents.d.ts
|
|
708
|
+
type OutboxEventRow = Selectable<OutboxEvents>;
|
|
709
|
+
//#endregion
|
|
710
|
+
//#region src/jobs/types.d.ts
|
|
711
|
+
type JobLogger = FastifyBaseLogger;
|
|
712
|
+
/**
|
|
713
|
+
* What a handler receives. Delivery is at least once: a handler may run again after a crash, so every
|
|
714
|
+
* side effect must be idempotent (use `id` or `idempotencyKey`) or resume from `checkpoint`.
|
|
715
|
+
*/
|
|
716
|
+
type JobContext = {
|
|
717
|
+
id: string;
|
|
718
|
+
type: string;
|
|
719
|
+
payload: unknown;
|
|
720
|
+
/** 1 on the first run. */
|
|
721
|
+
attempt: number;
|
|
722
|
+
maxAttempts: number;
|
|
723
|
+
idempotencyKey: string | null;
|
|
724
|
+
/** Progress saved by an earlier attempt, or null. */
|
|
725
|
+
checkpoint: unknown;
|
|
726
|
+
/** Persists progress so a retried attempt can resume. Returns false if this worker lost the lease. */
|
|
727
|
+
saveCheckpoint: (checkpoint: unknown) => Promise<boolean>;
|
|
728
|
+
/** Aborted on shutdown; long handlers should stop at the next safe point. */
|
|
729
|
+
signal: AbortSignal;
|
|
730
|
+
log: JobLogger;
|
|
731
|
+
};
|
|
732
|
+
/** Returns an optional JSON-serialisable result. Throw to fail the attempt; the queue retries with backoff. */
|
|
733
|
+
type JobHandler = (context: JobContext) => Promise<unknown>;
|
|
734
|
+
/**
|
|
735
|
+
* Turns an outbox event into follow-up work (usually by enqueueing jobs) inside the relay's transaction.
|
|
736
|
+
* Subscribers must only write to the database through `trx`; network calls belong in job handlers.
|
|
737
|
+
*/
|
|
738
|
+
type OutboxSubscriber = (event: OutboxEventRow, trx: Transaction<DB>) => Promise<void>;
|
|
739
|
+
//#endregion
|
|
740
|
+
//#region src/extensions/loader.d.ts
|
|
741
|
+
type LoadedProjectConfig = {
|
|
742
|
+
/** The config file, or undefined when the project has none (no extensions). */
|
|
743
|
+
file: string | undefined;
|
|
744
|
+
/** Where `extensions/` lives: the config file's directory, else the search directory. */
|
|
745
|
+
projectDir: string;
|
|
746
|
+
config: ShapioConfig;
|
|
747
|
+
};
|
|
748
|
+
//#endregion
|
|
749
|
+
//#region src/extensions/runtime.d.ts
|
|
750
|
+
/**
|
|
751
|
+
* One process's extensions (ADR 0009): the loaded project config with its services constructed once, its
|
|
752
|
+
* hooks registered on a content hook engine, and its jobs and outbox subscriber for the worker. The API and
|
|
753
|
+
* the worker (inline or dedicated) build it from the same config, so a scheduled or release publish runs
|
|
754
|
+
* the same hooks as a REST or GraphQL one.
|
|
755
|
+
*/
|
|
756
|
+
type ExtensionRuntime = {
|
|
757
|
+
loaded: LoadedProjectConfig;
|
|
758
|
+
services: ExtensionServices;
|
|
759
|
+
/** The content hook engine with the project's hooks registered (empty without a config). */
|
|
760
|
+
hooks: ContentHooks;
|
|
761
|
+
routes: readonly ExtensionRoute[];
|
|
762
|
+
jobHandlers: ReadonlyArray<[string, JobHandler]>;
|
|
763
|
+
outboxSubscribers: readonly OutboxSubscriber[];
|
|
764
|
+
permissions: PermissionEvaluator;
|
|
765
|
+
/** Aborts hook `signal`s; call on shutdown. Idempotent. */
|
|
766
|
+
close: () => void;
|
|
767
|
+
};
|
|
768
|
+
//#endregion
|
|
769
|
+
//#region src/permissions/policy.d.ts
|
|
770
|
+
type ModelField = {
|
|
771
|
+
id: string;
|
|
772
|
+
public: boolean;
|
|
773
|
+
};
|
|
774
|
+
/**
|
|
775
|
+
* The one port from permissions to the schema registry (package D implements it from the active schema).
|
|
776
|
+
* `getModelFields`: field definitions for `public` semantics; `undefined` means the model does not exist,
|
|
777
|
+
* which denies delivery access. `hasModel`: whether a model or component ID exists, so role grants can
|
|
778
|
+
* only name real models.
|
|
779
|
+
*/
|
|
780
|
+
type FieldVisibilityLookup = {
|
|
781
|
+
getModelFields: (modelId: string) => Promise<readonly ModelField[] | undefined>;
|
|
782
|
+
hasModel: (modelId: string) => Promise<boolean>;
|
|
783
|
+
};
|
|
784
|
+
//#endregion
|
|
785
|
+
//#region src/publishing/outbound/ssrf.d.ts
|
|
786
|
+
/**
|
|
787
|
+
* SSRF protection for every request Shapio sends to an address an admin typed in (webhooks, deploy hooks,
|
|
788
|
+
* provider APIs). The host is resolved once, every resolved address is checked, and the connection is then
|
|
789
|
+
* pinned to the checked address (outbound/request.ts), so a DNS answer that changes between the check and
|
|
790
|
+
* the connect (DNS rebinding) cannot redirect the request. Redirects are never followed.
|
|
791
|
+
*
|
|
792
|
+
* Private, loopback, link-local, carrier-grade NAT, multicast and reserved ranges are refused unless the
|
|
793
|
+
* target opted in (`allowPrivateNetwork`) AND the address is in the operator's allowlist
|
|
794
|
+
* (OUTBOUND_PRIVATE_NETWORK_ALLOWLIST). Both are needed: an admin account alone cannot reach the internal
|
|
795
|
+
* network, and the operator's list alone does not open every webhook to it.
|
|
796
|
+
*/
|
|
797
|
+
type ResolvedAddress = {
|
|
798
|
+
address: string;
|
|
799
|
+
family: 4 | 6;
|
|
800
|
+
};
|
|
801
|
+
/** DNS resolution, injectable so tests can make a public-looking name resolve to a private address. */
|
|
802
|
+
type HostResolver = (hostname: string) => Promise<ResolvedAddress[]>;
|
|
803
|
+
//#endregion
|
|
804
|
+
//#region src/repositories/publications.d.ts
|
|
805
|
+
/**
|
|
806
|
+
* One sequence number per transaction, taken on first use: everything a batch publishes, unpublishes or
|
|
807
|
+
* converts shares it, so the batch is exactly one snapshot.
|
|
808
|
+
*/
|
|
809
|
+
type SeqAllocator = {
|
|
810
|
+
next: () => Promise<number>;
|
|
811
|
+
/** The number if one was taken already. */
|
|
812
|
+
taken: () => number | undefined;
|
|
813
|
+
};
|
|
814
|
+
//#endregion
|
|
815
|
+
//#region src/schema/planner/steps.d.ts
|
|
816
|
+
/**
|
|
817
|
+
* Where a definition's values live inside entries: for a model, its own heads at the root; for a
|
|
818
|
+
* component, every model that embeds it, with the field-ID path from the entry root down to the component
|
|
819
|
+
* or dynamic-zone field that holds it.
|
|
820
|
+
*/
|
|
821
|
+
type ValueLocation = {
|
|
822
|
+
modelId: string;
|
|
823
|
+
path: string[];
|
|
824
|
+
};
|
|
825
|
+
/** Prerequisite work that reads or rewrites content. Run by the content ports (package E). */
|
|
826
|
+
type ContentStep = {
|
|
827
|
+
kind: 'validateRequired';
|
|
828
|
+
ownerId: string;
|
|
829
|
+
fieldId: string;
|
|
830
|
+
locations: ValueLocation[];
|
|
831
|
+
} | {
|
|
832
|
+
kind: 'backfill';
|
|
833
|
+
ownerId: string;
|
|
834
|
+
fieldId: string;
|
|
835
|
+
value: JsonValue;
|
|
836
|
+
locations: ValueLocation[];
|
|
837
|
+
} | {
|
|
838
|
+
kind: 'validateValues';
|
|
839
|
+
ownerId: string;
|
|
840
|
+
/** Absent for definition-level rules (e.g. a singleton holds at most one entry). */
|
|
841
|
+
fieldId?: string;
|
|
842
|
+
locations: ValueLocation[];
|
|
843
|
+
} | {
|
|
844
|
+
kind: 'checkUnique';
|
|
845
|
+
modelId: string;
|
|
846
|
+
fieldId: string;
|
|
847
|
+
/**
|
|
848
|
+
* The field is already unique under the active schema (its type changes): its live registry rows stay in
|
|
849
|
+
* force until activation, so the dry run stages its claims under a separate registry key and the
|
|
850
|
+
* activation swaps them in.
|
|
851
|
+
*/
|
|
852
|
+
rebuild?: boolean;
|
|
853
|
+
} | {
|
|
854
|
+
kind: 'convert';
|
|
855
|
+
ownerId: string;
|
|
856
|
+
change: SchemaChange;
|
|
857
|
+
locations: ValueLocation[];
|
|
858
|
+
};
|
|
859
|
+
type IndexStep = {
|
|
860
|
+
kind: 'buildIndex';
|
|
861
|
+
modelId: string;
|
|
862
|
+
fieldId: string;
|
|
863
|
+
fieldType: DataType;
|
|
864
|
+
/** Index layout: with the locale column (localized models) or without. Absent in older plans: localized. */
|
|
865
|
+
localized?: boolean;
|
|
866
|
+
indexName: string;
|
|
867
|
+
};
|
|
868
|
+
/** Work after activation, once nothing reads the old structure. */
|
|
869
|
+
type FollowUpStep = IndexStep | {
|
|
870
|
+
kind: 'dropIndex';
|
|
871
|
+
indexName: string;
|
|
872
|
+
} | {
|
|
873
|
+
kind: 'releaseUnique';
|
|
874
|
+
fieldId: string;
|
|
875
|
+
} |
|
|
876
|
+
/** Deletes a removed locale's heads, revisions and unique-registry rows (content ports). */
|
|
877
|
+
{
|
|
878
|
+
kind: 'purgeLocale';
|
|
879
|
+
code: string;
|
|
880
|
+
};
|
|
881
|
+
//#endregion
|
|
882
|
+
//#region src/schema/planner/contentPorts.d.ts
|
|
883
|
+
/**
|
|
884
|
+
* What the activation transaction offers the content rewrite: one publication sequence number per affected
|
|
885
|
+
* site (sites plan §H, ADR 0010 amendment: one snapshot per affected site), each taken late, on first use,
|
|
886
|
+
* under the schema lock, and a way to defer work until a site's number is known (rolling the publication log
|
|
887
|
+
* of converted published heads after every rewrite, so the number's row lock is held as briefly as possible).
|
|
888
|
+
* A site whose content does not change takes no number.
|
|
889
|
+
*/
|
|
890
|
+
type ActivationContext = {
|
|
891
|
+
/** The origin site's number: the shipping change set's site (the primary site without a change set). */
|
|
892
|
+
seq: SeqAllocator;
|
|
893
|
+
/** The number of one site, for content converted on it. */
|
|
894
|
+
seqFor: (siteId: string) => SeqAllocator;
|
|
895
|
+
/** Runs `work` with the site's sequence number, after every item's rewrite, before commit. */
|
|
896
|
+
atSeq: (siteId: string, work: (seq: number) => Promise<void>) => void;
|
|
897
|
+
};
|
|
898
|
+
/**
|
|
899
|
+
* The planner's view of content. Content storage belongs to package E, so the planner talks to it through
|
|
900
|
+
* these ports. Until E lands, the defaults report "no content", which is exactly true: no entries exist.
|
|
901
|
+
*/
|
|
902
|
+
type StepOutcome = {
|
|
903
|
+
ok: true;
|
|
904
|
+
watermark?: unknown;
|
|
905
|
+
} | {
|
|
906
|
+
ok: false;
|
|
907
|
+
/** Key (`stepKey`) of the step the content fails. */
|
|
908
|
+
step?: string;
|
|
909
|
+
reason: string;
|
|
910
|
+
invalidCount?: number;
|
|
911
|
+
sampleEntryIds?: string[];
|
|
912
|
+
};
|
|
913
|
+
type ContentStepContext = {
|
|
914
|
+
signal: AbortSignal;
|
|
915
|
+
/** Progress from an earlier attempt of this step, or null. */
|
|
916
|
+
checkpoint: unknown;
|
|
917
|
+
saveCheckpoint: (checkpoint: unknown) => Promise<boolean>;
|
|
918
|
+
log: FastifyBaseLogger;
|
|
919
|
+
};
|
|
920
|
+
/**
|
|
921
|
+
* A change's content steps (every prerequisite but index builds, in plan order) go through three stages
|
|
922
|
+
* (ADR 0002 pipeline): a dry run, the activation-time apply, and, if the change fails, a discard.
|
|
923
|
+
*/
|
|
924
|
+
type ContentMigrationPort = {
|
|
925
|
+
/**
|
|
926
|
+
* Dry run up to a watermark (resumable through the checkpoint): converts and backfills content in memory
|
|
927
|
+
* and checks it against the proposed schema, without writing content. Writes continue meanwhile under
|
|
928
|
+
* the old revision; whatever they change after the watermark is re-checked at activation.
|
|
929
|
+
*/
|
|
930
|
+
run: (steps: readonly ContentStep[], context: ContentStepContext) => Promise<StepOutcome>;
|
|
931
|
+
/**
|
|
932
|
+
* Inside the activation transaction, holding the exclusive model locks: re-checks the content changed
|
|
933
|
+
* since `watermark` (the transitional write policy's final delta scan), then writes converted and
|
|
934
|
+
* backfilled values. A failure aborts the activation and rolls every write back.
|
|
935
|
+
*/
|
|
936
|
+
apply: (steps: readonly ContentStep[], watermark: unknown, trx: Transaction<DB>, activation: ActivationContext) => Promise<StepOutcome>;
|
|
937
|
+
/** After the change failed for good: releases what the dry run staged (unique-registry claims). Idempotent. */
|
|
938
|
+
discard: (steps: readonly ContentStep[]) => Promise<void>;
|
|
939
|
+
/** Post-activation work that touches content (e.g. dropping unique-registry rows). Idempotent. */
|
|
940
|
+
runFollowUp: (step: FollowUpStep, log: FastifyBaseLogger) => Promise<void>;
|
|
941
|
+
};
|
|
942
|
+
type StepImpact = {
|
|
943
|
+
affectedHeads: number;
|
|
944
|
+
invalidHeads?: number;
|
|
945
|
+
};
|
|
946
|
+
type ContentImpactSource = {
|
|
947
|
+
/** Heads (every locale and state) of these models. */
|
|
948
|
+
countHeads: (modelIds: readonly string[]) => Promise<number>;
|
|
949
|
+
/** How many heads a step would touch and, where cheap to know, how many would fail it. */
|
|
950
|
+
assess: (step: ContentStep) => Promise<StepImpact>;
|
|
951
|
+
/** Heads stored in one locale (impact of deleting it). */
|
|
952
|
+
countLocaleHeads: (code: string) => Promise<number>;
|
|
953
|
+
};
|
|
954
|
+
type SchemaContentPorts = {
|
|
955
|
+
migration: ContentMigrationPort;
|
|
956
|
+
impact: ContentImpactSource;
|
|
957
|
+
};
|
|
958
|
+
//#endregion
|
|
959
|
+
//#region src/tls/certificates.d.ts
|
|
960
|
+
type CertificatePair = {
|
|
961
|
+
key: string;
|
|
962
|
+
cert: string;
|
|
963
|
+
};
|
|
964
|
+
//#endregion
|
|
965
|
+
//#region src/app.d.ts
|
|
966
|
+
declare module 'fastify' {
|
|
967
|
+
interface FastifyInstance {
|
|
968
|
+
/** Schema facts permissions need (field visibility, model existence); see permissions/policy.ts. */
|
|
969
|
+
schemaLookup: FieldVisibilityLookup;
|
|
970
|
+
/** HMAC signing secret: SESSION_SECRET, or generated once and stored (services/signingSecret.ts). */
|
|
971
|
+
signingSecret: string;
|
|
972
|
+
}
|
|
973
|
+
}
|
|
974
|
+
type AppDependencies = {
|
|
975
|
+
db: Database;
|
|
976
|
+
/** A pino logger to share with the worker; otherwise one is created from config. */
|
|
977
|
+
logger?: FastifyBaseLogger;
|
|
978
|
+
/** Overrides the role-based evaluator (tests). */
|
|
979
|
+
permissions?: PermissionEvaluator;
|
|
980
|
+
/** Resolved by the server before building the app; resolved here when omitted (tests, tools). */
|
|
981
|
+
signingSecret?: string;
|
|
982
|
+
/** Field definitions for `public` semantics. Defaults to the schema registry's active schema. */
|
|
983
|
+
fieldVisibility?: FieldVisibilityLookup;
|
|
984
|
+
/** Content storage as the schema planner sees it. Defaults to the real content ports (content/ports.ts). */
|
|
985
|
+
schemaContent?: SchemaContentPorts;
|
|
986
|
+
/** Content lifecycle hooks (tests). Defaults to the extension runtime's hooks. */
|
|
987
|
+
contentHooks?: ContentHooks;
|
|
988
|
+
/**
|
|
989
|
+
* Project extensions (shapio.config), shared with the worker. Omitted: loaded here from SHAPIO_CONFIG_PATH
|
|
990
|
+
* or `projectDir`, and closed with the app.
|
|
991
|
+
*/
|
|
992
|
+
extensions?: ExtensionRuntime;
|
|
993
|
+
/** LISTEN for schema changes (cache refresh). Default true; correctness never depends on it. */
|
|
994
|
+
schemaListen?: boolean;
|
|
995
|
+
/** Serve HTTPS with this certificate (from TLS_CERT_FILE/TLS_KEY_FILE). Omit for plain HTTP. */
|
|
996
|
+
tls?: CertificatePair;
|
|
997
|
+
/** OAuth provider endpoints (tests point them at a local fake). Defaults to the real providers. */
|
|
998
|
+
oauthEndpoints?: Partial<Record<OAuthProviderId, OAuthEndpoints>>;
|
|
999
|
+
/** The project directory (`shapio.config.js`, `extensions/`). Defaults to the working directory. */
|
|
1000
|
+
projectDir?: string;
|
|
1001
|
+
/** Overrides the custom editor manifest read from the project (tests). */
|
|
1002
|
+
editorManifest?: EditorManifest;
|
|
1003
|
+
/** Directory of the built admin SPA. Defaults to the bundled copy (npm) or apps/admin/dist (repo). */
|
|
1004
|
+
adminDistPath?: string | null;
|
|
1005
|
+
/** DNS resolution for outbound webhook/deploy requests (tests inject a controllable resolver). */
|
|
1006
|
+
outboundResolver?: HostResolver;
|
|
1007
|
+
};
|
|
1008
|
+
/**
|
|
1009
|
+
* Builds the Fastify app: plugins and routes, no listen(). Every route is mounted under BASE_PATH.
|
|
1010
|
+
* The caller owns the database handle and closes it after `app.close()`.
|
|
1011
|
+
*/
|
|
1012
|
+
export declare const buildApp: (config: AppConfig, deps: AppDependencies) => Promise<FastifyInstance>;
|
|
1013
|
+
//#endregion
|
|
1014
|
+
//#region src/jobs/worker.d.ts
|
|
1015
|
+
type Worker = {
|
|
1016
|
+
start: () => void;
|
|
1017
|
+
/** Stops claiming, waits up to `timeoutMs` for running jobs, then aborts them and releases their leases. */
|
|
1018
|
+
stop: (timeoutMs: number) => Promise<void>;
|
|
1019
|
+
/** Runs one claim + relay pass; for tests and tooling. Returns the number of jobs claimed. */
|
|
1020
|
+
tick: () => Promise<number>;
|
|
1021
|
+
readonly runningJobIds: ReadonlySet<string>;
|
|
1022
|
+
};
|
|
1023
|
+
//#endregion
|
|
1024
|
+
//#region src/server.d.ts
|
|
1025
|
+
type RunningServer = {
|
|
1026
|
+
app: FastifyInstance;
|
|
1027
|
+
worker: Worker | undefined;
|
|
1028
|
+
/** Port of the plain-HTTP listener that redirects to HTTPS (HTTP_PORT), when HTTPS is on. */
|
|
1029
|
+
httpPort: number | undefined;
|
|
1030
|
+
/** Stops the HTTP(S) servers and the worker, then closes the database pool. Idempotent. */
|
|
1031
|
+
close: () => Promise<void>;
|
|
1032
|
+
};
|
|
1033
|
+
/**
|
|
1034
|
+
* Starts Shapio: read the project config, migrate (under an advisory lock), set up TLS (none or certificate files), build the app,
|
|
1035
|
+
* listen, and start the in-process worker when WORKER_MODE=inline. Installs signal handlers for a
|
|
1036
|
+
* graceful shutdown.
|
|
1037
|
+
*/
|
|
1038
|
+
export declare const startServer: (config: AppConfig) => Promise<RunningServer>;
|
|
1039
|
+
//#endregion
|
|
1040
|
+
//#region src/worker.d.ts
|
|
1041
|
+
/**
|
|
1042
|
+
* Runs the job worker as its own process (WORKER_MODE=dedicated on the API, `shapio worker` here).
|
|
1043
|
+
* It never migrates: it refuses to start until the API has brought the schema up to date.
|
|
1044
|
+
*/
|
|
1045
|
+
export declare const startDedicatedWorker: (config: AppConfig) => Promise<Worker>;
|
|
1046
|
+
//#endregion
|
|
1047
|
+
//#region src/constants/version.d.ts
|
|
1048
|
+
export declare const SHAPIO_VERSION: string;
|
|
1049
|
+
//#endregion
|
|
1050
|
+
export { AfterHook, AfterHookContext, AfterHookEvent, type AppConfig, type AppDependencies, BeforeHook, BeforeHookContext, BeforeHookEvent, ContentReadEntry, ContentReadOptions, ContentReadService, CustomServices, EXTENSION_CONTRACT_VERSION, EnqueueOptions, EntryData, ExtensionHostConfig, ExtensionJobHandler, ExtensionJobService, ExtensionRoute, ExtensionRouteOptions, ExtensionServices, ExtensionSite, HookEntry, HookError, HookEvent, HookModel, JobHandlerContext, MediaReferenceService, MediaUsage, ModelHooks, type RunningServer, ServiceFactory, ServiceFactoryContext, ShapioConfig, ShapioServices, defineConfig, isHookError };
|
|
1051
|
+
//# sourceMappingURL=index.d.ts.map
|