@shapio/cms 0.5.4 → 0.5.5
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/dist/admin/assets/{AssetTile-DWaHjfcU.js → AssetTile-CaYPqR_F.js} +2 -2
- package/dist/admin/assets/{AssetTile-DWaHjfcU.js.map → AssetTile-CaYPqR_F.js.map} +1 -1
- package/dist/admin/assets/{AssistError-CYV_H4uu.js → AssistError-drmpXSbS.js} +2 -2
- package/dist/admin/assets/{AssistError-CYV_H4uu.js.map → AssistError-drmpXSbS.js.map} +1 -1
- package/dist/admin/assets/{BlockMenuItems-BRKp5YAK.js → BlockMenuItems-D-jZ0oaU.js} +2 -2
- package/dist/admin/assets/{BlockMenuItems-BRKp5YAK.js.map → BlockMenuItems-D-jZ0oaU.js.map} +1 -1
- package/dist/admin/assets/{Body-CdlxJrnW.js → Body-Gn_z2KPN.js} +2 -2
- package/dist/admin/assets/{Body-CdlxJrnW.js.map → Body-Gn_z2KPN.js.map} +1 -1
- package/dist/admin/assets/Builder-DyCcikfS.js +2 -0
- package/dist/admin/assets/Builder-DyCcikfS.js.map +1 -0
- package/dist/admin/assets/{CodeEditor-h7SDbh8e.js → CodeEditor-CzRU6och.js} +2 -2
- package/dist/admin/assets/{CodeEditor-h7SDbh8e.js.map → CodeEditor-CzRU6och.js.map} +1 -1
- package/dist/admin/assets/{ConfirmDialog-Dq6IrmS9.js → ConfirmDialog-DZRJfdvH.js} +2 -2
- package/dist/admin/assets/{ConfirmDialog-Dq6IrmS9.js.map → ConfirmDialog-DZRJfdvH.js.map} +1 -1
- package/dist/admin/assets/{CopyButton-BiMHd8OL.js → CopyButton-h4HYhnYp.js} +2 -2
- package/dist/admin/assets/{CopyButton-BiMHd8OL.js.map → CopyButton-h4HYhnYp.js.map} +1 -1
- package/dist/admin/assets/{CursorPager-CXI-RhTJ.js → CursorPager-H4SpVYw7.js} +2 -2
- package/dist/admin/assets/{CursorPager-CXI-RhTJ.js.map → CursorPager-H4SpVYw7.js.map} +1 -1
- package/dist/admin/assets/{ExternalLink-xUrKyqHx.js → ExternalLink-BNq7nAYL.js} +2 -2
- package/dist/admin/assets/{ExternalLink-xUrKyqHx.js.map → ExternalLink-BNq7nAYL.js.map} +1 -1
- package/dist/admin/assets/{FocalPoint-D_Ccn0US.js → FocalPoint-CSeKI4Iw.js} +2 -2
- package/dist/admin/assets/{FocalPoint-D_Ccn0US.js.map → FocalPoint-CSeKI4Iw.js.map} +1 -1
- package/dist/admin/assets/Form-DF_YmR1G.js +2 -0
- package/dist/admin/assets/{Form-DKfQ6_lP.js.map → Form-DF_YmR1G.js.map} +1 -1
- package/dist/admin/assets/{FormCheckboxGroup-CNexUHvc.js → FormCheckboxGroup-V3IKrvzc.js} +2 -2
- package/dist/admin/assets/{FormCheckboxGroup-CNexUHvc.js.map → FormCheckboxGroup-V3IKrvzc.js.map} +1 -1
- package/dist/admin/assets/{FormRadioGroup-Bz09LqOn.js → FormRadioGroup-DIv-MYgn.js} +2 -2
- package/dist/admin/assets/{FormRadioGroup-Bz09LqOn.js.map → FormRadioGroup-DIv-MYgn.js.map} +1 -1
- package/dist/admin/assets/{FormSelectField-rX_rC7NA.js → FormSelectField-CUhaPIMY.js} +2 -2
- package/dist/admin/assets/{FormSelectField-rX_rC7NA.js.map → FormSelectField-CUhaPIMY.js.map} +1 -1
- package/dist/admin/assets/{FormSwitchField-B0wQTcF3.js → FormSwitchField-DW8ysyk_.js} +2 -2
- package/dist/admin/assets/{FormSwitchField-B0wQTcF3.js.map → FormSwitchField-DW8ysyk_.js.map} +1 -1
- package/dist/admin/assets/{FormTextareaField-CQ6wnIlF.js → FormTextareaField-DbqZ-MwI.js} +2 -2
- package/dist/admin/assets/{FormTextareaField-CQ6wnIlF.js.map → FormTextareaField-DbqZ-MwI.js.map} +1 -1
- package/dist/admin/assets/{HintedLabel-BPZ7Qd6n.js → HintedLabel-BlLtqVVz.js} +2 -2
- package/dist/admin/assets/{HintedLabel-BPZ7Qd6n.js.map → HintedLabel-BlLtqVVz.js.map} +1 -1
- package/dist/admin/assets/{InfoHint-2HZJCzwW.js → InfoHint-bYMd_t0J.js} +2 -2
- package/dist/admin/assets/{InfoHint-2HZJCzwW.js.map → InfoHint-bYMd_t0J.js.map} +1 -1
- package/dist/admin/assets/{InsertMenuItem-DBjeJAgk.js → InsertMenuItem-D2HGERzb.js} +2 -2
- package/dist/admin/assets/{InsertMenuItem-DBjeJAgk.js.map → InsertMenuItem-D2HGERzb.js.map} +1 -1
- package/dist/admin/assets/{LinkTabs-uqCcqqdx.js → LinkTabs-ByB2eCIr.js} +2 -2
- package/dist/admin/assets/{LinkTabs-uqCcqqdx.js.map → LinkTabs-ByB2eCIr.js.map} +1 -1
- package/dist/admin/assets/{Match-CH4OI7xo.js → Match-GDx_orOH.js} +2 -2
- package/dist/admin/assets/{Match-CH4OI7xo.js.map → Match-GDx_orOH.js.map} +1 -1
- package/dist/admin/assets/{QueryView-UMDuxj-g.js → QueryView-UBO-U5Wo.js} +2 -2
- package/dist/admin/assets/{QueryView-UMDuxj-g.js.map → QueryView-UBO-U5Wo.js.map} +1 -1
- package/dist/admin/assets/{RadioTile-D_mY8BQv.js → RadioTile-CJbIIV8t.js} +2 -2
- package/dist/admin/assets/{RadioTile-D_mY8BQv.js.map → RadioTile-CJbIIV8t.js.map} +1 -1
- package/dist/admin/assets/{RichTextField-jy6R2FE-.js → RichTextField-M7HyUhYF.js} +5 -5
- package/dist/admin/assets/{RichTextField-jy6R2FE-.js.map → RichTextField-M7HyUhYF.js.map} +1 -1
- package/dist/admin/assets/{RowTitle-DuN-jQxy.js → RowTitle-DoxDM1XL.js} +2 -2
- package/dist/admin/assets/{RowTitle-DuN-jQxy.js.map → RowTitle-DoxDM1XL.js.map} +1 -1
- package/dist/admin/assets/{SecretReveal-TM7VYAeY.js → SecretReveal-kCkLH5jg.js} +2 -2
- package/dist/admin/assets/{SecretReveal-TM7VYAeY.js.map → SecretReveal-kCkLH5jg.js.map} +1 -1
- package/dist/admin/assets/{SharedGlyph-DcbEGwSL.js → SharedGlyph-D1OMHXPf.js} +2 -2
- package/dist/admin/assets/{SharedGlyph-DcbEGwSL.js.map → SharedGlyph-D1OMHXPf.js.map} +1 -1
- package/dist/admin/assets/StepList-BIQjDaWQ.js +2 -0
- package/dist/admin/assets/{StepList-B4I59Yl_.js.map → StepList-BIQjDaWQ.js.map} +1 -1
- package/dist/admin/assets/Structure-CO4aJZVP.js +2 -0
- package/dist/admin/assets/{Structure-BYK71uPq.js.map → Structure-CO4aJZVP.js.map} +1 -1
- package/dist/admin/assets/{SubNavLink-Ccx9PJyM.js → SubNavLink-CPJFIt1j.js} +2 -2
- package/dist/admin/assets/{SubNavLink-Ccx9PJyM.js.map → SubNavLink-CPJFIt1j.js.map} +1 -1
- package/dist/admin/assets/{SuggestAltButton-Vvg9XEqL.js → SuggestAltButton-CbRUxD5s.js} +2 -2
- package/dist/admin/assets/{SuggestAltButton-Vvg9XEqL.js.map → SuggestAltButton-CbRUxD5s.js.map} +1 -1
- package/dist/admin/assets/{TextLink-_2c_cSwP.js → TextLink-DnrMaF2F.js} +2 -2
- package/dist/admin/assets/{TextLink-_2c_cSwP.js.map → TextLink-DnrMaF2F.js.map} +1 -1
- package/dist/admin/assets/{Thumbnail-B1iRlbxI.js → Thumbnail-D1XuDElk.js} +2 -2
- package/dist/admin/assets/{Thumbnail-B1iRlbxI.js.map → Thumbnail-D1XuDElk.js.map} +1 -1
- package/dist/admin/assets/{UnsavedChangesGuard-CrtHd2la.js → UnsavedChangesGuard-C1n7egF6.js} +2 -2
- package/dist/admin/assets/{UnsavedChangesGuard-CrtHd2la.js.map → UnsavedChangesGuard-C1n7egF6.js.map} +1 -1
- package/dist/admin/assets/{UserAvatar-C-_SZaBb.js → UserAvatar-Bl32IpG_.js} +2 -2
- package/dist/admin/assets/{UserAvatar-C-_SZaBb.js.map → UserAvatar-Bl32IpG_.js.map} +1 -1
- package/dist/admin/assets/auth-C4fHG9Iu.js +2 -0
- package/dist/admin/assets/{auth-kvLrpCst.js.map → auth-C4fHG9Iu.js.map} +1 -1
- package/dist/admin/assets/{badge-CB016qlm.js → badge-ydvfgE8a.js} +2 -2
- package/dist/admin/assets/{badge-CB016qlm.js.map → badge-ydvfgE8a.js.map} +1 -1
- package/dist/admin/assets/{boxes-CYCCewHl.js → boxes-D6Y4Cenx.js} +2 -2
- package/dist/admin/assets/{boxes-CYCCewHl.js.map → boxes-D6Y4Cenx.js.map} +1 -1
- package/dist/admin/assets/{calendar-clock-BJHRssUa.js → calendar-clock-DFUgXWXg.js} +2 -2
- package/dist/admin/assets/{calendar-clock-BJHRssUa.js.map → calendar-clock-DFUgXWXg.js.map} +1 -1
- package/dist/admin/assets/changeSets-DgfCKja3.js +2 -0
- package/dist/admin/assets/{changeSets-BjP6UzCi.js.map → changeSets-DgfCKja3.js.map} +1 -1
- package/dist/admin/assets/chevron-left-CZXrLV99.js +2 -0
- package/dist/admin/assets/{chevron-left-uCIwt51T.js.map → chevron-left-CZXrLV99.js.map} +1 -1
- package/dist/admin/assets/{circle-check-nVBFETQc.js → circle-check-De27poaB.js} +2 -2
- package/dist/admin/assets/{circle-check-nVBFETQc.js.map → circle-check-De27poaB.js.map} +1 -1
- package/dist/admin/assets/{clock-BJiK6mtP.js → clock-BGAXsuo4.js} +2 -2
- package/dist/admin/assets/{clock-BJiK6mtP.js.map → clock-BGAXsuo4.js.map} +1 -1
- package/dist/admin/assets/{constants-DgCYLdxl.js → constants-esJAnNTh.js} +2 -2
- package/dist/admin/assets/{constants-DgCYLdxl.js.map → constants-esJAnNTh.js.map} +1 -1
- package/dist/admin/assets/content-DsMSB6Wb.js +3 -0
- package/dist/admin/assets/content-DsMSB6Wb.js.map +1 -0
- package/dist/admin/assets/{contentCounts-K6UCGeqH.js → contentCounts-DknqJ4kh.js} +2 -2
- package/dist/admin/assets/{contentCounts-K6UCGeqH.js.map → contentCounts-DknqJ4kh.js.map} +1 -1
- package/dist/admin/assets/{contentTypes-DDb1tieq.js → contentTypes-C-AKiYu1.js} +2 -2
- package/dist/admin/assets/{contentTypes-DDb1tieq.js.map → contentTypes-C-AKiYu1.js.map} +1 -1
- package/dist/admin/assets/{context-BJ7ilMj9.js → context-fImO9k99.js} +2 -2
- package/dist/admin/assets/{context-BJ7ilMj9.js.map → context-fImO9k99.js.map} +1 -1
- package/dist/admin/assets/{copy-CWYrWaJy.js → copy-B5owk67M.js} +2 -2
- package/dist/admin/assets/{copy-CWYrWaJy.js.map → copy-B5owk67M.js.map} +1 -1
- package/dist/admin/assets/createLucideIcon-CqygG5K6.js +2 -0
- package/dist/admin/assets/createLucideIcon-CqygG5K6.js.map +1 -0
- package/dist/admin/assets/develop-DL-2W9jv.js +11 -0
- package/dist/admin/assets/develop-DL-2W9jv.js.map +1 -0
- package/dist/admin/assets/{dropdown-menu-jrFjkuhR.js → dropdown-menu-C53v9ioW.js} +2 -2
- package/dist/admin/assets/{dropdown-menu-jrFjkuhR.js.map → dropdown-menu-C53v9ioW.js.map} +1 -1
- package/dist/admin/assets/{ellipsis-D304Uu9C.js → ellipsis-BHtU4ov6.js} +2 -2
- package/dist/admin/assets/{ellipsis-D304Uu9C.js.map → ellipsis-BHtU4ov6.js.map} +1 -1
- package/dist/admin/assets/es2015-DrAA1N2V.js +42 -0
- package/dist/admin/assets/es2015-DrAA1N2V.js.map +1 -0
- package/dist/admin/assets/{external-link-s_y1Tlvw.js → external-link-nZp2VpKw.js} +2 -2
- package/dist/admin/assets/{external-link-s_y1Tlvw.js.map → external-link-nZp2VpKw.js.map} +1 -1
- package/dist/admin/assets/{field-DkUe0lrH.js → field-W1dB_h6d.js} +2 -2
- package/dist/admin/assets/{field-DkUe0lrH.js.map → field-W1dB_h6d.js.map} +1 -1
- package/dist/admin/assets/{file-stack-DV3BHV7A.js → file-stack-8rRouTJj.js} +2 -2
- package/dist/admin/assets/{file-stack-DV3BHV7A.js.map → file-stack-8rRouTJj.js.map} +1 -1
- package/dist/admin/assets/{fileRoute-BTxwuLEP.js → fileRoute-DzWMBrRx.js} +2 -2
- package/dist/admin/assets/{fileRoute-BTxwuLEP.js.map → fileRoute-DzWMBrRx.js.map} +1 -1
- package/dist/admin/assets/{folder-plus-AIA7s5Da.js → folder-plus-B3L3b389.js} +2 -2
- package/dist/admin/assets/{folder-plus-AIA7s5Da.js.map → folder-plus-B3L3b389.js.map} +1 -1
- package/dist/admin/assets/{followPlural-xUd57Rcj.js → followPlural-D-5ZJqJF.js} +2 -2
- package/dist/admin/assets/{followPlural-xUd57Rcj.js.map → followPlural-D-5ZJqJF.js.map} +1 -1
- package/dist/admin/assets/{globe-DXrE-_sR.js → globe-DKkjr9MZ.js} +2 -2
- package/dist/admin/assets/{globe-DXrE-_sR.js.map → globe-DKkjr9MZ.js.map} +1 -1
- package/dist/admin/assets/{image-BImUdARR.js → image-B6aL7hP8.js} +2 -2
- package/dist/admin/assets/{image-BImUdARR.js.map → image-B6aL7hP8.js.map} +1 -1
- package/dist/admin/assets/{image-off-CEBznyUC.js → image-off-TVxEyb74.js} +2 -2
- package/dist/admin/assets/{image-off-CEBznyUC.js.map → image-off-TVxEyb74.js.map} +1 -1
- package/dist/admin/assets/{inbox-BQ_HOjFd.js → inbox-BKqu1EfP.js} +2 -2
- package/dist/admin/assets/{inbox-BQ_HOjFd.js.map → inbox-BKqu1EfP.js.map} +1 -1
- package/dist/admin/assets/{inbox-BZGf97fS.js → inbox-DUqOrFEA.js} +2 -2
- package/dist/admin/assets/{inbox-BZGf97fS.js.map → inbox-DUqOrFEA.js.map} +1 -1
- package/dist/admin/assets/index-BEM45u2w.css +2 -0
- package/dist/admin/assets/index-D03RZB7e.js +4 -0
- package/dist/admin/assets/index-D03RZB7e.js.map +1 -0
- package/dist/admin/assets/{key-round-BJTVRy3_.js → key-round-Dmdr1vP5.js} +2 -2
- package/dist/admin/assets/{key-round-BJTVRy3_.js.map → key-round-Dmdr1vP5.js.map} +1 -1
- package/dist/admin/assets/{labels-S4ZMHvJW.js → labels-CHE0gg1n.js} +2 -2
- package/dist/admin/assets/{labels-S4ZMHvJW.js.map → labels-CHE0gg1n.js.map} +1 -1
- package/dist/admin/assets/{languages-L4cGzT6V.js → languages-BbfFIygP.js} +2 -2
- package/dist/admin/assets/{languages-L4cGzT6V.js.map → languages-BbfFIygP.js.map} +1 -1
- package/dist/admin/assets/{layers-BGHZayyB.js → layers-B0jT4rc4.js} +2 -2
- package/dist/admin/assets/{layers-BGHZayyB.js.map → layers-B0jT4rc4.js.map} +1 -1
- package/dist/admin/assets/{link-2-off-c1sYGivC.js → link-2-off-DC06jLDj.js} +2 -2
- package/dist/admin/assets/{link-2-off-c1sYGivC.js.map → link-2-off-DC06jLDj.js.map} +1 -1
- package/dist/admin/assets/{link-BGUl1m0y.js → link-B3O0VUVT.js} +2 -2
- package/dist/admin/assets/{link-BGUl1m0y.js.map → link-B3O0VUVT.js.map} +1 -1
- package/dist/admin/assets/{loader-circle-BaUsKfL8.js → loader-circle-C-9trZPI.js} +2 -2
- package/dist/admin/assets/{loader-circle-BaUsKfL8.js.map → loader-circle-C-9trZPI.js.map} +1 -1
- package/dist/admin/assets/{locales-CLqYl3dG.js → locales-e7B5t6id.js} +2 -2
- package/dist/admin/assets/{locales-CLqYl3dG.js.map → locales-e7B5t6id.js.map} +1 -1
- package/dist/admin/assets/{media-D6kY5Cj6.js → media-BUUEsWxd.js} +2 -2
- package/dist/admin/assets/{media-D6kY5Cj6.js.map → media-BUUEsWxd.js.map} +1 -1
- package/dist/admin/assets/{media-azW3_Am5.js → media-VCJUbYzJ.js} +2 -2
- package/dist/admin/assets/{media-azW3_Am5.js.map → media-VCJUbYzJ.js.map} +1 -1
- package/dist/admin/assets/network-Bolr2lmf.js +2 -0
- package/dist/admin/assets/{network-BbLrO3ZX.js.map → network-Bolr2lmf.js.map} +1 -1
- package/dist/admin/assets/{pencil-BQpwTTXw.js → pencil-BVSFlU14.js} +2 -2
- package/dist/admin/assets/{pencil-BQpwTTXw.js.map → pencil-BVSFlU14.js.map} +1 -1
- package/dist/admin/assets/{plus-BYBGXiDV.js → plus-WfYKHW7G.js} +2 -2
- package/dist/admin/assets/{plus-BYBGXiDV.js.map → plus-WfYKHW7G.js.map} +1 -1
- package/dist/admin/assets/publishing-ClNjPLQ9.js +2 -0
- package/dist/admin/assets/publishing-ClNjPLQ9.js.map +1 -0
- package/dist/admin/assets/{radio-group-szmd95N4.js → radio-group-rFxn7cz2.js} +2 -2
- package/dist/admin/assets/{radio-group-szmd95N4.js.map → radio-group-rFxn7cz2.js.map} +1 -1
- package/dist/admin/assets/{rotate-ccw-TD7gQ_S5.js → rotate-ccw-Cvc_uA58.js} +2 -2
- package/dist/admin/assets/{rotate-ccw-TD7gQ_S5.js.map → rotate-ccw-Cvc_uA58.js.map} +1 -1
- package/dist/admin/assets/{schedules-DdnCCx_b.js → schedules-CBGpjEg7.js} +2 -2
- package/dist/admin/assets/{schedules-DdnCCx_b.js.map → schedules-CBGpjEg7.js.map} +1 -1
- package/dist/admin/assets/{schema-BzJ3fK72.js → schema-D9BgCVzZ.js} +2 -2
- package/dist/admin/assets/{schema-BzJ3fK72.js.map → schema-D9BgCVzZ.js.map} +1 -1
- package/dist/admin/assets/{scroll-text-DdRRr86a.js → scroll-text-gKYBbibb.js} +2 -2
- package/dist/admin/assets/{scroll-text-DdRRr86a.js.map → scroll-text-gKYBbibb.js.map} +1 -1
- package/dist/admin/assets/{search-JRmBbB7P.js → search-CW3iBC4k.js} +2 -2
- package/dist/admin/assets/{search-JRmBbB7P.js.map → search-CW3iBC4k.js.map} +1 -1
- package/dist/admin/assets/{searchSchemas-VaNHAlfp.js → searchSchemas-C4qp-vCa.js} +2 -2
- package/dist/admin/assets/{searchSchemas-VaNHAlfp.js.map → searchSchemas-C4qp-vCa.js.map} +1 -1
- package/dist/admin/assets/{sections-CbJVJmgY.js → sections-C7Z6Xd8r.js} +2 -2
- package/dist/admin/assets/{sections-CbJVJmgY.js.map → sections-C7Z6Xd8r.js.map} +1 -1
- package/dist/admin/assets/{sections-BsLTv5pq.js → sections-CN5fIoAr.js} +2 -2
- package/dist/admin/assets/{sections-BsLTv5pq.js.map → sections-CN5fIoAr.js.map} +1 -1
- package/dist/admin/assets/{select-p7RjCHS1.js → select-DUhL27UN.js} +2 -2
- package/dist/admin/assets/{select-p7RjCHS1.js.map → select-DUhL27UN.js.map} +1 -1
- package/dist/admin/assets/{send-BcDsf__t.js → send-DRA-Pe46.js} +2 -2
- package/dist/admin/assets/{send-BcDsf__t.js.map → send-DRA-Pe46.js.map} +1 -1
- package/dist/admin/assets/{seo-C88lYd48.js → seo-l1ZORjtv.js} +2 -2
- package/dist/admin/assets/{seo-C88lYd48.js.map → seo-l1ZORjtv.js.map} +1 -1
- package/dist/admin/assets/settings-DgoG3H8C.js +2 -0
- package/dist/admin/assets/{settings-2YUiWx9J.js.map → settings-DgoG3H8C.js.map} +1 -1
- package/dist/admin/assets/shapes-BZ87ap5s.js +6 -0
- package/dist/admin/assets/shapes-BZ87ap5s.js.map +1 -0
- package/dist/admin/assets/{skeleton-BUvrrXQ7.js → skeleton-Dyi_b1wq.js} +2 -2
- package/dist/admin/assets/{skeleton-BUvrrXQ7.js.map → skeleton-Dyi_b1wq.js.map} +1 -1
- package/dist/admin/assets/{snapshots-IQxgEhwm.js → snapshots-CT-zs6Up.js} +2 -2
- package/dist/admin/assets/{snapshots-IQxgEhwm.js.map → snapshots-CT-zs6Up.js.map} +1 -1
- package/dist/admin/assets/{sparkles-DSj-egu-.js → sparkles-DCRAqbqD.js} +2 -2
- package/dist/admin/assets/{sparkles-DSj-egu-.js.map → sparkles-DCRAqbqD.js.map} +1 -1
- package/dist/admin/assets/src-BcLeD2-K.js +7 -0
- package/dist/admin/assets/src-BcLeD2-K.js.map +1 -0
- package/dist/admin/assets/{stableId-DQQ5viUn.js → stableId-iRkUbVIP.js} +2 -2
- package/dist/admin/assets/{stableId-DQQ5viUn.js.map → stableId-iRkUbVIP.js.map} +1 -1
- package/dist/admin/assets/{store-Rdj8W9EY.js → store-DknnssoQ.js} +2 -2
- package/dist/admin/assets/{store-Rdj8W9EY.js.map → store-DknnssoQ.js.map} +1 -1
- package/dist/admin/assets/{switch-Co2wfi3S.js → switch-C3dDDUIk.js} +2 -2
- package/dist/admin/assets/{switch-Co2wfi3S.js.map → switch-C3dDDUIk.js.map} +1 -1
- package/dist/admin/assets/{theme-xFjfWxsg.js → theme-DPe080iG.js} +2 -2
- package/dist/admin/assets/{theme-xFjfWxsg.js.map → theme-DPe080iG.js.map} +1 -1
- package/dist/admin/assets/{titles-BMPQZALy.js → titles-C5PaMgFJ.js} +2 -2
- package/dist/admin/assets/{titles-BMPQZALy.js.map → titles-C5PaMgFJ.js.map} +1 -1
- package/dist/admin/assets/{tokens-DB2OodVc.js → tokens-BlIDIMY9.js} +2 -2
- package/dist/admin/assets/{tokens-DB2OodVc.js.map → tokens-BlIDIMY9.js.map} +1 -1
- package/dist/admin/assets/{tooltip-B_8HZ1Wu.js → tooltip-BEaZkRPK.js} +2 -2
- package/dist/admin/assets/{tooltip-B_8HZ1Wu.js.map → tooltip-BEaZkRPK.js.map} +1 -1
- package/dist/admin/assets/{undo-2-CagAc44E.js → undo-2-Zd1OT6qk.js} +2 -2
- package/dist/admin/assets/{undo-2-CagAc44E.js.map → undo-2-Zd1OT6qk.js.map} +1 -1
- package/dist/admin/assets/{useAuditLabels-CT1QmcqM.js → useAuditLabels-DWBpLOTB.js} +2 -2
- package/dist/admin/assets/{useAuditLabels-CT1QmcqM.js.map → useAuditLabels-DWBpLOTB.js.map} +1 -1
- package/dist/admin/assets/useConfirmTarget-9JmfiY2X.js +2 -0
- package/dist/admin/assets/useConfirmTarget-9JmfiY2X.js.map +1 -0
- package/dist/admin/assets/{useContentSchema-Ca1tmrC5.js → useContentSchema-wLDa2L3f.js} +2 -2
- package/dist/admin/assets/{useContentSchema-Ca1tmrC5.js.map → useContentSchema-wLDa2L3f.js.map} +1 -1
- package/dist/admin/assets/useCursorPager-Dc-9B67j.js +2 -0
- package/dist/admin/assets/useCursorPager-Dc-9B67j.js.map +1 -0
- package/dist/admin/assets/{useDiscardGuard-B8dlCh6M.js → useDiscardGuard-WTUINqD5.js} +2 -2
- package/dist/admin/assets/{useDiscardGuard-B8dlCh6M.js.map → useDiscardGuard-WTUINqD5.js.map} +1 -1
- package/dist/admin/assets/{useMediaPickerDialog-Cr7frtLB.js → useMediaPickerDialog-CFN9ZKfe.js} +2 -2
- package/dist/admin/assets/{useMediaPickerDialog-Cr7frtLB.js.map → useMediaPickerDialog-CFN9ZKfe.js.map} +1 -1
- package/dist/admin/assets/{useMediaUploader-DjpdBcVv.js → useMediaUploader-B42H_CMG.js} +2 -2
- package/dist/admin/assets/{useMediaUploader-DjpdBcVv.js.map → useMediaUploader-B42H_CMG.js.map} +1 -1
- package/dist/admin/assets/useNetworkPermission-CegwqQXR.js +2 -0
- package/dist/admin/assets/useNetworkPermission-CegwqQXR.js.map +1 -0
- package/dist/admin/assets/{usePaletteItems-B3OEkGXv.js → usePaletteItems-B3y2t7Ly.js} +2 -2
- package/dist/admin/assets/{usePaletteItems-B3OEkGXv.js.map → usePaletteItems-B3y2t7Ly.js.map} +1 -1
- package/dist/admin/assets/{usePlaces-CdX6q9xt.js → usePlaces-CAXr-IO9.js} +2 -2
- package/dist/admin/assets/{usePlaces-CdX6q9xt.js.map → usePlaces-CAXr-IO9.js.map} +1 -1
- package/dist/admin/assets/{useQueries-P7D4677o.js → useQueries-CX6eFr24.js} +2 -2
- package/dist/admin/assets/{useQueries-P7D4677o.js.map → useQueries-CX6eFr24.js.map} +1 -1
- package/dist/admin/assets/{useResolvedScheme-O1g9lYxQ.js → useResolvedScheme-aV0QDPi3.js} +2 -2
- package/dist/admin/assets/{useResolvedScheme-O1g9lYxQ.js.map → useResolvedScheme-aV0QDPi3.js.map} +1 -1
- package/dist/admin/assets/{useSchemaScopeAccess-DJo7rYB7.js → useSchemaScopeAccess-DyfiZnzs.js} +2 -2
- package/dist/admin/assets/{useSchemaScopeAccess-DJo7rYB7.js.map → useSchemaScopeAccess-DyfiZnzs.js.map} +1 -1
- package/dist/admin/assets/{users-eCGpE8u4.js → users-CDoJRL24.js} +2 -2
- package/dist/admin/assets/{users-eCGpE8u4.js.map → users-CDoJRL24.js.map} +1 -1
- package/dist/admin/assets/{users-sDlmJ2ml.js → users-ohHZnBJW.js} +2 -2
- package/dist/admin/assets/{users-sDlmJ2ml.js.map → users-ohHZnBJW.js.map} +1 -1
- package/dist/admin/assets/{zod-DtMsJRUH.js → zod-C-k48Hnc.js} +2 -2
- package/dist/admin/assets/{zod-DtMsJRUH.js.map → zod-C-k48Hnc.js.map} +1 -1
- package/dist/admin/index.html +59 -58
- package/dist/cli.js +129 -4
- package/dist/cli.js.map +1 -1
- package/dist/config.d.ts +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +1 -1
- package/dist/{public-rn-FEAIR.d.ts → public-BO_wneBL.d.ts} +18 -1
- package/dist/{s3Adapter-Bs5SUqE1.js → s3Adapter-sL1zP4Zl.js} +2 -2
- package/dist/{s3Adapter-Bs5SUqE1.js.map → s3Adapter-sL1zP4Zl.js.map} +1 -1
- package/dist/{worker-CFEk-WtR.js → worker-DMES6pqh.js} +486 -161
- package/dist/worker-DMES6pqh.js.map +1 -0
- package/package.json +5 -5
- package/dist/admin/assets/Builder-D8AVakt1.js +0 -2
- package/dist/admin/assets/Builder-D8AVakt1.js.map +0 -1
- package/dist/admin/assets/Form-DKfQ6_lP.js +0 -2
- package/dist/admin/assets/StepList-B4I59Yl_.js +0 -2
- package/dist/admin/assets/Structure-BYK71uPq.js +0 -2
- package/dist/admin/assets/auth-kvLrpCst.js +0 -2
- package/dist/admin/assets/changeSets-BjP6UzCi.js +0 -2
- package/dist/admin/assets/chevron-left-uCIwt51T.js +0 -2
- package/dist/admin/assets/content-DTKf5anG.js +0 -3
- package/dist/admin/assets/content-DTKf5anG.js.map +0 -1
- package/dist/admin/assets/createLucideIcon-CJwW5JJW.js +0 -2
- package/dist/admin/assets/createLucideIcon-CJwW5JJW.js.map +0 -1
- package/dist/admin/assets/develop-CXljZJGt.js +0 -11
- package/dist/admin/assets/develop-CXljZJGt.js.map +0 -1
- package/dist/admin/assets/es2015-DgNe6MPq.js +0 -42
- package/dist/admin/assets/es2015-DgNe6MPq.js.map +0 -1
- package/dist/admin/assets/index-BF63XIym.js +0 -4
- package/dist/admin/assets/index-BF63XIym.js.map +0 -1
- package/dist/admin/assets/index-DJe1l94K.css +0 -2
- package/dist/admin/assets/network-BbLrO3ZX.js +0 -2
- package/dist/admin/assets/publishing-sgYacQ-C.js +0 -2
- package/dist/admin/assets/publishing-sgYacQ-C.js.map +0 -1
- package/dist/admin/assets/settings-2YUiWx9J.js +0 -2
- package/dist/admin/assets/src-CeOxD_sk.js +0 -4
- package/dist/admin/assets/src-CeOxD_sk.js.map +0 -1
- package/dist/admin/assets/tabs-Dyd8Q_Ja.js +0 -6
- package/dist/admin/assets/tabs-Dyd8Q_Ja.js.map +0 -1
- package/dist/admin/assets/useConfirmTarget-D6FvyjDd.js +0 -2
- package/dist/admin/assets/useConfirmTarget-D6FvyjDd.js.map +0 -1
- package/dist/admin/assets/useCursorPager-DTe6uEBE.js +0 -2
- package/dist/admin/assets/useCursorPager-DTe6uEBE.js.map +0 -1
- package/dist/worker-CFEk-WtR.js.map +0 -1
|
@@ -4723,6 +4723,17 @@ const COLUMNS$2 = [
|
|
|
4723
4723
|
/** Every head of an entry, locked for the rest of the transaction. */
|
|
4724
4724
|
const lockForEntry = (entryId, trx) => trx.selectFrom("entry_heads").select(COLUMNS$2).where("entry_id", "=", entryId).orderBy("locale").orderBy("state").forUpdate().execute();
|
|
4725
4725
|
const findForEntry = (entryId, executor = db) => executor.selectFrom("entry_heads").select(COLUMNS$2).where("entry_id", "=", entryId).execute();
|
|
4726
|
+
/** The heads of one site's entries among `entryIds` that belong to `modelIds` (titles of related entries). */
|
|
4727
|
+
const findForEntriesOnSite = (siteId, modelIds, entryIds, executor = db) => entryIds.length === 0 || modelIds.length === 0 ? Promise.resolve([]) : executor.selectFrom("entry_heads").select([
|
|
4728
|
+
"entry_id",
|
|
4729
|
+
"model_id",
|
|
4730
|
+
"locale",
|
|
4731
|
+
"state",
|
|
4732
|
+
"revision_id",
|
|
4733
|
+
"data",
|
|
4734
|
+
"version",
|
|
4735
|
+
"autosaved_at"
|
|
4736
|
+
]).where("site_id", "=", siteId).where("model_id", "in", modelIds).where("entry_id", "in", entryIds).execute();
|
|
4726
4737
|
const insert$28 = (head, trx = db) => trx.insertInto("entry_heads").values({
|
|
4727
4738
|
entry_id: head.entryId,
|
|
4728
4739
|
site_id: entrySiteOf(trx, head.entryId),
|
|
@@ -5174,7 +5185,7 @@ const NODE_KEYS = /* @__PURE__ */ new Set([
|
|
|
5174
5185
|
"marks"
|
|
5175
5186
|
]);
|
|
5176
5187
|
const MAX_PROBLEMS = 20;
|
|
5177
|
-
const isRecord$
|
|
5188
|
+
const isRecord$15 = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
|
|
5178
5189
|
const fail = (walk, path, message) => {
|
|
5179
5190
|
if (walk.problems.length < MAX_PROBLEMS) walk.problems.push({
|
|
5180
5191
|
path,
|
|
@@ -5182,7 +5193,7 @@ const fail = (walk, path, message) => {
|
|
|
5182
5193
|
});
|
|
5183
5194
|
};
|
|
5184
5195
|
const checkAttrs = (walk, path, rules, raw) => {
|
|
5185
|
-
if (raw !== void 0 && !isRecord$
|
|
5196
|
+
if (raw !== void 0 && !isRecord$15(raw)) return fail(walk, `${path}/attrs`, "must be an object");
|
|
5186
5197
|
const given = raw ?? {};
|
|
5187
5198
|
const attrs = {};
|
|
5188
5199
|
for (const key of Object.keys(given)) if (!rules || !Object.hasOwn(rules, key)) fail(walk, `${path}/attrs/${key}`, "is not an allowed attribute");
|
|
@@ -5204,7 +5215,7 @@ const checkMarks = (walk, path, raw, allowed) => {
|
|
|
5204
5215
|
const marks = [];
|
|
5205
5216
|
raw.forEach((mark, index) => {
|
|
5206
5217
|
const at = `${path}/marks/${index}`;
|
|
5207
|
-
if (!isRecord$
|
|
5218
|
+
if (!isRecord$15(mark) || typeof mark.type !== "string" || !Object.hasOwn(MARK_RULES, mark.type)) {
|
|
5208
5219
|
fail(walk, at, "is not an allowed mark");
|
|
5209
5220
|
return;
|
|
5210
5221
|
}
|
|
@@ -5225,7 +5236,7 @@ const matchesAllow = (allow, type) => {
|
|
|
5225
5236
|
};
|
|
5226
5237
|
const checkNode = (walk, raw, path, depth, context) => {
|
|
5227
5238
|
if (depth > 40) return fail(walk, path, "is nested too deeply");
|
|
5228
|
-
if (!isRecord$
|
|
5239
|
+
if (!isRecord$15(raw) || typeof raw.type !== "string") return fail(walk, path, "must be a node with a type");
|
|
5229
5240
|
const { type } = raw;
|
|
5230
5241
|
const rule = Object.hasOwn(NODE_RULES, type) ? NODE_RULES[type] : void 0;
|
|
5231
5242
|
if (!rule) return fail(walk, path, `"${type}" is not an allowed node`);
|
|
@@ -5278,7 +5289,7 @@ const validateRichText = (value) => {
|
|
|
5278
5289
|
problems: [],
|
|
5279
5290
|
textLength: 0
|
|
5280
5291
|
};
|
|
5281
|
-
if (!isRecord$
|
|
5292
|
+
if (!isRecord$15(value)) return {
|
|
5282
5293
|
ok: false,
|
|
5283
5294
|
problems: [{
|
|
5284
5295
|
path: "",
|
|
@@ -5382,7 +5393,7 @@ const DEFAULT_SEO_KEYS = {
|
|
|
5382
5393
|
canonical: "canonical",
|
|
5383
5394
|
noindex: "noindex"
|
|
5384
5395
|
};
|
|
5385
|
-
const isRecord$
|
|
5396
|
+
const isRecord$14 = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
|
|
5386
5397
|
const text = (value) => typeof value === "string" && value.trim() !== "" ? value : null;
|
|
5387
5398
|
/**
|
|
5388
5399
|
* The effective SEO values of one delivered entry, in the same shape as the raw value (plan seo-fields): the
|
|
@@ -5392,7 +5403,7 @@ const text = (value) => typeof value === "string" && value.trim() !== "" ? value
|
|
|
5392
5403
|
*/
|
|
5393
5404
|
const resolveSeo = (raw, context) => {
|
|
5394
5405
|
const keys = context.keys ?? DEFAULT_SEO_KEYS;
|
|
5395
|
-
const output = isRecord$
|
|
5406
|
+
const output = isRecord$14(raw) ? { ...raw } : {};
|
|
5396
5407
|
const value = (key) => keys[key] === void 0 ? void 0 : output[keys[key]];
|
|
5397
5408
|
const set = (key, next) => {
|
|
5398
5409
|
if (keys[key] !== void 0) output[keys[key]] = next;
|
|
@@ -5918,6 +5929,22 @@ const closed$3$1 = { additionalProperties: false };
|
|
|
5918
5929
|
const MODEL_KINDS = ["collection", "singleton"];
|
|
5919
5930
|
const DEFINITION_KINDS = [...MODEL_KINDS, "component"];
|
|
5920
5931
|
const SORT_DIRECTIONS = ["asc", "desc"];
|
|
5932
|
+
/**
|
|
5933
|
+
* How an entry of a model opens: `document` (title typed into the page, blocks in a canvas, properties in
|
|
5934
|
+
* the strip and the settings drawer) or `form` (every field inline at its `width`, sections from
|
|
5935
|
+
* `display.groups`). Unset means `document`; normalizing drops an explicit `document`.
|
|
5936
|
+
*/
|
|
5937
|
+
const ENTRY_LAYOUTS = ["document", "form"];
|
|
5938
|
+
/**
|
|
5939
|
+
* A field's width in a form-layout entry, as a share of the row: rows fill in field order and wrap. Unset
|
|
5940
|
+
* means `full`; normalizing drops an explicit `full`.
|
|
5941
|
+
*/
|
|
5942
|
+
const FIELD_WIDTHS = [
|
|
5943
|
+
"full",
|
|
5944
|
+
"two-thirds",
|
|
5945
|
+
"half",
|
|
5946
|
+
"third"
|
|
5947
|
+
];
|
|
5921
5948
|
const MAX_DESCRIPTION_LENGTH = 2e3;
|
|
5922
5949
|
const Label = Type.String({
|
|
5923
5950
|
minLength: 1,
|
|
@@ -5952,7 +5979,12 @@ const FieldInputSchema = Type.Object({
|
|
|
5952
5979
|
defaultValue: Type.Optional(Type.Unknown()),
|
|
5953
5980
|
/** Type-specific settings, validated against SETTINGS_SCHEMAS[type]. */
|
|
5954
5981
|
settings: Type.Optional(Type.Record(Type.String(), Type.Unknown())),
|
|
5955
|
-
editor: Type.Optional(EditorChoiceInputSchema)
|
|
5982
|
+
editor: Type.Optional(EditorChoiceInputSchema),
|
|
5983
|
+
/**
|
|
5984
|
+
* Width in a form-layout entry (`display.layout: 'form'`). Default `full`. Model fields only: the
|
|
5985
|
+
* validator refuses it on a component's field.
|
|
5986
|
+
*/
|
|
5987
|
+
width: Type.Optional(Type.Enum(FIELD_WIDTHS))
|
|
5956
5988
|
}, closed$3$1);
|
|
5957
5989
|
const FieldGroupSchema = Type.Object({
|
|
5958
5990
|
id: Type.String({
|
|
@@ -5963,6 +5995,8 @@ const FieldGroupSchema = Type.Object({
|
|
|
5963
5995
|
fieldIds: Type.Array(Type.String())
|
|
5964
5996
|
}, closed$3$1);
|
|
5965
5997
|
const ModelDisplayInputSchema = Type.Object({
|
|
5998
|
+
/** How entries open: `document` (default) or `form`. See `ENTRY_LAYOUTS`. */
|
|
5999
|
+
layout: Type.Optional(Type.Enum(ENTRY_LAYOUTS)),
|
|
5966
6000
|
/** Field whose value labels an entry in lists, pickers and relation summaries. */
|
|
5967
6001
|
titleFieldId: Type.Optional(Type.String()),
|
|
5968
6002
|
/** Columns of the content list, in order. */
|
|
@@ -6469,6 +6503,13 @@ const effectiveLayout = (model) => {
|
|
|
6469
6503
|
strip: model.display.stripFieldIds === void 0 ? null : unique$1(byIds(properties, model.display.stripFieldIds))
|
|
6470
6504
|
};
|
|
6471
6505
|
};
|
|
6506
|
+
/** How the model's entries open (`display.layout`): `document` unless set to `form`. */
|
|
6507
|
+
const entryLayoutOf = (model) => model.display.layout ?? "document";
|
|
6508
|
+
/**
|
|
6509
|
+
* The entry's rich-text body, which "Summarize from body" reads: the document's rich-text canvas fields, or
|
|
6510
|
+
* every live rich-text field of a form (a form has no canvas; its fields are all on the page).
|
|
6511
|
+
*/
|
|
6512
|
+
const richTextBodyOf = (model) => entryLayoutOf(model) === "form" ? model.fields.filter((field) => field.type === "richtext" && !field.deprecated) : effectiveLayout(model).canvas.filter((field) => field.type === "richtext");
|
|
6472
6513
|
/**
|
|
6473
6514
|
* API keys (models, components, fields) must be valid GraphQL names from day one (CONTRIBUTING.md rule 4),
|
|
6474
6515
|
* so GraphQL can expose them without renames.
|
|
@@ -6565,17 +6606,22 @@ const normalizeField = (field) => {
|
|
|
6565
6606
|
editor: {
|
|
6566
6607
|
id: field.editor?.id ?? DEFAULT_EDITORS[field.type],
|
|
6567
6608
|
options: field.editor?.options ?? {}
|
|
6568
|
-
}
|
|
6609
|
+
},
|
|
6610
|
+
width: field.width === "full" ? void 0 : field.width
|
|
6569
6611
|
};
|
|
6570
6612
|
return withoutEmpty(normalized);
|
|
6571
6613
|
};
|
|
6572
|
-
const normalizeModelDisplay = (display) => withoutEmpty({
|
|
6614
|
+
const normalizeModelDisplay = (display) => withoutEmpty({
|
|
6615
|
+
...display,
|
|
6616
|
+
layout: display?.layout === "document" ? void 0 : display?.layout
|
|
6617
|
+
});
|
|
6573
6618
|
const normalizeComponentDisplay = (display) => withoutEmpty({ ...display });
|
|
6574
6619
|
/**
|
|
6575
6620
|
* Applies defaults so that two definitions meaning the same thing are byte-identical once serialized
|
|
6576
6621
|
* canonically: a hand-written file that omits `public` hashes the same as one that says `public: true`.
|
|
6577
|
-
* Empty optional strings and arrays are dropped
|
|
6578
|
-
*
|
|
6622
|
+
* Empty optional strings and arrays are dropped, and so are the defaults of keys added after definitions
|
|
6623
|
+
* were first hashed (`width: 'full'`, `display.layout: 'document'`). A collection without a plural API ID
|
|
6624
|
+
* gets the suggested one (`suggestPlural`), so files and definitions from before plural API IDs keep working.
|
|
6579
6625
|
*/
|
|
6580
6626
|
const normalizeDefinition = (input) => {
|
|
6581
6627
|
const fields = input.fields.map(normalizeField);
|
|
@@ -6968,6 +7014,7 @@ const checkFlags = (field, path, isComponent) => {
|
|
|
6968
7014
|
"filterable",
|
|
6969
7015
|
"sortable"
|
|
6970
7016
|
]) if (field[flag]) reject(flag, `fields of a component cannot be ${flag}`);
|
|
7017
|
+
if (field.width !== void 0) reject("width", "fields of a component have no width");
|
|
6971
7018
|
}
|
|
6972
7019
|
if (field.deprecated && field.required) reject("required", "a deprecated field cannot be required");
|
|
6973
7020
|
return issues;
|
|
@@ -7384,7 +7431,8 @@ const DEFINITION_METADATA = [
|
|
|
7384
7431
|
const FIELD_METADATA = [
|
|
7385
7432
|
"label",
|
|
7386
7433
|
"description",
|
|
7387
|
-
"defaultValue"
|
|
7434
|
+
"defaultValue",
|
|
7435
|
+
"width"
|
|
7388
7436
|
];
|
|
7389
7437
|
const FIELD_FLAGS = [
|
|
7390
7438
|
["required", "field.required"],
|
|
@@ -8100,6 +8148,15 @@ const plainTextToRichText = (text) => {
|
|
|
8100
8148
|
};
|
|
8101
8149
|
};
|
|
8102
8150
|
/**
|
|
8151
|
+
* A stored rich text value (`{ format, version, doc }`) as one line of plain text: blocks separated by a
|
|
8152
|
+
* space, whitespace collapsed. For summaries (list cells, collapsed items, review rows), never for delivery.
|
|
8153
|
+
* Anything that is not a valid document (an unconverted value of a field that became rich text) reads as ''.
|
|
8154
|
+
*/
|
|
8155
|
+
const richTextPlainText = (value) => {
|
|
8156
|
+
const result = validateRichText(value);
|
|
8157
|
+
return result.ok ? richTextToPlainText(result.document).replace(/\s+/g, " ").trim() : "";
|
|
8158
|
+
};
|
|
8159
|
+
/**
|
|
8103
8160
|
* Admin themes (docs/plans/themes.md): a theme is a named, complete set of these tokens for a light variant, a
|
|
8104
8161
|
* dark variant or both. One list, shared by the admin's stylesheets (and their tests) and the API, which
|
|
8105
8162
|
* validates themes declared by extensions (`shapio.config` `themes`).
|
|
@@ -8608,7 +8665,7 @@ const isReferenceId = (value) => isStableId(value);
|
|
|
8608
8665
|
* keeps values until an explicit cleanup); deprecated fields' values are kept but not validated.
|
|
8609
8666
|
*/
|
|
8610
8667
|
const COMPONENT_KEY = "__component";
|
|
8611
|
-
const isRecord$
|
|
8668
|
+
const isRecord$13 = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
|
|
8612
8669
|
const isMissingValue = (value) => value === void 0 || value === null || value === "" || Array.isArray(value) && value.length === 0;
|
|
8613
8670
|
const issue = (walk, path, code, message) => {
|
|
8614
8671
|
walk.issues.push({
|
|
@@ -8642,7 +8699,7 @@ const validateFields = (definition, data, path, walk, components) => {
|
|
|
8642
8699
|
}
|
|
8643
8700
|
return output;
|
|
8644
8701
|
};
|
|
8645
|
-
const checkComponentObject = (component, value, path, walk, components) => isRecord$
|
|
8702
|
+
const checkComponentObject = (component, value, path, walk, components) => isRecord$13(value) ? validateFields(component, value, path, walk, components) : issue(walk, path, "INVALID_TYPE", "must be an object");
|
|
8646
8703
|
const isJson = (text) => {
|
|
8647
8704
|
try {
|
|
8648
8705
|
JSON.parse(text);
|
|
@@ -8674,7 +8731,7 @@ const checkStructured = (field, value, path, walk, components) => {
|
|
|
8674
8731
|
checkCount(walk, path, value.length, field.settings);
|
|
8675
8732
|
return value.map((item, index) => {
|
|
8676
8733
|
const at = pointer(path, index);
|
|
8677
|
-
const componentId = isRecord$
|
|
8734
|
+
const componentId = isRecord$13(item) ? item[COMPONENT_KEY] : void 0;
|
|
8678
8735
|
const component = typeof componentId === "string" && field.settings.components.includes(componentId) ? components.get(componentId) : void 0;
|
|
8679
8736
|
if (!component) return issue(walk, pointer(at, COMPONENT_KEY), "UNKNOWN_COMPONENT", "is not allowed in this zone");
|
|
8680
8737
|
const fields = checkComponentObject(component, item, at, walk, components);
|
|
@@ -8760,7 +8817,7 @@ const mapInput = (definition, input, path, issues, components) => {
|
|
|
8760
8817
|
}
|
|
8761
8818
|
return output;
|
|
8762
8819
|
};
|
|
8763
|
-
const mapComponentInput = (component, value, path, issues, components) => component && isRecord$
|
|
8820
|
+
const mapComponentInput = (component, value, path, issues, components) => component && isRecord$13(value) ? mapInput(component, value, path, issues, components) : value;
|
|
8764
8821
|
function mapFieldInput(field, value, path, issues, components) {
|
|
8765
8822
|
if (field.type === "component") {
|
|
8766
8823
|
const component = components.get(field.settings.component);
|
|
@@ -8768,7 +8825,7 @@ function mapFieldInput(field, value, path, issues, components) {
|
|
|
8768
8825
|
}
|
|
8769
8826
|
if (field.type === "dynamiczone" && Array.isArray(value)) return value.map((item, index) => {
|
|
8770
8827
|
const at = pointer(path, index);
|
|
8771
|
-
const apiKey = isRecord$
|
|
8828
|
+
const apiKey = isRecord$13(item) ? item[COMPONENT_KEY] : void 0;
|
|
8772
8829
|
const component = field.settings.components.map((id) => components.get(id)).find((candidate) => candidate?.apiKey === apiKey);
|
|
8773
8830
|
if (!component) {
|
|
8774
8831
|
issues.push({
|
|
@@ -8831,7 +8888,7 @@ const buildValidator = (snapshot, model) => {
|
|
|
8831
8888
|
};
|
|
8832
8889
|
//#endregion
|
|
8833
8890
|
//#region src/content/relations.ts
|
|
8834
|
-
const isRecord$
|
|
8891
|
+
const isRecord$12 = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
|
|
8835
8892
|
const referenceIds = (value) => (Array.isArray(value) ? value : [value]).filter((item) => typeof item === "string");
|
|
8836
8893
|
const walkFields$1 = (fields, data, components, visit) => {
|
|
8837
8894
|
for (const field of fields) {
|
|
@@ -8843,10 +8900,10 @@ const walkFields$1 = (fields, data, components, visit) => {
|
|
|
8843
8900
|
});
|
|
8844
8901
|
else if (field.type === "component") {
|
|
8845
8902
|
const component = components.get(field.settings.component)?.definition;
|
|
8846
|
-
for (const item of Array.isArray(value) ? value : [value]) if (component && isRecord$
|
|
8903
|
+
for (const item of Array.isArray(value) ? value : [value]) if (component && isRecord$12(item)) walkFields$1(component.fields, item, components, visit);
|
|
8847
8904
|
} else if (field.type === "dynamiczone" && Array.isArray(value)) for (const item of value) {
|
|
8848
|
-
const component = isRecord$
|
|
8849
|
-
if (component && isRecord$
|
|
8905
|
+
const component = isRecord$12(item) ? components.get(String(item[COMPONENT_KEY]))?.definition : void 0;
|
|
8906
|
+
if (component && isRecord$12(item)) walkFields$1(component.fields, item, components, visit);
|
|
8850
8907
|
}
|
|
8851
8908
|
}
|
|
8852
8909
|
};
|
|
@@ -9039,14 +9096,14 @@ const findValueLocations = (definitions, ownerId) => {
|
|
|
9039
9096
|
* a model's own fields, every instance of the component otherwise. The returned objects are references
|
|
9040
9097
|
* into `data`, so callers mutate a clone.
|
|
9041
9098
|
*/
|
|
9042
|
-
const isRecord$
|
|
9099
|
+
const isRecord$11 = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
|
|
9043
9100
|
const ownerContainers = (data, path, ownerId) => {
|
|
9044
9101
|
let current = [data];
|
|
9045
9102
|
path.forEach((fieldId, index) => {
|
|
9046
9103
|
const last = index === path.length - 1;
|
|
9047
9104
|
current = current.flatMap((container) => {
|
|
9048
9105
|
const value = container[fieldId];
|
|
9049
|
-
return (Array.isArray(value) ? value : value === void 0 || value === null ? [] : [value]).filter(isRecord$
|
|
9106
|
+
return (Array.isArray(value) ? value : value === void 0 || value === null ? [] : [value]).filter(isRecord$11).filter((item) => !last || item["__component"] === void 0 || item["__component"] === ownerId);
|
|
9050
9107
|
});
|
|
9051
9108
|
});
|
|
9052
9109
|
return current;
|
|
@@ -10248,6 +10305,8 @@ const findById$16 = (id, trx = db) => trx.selectFrom("media_assets").selectAll()
|
|
|
10248
10305
|
const findLiveOnSite = (siteId, id, trx = db) => live(trx).selectAll().where("site_id", "=", siteId).where("id", "=", id).executeTakeFirst();
|
|
10249
10306
|
/** The live assets of one site among `ids`. */
|
|
10250
10307
|
const findLiveManyOnSite = (siteId, ids, trx = db) => ids.length === 0 ? Promise.resolve([]) : live(trx).selectAll().where("site_id", "=", siteId).where("id", "in", ids).execute();
|
|
10308
|
+
/** The original file names of one site's live assets among `ids` (review summaries). */
|
|
10309
|
+
const findNamesOnSite = (siteId, ids, trx = db) => ids.length === 0 ? Promise.resolve([]) : live(trx).select(["id", "original_filename"]).where("site_id", "=", siteId).where("id", "in", ids).execute();
|
|
10251
10310
|
/** Locks the row for the rest of the transaction (deleted rows too, so callers can report them). Jobs only. */
|
|
10252
10311
|
const lockById$5 = (id, trx) => trx.selectFrom("media_assets").selectAll().where("id", "=", id).forUpdate().executeTakeFirst();
|
|
10253
10312
|
/** Locks one site's asset row (deleted rows too); another site's asset reads as missing. */
|
|
@@ -11604,7 +11663,7 @@ const principalFromColumns = (type, id) => {
|
|
|
11604
11663
|
};
|
|
11605
11664
|
//#endregion
|
|
11606
11665
|
//#region src/content/media.ts
|
|
11607
|
-
const isRecord$
|
|
11666
|
+
const isRecord$10 = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
|
|
11608
11667
|
const collect$1 = (model, fields, data, add) => {
|
|
11609
11668
|
for (const field of fields) {
|
|
11610
11669
|
const value = data[field.id];
|
|
@@ -11614,16 +11673,16 @@ const collect$1 = (model, fields, data, add) => {
|
|
|
11614
11673
|
(Array.isArray(value) ? value : [value]).forEach((id) => typeof id === "string" && add(id));
|
|
11615
11674
|
break;
|
|
11616
11675
|
case "richtext":
|
|
11617
|
-
if (isRecord$
|
|
11676
|
+
if (isRecord$10(value) && isRecord$10(value.doc)) richTextMediaIds(value).forEach(add);
|
|
11618
11677
|
break;
|
|
11619
11678
|
case "component": {
|
|
11620
11679
|
const component = model.components.get(field.settings.component)?.definition;
|
|
11621
|
-
for (const item of Array.isArray(value) ? value : [value]) if (component && isRecord$
|
|
11680
|
+
for (const item of Array.isArray(value) ? value : [value]) if (component && isRecord$10(item)) collect$1(model, component.fields, item, add);
|
|
11622
11681
|
break;
|
|
11623
11682
|
}
|
|
11624
11683
|
case "dynamiczone": for (const item of Array.isArray(value) ? value : []) {
|
|
11625
|
-
const component = isRecord$
|
|
11626
|
-
if (component && isRecord$
|
|
11684
|
+
const component = isRecord$10(item) ? model.components.get(String(item[COMPONENT_KEY]))?.definition : void 0;
|
|
11685
|
+
if (component && isRecord$10(item)) collect$1(model, component.fields, item, add);
|
|
11627
11686
|
}
|
|
11628
11687
|
}
|
|
11629
11688
|
}
|
|
@@ -13017,7 +13076,7 @@ const projectRichText = (document, mode, options) => {
|
|
|
13017
13076
|
shaped[RICH_TEXT_HTML] = render;
|
|
13018
13077
|
return shaped;
|
|
13019
13078
|
};
|
|
13020
|
-
const isRecord$
|
|
13079
|
+
const isRecord$9 = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
|
|
13021
13080
|
const isListField = (field) => field.type === "relation" && field.settings.cardinality === "many" || field.type === "media" && field.settings.multiple || field.type === "component" && field.settings.repeatable || field.type === "dynamiczone";
|
|
13022
13081
|
const projectRelation = (field, value, options, topLevel) => {
|
|
13023
13082
|
const ids = (Array.isArray(value) ? value : [value]).filter((id) => typeof id === "string");
|
|
@@ -13028,7 +13087,7 @@ const projectRelation = (field, value, options, topLevel) => {
|
|
|
13028
13087
|
});
|
|
13029
13088
|
return field.settings.cardinality === "many" ? shown : shown[0] ?? null;
|
|
13030
13089
|
};
|
|
13031
|
-
const projectComponent = (component, value, options) => component && isRecord$
|
|
13090
|
+
const projectComponent = (component, value, options) => component && isRecord$9(value) ? projectFields(component.fields.filter((field) => !field.deprecated), value, options, false) : null;
|
|
13032
13091
|
const isStringOrStrings = (value) => typeof value === "string" || Array.isArray(value) && value.every((item) => typeof item === "string");
|
|
13033
13092
|
/**
|
|
13034
13093
|
* Whether a stored value has the shape the field's current type produces. Old snapshots are served through
|
|
@@ -13041,11 +13100,11 @@ const matchesFieldType = (field, value) => {
|
|
|
13041
13100
|
case "integer": return typeof value === "number";
|
|
13042
13101
|
case "boolean": return typeof value === "boolean";
|
|
13043
13102
|
case "json": return true;
|
|
13044
|
-
case "richtext": return isRecord$
|
|
13103
|
+
case "richtext": return isRecord$9(value) && isRecord$9(value.doc);
|
|
13045
13104
|
case "relation":
|
|
13046
13105
|
case "media": return isStringOrStrings(value);
|
|
13047
13106
|
case "enum": return field.settings.multiple ? Array.isArray(value) && value.every((item) => typeof item === "string") : typeof value === "string";
|
|
13048
|
-
case "component": return field.settings.repeatable ? Array.isArray(value) : isRecord$
|
|
13107
|
+
case "component": return field.settings.repeatable ? Array.isArray(value) : isRecord$9(value);
|
|
13049
13108
|
case "dynamiczone": return Array.isArray(value);
|
|
13050
13109
|
default: return typeof value === "string";
|
|
13051
13110
|
}
|
|
@@ -13059,7 +13118,7 @@ const projectValue = (field, value, options, topLevel) => {
|
|
|
13059
13118
|
return field.settings.repeatable ? (Array.isArray(value) ? value : []).map((item) => projectComponent(component, item, options)) : projectComponent(component, value, options);
|
|
13060
13119
|
}
|
|
13061
13120
|
case "dynamiczone": return (Array.isArray(value) ? value : []).flatMap((item) => {
|
|
13062
|
-
const component = isRecord$
|
|
13121
|
+
const component = isRecord$9(item) ? options.model.components.get(String(item[COMPONENT_KEY]))?.definition : void 0;
|
|
13063
13122
|
const projected = projectComponent(component, item, options);
|
|
13064
13123
|
return component && projected ? [{
|
|
13065
13124
|
[COMPONENT_KEY]: component.apiKey,
|
|
@@ -13267,11 +13326,11 @@ const createAfterHookJobHandler = (environment) => async (job) => {
|
|
|
13267
13326
|
};
|
|
13268
13327
|
//#endregion
|
|
13269
13328
|
//#region src/extensions/jobs.ts
|
|
13270
|
-
const isRecord$
|
|
13329
|
+
const isRecord$8 = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
|
|
13271
13330
|
/** The project's job handlers, registered as `ext.<name>` so they never collide with Shapio's job types. */
|
|
13272
13331
|
const createExtensionJobHandlers = (jobs, services) => Object.entries(jobs).map(([name, handler]) => [`${EXTENSION_JOB_PREFIX}${name}`, (job) => handler({
|
|
13273
13332
|
jobId: job.id,
|
|
13274
|
-
payload: isRecord$
|
|
13333
|
+
payload: isRecord$8(job.payload) ? job.payload : {},
|
|
13275
13334
|
attempt: job.attempt,
|
|
13276
13335
|
maxAttempts: job.maxAttempts,
|
|
13277
13336
|
idempotencyKey: job.idempotencyKey,
|
|
@@ -13329,7 +13388,7 @@ const shapioConfigSchema = Type.Object({
|
|
|
13329
13388
|
jobs: Type.Optional(Type.Record(Type.String(), anyFunction)),
|
|
13330
13389
|
themes: Type.Optional(Type.Array(themeSchema))
|
|
13331
13390
|
}, closed$11);
|
|
13332
|
-
const isRecord$
|
|
13391
|
+
const isRecord$7 = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
|
|
13333
13392
|
const TOP_LEVEL_KEYS$1 = Object.keys(shapioConfigSchema.properties);
|
|
13334
13393
|
const HOOK_EVENTS = Object.keys(modelHooksSchema.properties);
|
|
13335
13394
|
/** Names the unknown key and what is allowed in its place. */
|
|
@@ -13341,7 +13400,7 @@ const unknownKeyMessage = (path) => {
|
|
|
13341
13400
|
if (segments[0] === "themes" && segments.length === 4) return `unknown theme token "${key}"; the tokens are listed in documentation/extensions.md`;
|
|
13342
13401
|
return `unknown key "${key}"`;
|
|
13343
13402
|
};
|
|
13344
|
-
const keysOf$1 = (value) => isRecord$
|
|
13403
|
+
const keysOf$1 = (value) => isRecord$7(value) ? Object.keys(value) : [];
|
|
13345
13404
|
/** Rules TypeBox cannot express (key patterns, uniqueness, reserved names); tolerant of a malformed config. */
|
|
13346
13405
|
const findNamingProblems = (config) => {
|
|
13347
13406
|
const problems = [];
|
|
@@ -13351,7 +13410,7 @@ const findNamingProblems = (config) => {
|
|
|
13351
13410
|
});
|
|
13352
13411
|
const prefixes = /* @__PURE__ */ new Set();
|
|
13353
13412
|
(Array.isArray(config.routes) ? config.routes : []).forEach((route, index) => {
|
|
13354
|
-
if (!isRecord$
|
|
13413
|
+
if (!isRecord$7(route) || typeof route.prefix !== "string") return;
|
|
13355
13414
|
if (!ROUTE_PREFIX_PATTERN.test(route.prefix)) problems.push({
|
|
13356
13415
|
path: `/routes/${index}/prefix`,
|
|
13357
13416
|
message: "must be lower-case letters, digits and dashes (it becomes /api/ext/<prefix>)"
|
|
@@ -13382,7 +13441,7 @@ const findThemeProblems = (themes) => {
|
|
|
13382
13441
|
const problems = [];
|
|
13383
13442
|
const keys = /* @__PURE__ */ new Set();
|
|
13384
13443
|
(Array.isArray(themes) ? themes : []).forEach((theme, index) => {
|
|
13385
|
-
if (!isRecord$
|
|
13444
|
+
if (!isRecord$7(theme)) return;
|
|
13386
13445
|
const path = `/themes/${index}`;
|
|
13387
13446
|
if (typeof theme.key === "string") {
|
|
13388
13447
|
if (!THEME_KEY_PATTERN.test(theme.key)) problems.push({
|
|
@@ -13405,7 +13464,7 @@ const findThemeProblems = (themes) => {
|
|
|
13405
13464
|
});
|
|
13406
13465
|
for (const variant of THEME_VARIANTS) {
|
|
13407
13466
|
const tokens = theme[variant];
|
|
13408
|
-
for (const [token, value] of Object.entries(isRecord$
|
|
13467
|
+
for (const [token, value] of Object.entries(isRecord$7(tokens) ? tokens : {})) if (typeof value === "string" && !THEME_COLOUR_PATTERN.test(value)) problems.push({
|
|
13409
13468
|
path: `${path}/${variant}/${token}`,
|
|
13410
13469
|
message: `"${value}" is not a colour: use #rrggbb, rgb(), hsl(), oklch() or oklab()`
|
|
13411
13470
|
});
|
|
@@ -13415,7 +13474,7 @@ const findThemeProblems = (themes) => {
|
|
|
13415
13474
|
};
|
|
13416
13475
|
/** Every problem with a loaded config export, or none. */
|
|
13417
13476
|
const findConfigProblems$1 = (value) => {
|
|
13418
|
-
if (!isRecord$
|
|
13477
|
+
if (!isRecord$7(value)) return [{
|
|
13419
13478
|
path: "",
|
|
13420
13479
|
message: "the config must be an object (export const config = defineConfig({ ... }))"
|
|
13421
13480
|
}];
|
|
@@ -15441,7 +15500,7 @@ const resolveMediaOrigins = async (storage) => {
|
|
|
15441
15500
|
const base = originOf(storage.publicBaseUrl);
|
|
15442
15501
|
if (base) origins.add(base);
|
|
15443
15502
|
if (storage.s3) {
|
|
15444
|
-
const { createS3Adapter } = await import("./s3Adapter-
|
|
15503
|
+
const { createS3Adapter } = await import("./s3Adapter-sL1zP4Zl.js");
|
|
15445
15504
|
const adapter = createS3Adapter({
|
|
15446
15505
|
config: storage.s3,
|
|
15447
15506
|
publicBaseUrl: void 0
|
|
@@ -20238,7 +20297,7 @@ const entryNode = (entry, scope) => ({
|
|
|
20238
20297
|
//#region src/schema/codegen/graphql/outputTypes.ts
|
|
20239
20298
|
const list$9 = (type) => new GraphQLList(new GraphQLNonNull(type));
|
|
20240
20299
|
const maskedFieldError = (field) => new AppError(403, "FORBIDDEN_FIELD", `Your role may not read "${field.apiKey}"`, { field: field.apiKey });
|
|
20241
|
-
const isRecord$
|
|
20300
|
+
const isRecord$6 = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
|
|
20242
20301
|
const enumType = (build, owner, field) => memoType(build.enums, `${owner.id}:${field.id}`, () => new GraphQLEnumType({
|
|
20243
20302
|
name: fieldTypeName(owner, field, "Enum"),
|
|
20244
20303
|
values: Object.fromEntries(field.settings.values.map((entry) => [entry.value, {
|
|
@@ -20280,7 +20339,7 @@ const componentField = (build, field) => {
|
|
|
20280
20339
|
const component = componentById$2(build, field.settings.component);
|
|
20281
20340
|
if (!component || liveFields$1(component.fields).length === 0) return;
|
|
20282
20341
|
const type = componentType(build, component);
|
|
20283
|
-
const toNode = (value, node) => isRecord$
|
|
20342
|
+
const toNode = (value, node) => isRecord$6(value) ? {
|
|
20284
20343
|
data: value,
|
|
20285
20344
|
scope: node.scope
|
|
20286
20345
|
} : null;
|
|
@@ -20318,7 +20377,7 @@ const zoneField = (build, owner, field) => {
|
|
|
20318
20377
|
type: list$9(type),
|
|
20319
20378
|
resolve: (node) => {
|
|
20320
20379
|
const values = node.data[field.apiKey];
|
|
20321
|
-
return (Array.isArray(values) ? values : []).flatMap((value) => isRecord$
|
|
20380
|
+
return (Array.isArray(values) ? values : []).flatMap((value) => isRecord$6(value) && allowed.has(String(value["__component"])) ? [{
|
|
20322
20381
|
data: value,
|
|
20323
20382
|
scope: node.scope
|
|
20324
20383
|
}] : []);
|
|
@@ -20492,21 +20551,21 @@ const zoneInput = (build, owner, field) => inputObject(build, `zone:${owner.id}:
|
|
|
20492
20551
|
return fields;
|
|
20493
20552
|
});
|
|
20494
20553
|
const modelInput = (build, model) => inputObject(build, `model:${model.id}`, modelTypeName(model, "Input"), () => inputFields(build, model));
|
|
20495
|
-
const isRecord$
|
|
20554
|
+
const isRecord$5 = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
|
|
20496
20555
|
const invalidZoneItem = (field) => new AppError(400, "INVALID_INPUT", `Each "${field.apiKey}" item needs exactly one component key`, { field: field.apiKey });
|
|
20497
20556
|
const toWriteValue = (build, field, value) => {
|
|
20498
20557
|
if (value === null || value === void 0) return value;
|
|
20499
20558
|
switch (field.type) {
|
|
20500
20559
|
case "component": {
|
|
20501
20560
|
const component = componentById$1(build, field.settings.component);
|
|
20502
|
-
const convert = (item) => component && isRecord$
|
|
20561
|
+
const convert = (item) => component && isRecord$5(item) ? toWriteData(build, component, item) : item;
|
|
20503
20562
|
return Array.isArray(value) ? value.map(convert) : convert(value);
|
|
20504
20563
|
}
|
|
20505
20564
|
case "dynamiczone": return (Array.isArray(value) ? value : []).map((item) => {
|
|
20506
|
-
const keys = isRecord$
|
|
20565
|
+
const keys = isRecord$5(item) ? Object.keys(item).filter((key) => item[key] != null) : [];
|
|
20507
20566
|
const [key] = keys;
|
|
20508
20567
|
const component = key ? build.snapshot.componentsByApiKey.get(key)?.definition : void 0;
|
|
20509
|
-
if (keys.length !== 1 || !key || !component || !isRecord$
|
|
20568
|
+
if (keys.length !== 1 || !key || !component || !isRecord$5(item) || !isComponentDefinition(component)) throw invalidZoneItem(field);
|
|
20510
20569
|
return {
|
|
20511
20570
|
[COMPONENT_KEY]: key,
|
|
20512
20571
|
...toWriteData(build, component, item[key])
|
|
@@ -20810,14 +20869,14 @@ const createSortInput = (model, fixed) => new GraphQLInputObjectType({
|
|
|
20810
20869
|
}
|
|
20811
20870
|
});
|
|
20812
20871
|
const OPERATOR_BY_NAME = new Map(FILTER_OPERATORS.map((operator) => [operatorFieldName(operator), operator]));
|
|
20813
|
-
const isRecord$
|
|
20872
|
+
const isRecord$4 = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
|
|
20814
20873
|
const toText = (value, label) => {
|
|
20815
20874
|
if (typeof value === "string") return value;
|
|
20816
20875
|
if (typeof value === "number" || typeof value === "boolean") return String(value);
|
|
20817
20876
|
throw queryInvalid(`"${label}" needs a scalar value`);
|
|
20818
20877
|
};
|
|
20819
20878
|
const conditionParams = (prefix, key, conditions, out) => {
|
|
20820
|
-
if (!isRecord$
|
|
20879
|
+
if (!isRecord$4(conditions)) return;
|
|
20821
20880
|
for (const [name, operand] of Object.entries(conditions)) {
|
|
20822
20881
|
const operator = OPERATOR_BY_NAME.get(name);
|
|
20823
20882
|
if (operator === void 0 || operand === null || operand === void 0) continue;
|
|
@@ -20832,11 +20891,11 @@ const filterParamsAt = (prefix, filter, out) => {
|
|
|
20832
20891
|
for (const [key, value] of Object.entries(filter)) {
|
|
20833
20892
|
if (value === null || value === void 0) continue;
|
|
20834
20893
|
if (key === "and" || key === "or") {
|
|
20835
|
-
const children = value.filter(isRecord$
|
|
20894
|
+
const children = value.filter(isRecord$4);
|
|
20836
20895
|
if (children.length === 0) throw queryInvalid(`${key} needs at least one filter`);
|
|
20837
20896
|
children.forEach((child, index) => filterParamsAt(`${prefix}[${LOGICAL_KEYS[key]}][${index}]`, child, out));
|
|
20838
20897
|
} else if (key === "not") {
|
|
20839
|
-
if (isRecord$
|
|
20898
|
+
if (isRecord$4(value)) filterParamsAt(`${prefix}[$not]`, value, out);
|
|
20840
20899
|
} else conditionParams(prefix, key, value, out);
|
|
20841
20900
|
}
|
|
20842
20901
|
};
|
|
@@ -21808,7 +21867,7 @@ const createMediaStorage = async (config, deps) => {
|
|
|
21808
21867
|
publicBaseUrl: config.publicBaseUrl
|
|
21809
21868
|
}));
|
|
21810
21869
|
if (config.s3) {
|
|
21811
|
-
const { createS3Adapter } = await import("./s3Adapter-
|
|
21870
|
+
const { createS3Adapter } = await import("./s3Adapter-sL1zP4Zl.js");
|
|
21812
21871
|
adapters.set("s3", createS3Adapter({
|
|
21813
21872
|
config: config.s3,
|
|
21814
21873
|
publicBaseUrl: config.publicBaseUrl
|
|
@@ -21890,66 +21949,15 @@ const requestLogPlugin = fp(async (app) => {
|
|
|
21890
21949
|
});
|
|
21891
21950
|
}, { name: "shapio-request-log" });
|
|
21892
21951
|
//#endregion
|
|
21893
|
-
//#region src/plugins/security.ts
|
|
21894
|
-
const CORS_METHODS = [
|
|
21895
|
-
"GET",
|
|
21896
|
-
"HEAD",
|
|
21897
|
-
"POST",
|
|
21898
|
-
"PUT",
|
|
21899
|
-
"PATCH",
|
|
21900
|
-
"DELETE"
|
|
21901
|
-
];
|
|
21902
|
-
/**
|
|
21903
|
-
* Baseline HTTP hardening: security headers, CORS (off unless origins are configured; the admin and API
|
|
21904
|
-
* share one origin, so CORS is only for the user's own sites and apps), a global rate limit keyed by the
|
|
21905
|
-
* client IP (which honours TRUST_PROXY), and @fastify/sensible's httpErrors.
|
|
21906
|
-
* The rate-limit store is in memory, so with several instances each counts on its own (documented: put a
|
|
21907
|
-
* shared limiter in front for strict limits; ADR 0008).
|
|
21908
|
-
*/
|
|
21909
|
-
const securityPlugin = fp(async (app, { http, httpsPublicUrl, mediaOrigins = [] }) => {
|
|
21910
|
-
await app.register(sensible);
|
|
21911
|
-
await app.register(helmet, {
|
|
21912
|
-
global: true,
|
|
21913
|
-
hsts: httpsPublicUrl,
|
|
21914
|
-
contentSecurityPolicy: { directives: {
|
|
21915
|
-
upgradeInsecureRequests: httpsPublicUrl ? [] : null,
|
|
21916
|
-
imgSrc: [
|
|
21917
|
-
"'self'",
|
|
21918
|
-
"data:",
|
|
21919
|
-
"blob:",
|
|
21920
|
-
...mediaOrigins
|
|
21921
|
-
],
|
|
21922
|
-
mediaSrc: [
|
|
21923
|
-
"'self'",
|
|
21924
|
-
"blob:",
|
|
21925
|
-
...mediaOrigins
|
|
21926
|
-
],
|
|
21927
|
-
connectSrc: ["'self'", ...mediaOrigins]
|
|
21928
|
-
} }
|
|
21929
|
-
});
|
|
21930
|
-
await app.register(cors, {
|
|
21931
|
-
origin: http.corsOrigins.length > 0 ? http.corsOrigins : false,
|
|
21932
|
-
credentials: false,
|
|
21933
|
-
methods: CORS_METHODS
|
|
21934
|
-
});
|
|
21935
|
-
await app.register(rateLimit, {
|
|
21936
|
-
global: true,
|
|
21937
|
-
max: http.rateLimitMax,
|
|
21938
|
-
timeWindow: http.rateLimitWindowMs
|
|
21939
|
-
});
|
|
21940
|
-
}, { name: "shapio-security" });
|
|
21941
|
-
//#endregion
|
|
21942
|
-
//#region src/plugins/services.ts
|
|
21943
|
-
/** Exposes config, the database, the permission evaluator and the URL builder to plugins and routes. */
|
|
21944
|
-
const servicesPlugin = fp(async (app, { config, db, permissions, urls }) => {
|
|
21945
|
-
app.decorate("config", config);
|
|
21946
|
-
app.decorate("urls", urls);
|
|
21947
|
-
app.decorate("db", db);
|
|
21948
|
-
app.decorate("permissions", permissions);
|
|
21949
|
-
}, { name: "shapio-services" });
|
|
21950
|
-
//#endregion
|
|
21951
21952
|
//#region src/plugins/staticAdmin.ts
|
|
21952
21953
|
const ADMIN_PATH = "/admin/";
|
|
21954
|
+
/** Where the admin is served: `${BASE_PATH}/admin/`. */
|
|
21955
|
+
const adminPrefixFor = (urls) => urls.withBasePath(ADMIN_PATH);
|
|
21956
|
+
/**
|
|
21957
|
+
* A request for one of the admin's own files (`assets/*.js`, fonts, favicons, `theme-init.js`), not the page
|
|
21958
|
+
* itself: public, cacheable and loaded many at a time on every reload, so the global rate limit skips them.
|
|
21959
|
+
*/
|
|
21960
|
+
const isAdminFileRequest = (url, adminPrefix) => url.startsWith(adminPrefix) && looksLikeFile(url);
|
|
21953
21961
|
/**
|
|
21954
21962
|
* Injects `<base href>` so the admin, built with relative asset URLs (Vite `base: './'`), works under
|
|
21955
21963
|
* any BASE_PATH without a rebuild. The SPA router reads its basename from `document.baseURI`.
|
|
@@ -21994,7 +22002,7 @@ const staticAdminPlugin = fp(async (app, { distPath, urls, frameSources }) => {
|
|
|
21994
22002
|
app.log.info("admin bundle not found; the admin UI is not served (run the Vite dev server instead)");
|
|
21995
22003
|
return;
|
|
21996
22004
|
}
|
|
21997
|
-
const adminPrefix = urls
|
|
22005
|
+
const adminPrefix = adminPrefixFor(urls);
|
|
21998
22006
|
const indexHtml = injectBaseHref(readFileSync(indexFile, "utf8"), adminPrefix);
|
|
21999
22007
|
const scriptHashes = importMapHashes(indexHtml);
|
|
22000
22008
|
const sendIndex = async (_request, reply) => {
|
|
@@ -22024,6 +22032,65 @@ const staticAdminPlugin = fp(async (app, { distPath, urls, frameSources }) => {
|
|
|
22024
22032
|
if (urls.basePath !== "") app.get(urls.basePath, async (_request, reply) => reply.redirect(adminPrefix, 302));
|
|
22025
22033
|
}, { name: "shapio-static-admin" });
|
|
22026
22034
|
//#endregion
|
|
22035
|
+
//#region src/plugins/security.ts
|
|
22036
|
+
const CORS_METHODS = [
|
|
22037
|
+
"GET",
|
|
22038
|
+
"HEAD",
|
|
22039
|
+
"POST",
|
|
22040
|
+
"PUT",
|
|
22041
|
+
"PATCH",
|
|
22042
|
+
"DELETE"
|
|
22043
|
+
];
|
|
22044
|
+
/**
|
|
22045
|
+
* Baseline HTTP hardening: security headers, CORS (off unless origins are configured; the admin and API
|
|
22046
|
+
* share one origin, so CORS is only for the user's own sites and apps), a global rate limit keyed by the
|
|
22047
|
+
* client IP (which honours TRUST_PROXY), and @fastify/sensible's httpErrors.
|
|
22048
|
+
* The rate-limit store is in memory, so with several instances each counts on its own (documented: put a
|
|
22049
|
+
* shared limiter in front for strict limits; ADR 0008).
|
|
22050
|
+
*/
|
|
22051
|
+
const securityPlugin = fp(async (app, { http, httpsPublicUrl, mediaOrigins = [], adminPrefix }) => {
|
|
22052
|
+
await app.register(sensible);
|
|
22053
|
+
await app.register(helmet, {
|
|
22054
|
+
global: true,
|
|
22055
|
+
hsts: httpsPublicUrl,
|
|
22056
|
+
contentSecurityPolicy: { directives: {
|
|
22057
|
+
upgradeInsecureRequests: httpsPublicUrl ? [] : null,
|
|
22058
|
+
imgSrc: [
|
|
22059
|
+
"'self'",
|
|
22060
|
+
"data:",
|
|
22061
|
+
"blob:",
|
|
22062
|
+
...mediaOrigins
|
|
22063
|
+
],
|
|
22064
|
+
mediaSrc: [
|
|
22065
|
+
"'self'",
|
|
22066
|
+
"blob:",
|
|
22067
|
+
...mediaOrigins
|
|
22068
|
+
],
|
|
22069
|
+
connectSrc: ["'self'", ...mediaOrigins]
|
|
22070
|
+
} }
|
|
22071
|
+
});
|
|
22072
|
+
await app.register(cors, {
|
|
22073
|
+
origin: http.corsOrigins.length > 0 ? http.corsOrigins : false,
|
|
22074
|
+
credentials: false,
|
|
22075
|
+
methods: CORS_METHODS
|
|
22076
|
+
});
|
|
22077
|
+
await app.register(rateLimit, {
|
|
22078
|
+
global: true,
|
|
22079
|
+
max: http.rateLimitMax,
|
|
22080
|
+
timeWindow: http.rateLimitWindowMs,
|
|
22081
|
+
allowList: (request) => isAdminFileRequest(request.url, adminPrefix)
|
|
22082
|
+
});
|
|
22083
|
+
}, { name: "shapio-security" });
|
|
22084
|
+
//#endregion
|
|
22085
|
+
//#region src/plugins/services.ts
|
|
22086
|
+
/** Exposes config, the database, the permission evaluator and the URL builder to plugins and routes. */
|
|
22087
|
+
const servicesPlugin = fp(async (app, { config, db, permissions, urls }) => {
|
|
22088
|
+
app.decorate("config", config);
|
|
22089
|
+
app.decorate("urls", urls);
|
|
22090
|
+
app.decorate("db", db);
|
|
22091
|
+
app.decorate("permissions", permissions);
|
|
22092
|
+
}, { name: "shapio-services" });
|
|
22093
|
+
//#endregion
|
|
22027
22094
|
//#region src/plugins/themeCatalogue.ts
|
|
22028
22095
|
/** The catalogue is built from the project config by the app (extensions/themeStylesheet.ts). */
|
|
22029
22096
|
const themeCataloguePlugin = fp(async (app, { catalogue }) => {
|
|
@@ -24251,7 +24318,7 @@ const toDefinitionInput = (draft, id, resolve) => {
|
|
|
24251
24318
|
};
|
|
24252
24319
|
};
|
|
24253
24320
|
/** IDs of new definitions a definition refers to (relations, components, zones). */
|
|
24254
|
-
const referencesOf = (definition) => definition.fields.flatMap((field) => {
|
|
24321
|
+
const referencesOf$1 = (definition) => definition.fields.flatMap((field) => {
|
|
24255
24322
|
switch (field.type) {
|
|
24256
24323
|
case "relation": return [field.settings.target];
|
|
24257
24324
|
case "component": return [field.settings.component];
|
|
@@ -24276,7 +24343,7 @@ const dependencyOrder = (definitions) => {
|
|
|
24276
24343
|
return;
|
|
24277
24344
|
}
|
|
24278
24345
|
state.set(definition.id, "visiting");
|
|
24279
|
-
for (const id of referencesOf(definition)) {
|
|
24346
|
+
for (const id of referencesOf$1(definition)) {
|
|
24280
24347
|
const target = byId.get(id);
|
|
24281
24348
|
if (target && target.id !== definition.id) visit(target, [...path, definition.apiKey]);
|
|
24282
24349
|
}
|
|
@@ -24400,22 +24467,22 @@ const summarizePrompt = (input) => ({
|
|
|
24400
24467
|
//#region src/services/assist/summarize.ts
|
|
24401
24468
|
const notSummarizable = (fieldApiKey, reason) => new AppError(400, "ASSIST_FIELD_NOT_SUMMARIZABLE", `"${fieldApiKey}" cannot be summarized into: ${reason}`, { field: fieldApiKey });
|
|
24402
24469
|
/**
|
|
24403
|
-
* The target must be a live string or text field (not the title) of a model
|
|
24404
|
-
*
|
|
24405
|
-
* that
|
|
24470
|
+
* The target must be a live string or text field (not the title) of a model with a rich-text body
|
|
24471
|
+
* (`richTextBodyOf`: the document's rich-text canvas fields, or every rich-text field of a form), wherever
|
|
24472
|
+
* the field is placed: the summary is made from that body (plan §I).
|
|
24406
24473
|
*/
|
|
24407
24474
|
const summaryTarget = (definition, fieldApiKey) => {
|
|
24408
|
-
const
|
|
24409
|
-
if (
|
|
24475
|
+
const title = effectiveTitleField(definition);
|
|
24476
|
+
if (title?.apiKey === fieldApiKey) throw notSummarizable(fieldApiKey, "it is the title");
|
|
24410
24477
|
const field = definition.fields.find((candidate) => candidate.apiKey === fieldApiKey && !candidate.deprecated);
|
|
24411
24478
|
if (!field) throw notSummarizable(fieldApiKey, "it is not a field of this model");
|
|
24412
24479
|
if (field.type !== "string" && field.type !== "text") throw notSummarizable(fieldApiKey, "only string and text fields hold summaries");
|
|
24413
|
-
const
|
|
24414
|
-
if (
|
|
24480
|
+
const body = richTextBodyOf(definition);
|
|
24481
|
+
if (body.length === 0) throw notSummarizable(fieldApiKey, "the model has no rich-text body to summarize");
|
|
24415
24482
|
return {
|
|
24416
24483
|
field,
|
|
24417
|
-
|
|
24418
|
-
title
|
|
24484
|
+
body,
|
|
24485
|
+
title
|
|
24419
24486
|
};
|
|
24420
24487
|
};
|
|
24421
24488
|
const plainTextOf = (value) => typeof value === "object" && value !== null && "doc" in value ? richTextToPlainText(value) : "";
|
|
@@ -24427,7 +24494,7 @@ const summarizeEntry = async (context, input) => {
|
|
|
24427
24494
|
if (!maskAllows(updatePolicy.writeMask, target.field)) throw new AppError(403, "FORBIDDEN", `Your role does not allow editing "${input.fieldApiKey}"`);
|
|
24428
24495
|
const locale = writeLocaleFor(context.snapshot, model.definition, input.locale);
|
|
24429
24496
|
const { draft } = await loadEntryDraft(context, model, readPolicy, input.entryId, locale);
|
|
24430
|
-
const body = target.
|
|
24497
|
+
const body = target.body.filter((field) => maskAllows(readPolicy.readMask, field)).map((field) => plainTextOf(draft.data[field.id])).filter((text) => text.trim() !== "").join("\n\n").slice(0, ASSIST_SUMMARY_SOURCE_CHARS);
|
|
24431
24498
|
if (body.trim() === "") throw new AppError(422, "ASSIST_NOTHING_TO_SUMMARIZE", "The entry has no body text to summarize yet");
|
|
24432
24499
|
const titleValue = target.title && maskAllows(readPolicy.readMask, target.title) ? draft.data[target.title.id] : void 0;
|
|
24433
24500
|
const { maxLength, minLength } = target.field.settings;
|
|
@@ -24495,7 +24562,7 @@ const TRANSLATABLE_SCALARS = /* @__PURE__ */ new Set(["string", "text"]);
|
|
|
24495
24562
|
const TEXT_BLOCKS = /* @__PURE__ */ new Set(["paragraph", "heading"]);
|
|
24496
24563
|
const TAG_PATTERN = /<m(\d+)>|<\/m(\d+)>|<b(\d+)\/>/g;
|
|
24497
24564
|
const MAX_IMAGE_TEXT = 1e3;
|
|
24498
|
-
const isRecord$
|
|
24565
|
+
const isRecord$3 = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
|
|
24499
24566
|
const hasText = (value) => value.trim() !== "";
|
|
24500
24567
|
/** A text block's inline children as one string with tags, and what each tag stands for. */
|
|
24501
24568
|
const encodeBlock = (children) => {
|
|
@@ -24618,7 +24685,7 @@ const walkRichNode = (node, path, state) => {
|
|
|
24618
24685
|
};
|
|
24619
24686
|
};
|
|
24620
24687
|
const componentById = (model, id) => typeof id === "string" ? model.components.get(id)?.definition : void 0;
|
|
24621
|
-
const walkComponentValue = (component, value, path, state) => component && isRecord$
|
|
24688
|
+
const walkComponentValue = (component, value, path, state) => component && isRecord$3(value) ? walkFields(component.fields.filter((field) => !field.deprecated), value, path, state) : value;
|
|
24622
24689
|
const walkValue = (field, value, path, state) => {
|
|
24623
24690
|
if (value === void 0 || value === null) return value;
|
|
24624
24691
|
if (TRANSLATABLE_SCALARS.has(field.type)) {
|
|
@@ -24631,7 +24698,7 @@ const walkValue = (field, value, path, state) => {
|
|
|
24631
24698
|
}) : value;
|
|
24632
24699
|
}
|
|
24633
24700
|
switch (field.type) {
|
|
24634
|
-
case "richtext": return isRecord$
|
|
24701
|
+
case "richtext": return isRecord$3(value) && isRecord$3(value.doc) ? {
|
|
24635
24702
|
...value,
|
|
24636
24703
|
doc: walkRichNode(value.doc, path, state)
|
|
24637
24704
|
} : value;
|
|
@@ -24640,7 +24707,7 @@ const walkValue = (field, value, path, state) => {
|
|
|
24640
24707
|
return field.settings.repeatable && Array.isArray(value) ? value.map((item, index) => walkComponentValue(component, item, pointer(path, index), state)) : walkComponentValue(component, value, path, state);
|
|
24641
24708
|
}
|
|
24642
24709
|
case "dynamiczone": return Array.isArray(value) ? value.map((item, index) => {
|
|
24643
|
-
const component = isRecord$
|
|
24710
|
+
const component = isRecord$3(item) ? componentById(state.model, item[COMPONENT_KEY]) : void 0;
|
|
24644
24711
|
return walkComponentValue(component, item, pointer(path, index), state);
|
|
24645
24712
|
}) : value;
|
|
24646
24713
|
default: return value;
|
|
@@ -28311,7 +28378,7 @@ const summarizeFindings$1 = async (context) => {
|
|
|
28311
28378
|
};
|
|
28312
28379
|
//#endregion
|
|
28313
28380
|
//#region src/content/health/imageUses.ts
|
|
28314
|
-
const isRecord$
|
|
28381
|
+
const isRecord$2 = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
|
|
28315
28382
|
const richTextImages = (node, found) => {
|
|
28316
28383
|
if (node.type === "image" && typeof node.attrs?.mediaId === "string") {
|
|
28317
28384
|
const alt = typeof node.attrs.alt === "string" && node.attrs.alt.trim() !== "" ? node.attrs.alt : null;
|
|
@@ -28334,14 +28401,14 @@ const collect = (model, fields, data, base, add) => {
|
|
|
28334
28401
|
break;
|
|
28335
28402
|
case "richtext": {
|
|
28336
28403
|
const found = [];
|
|
28337
|
-
if (isRecord$
|
|
28404
|
+
if (isRecord$2(value) && isRecord$2(value.doc)) richTextImages(value.doc, found);
|
|
28338
28405
|
found.forEach((image) => add(path, image.assetId, image.alt));
|
|
28339
28406
|
break;
|
|
28340
28407
|
}
|
|
28341
28408
|
case "component": {
|
|
28342
28409
|
const component = componentOf(model, field.settings.component);
|
|
28343
28410
|
(field.settings.repeatable && Array.isArray(value) ? value : [value]).forEach((item, index) => {
|
|
28344
|
-
if (component && isRecord$
|
|
28411
|
+
if (component && isRecord$2(item)) {
|
|
28345
28412
|
const itemPath = field.settings.repeatable ? pointer(path, index) : path;
|
|
28346
28413
|
collect(model, component.fields, item, itemPath, add);
|
|
28347
28414
|
}
|
|
@@ -28349,8 +28416,8 @@ const collect = (model, fields, data, base, add) => {
|
|
|
28349
28416
|
break;
|
|
28350
28417
|
}
|
|
28351
28418
|
case "dynamiczone": (Array.isArray(value) ? value : []).forEach((item, index) => {
|
|
28352
|
-
const component = isRecord$
|
|
28353
|
-
if (component && isRecord$
|
|
28419
|
+
const component = isRecord$2(item) ? componentOf(model, item[COMPONENT_KEY]) : void 0;
|
|
28420
|
+
if (component && isRecord$2(item)) collect(model, component.fields, item, pointer(path, index), add);
|
|
28354
28421
|
});
|
|
28355
28422
|
}
|
|
28356
28423
|
}
|
|
@@ -32123,6 +32190,146 @@ const deleteSchemaDraft = async (context, id, definitionId) => {
|
|
|
32123
32190
|
});
|
|
32124
32191
|
return getChangeSet$1(context, id);
|
|
32125
32192
|
};
|
|
32193
|
+
const CODE_LANGUAGE_LABELS = {
|
|
32194
|
+
plain: "Plain text",
|
|
32195
|
+
html: "HTML",
|
|
32196
|
+
css: "CSS",
|
|
32197
|
+
javascript: "JavaScript",
|
|
32198
|
+
json: "JSON",
|
|
32199
|
+
yaml: "YAML",
|
|
32200
|
+
markdown: "Markdown"
|
|
32201
|
+
};
|
|
32202
|
+
/** Item summaries use the same textual types as the admin's collapsed items (fields/helpers/summary.ts). */
|
|
32203
|
+
const TEXTUAL_TYPES = /* @__PURE__ */ new Set([
|
|
32204
|
+
"string",
|
|
32205
|
+
"text",
|
|
32206
|
+
"slug",
|
|
32207
|
+
"email",
|
|
32208
|
+
"url",
|
|
32209
|
+
"uid",
|
|
32210
|
+
"enum"
|
|
32211
|
+
]);
|
|
32212
|
+
const truncate = (text) => text.length > 160 ? `${text.slice(0, 159)}…` : text;
|
|
32213
|
+
const isRecord$1 = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
|
|
32214
|
+
const isEmpty = (value) => value === null || value === void 0 || value === "" || Array.isArray(value) && value.length === 0 || isRecord$1(value) && Object.keys(value).length === 0;
|
|
32215
|
+
const listOf = (value) => Array.isArray(value) ? value : [value];
|
|
32216
|
+
const plural = (count, one, many) => `${count} ${count === 1 ? one : many}`;
|
|
32217
|
+
const rawText = (value) => truncate(typeof value === "string" ? value : JSON.stringify(value));
|
|
32218
|
+
/** A component item's label: its title field's value, else the first non-empty text field (as the admin). */
|
|
32219
|
+
const summarizeItem = (component, item, lookups) => {
|
|
32220
|
+
if (!isRecord$1(item)) return "";
|
|
32221
|
+
const titleField = component.fields.find((field) => field.id === component.display.titleFieldId);
|
|
32222
|
+
const candidates = titleField ? [titleField, ...component.fields] : component.fields;
|
|
32223
|
+
for (const field of candidates) if (TEXTUAL_TYPES.has(field.type) || field.type === "richtext") {
|
|
32224
|
+
const summary = summarizeValue(field, item[field.id], lookups);
|
|
32225
|
+
if (summary) return summary;
|
|
32226
|
+
}
|
|
32227
|
+
return "";
|
|
32228
|
+
};
|
|
32229
|
+
const labelled = (label, summary) => summary ? `${label} (${summary})` : label;
|
|
32230
|
+
const componentSummary = (field, value, lookups) => {
|
|
32231
|
+
const component = lookups.component(field.settings.component);
|
|
32232
|
+
const items = listOf(value);
|
|
32233
|
+
if (!component || !items.every(isRecord$1)) return;
|
|
32234
|
+
const summaries = items.map((item) => summarizeItem(component, item, lookups)).filter(Boolean);
|
|
32235
|
+
if (!field.settings.repeatable) return summaries[0] ? `${component.label}: ${summaries[0]}` : component.label;
|
|
32236
|
+
const head = `${plural(items.length, "item", "items")} (${component.label})`;
|
|
32237
|
+
return summaries.length > 0 ? `${head}: ${summaries.join(", ")}` : head;
|
|
32238
|
+
};
|
|
32239
|
+
const zoneSummary = (value, lookups) => {
|
|
32240
|
+
if (!Array.isArray(value) || !value.every(isRecord$1)) return;
|
|
32241
|
+
const blocks = value.map((item) => {
|
|
32242
|
+
const id = item[COMPONENT_KEY];
|
|
32243
|
+
const component = typeof id === "string" ? lookups.component(id) : void 0;
|
|
32244
|
+
return component ? labelled(component.label, summarizeItem(component, item, lookups)) : String(id);
|
|
32245
|
+
});
|
|
32246
|
+
return `${plural(value.length, "block", "blocks")}: ${blocks.join(", ")}`;
|
|
32247
|
+
};
|
|
32248
|
+
const referenceSummary = (value, resolve) => {
|
|
32249
|
+
const ids = listOf(value);
|
|
32250
|
+
return ids.every((id) => typeof id === "string") ? ids.map((id) => resolve(id) ?? id).join(", ") : void 0;
|
|
32251
|
+
};
|
|
32252
|
+
const structuredSummary = (field, value, lookups) => {
|
|
32253
|
+
switch (field.type) {
|
|
32254
|
+
case "richtext": return isRecord$1(value) ? richTextPlainText(value) || void 0 : void 0;
|
|
32255
|
+
case "media": return referenceSummary(value, lookups.mediaName);
|
|
32256
|
+
case "relation": return referenceSummary(value, lookups.entryTitle);
|
|
32257
|
+
case "component": return componentSummary(field, value, lookups);
|
|
32258
|
+
case "dynamiczone": return zoneSummary(value, lookups);
|
|
32259
|
+
case "code": return typeof value === "string" ? `${CODE_LANGUAGE_LABELS[field.settings.language] ?? field.settings.language}, ${plural(value.split("\n").length, "line", "lines")}` : void 0;
|
|
32260
|
+
case "json": return JSON.stringify(value);
|
|
32261
|
+
case "enum": {
|
|
32262
|
+
const values = listOf(value);
|
|
32263
|
+
return values.every((item) => typeof item === "string") ? values.map((item) => field.settings.values.find((option) => option.value === item)?.label ?? item).join(", ") : void 0;
|
|
32264
|
+
}
|
|
32265
|
+
case "boolean": return typeof value === "boolean" ? value ? "Yes" : "No" : void 0;
|
|
32266
|
+
default: return typeof value === "string" || typeof value === "number" ? String(value) : void 0;
|
|
32267
|
+
}
|
|
32268
|
+
};
|
|
32269
|
+
/** The value as one line of at most MAX_SUMMARY characters; null when empty. */
|
|
32270
|
+
const summarizeValue = (field, value, lookups) => {
|
|
32271
|
+
if (isEmpty(value)) return null;
|
|
32272
|
+
const summary = structuredSummary(field, value, lookups);
|
|
32273
|
+
return summary === void 0 ? rawText(value) : truncate(summary);
|
|
32274
|
+
};
|
|
32275
|
+
/** Media and related entry IDs a value refers to directly (top-level media and relation fields). */
|
|
32276
|
+
const referencesOf = (field, value) => (field.type === "media" || field.type === "relation") && !isEmpty(value) ? listOf(value).filter((id) => isStableId(id)) : [];
|
|
32277
|
+
const componentLookup = (snapshots) => (id) => {
|
|
32278
|
+
for (const snapshot of snapshots) {
|
|
32279
|
+
const definition = snapshot.byId.get(id)?.definition;
|
|
32280
|
+
if (definition && isComponentDefinition(definition)) return definition;
|
|
32281
|
+
}
|
|
32282
|
+
};
|
|
32283
|
+
/** Original file names of the referenced assets on the site, when the reviewer may browse media. */
|
|
32284
|
+
const loadMediaNames = async (context, ids) => {
|
|
32285
|
+
if (ids.length === 0 || !await context.permissions.canPerform(context.actor, "media.read")) return /* @__PURE__ */ new Map();
|
|
32286
|
+
const rows = await findNamesOnSite(context.site.id, ids, context.db);
|
|
32287
|
+
return new Map(rows.map((row) => [row.id, row.original_filename]));
|
|
32288
|
+
};
|
|
32289
|
+
/** Target models whose entries' titles the reviewer may read (the model and its title field). */
|
|
32290
|
+
const readableTargets = async (context, snapshot, modelIds) => {
|
|
32291
|
+
const readable = [];
|
|
32292
|
+
for (const modelId of modelIds) {
|
|
32293
|
+
const definition = snapshot.byId.get(modelId)?.definition;
|
|
32294
|
+
const titleField = definition ? effectiveTitleField(definition) : void 0;
|
|
32295
|
+
if (!titleField) continue;
|
|
32296
|
+
const policy = await context.permissions.evaluate(context.actor, {
|
|
32297
|
+
action: "read",
|
|
32298
|
+
modelId
|
|
32299
|
+
});
|
|
32300
|
+
if (policy.allowed && maskAllows(policy.readMask, titleField)) readable.push(modelId);
|
|
32301
|
+
}
|
|
32302
|
+
return readable;
|
|
32303
|
+
};
|
|
32304
|
+
/**
|
|
32305
|
+
* Loads what the summaries refer to, in one query each: asset names (site-scoped, `media.read`) and the titles
|
|
32306
|
+
* of related entries (site-scoped, only for target models whose title field the reviewer may read). Returns
|
|
32307
|
+
* lookups for one locale (a related entry's title in the item's locale, else another).
|
|
32308
|
+
*/
|
|
32309
|
+
const loadSummaryLookups = async (context, snapshots, fields) => {
|
|
32310
|
+
const mediaIds = /* @__PURE__ */ new Set();
|
|
32311
|
+
const entryIds = /* @__PURE__ */ new Set();
|
|
32312
|
+
const targetModels = /* @__PURE__ */ new Set();
|
|
32313
|
+
for (const { field, values } of fields) {
|
|
32314
|
+
const ids = values.flatMap((value) => referencesOf(field, value));
|
|
32315
|
+
if (field.type === "media") ids.forEach((id) => mediaIds.add(id));
|
|
32316
|
+
else if (field.type === "relation" && ids.length > 0) {
|
|
32317
|
+
ids.forEach((id) => entryIds.add(id));
|
|
32318
|
+
targetModels.add(field.settings.target);
|
|
32319
|
+
}
|
|
32320
|
+
}
|
|
32321
|
+
const [snapshot] = snapshots;
|
|
32322
|
+
const [mediaNames, heads] = await Promise.all([loadMediaNames(context, [...mediaIds]), entryIds.size === 0 ? Promise.resolve([]) : readableTargets(context, snapshot, targetModels).then((models) => findForEntriesOnSite(context.site.id, models, [...entryIds], context.db))]);
|
|
32323
|
+
const component = componentLookup(snapshots);
|
|
32324
|
+
return (locale) => ({
|
|
32325
|
+
component,
|
|
32326
|
+
mediaName: (id) => mediaNames.get(id),
|
|
32327
|
+
entryTitle: (id) => {
|
|
32328
|
+
const own = heads.filter((head) => head.entry_id === id);
|
|
32329
|
+
return own[0] ? titleOf(snapshot, own[0].model_id, own, locale) ?? void 0 : void 0;
|
|
32330
|
+
}
|
|
32331
|
+
});
|
|
32332
|
+
};
|
|
32126
32333
|
//#endregion
|
|
32127
32334
|
//#region src/services/changeSetReview.ts
|
|
32128
32335
|
/** Entry content cannot use fields that only the set's drafts add (v1): they are written after shipping. */
|
|
@@ -32158,13 +32365,26 @@ const fieldDiff = (fields, before, after) => fields.flatMap((field) => {
|
|
|
32158
32365
|
const old = before?.[field.id] ?? null;
|
|
32159
32366
|
const next = after?.[field.id] ?? null;
|
|
32160
32367
|
return sameValue(old, next) ? [] : [{
|
|
32161
|
-
|
|
32162
|
-
apiKey: field.apiKey,
|
|
32163
|
-
label: field.label,
|
|
32368
|
+
field,
|
|
32164
32369
|
before: old,
|
|
32165
32370
|
after: next
|
|
32166
32371
|
}];
|
|
32167
32372
|
});
|
|
32373
|
+
const withSummaries = (entry, lookups) => ({
|
|
32374
|
+
...entry,
|
|
32375
|
+
fields: entry.fields.map(({ field, before, after }) => ({
|
|
32376
|
+
fieldId: field.id,
|
|
32377
|
+
apiKey: field.apiKey,
|
|
32378
|
+
label: field.label,
|
|
32379
|
+
type: field.type,
|
|
32380
|
+
before,
|
|
32381
|
+
after,
|
|
32382
|
+
summary: {
|
|
32383
|
+
before: summarizeValue(field, before, lookups),
|
|
32384
|
+
after: summarizeValue(field, after, lookups)
|
|
32385
|
+
}
|
|
32386
|
+
}))
|
|
32387
|
+
});
|
|
32168
32388
|
/** What an item publishes: its source revision (restore), the draft, or nothing (unpublish). */
|
|
32169
32389
|
const afterOf = async (review, item, draft) => {
|
|
32170
32390
|
if (item.action === "unpublish") return null;
|
|
@@ -32317,8 +32537,13 @@ const getChangeSetReview = async (context, id) => {
|
|
|
32317
32537
|
converted: convertedModelIds(plans),
|
|
32318
32538
|
heads: await findHeadsForEntries([...new Set(entryItems.map((item) => item.entry_id ?? ""))], context.db)
|
|
32319
32539
|
};
|
|
32320
|
-
const
|
|
32321
|
-
for (const item of entryItems)
|
|
32540
|
+
const raw = [];
|
|
32541
|
+
for (const item of entryItems) raw.push(await reviewEntry(review, item));
|
|
32542
|
+
const lookupsFor = await loadSummaryLookups(context, [review.proposed, context.snapshot], raw.flatMap((entry) => entry.fields.map(({ field, before, after }) => ({
|
|
32543
|
+
field,
|
|
32544
|
+
values: [before, after]
|
|
32545
|
+
}))));
|
|
32546
|
+
const entries = raw.map((entry) => withSummaries(entry, lookupsFor(entry.locale)));
|
|
32322
32547
|
const schema = await reviewSchema(context, id, plans, items);
|
|
32323
32548
|
const notices = [...plans.length > 0 && entryItems.length > 0 ? [NOTICE_NEW_FIELDS_AFTER_SHIP] : [], ...entryItems.some((item) => review.converted.has(item.model_id ?? "")) ? [NOTICE_CONVERTED_ON_SHIP] : []];
|
|
32324
32549
|
return {
|
|
@@ -35115,8 +35340,14 @@ const FieldDiffSchema = Type.Object({
|
|
|
35115
35340
|
fieldId: Type.String(),
|
|
35116
35341
|
apiKey: Type.String(),
|
|
35117
35342
|
label: Type.String(),
|
|
35343
|
+
type: Type.Enum(DATA_TYPES),
|
|
35118
35344
|
before: Type.Unknown(),
|
|
35119
|
-
after: Type.Unknown()
|
|
35345
|
+
after: Type.Unknown(),
|
|
35346
|
+
/** Readable one-line summaries of `before` and `after` (null when empty). */
|
|
35347
|
+
summary: Type.Object({
|
|
35348
|
+
before: NullableString,
|
|
35349
|
+
after: NullableString
|
|
35350
|
+
})
|
|
35120
35351
|
});
|
|
35121
35352
|
const ReviewIssueSchema = Type.Object({
|
|
35122
35353
|
path: Type.String(),
|
|
@@ -35500,9 +35731,28 @@ const toRunView = (row) => {
|
|
|
35500
35731
|
};
|
|
35501
35732
|
};
|
|
35502
35733
|
const connectionNotFound = (id) => new AppError(404, "CONNECTION_NOT_FOUND", `No deployment connection ${id}`, { id });
|
|
35734
|
+
const isSecretUnreadable = (error) => error instanceof AppError && error.code === "SECRET_UNREADABLE";
|
|
35735
|
+
/**
|
|
35736
|
+
* The connection's literal secrets, or none with `unreadable` when they cannot be decrypted: one connection
|
|
35737
|
+
* whose secrets were sealed under another key must not break the list, and is repaired by entering them again.
|
|
35738
|
+
*/
|
|
35739
|
+
const readStoredSecrets = (runtime, row) => {
|
|
35740
|
+
try {
|
|
35741
|
+
return {
|
|
35742
|
+
literal: runtime.secrets.decryptJson(row.secrets_encrypted),
|
|
35743
|
+
unreadable: false
|
|
35744
|
+
};
|
|
35745
|
+
} catch (error) {
|
|
35746
|
+
if (!isSecretUnreadable(error)) throw error;
|
|
35747
|
+
return {
|
|
35748
|
+
literal: {},
|
|
35749
|
+
unreadable: true
|
|
35750
|
+
};
|
|
35751
|
+
}
|
|
35752
|
+
};
|
|
35503
35753
|
const toConnectionView = (runtime, row, runs) => {
|
|
35504
35754
|
const provider = providerFor(row.provider);
|
|
35505
|
-
const stored = runtime
|
|
35755
|
+
const { literal: stored, unreadable } = readStoredSecrets(runtime, row);
|
|
35506
35756
|
const refs = envRefsOf(row.secret_env_refs);
|
|
35507
35757
|
return {
|
|
35508
35758
|
id: row.id,
|
|
@@ -35525,7 +35775,8 @@ const toConnectionView = (runtime, row, runs) => {
|
|
|
35525
35775
|
createdBy: row.created_by,
|
|
35526
35776
|
createdAt: row.created_at,
|
|
35527
35777
|
updatedAt: row.updated_at,
|
|
35528
|
-
version: row.version
|
|
35778
|
+
version: row.version,
|
|
35779
|
+
secretsUnreadable: unreadable
|
|
35529
35780
|
};
|
|
35530
35781
|
};
|
|
35531
35782
|
const viewsOf = async (runtime, rows) => {
|
|
@@ -35692,16 +35943,26 @@ const updateConnection$1 = async (runtime, context, id, input) => {
|
|
|
35692
35943
|
const current = await findConnection(runtime, context.site, id);
|
|
35693
35944
|
const provider = providerFor(current.provider);
|
|
35694
35945
|
const settings = input.settings ? validateSettings(provider, input.settings) : settingsOf$3(current);
|
|
35695
|
-
const
|
|
35696
|
-
|
|
35697
|
-
|
|
35946
|
+
const stored = readStoredSecrets(runtime, current);
|
|
35947
|
+
const secretsGiven = Object.values(input.secrets ?? {}).some((value) => value.trim() !== "");
|
|
35948
|
+
const regenerate = stored.unreadable && provider.secrets.some((spec) => spec.generated && input.secrets?.[spec.name]?.trim() === "");
|
|
35949
|
+
const keepSealed = stored.unreadable && !secretsGiven && !regenerate;
|
|
35950
|
+
const refs = envRefsOf(current.secret_env_refs);
|
|
35951
|
+
const merged = keepSealed ? {
|
|
35952
|
+
literal: {},
|
|
35953
|
+
refs,
|
|
35954
|
+
generated: {}
|
|
35955
|
+
} : mergeSecrets(provider, {
|
|
35956
|
+
literal: stored.literal,
|
|
35957
|
+
refs
|
|
35698
35958
|
}, input.secrets, runtime.config.secretEnvAllowlist);
|
|
35959
|
+
const { literal } = merged;
|
|
35699
35960
|
const allowPrivateNetwork = input.allowPrivateNetwork ?? current.allow_private_network;
|
|
35700
35961
|
await assertDestinations(runtime, provider, {
|
|
35701
35962
|
settings,
|
|
35702
35963
|
secrets: knownSecrets(runtime, {
|
|
35703
35964
|
literal,
|
|
35704
|
-
refs
|
|
35965
|
+
refs: merged.refs
|
|
35705
35966
|
})
|
|
35706
35967
|
}, allowPrivateNetwork);
|
|
35707
35968
|
const deliveryRoleId = input.deliveryRoleId !== void 0 ? await validateDeliveryRole(runtime, input.deliveryRoleId) : void 0;
|
|
@@ -35709,8 +35970,8 @@ const updateConnection$1 = async (runtime, context, id, input) => {
|
|
|
35709
35970
|
if (!await update$1(id, {
|
|
35710
35971
|
...input.name !== void 0 ? { name: input.name.trim() } : {},
|
|
35711
35972
|
settings: JSON.stringify(settings),
|
|
35712
|
-
secrets_encrypted: runtime.secrets.encryptJson(literal),
|
|
35713
|
-
secret_env_refs: JSON.stringify(refs),
|
|
35973
|
+
...keepSealed ? {} : { secrets_encrypted: runtime.secrets.encryptJson(literal) },
|
|
35974
|
+
secret_env_refs: JSON.stringify(merged.refs),
|
|
35714
35975
|
...deliveryRoleId !== void 0 ? { delivery_role_id: deliveryRoleId } : {},
|
|
35715
35976
|
...input.previewUrlTemplate !== void 0 ? { preview_url_template: validatePreviewTemplate(runtime, input.previewUrlTemplate) } : {},
|
|
35716
35977
|
...input.triggerPolicy !== void 0 ? { trigger_policy: validateTriggers(provider, input.triggerPolicy) } : {},
|
|
@@ -35727,11 +35988,16 @@ const updateConnection$1 = async (runtime, context, id, input) => {
|
|
|
35727
35988
|
},
|
|
35728
35989
|
metadata: {
|
|
35729
35990
|
changes: Object.keys(input).filter((key) => key !== "expectedVersion" && key !== "secrets"),
|
|
35730
|
-
secretsReplaced: Object.keys(input.secrets ?? {}).filter((key) => input.secrets?.[key])
|
|
35991
|
+
secretsReplaced: Object.keys(input.secrets ?? {}).filter((key) => input.secrets?.[key]),
|
|
35992
|
+
...Object.keys(merged.generated).length > 0 ? { secretsGenerated: Object.keys(merged.generated) } : {}
|
|
35731
35993
|
}
|
|
35732
35994
|
});
|
|
35733
35995
|
});
|
|
35734
|
-
|
|
35996
|
+
const connection = await getConnection$1(runtime, context.site, id);
|
|
35997
|
+
return Object.keys(merged.generated).length > 0 ? {
|
|
35998
|
+
...connection,
|
|
35999
|
+
generatedSecrets: merged.generated
|
|
36000
|
+
} : connection;
|
|
35735
36001
|
};
|
|
35736
36002
|
const deleteConnection$1 = async (runtime, context, id) => {
|
|
35737
36003
|
await runtime.db.transaction().execute(async (trx) => {
|
|
@@ -35901,7 +36167,14 @@ const ConnectionSchema$1 = Type.Object({
|
|
|
35901
36167
|
createdBy: Type.Union([UuidSchema, Type.Null()]),
|
|
35902
36168
|
createdAt: DateTimeSchema,
|
|
35903
36169
|
updatedAt: DateTimeSchema,
|
|
35904
|
-
version: Type.Integer()
|
|
36170
|
+
version: Type.Integer(),
|
|
36171
|
+
/** The stored secrets cannot be decrypted (SESSION_SECRET changed): enter them again. */
|
|
36172
|
+
secretsUnreadable: Type.Boolean()
|
|
36173
|
+
});
|
|
36174
|
+
/** An update may mint a replacement for an unreadable generated secret: shown once. */
|
|
36175
|
+
const UpdatedConnectionSchema = Type.Object({
|
|
36176
|
+
...ConnectionSchema$1.properties,
|
|
36177
|
+
generatedSecrets: Type.Optional(Type.Record(Type.String(), Type.String()))
|
|
35905
36178
|
});
|
|
35906
36179
|
const errors$7 = {
|
|
35907
36180
|
400: ErrorResponseSchema,
|
|
@@ -35958,7 +36231,7 @@ const updateConnectionSchema = {
|
|
|
35958
36231
|
expectedVersion: VersionSchema
|
|
35959
36232
|
}, { additionalProperties: false }),
|
|
35960
36233
|
response: {
|
|
35961
|
-
200:
|
|
36234
|
+
200: UpdatedConnectionSchema,
|
|
35962
36235
|
...errors$7
|
|
35963
36236
|
}
|
|
35964
36237
|
};
|
|
@@ -39228,7 +39501,7 @@ const openStoredBundle = (storage, stored) => storage.get(stored.driver).getStre
|
|
|
39228
39501
|
const removeStoredBundle = (storage, stored) => storage.get(stored.driver).delete(stored.key);
|
|
39229
39502
|
//#endregion
|
|
39230
39503
|
//#region src/constants/version.ts
|
|
39231
|
-
const SHAPIO_VERSION = "0.5.
|
|
39504
|
+
const SHAPIO_VERSION = "0.5.5";
|
|
39232
39505
|
//#endregion
|
|
39233
39506
|
//#region src/repositories/transferExport.ts
|
|
39234
39507
|
/**
|
|
@@ -47549,7 +47822,8 @@ const buildApp = async (config, deps) => {
|
|
|
47549
47822
|
await app.register(securityPlugin, {
|
|
47550
47823
|
http: config.http,
|
|
47551
47824
|
httpsPublicUrl: urls.publicUrl.startsWith("https:"),
|
|
47552
|
-
mediaOrigins: await resolveMediaOrigins(config.storage)
|
|
47825
|
+
mediaOrigins: await resolveMediaOrigins(config.storage),
|
|
47826
|
+
adminPrefix: adminPrefixFor(urls)
|
|
47553
47827
|
});
|
|
47554
47828
|
app.decorate("schemaLookup", schemaLookup);
|
|
47555
47829
|
app.decorate("signingSecret", deps.signingSecret ?? await resolveSigningSecret(deps.db, config.sessionSecret, app.log));
|
|
@@ -48591,12 +48865,58 @@ const pruneExtensionHookRuns = async (before, limit, trx = db) => deleted(await
|
|
|
48591
48865
|
const pruneResolvedHealthFindings = async (before, limit, trx = db) => deleted(await trx.deleteFrom("content_health_findings").where("id", "in", (eb) => eb.selectFrom("content_health_findings").select("id").where("resolved_at", "is not", null).where("resolved_at", "<", before).limit(limit)).executeTakeFirstOrThrow());
|
|
48592
48866
|
/** Presence rows of tabs that stopped sending heartbeats (reads ignore them already; this frees space). */
|
|
48593
48867
|
const pruneStalePresence = async (before, limit, trx = db) => deleted(await trx.deleteFrom("editor_presence").where("last_seen_at", "<", before).where("entry_id", "in", (eb) => eb.selectFrom("editor_presence").select("entry_id").where("last_seen_at", "<", before).limit(limit)).executeTakeFirstOrThrow());
|
|
48868
|
+
/**
|
|
48869
|
+
* Dead jobs of one type that finished before a cutoff, with their payload, in id order after `afterId`
|
|
48870
|
+
* (keyset paging). Read only: dead jobs stay for an operator.
|
|
48871
|
+
*/
|
|
48872
|
+
const listDeadJobs = (type, before, afterId, limit, trx = db) => trx.selectFrom("jobs").select(["id", "payload"]).where("type", "=", type).where("status", "=", "dead").where("finished_at", "<", before).$if(afterId !== null, (qb) => qb.where("id", ">", afterId)).orderBy("id").limit(limit).execute();
|
|
48873
|
+
//#endregion
|
|
48874
|
+
//#region src/content/transfer/deadBundles.ts
|
|
48875
|
+
const PAGE_SIZE = 500;
|
|
48876
|
+
/** The stored bundle a `transfer.import` payload names; undefined when the payload has none. */
|
|
48877
|
+
const bundleOf = (payload) => {
|
|
48878
|
+
const bundle = payload?.bundle;
|
|
48879
|
+
return typeof bundle?.driver === "string" && typeof bundle.key === "string" ? {
|
|
48880
|
+
driver: bundle.driver,
|
|
48881
|
+
key: bundle.key
|
|
48882
|
+
} : void 0;
|
|
48883
|
+
};
|
|
48884
|
+
/**
|
|
48885
|
+
* Removes the stored bundles of `transfer.import` jobs that died before `before`. A dead job keeps its bundle
|
|
48886
|
+
* for the retention period so an operator's retry can still run; after that the bundle only takes space. The
|
|
48887
|
+
* job rows stay. Deleting a missing object succeeds, so bundles already gone (an earlier sweep, a cleanup
|
|
48888
|
+
* phase) cost a no-op each. A bundle that cannot be removed is logged and left for the next day's sweep.
|
|
48889
|
+
*/
|
|
48890
|
+
const removeDeadImportBundles = async (db, storage, before, { signal, log }) => {
|
|
48891
|
+
let removed = 0;
|
|
48892
|
+
let afterId = null;
|
|
48893
|
+
for (;;) {
|
|
48894
|
+
const jobs = await listDeadJobs(TRANSFER_IMPORT_JOB, before, afterId, PAGE_SIZE, db);
|
|
48895
|
+
for (const job of jobs) {
|
|
48896
|
+
const bundle = bundleOf(job.payload);
|
|
48897
|
+
if (!bundle) continue;
|
|
48898
|
+
try {
|
|
48899
|
+
await removeStoredBundle(storage, bundle);
|
|
48900
|
+
removed += 1;
|
|
48901
|
+
} catch (error) {
|
|
48902
|
+
log.warn({
|
|
48903
|
+
err: describeError(error),
|
|
48904
|
+
jobId: job.id,
|
|
48905
|
+
key: bundle.key
|
|
48906
|
+
}, "could not remove the bundle of a dead import");
|
|
48907
|
+
}
|
|
48908
|
+
}
|
|
48909
|
+
afterId = jobs.at(-1)?.id ?? afterId;
|
|
48910
|
+
if (jobs.length < PAGE_SIZE || signal.aborted) return removed;
|
|
48911
|
+
}
|
|
48912
|
+
};
|
|
48594
48913
|
//#endregion
|
|
48595
48914
|
//#region src/jobs/retention.ts
|
|
48596
48915
|
/**
|
|
48597
48916
|
* `system.retention`: once a day, delete finished bookkeeping older than RETENTION_DAYS (succeeded jobs,
|
|
48598
48917
|
* dispatched outbox events, after-hook run records, resolved health findings) and stale presence rows; usage
|
|
48599
|
-
* counters and assist runs older than USAGE_RETENTION_DAYS. Dead jobs and undispatched events stay for an operator
|
|
48918
|
+
* counters and assist runs older than USAGE_RETENTION_DAYS. Dead jobs and undispatched events stay for an operator;
|
|
48919
|
+
* the stored bundles of imports that died before the cutoff are removed (with `storage`).
|
|
48600
48920
|
* One job per UTC day (idempotency key `system.retention:<date>`); each run schedules the next day's, and
|
|
48601
48921
|
* every worker start makes sure today's exists, so instances starting together still create one.
|
|
48602
48922
|
*/
|
|
@@ -48621,7 +48941,7 @@ const pruneAll = async (prune, db, before, signal) => {
|
|
|
48621
48941
|
if (removed < BATCH_SIZE || signal.aborted) return total;
|
|
48622
48942
|
}
|
|
48623
48943
|
};
|
|
48624
|
-
const createRetentionJobHandlers = (db, { days, usageDays = days, now = () => /* @__PURE__ */ new Date() }) => [[RETENTION_JOB, async (job) => {
|
|
48944
|
+
const createRetentionJobHandlers = (db, { days, usageDays = days, now = () => /* @__PURE__ */ new Date(), storage }) => [[RETENTION_JOB, async (job) => {
|
|
48625
48945
|
const at = now();
|
|
48626
48946
|
const before = /* @__PURE__ */ new Date(at.getTime() - days * DAY_MS);
|
|
48627
48947
|
const usageBefore = usageDayOf(/* @__PURE__ */ new Date(at.getTime() - (usageDays - 1) * DAY_MS));
|
|
@@ -48633,7 +48953,11 @@ const createRetentionJobHandlers = (db, { days, usageDays = days, now = () => /*
|
|
|
48633
48953
|
tokenReads: await pruneAll(pruneTokenReads, db, usageBefore, job.signal),
|
|
48634
48954
|
assistRuns: await pruneAll(pruneRuns, db, /* @__PURE__ */ new Date(at.getTime() - usageDays * DAY_MS), job.signal),
|
|
48635
48955
|
healthFindings: await pruneAll(pruneResolvedHealthFindings, db, before, job.signal),
|
|
48636
|
-
editorPresence: await pruneAll(pruneStalePresence, db, /* @__PURE__ */ new Date(at.getTime() - PRESENCE_RETENTION_MS), job.signal)
|
|
48956
|
+
editorPresence: await pruneAll(pruneStalePresence, db, /* @__PURE__ */ new Date(at.getTime() - PRESENCE_RETENTION_MS), job.signal),
|
|
48957
|
+
transferBundles: storage ? await removeDeadImportBundles(db, storage, before, {
|
|
48958
|
+
signal: job.signal,
|
|
48959
|
+
log: job.log
|
|
48960
|
+
}) : 0
|
|
48637
48961
|
};
|
|
48638
48962
|
const next = new Date(at.getTime() + DAY_MS);
|
|
48639
48963
|
await enqueueJob({
|
|
@@ -49716,7 +50040,8 @@ const createConfiguredWorker = async (config, db, logger, signingSecret, extensi
|
|
|
49716
50040
|
...extensions.jobHandlers,
|
|
49717
50041
|
...createRetentionJobHandlers(db, {
|
|
49718
50042
|
days: config.retention.days,
|
|
49719
|
-
usageDays: config.usage.retentionDays
|
|
50043
|
+
usageDays: config.usage.retentionDays,
|
|
50044
|
+
storage
|
|
49720
50045
|
}),
|
|
49721
50046
|
...createContentHealthJobHandlers({
|
|
49722
50047
|
db,
|
|
@@ -49870,6 +50195,6 @@ const startDedicatedWorker = async (config) => {
|
|
|
49870
50195
|
return worker;
|
|
49871
50196
|
};
|
|
49872
50197
|
//#endregion
|
|
49873
|
-
export {
|
|
50198
|
+
export { parseDefinition as $, buildEditorManifest as A, RESERVED_DEFINITION_API_KEYS as B, loopbackUrl as C, BEFORE_EVENTS as D, AFTER_EVENTS as E, lockById$5 as F, THEME_VARIANTS as G, RESERVED_TYPE_NAMES as H, update$8 as I, generatedNames as J, checkThemeContrast as K, STORAGE_DRIVERS$1 as L, isValidStorageKey as M, listForAssets as N, EXTENSION_JOB_PREFIX as O, listLiveByDriver as P, mergePulledLock as Q, describeError as R, createUrlBuilder as S, loadProjectConfig as T, SCHEMA_KIND_DIRECTORIES as U, RESERVED_FIELD_API_KEYS as V, SITES_DIRECTORY as W, lockCoversSite as X, hashDefinition as Y, lockEntriesForSite as Z, listAllSites as _, loadConfig as a, serializeLockFile as at, generateToken as b, bucketContentDisposition as c, upgradeLockFile as ct, migrateToLatest as d, RICHTEXT_FORMAT as dt, parseLockFile as et, SHAPIO_VERSION as f, SAFE_LINK_PATTERN as ft, createSite$1 as g, sqliteDriverOf as gt, ObjectNotFoundError as h, createDb as ht, assertDatabaseReachable as i, serializeDefinition as it, encodeKeyPath as j, EXTENSION_ROUTE_ROOT as k, contentDisposition as l, validateSchema as lt, InvalidStorageKeyError as m, validateRichText as mt, startServer as n, schemaFilePath as nt, loadEnvFileIfPresent as o, suggestPlural as ot, createMediaStorage as p, createStableId as pt, foldApiKey as q, copyObjectVerified as r, scopeDirectory as rt, buildApp as s, toTypeName as st, startDedicatedWorker as t, routeKeyOf as tt, getPendingMigrations as u, withSiteCovered as ut, createAdminDirect as v, SITE_KEY_PATTERN as w, createLogger as x, SYSTEM_CLI_ACTOR as y, LOCK_FILE_PATH as z };
|
|
49874
50199
|
|
|
49875
|
-
//# sourceMappingURL=worker-
|
|
50200
|
+
//# sourceMappingURL=worker-DMES6pqh.js.map
|