@shapio/cms 0.2.1 → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/admin/assets/{AssistError-hVUWpP3F.js → AssistError-BITJ_tpg.js} +2 -2
- package/dist/admin/assets/{AssistError-hVUWpP3F.js.map → AssistError-BITJ_tpg.js.map} +1 -1
- package/dist/admin/assets/{BlockMenuItems-B0g93m6M.js → BlockMenuItems-CcluK965.js} +2 -2
- package/dist/admin/assets/{BlockMenuItems-B0g93m6M.js.map → BlockMenuItems-CcluK965.js.map} +1 -1
- package/dist/admin/assets/Body-BXa9DhtH.js +2 -0
- package/dist/admin/assets/{Body-CFQKONK4.js.map → Body-BXa9DhtH.js.map} +1 -1
- package/dist/admin/assets/Builder-DcpRfXuc.js +2 -0
- package/dist/admin/assets/Builder-DcpRfXuc.js.map +1 -0
- package/dist/admin/assets/{ConfirmDialog-D6rs75TP.js → ConfirmDialog-B9nWhIIz.js} +2 -2
- package/dist/admin/assets/{ConfirmDialog-D6rs75TP.js.map → ConfirmDialog-B9nWhIIz.js.map} +1 -1
- package/dist/admin/assets/{CopyButton-Bc7crFDE.js → CopyButton-BoWb-xi1.js} +2 -2
- package/dist/admin/assets/{CopyButton-Bc7crFDE.js.map → CopyButton-BoWb-xi1.js.map} +1 -1
- package/dist/admin/assets/{CursorPager-BFPD_adV.js → CursorPager-BnxmTk47.js} +2 -2
- package/dist/admin/assets/{CursorPager-BFPD_adV.js.map → CursorPager-BnxmTk47.js.map} +1 -1
- package/dist/admin/assets/{ExternalLink-Cdfcyyed.js → ExternalLink-Eeb9mONJ.js} +2 -2
- package/dist/admin/assets/{ExternalLink-Cdfcyyed.js.map → ExternalLink-Eeb9mONJ.js.map} +1 -1
- package/dist/admin/assets/Form-DZRLD3vH.js +2 -0
- package/dist/admin/assets/Form-DZRLD3vH.js.map +1 -0
- package/dist/admin/assets/{FormCheckboxGroup-Bicl1CBP.js → FormCheckboxGroup-uIC2XQIL.js} +2 -2
- package/dist/admin/assets/{FormCheckboxGroup-Bicl1CBP.js.map → FormCheckboxGroup-uIC2XQIL.js.map} +1 -1
- package/dist/admin/assets/{FormRadioGroup-34iVSV4L.js → FormRadioGroup-hd95vPOu.js} +2 -2
- package/dist/admin/assets/{FormRadioGroup-34iVSV4L.js.map → FormRadioGroup-hd95vPOu.js.map} +1 -1
- package/dist/admin/assets/{FormSelectField-Ba4fIu-8.js → FormSelectField-D7VHmnx5.js} +2 -2
- package/dist/admin/assets/{FormSelectField-Ba4fIu-8.js.map → FormSelectField-D7VHmnx5.js.map} +1 -1
- package/dist/admin/assets/{FormSwitchField-DN6bfPC0.js → FormSwitchField-ft8Jbe6E.js} +2 -2
- package/dist/admin/assets/{FormSwitchField-DN6bfPC0.js.map → FormSwitchField-ft8Jbe6E.js.map} +1 -1
- package/dist/admin/assets/{FormTextareaField-WsNjLm32.js → FormTextareaField-DzyOzfZb.js} +2 -2
- package/dist/admin/assets/{FormTextareaField-WsNjLm32.js.map → FormTextareaField-DzyOzfZb.js.map} +1 -1
- package/dist/admin/assets/{HintedLabel-jKLM0ETt.js → HintedLabel-CvC46uy_.js} +2 -2
- package/dist/admin/assets/{HintedLabel-jKLM0ETt.js.map → HintedLabel-CvC46uy_.js.map} +1 -1
- package/dist/admin/assets/{InfoHint-DBqcrmZ3.js → InfoHint-GJLRVumb.js} +2 -2
- package/dist/admin/assets/{InfoHint-DBqcrmZ3.js.map → InfoHint-GJLRVumb.js.map} +1 -1
- package/dist/admin/assets/{InsertMenuItem-CRKXblK5.js → InsertMenuItem-D976G0Rj.js} +2 -2
- package/dist/admin/assets/{InsertMenuItem-CRKXblK5.js.map → InsertMenuItem-D976G0Rj.js.map} +1 -1
- package/dist/admin/assets/LinkTabs-BZSlA57U.js +2 -0
- package/dist/admin/assets/{LinkTabs-Bn2JVqOL.js.map → LinkTabs-BZSlA57U.js.map} +1 -1
- package/dist/admin/assets/Match-DdxTHHM4.js +2 -0
- package/dist/admin/assets/{Match-DaYgKrk7.js.map → Match-DdxTHHM4.js.map} +1 -1
- package/dist/admin/assets/{Panel-6wFe96Gr.js → Panel-iIKjEURi.js} +2 -2
- package/dist/admin/assets/{Panel-6wFe96Gr.js.map → Panel-iIKjEURi.js.map} +1 -1
- package/dist/admin/assets/{QueryView-DFZtm0fn.js → QueryView-D6aZQJRN.js} +2 -2
- package/dist/admin/assets/{QueryView-DFZtm0fn.js.map → QueryView-D6aZQJRN.js.map} +1 -1
- package/dist/admin/assets/{RadioTile-DsTyz7ml.js → RadioTile-BpB79rIK.js} +2 -2
- package/dist/admin/assets/{RadioTile-DsTyz7ml.js.map → RadioTile-BpB79rIK.js.map} +1 -1
- package/dist/admin/assets/{RichTextField-BGkH403g.js → RichTextField-BuHCONPu.js} +2 -2
- package/dist/admin/assets/{RichTextField-BGkH403g.js.map → RichTextField-BuHCONPu.js.map} +1 -1
- package/dist/admin/assets/{RowTitle-sFt6NjO4.js → RowTitle--uFCpx8n.js} +2 -2
- package/dist/admin/assets/{RowTitle-sFt6NjO4.js.map → RowTitle--uFCpx8n.js.map} +1 -1
- package/dist/admin/assets/{SecretReveal-Z6MOFdcL.js → SecretReveal-DFpzeNE0.js} +2 -2
- package/dist/admin/assets/{SecretReveal-Z6MOFdcL.js.map → SecretReveal-DFpzeNE0.js.map} +1 -1
- package/dist/admin/assets/SharedGlyph-Cqkx30tn.js +2 -0
- package/dist/admin/assets/SharedGlyph-Cqkx30tn.js.map +1 -0
- package/dist/admin/assets/{StepList-BTP_EMzx.js → StepList-BY5MuJPJ.js} +2 -2
- package/dist/admin/assets/{StepList-BTP_EMzx.js.map → StepList-BY5MuJPJ.js.map} +1 -1
- package/dist/admin/assets/Structure-CqRa2t7z.js +2 -0
- package/dist/admin/assets/{Structure-D5-hCUuF.js.map → Structure-CqRa2t7z.js.map} +1 -1
- package/dist/admin/assets/SubNavLink-B2o4kSZ9.js +2 -0
- package/dist/admin/assets/{SubNavLink-C5oN5mzB.js.map → SubNavLink-B2o4kSZ9.js.map} +1 -1
- package/dist/admin/assets/{SuggestAltButton-BuN35BBL.js → SuggestAltButton-4rf2xhEJ.js} +2 -2
- package/dist/admin/assets/{SuggestAltButton-BuN35BBL.js.map → SuggestAltButton-4rf2xhEJ.js.map} +1 -1
- package/dist/admin/assets/TextLink-D15oyXlc.js +2 -0
- package/dist/admin/assets/{TextLink-B4a6j3r6.js.map → TextLink-D15oyXlc.js.map} +1 -1
- package/dist/admin/assets/{Thumbnail-u8NE5NhQ.js → Thumbnail-CP5mfgNY.js} +2 -2
- package/dist/admin/assets/{Thumbnail-u8NE5NhQ.js.map → Thumbnail-CP5mfgNY.js.map} +1 -1
- package/dist/admin/assets/UnsavedChangesGuard-DgOASh0p.js +2 -0
- package/dist/admin/assets/{UnsavedChangesGuard-BYwMTDsE.js.map → UnsavedChangesGuard-DgOASh0p.js.map} +1 -1
- package/dist/admin/assets/{UserAvatar-D-yX0ozh.js → UserAvatar-BocvNVL-.js} +2 -2
- package/dist/admin/assets/{UserAvatar-D-yX0ozh.js.map → UserAvatar-BocvNVL-.js.map} +1 -1
- package/dist/admin/assets/{arrow-up-Ws7W9KsZ.js → arrow-up-gf_j6SVQ.js} +2 -2
- package/dist/admin/assets/{arrow-up-Ws7W9KsZ.js.map → arrow-up-gf_j6SVQ.js.map} +1 -1
- package/dist/admin/assets/auth-pcS9CCXu.js +2 -0
- package/dist/admin/assets/auth-pcS9CCXu.js.map +1 -0
- package/dist/admin/assets/badge-DD0mE96i.js +2 -0
- package/dist/admin/assets/{badge-CMox6-v3.js.map → badge-DD0mE96i.js.map} +1 -1
- package/dist/admin/assets/boxes-DcK-kaSa.js +2 -0
- package/dist/admin/assets/boxes-DcK-kaSa.js.map +1 -0
- package/dist/admin/assets/{calendar-clock-9W0Lkt89.js → calendar-clock-DEwACe0M.js} +2 -2
- package/dist/admin/assets/{calendar-clock-9W0Lkt89.js.map → calendar-clock-DEwACe0M.js.map} +1 -1
- package/dist/admin/assets/{changeSets-CO7JdILW.js → changeSets-BjUEfYbj.js} +2 -2
- package/dist/admin/assets/{changeSets-CO7JdILW.js.map → changeSets-BjUEfYbj.js.map} +1 -1
- package/dist/admin/assets/chevron-left-BsQYDUEC.js +2 -0
- package/dist/admin/assets/{chevron-left-DyqYjcMB.js.map → chevron-left-BsQYDUEC.js.map} +1 -1
- package/dist/admin/assets/{circle-check-aJ2DW5t4.js → circle-check-Dq1owihe.js} +2 -2
- package/dist/admin/assets/{circle-check-aJ2DW5t4.js.map → circle-check-Dq1owihe.js.map} +1 -1
- package/dist/admin/assets/{circle-x-BnRBht9z.js → circle-x-Dx6zIZko.js} +2 -2
- package/dist/admin/assets/{circle-x-BnRBht9z.js.map → circle-x-Dx6zIZko.js.map} +1 -1
- package/dist/admin/assets/{clock-DRtFQbTs.js → clock-DQvkffqQ.js} +2 -2
- package/dist/admin/assets/{clock-DRtFQbTs.js.map → clock-DQvkffqQ.js.map} +1 -1
- package/dist/admin/assets/cn-BQ3voEft.js +2 -0
- package/dist/admin/assets/cn-BQ3voEft.js.map +1 -0
- package/dist/admin/assets/coerce-OsqQRj19.js +2 -0
- package/dist/admin/assets/{coerce-COM3rk1i.js.map → coerce-OsqQRj19.js.map} +1 -1
- package/dist/admin/assets/constants-SrImR6C3.js +2 -0
- package/dist/admin/assets/constants-SrImR6C3.js.map +1 -0
- package/dist/admin/assets/content-_SLbbnfX.js +3 -0
- package/dist/admin/assets/content-_SLbbnfX.js.map +1 -0
- package/dist/admin/assets/{contentCounts-Ct0tYgHD.js → contentCounts-Ch3uMXVU.js} +2 -2
- package/dist/admin/assets/{contentCounts-Ct0tYgHD.js.map → contentCounts-Ch3uMXVU.js.map} +1 -1
- package/dist/admin/assets/contentTypes-BCOdUK_Z.js +2 -0
- package/dist/admin/assets/contentTypes-BCOdUK_Z.js.map +1 -0
- package/dist/admin/assets/{copy-B5B8RjV0.js → copy-BDc3r0fO.js} +2 -2
- package/dist/admin/assets/{copy-B5B8RjV0.js.map → copy-BDc3r0fO.js.map} +1 -1
- package/dist/admin/assets/{dateTimeLocal-BuBv3it2.js → dateTimeLocal-C92tyKwz.js} +2 -2
- package/dist/admin/assets/{dateTimeLocal-BuBv3it2.js.map → dateTimeLocal-C92tyKwz.js.map} +1 -1
- package/dist/admin/assets/develop-DS9TlDmv.js +11 -0
- package/dist/admin/assets/develop-DS9TlDmv.js.map +1 -0
- package/dist/admin/assets/{dropdown-menu-CW3fabv5.js → dropdown-menu-gmP2Rp3n.js} +2 -2
- package/dist/admin/assets/{dropdown-menu-CW3fabv5.js.map → dropdown-menu-gmP2Rp3n.js.map} +1 -1
- package/dist/admin/assets/{ellipsis-DNdmromA.js → ellipsis-NK0pWgqU.js} +2 -2
- package/dist/admin/assets/{ellipsis-DNdmromA.js.map → ellipsis-NK0pWgqU.js.map} +1 -1
- package/dist/admin/assets/{external-link-YnuWXDBk.js → external-link-D3Aoi2yX.js} +2 -2
- package/dist/admin/assets/{external-link-YnuWXDBk.js.map → external-link-D3Aoi2yX.js.map} +1 -1
- package/dist/admin/assets/{file-text-CB7Bc0GA.js → file-text-DxXAmmxL.js} +2 -2
- package/dist/admin/assets/{file-text-CB7Bc0GA.js.map → file-text-DxXAmmxL.js.map} +1 -1
- package/dist/admin/assets/fileRoute-C2tOrKhO.js +2 -0
- package/dist/admin/assets/{fileRoute-BYwireXG.js.map → fileRoute-C2tOrKhO.js.map} +1 -1
- package/dist/admin/assets/followPlural-CN6cQfNk.js +2 -0
- package/dist/admin/assets/followPlural-CN6cQfNk.js.map +1 -0
- package/dist/admin/assets/{globe-Bvs3UC3V.js → globe-CuElSilX.js} +2 -2
- package/dist/admin/assets/{globe-Bvs3UC3V.js.map → globe-CuElSilX.js.map} +1 -1
- package/dist/admin/assets/{image-CeoxwJeM.js → image-CsH8dZve.js} +2 -2
- package/dist/admin/assets/{image-CeoxwJeM.js.map → image-CsH8dZve.js.map} +1 -1
- package/dist/admin/assets/{image-off-iVqYw2Zc.js → image-off-B_uBCsYu.js} +2 -2
- package/dist/admin/assets/{image-off-iVqYw2Zc.js.map → image-off-B_uBCsYu.js.map} +1 -1
- package/dist/admin/assets/{inbox-DYbEOpaQ.js → inbox-3iAHL3pC.js} +2 -2
- package/dist/admin/assets/{inbox-DYbEOpaQ.js.map → inbox-3iAHL3pC.js.map} +1 -1
- package/dist/admin/assets/inbox-DsuXNaKE.js +2 -0
- package/dist/admin/assets/{inbox-wDoqym--.js.map → inbox-DsuXNaKE.js.map} +1 -1
- package/dist/admin/assets/index-BSzXA60W.js +4 -0
- package/dist/admin/assets/index-BSzXA60W.js.map +1 -0
- package/dist/admin/assets/{key-round-Bcw6qqcb.js → key-round-B17HiT3K.js} +2 -2
- package/dist/admin/assets/{key-round-Bcw6qqcb.js.map → key-round-B17HiT3K.js.map} +1 -1
- package/dist/admin/assets/link-2-off-hWGS8LW6.js +2 -0
- package/dist/admin/assets/link-2-off-hWGS8LW6.js.map +1 -0
- package/dist/admin/assets/{link-CKr_uUfb.js → link-bhHmG4Tc.js} +2 -2
- package/dist/admin/assets/{link-CKr_uUfb.js.map → link-bhHmG4Tc.js.map} +1 -1
- package/dist/admin/assets/{list-BElvKZw_.js → list-DRtRdjBC.js} +2 -2
- package/dist/admin/assets/{list-BElvKZw_.js.map → list-DRtRdjBC.js.map} +1 -1
- package/dist/admin/assets/{locales-Bnv3qcdZ.js → locales-BzPbz8FF.js} +2 -2
- package/dist/admin/assets/{locales-Bnv3qcdZ.js.map → locales-BzPbz8FF.js.map} +1 -1
- package/dist/admin/assets/media-WLnWaL7U.js +2 -0
- package/dist/admin/assets/{media-DjK3xGFN.js.map → media-WLnWaL7U.js.map} +1 -1
- package/dist/admin/assets/{media-BfDqe_2P.js → media-Xzot1ueY.js} +2 -2
- package/dist/admin/assets/{media-BfDqe_2P.js.map → media-Xzot1ueY.js.map} +1 -1
- package/dist/admin/assets/network-DHGqLwji.js +2 -0
- package/dist/admin/assets/network-DHGqLwji.js.map +1 -0
- package/dist/admin/assets/{pencil-Zd05MDs2.js → pencil-Bdp2z9D_.js} +2 -2
- package/dist/admin/assets/{pencil-Zd05MDs2.js.map → pencil-Bdp2z9D_.js.map} +1 -1
- package/dist/admin/assets/{plus-B0gd63Da.js → plus-BN_iSsnp.js} +2 -2
- package/dist/admin/assets/{plus-B0gd63Da.js.map → plus-BN_iSsnp.js.map} +1 -1
- package/dist/admin/assets/{preload-helper-CJKHb_rG.js → preload-helper-DAbCfXID.js} +2 -2
- package/dist/admin/assets/{preload-helper-CJKHb_rG.js.map → preload-helper-DAbCfXID.js.map} +1 -1
- package/dist/admin/assets/publishing-d9yhMwgA.js +2 -0
- package/dist/admin/assets/{publishing-vCVjaSGF.js.map → publishing-d9yhMwgA.js.map} +1 -1
- package/dist/admin/assets/{radio-group-DVR0mTpo.js → radio-group-DHIxK-IU.js} +2 -2
- package/dist/admin/assets/{radio-group-DVR0mTpo.js.map → radio-group-DHIxK-IU.js.map} +1 -1
- package/dist/admin/assets/{rotate-ccw-BOTDOdHf.js → rotate-ccw-CBoZle-b.js} +2 -2
- package/dist/admin/assets/{rotate-ccw-BOTDOdHf.js.map → rotate-ccw-CBoZle-b.js.map} +1 -1
- package/dist/admin/assets/{schedules-CG-ZphRK.js → schedules-Dy89Nm6P.js} +2 -2
- package/dist/admin/assets/{schedules-CG-ZphRK.js.map → schedules-Dy89Nm6P.js.map} +1 -1
- package/dist/admin/assets/schema-B4smPFcR.js +2 -0
- package/dist/admin/assets/schema-B4smPFcR.js.map +1 -0
- package/dist/admin/assets/{scroll-text-D-gHqYwR.js → scroll-text-UbyzpWh-.js} +2 -2
- package/dist/admin/assets/{scroll-text-D-gHqYwR.js.map → scroll-text-UbyzpWh-.js.map} +1 -1
- package/dist/admin/assets/{search-BcPL1qyc.js → search-_YlNpPvU.js} +2 -2
- package/dist/admin/assets/{search-BcPL1qyc.js.map → search-_YlNpPvU.js.map} +1 -1
- package/dist/admin/assets/searchSchema-CvOhn4FV.js +2 -0
- package/dist/admin/assets/{searchSchema-BGrRDBL_.js.map → searchSchema-CvOhn4FV.js.map} +1 -1
- package/dist/admin/assets/searchSchemas-BxRnxenn.js +2 -0
- package/dist/admin/assets/searchSchemas-BxRnxenn.js.map +1 -0
- package/dist/admin/assets/{sections-i9TeeK-h.js → sections-Bb3Q4bcY.js} +2 -2
- package/dist/admin/assets/{sections-i9TeeK-h.js.map → sections-Bb3Q4bcY.js.map} +1 -1
- package/dist/admin/assets/{sections-BrGcWOnw.js → sections-DiySZZHb.js} +2 -2
- package/dist/admin/assets/{sections-BrGcWOnw.js.map → sections-DiySZZHb.js.map} +1 -1
- package/dist/admin/assets/{select--nGB4WjU.js → select-tHVWX85X.js} +2 -2
- package/dist/admin/assets/{select--nGB4WjU.js.map → select-tHVWX85X.js.map} +1 -1
- package/dist/admin/assets/{send-Bu3RRfdI.js → send-BqECHYi6.js} +2 -2
- package/dist/admin/assets/{send-Bu3RRfdI.js.map → send-BqECHYi6.js.map} +1 -1
- package/dist/admin/assets/settings-D-v8gL8F.js +2 -0
- package/dist/admin/assets/settings-D-v8gL8F.js.map +1 -0
- package/dist/admin/assets/skeleton-C3QLIh7W.js +42 -0
- package/dist/admin/assets/skeleton-C3QLIh7W.js.map +1 -0
- package/dist/admin/assets/snapshots-BQrhsCmC.js +2 -0
- package/dist/admin/assets/{snapshots-CKjK-vkL.js.map → snapshots-BQrhsCmC.js.map} +1 -1
- package/dist/admin/assets/{sparkles-B_NX7PAY.js → sparkles-BW4CbD6W.js} +2 -2
- package/dist/admin/assets/{sparkles-B_NX7PAY.js.map → sparkles-BW4CbD6W.js.map} +1 -1
- package/dist/admin/assets/src-XaU0N8C-.js +4 -0
- package/dist/admin/assets/src-XaU0N8C-.js.map +1 -0
- package/dist/admin/assets/{stableId-Dmr2Afn_.js → stableId-C9Yq5iUw.js} +2 -2
- package/dist/admin/assets/{stableId-Dmr2Afn_.js.map → stableId-C9Yq5iUw.js.map} +1 -1
- package/dist/admin/assets/{store-B5xrQ1Ex.js → store-BphwUzV5.js} +2 -2
- package/dist/admin/assets/{store-B5xrQ1Ex.js.map → store-BphwUzV5.js.map} +1 -1
- package/dist/admin/assets/{switch-B-FbT-l8.js → switch-BVy02Vc8.js} +2 -2
- package/dist/admin/assets/{switch-B-FbT-l8.js.map → switch-BVy02Vc8.js.map} +1 -1
- package/dist/admin/assets/{table-DQzCPm7J.js → table-CZYtdoHn.js} +2 -2
- package/dist/admin/assets/{table-DQzCPm7J.js.map → table-CZYtdoHn.js.map} +1 -1
- package/dist/admin/assets/tabs-quHbeVxA.js +5 -0
- package/dist/admin/assets/{tabs-YThoOiE3.js.map → tabs-quHbeVxA.js.map} +1 -1
- package/dist/admin/assets/{textarea-_wcx8Mn1.js → textarea-B8Vl5gJ1.js} +2 -2
- package/dist/admin/assets/{textarea-_wcx8Mn1.js.map → textarea-B8Vl5gJ1.js.map} +1 -1
- package/dist/admin/assets/titles-B2z5ckxG.js +2 -0
- package/dist/admin/assets/{titles-DyCBLXue.js.map → titles-B2z5ckxG.js.map} +1 -1
- package/dist/admin/assets/{tokens-CqsxrApC.js → tokens-Fh_OeIlf.js} +2 -2
- package/dist/admin/assets/{tokens-CqsxrApC.js.map → tokens-Fh_OeIlf.js.map} +1 -1
- package/dist/admin/assets/{tooltip-BMe4HylJ.js → tooltip-DwqM3opE.js} +2 -2
- package/dist/admin/assets/{tooltip-BMe4HylJ.js.map → tooltip-DwqM3opE.js.map} +1 -1
- package/dist/admin/assets/{undo-2-DMOHOH6w.js → undo-2-D4Fz4JMZ.js} +2 -2
- package/dist/admin/assets/{undo-2-DMOHOH6w.js.map → undo-2-D4Fz4JMZ.js.map} +1 -1
- package/dist/admin/assets/{useAuditLabels-CSw_kwLs.js → useAuditLabels-DKrsrciQ.js} +2 -2
- package/dist/admin/assets/{useAuditLabels-CSw_kwLs.js.map → useAuditLabels-DKrsrciQ.js.map} +1 -1
- package/dist/admin/assets/useConfirmTarget-Dp8mCulm.js +2 -0
- package/dist/admin/assets/useConfirmTarget-Dp8mCulm.js.map +1 -0
- package/dist/admin/assets/{useContentSchema-CS5QQcRk.js → useContentSchema-Bv4_6VJR.js} +2 -2
- package/dist/admin/assets/{useContentSchema-CS5QQcRk.js.map → useContentSchema-Bv4_6VJR.js.map} +1 -1
- package/dist/admin/assets/{useCursorPager-Dt_axwd1.js → useCursorPager-B1upg5EU.js} +2 -2
- package/dist/admin/assets/{useCursorPager-Dt_axwd1.js.map → useCursorPager-B1upg5EU.js.map} +1 -1
- package/dist/admin/assets/{useDiscardGuard-7rRGpd4q.js → useDiscardGuard-34ynGJIk.js} +2 -2
- package/dist/admin/assets/{useDiscardGuard-7rRGpd4q.js.map → useDiscardGuard-34ynGJIk.js.map} +1 -1
- package/dist/admin/assets/{useMediaUploader-CBUcNW6d.js → useMediaUploader-QXSjZStv.js} +2 -2
- package/dist/admin/assets/{useMediaUploader-CBUcNW6d.js.map → useMediaUploader-QXSjZStv.js.map} +1 -1
- package/dist/admin/assets/{usePaletteItems-bbTIqpPu.js → usePaletteItems-62-TZhy7.js} +2 -2
- package/dist/admin/assets/{usePaletteItems-bbTIqpPu.js.map → usePaletteItems-62-TZhy7.js.map} +1 -1
- package/dist/admin/assets/usePlaces-CY6f2DmI.js +2 -0
- package/dist/admin/assets/usePlaces-CY6f2DmI.js.map +1 -0
- package/dist/admin/assets/{useQueries-DKGIdq6A.js → useQueries-BuKJBA0M.js} +2 -2
- package/dist/admin/assets/{useQueries-DKGIdq6A.js.map → useQueries-BuKJBA0M.js.map} +1 -1
- package/dist/admin/assets/useSchemaScopeAccess-DUBeS9kU.js +2 -0
- package/dist/admin/assets/useSchemaScopeAccess-DUBeS9kU.js.map +1 -0
- package/dist/admin/assets/{users-C1ZSee3N.js → users-BOn2ohJQ.js} +2 -2
- package/dist/admin/assets/{users-C1ZSee3N.js.map → users-BOn2ohJQ.js.map} +1 -1
- package/dist/admin/assets/{users-DMfQL0s4.js → users-BkKc4MNB.js} +2 -2
- package/dist/admin/assets/{users-DMfQL0s4.js.map → users-BkKc4MNB.js.map} +1 -1
- package/dist/admin/assets/{zod-Pf5A-ax4.js → zod-BHAd1wTC.js} +2 -2
- package/dist/admin/assets/{zod-Pf5A-ax4.js.map → zod-BHAd1wTC.js.map} +1 -1
- package/dist/admin/index.html +56 -55
- package/dist/cli.js +383 -163
- package/dist/cli.js.map +1 -1
- package/dist/config.d.ts +1 -1
- package/dist/config.js.map +1 -1
- package/dist/index.d.ts +6 -1
- package/dist/index.js +1 -1
- package/dist/{public-CKU0Gkfq.d.ts → public-CGO8RBn3.d.ts} +10 -2
- package/dist/{worker-C-MSYr4l.js → worker-BLXy8aRW.js} +2307 -1220
- package/dist/worker-BLXy8aRW.js.map +1 -0
- package/package.json +5 -6
- package/dist/admin/assets/Body-CFQKONK4.js +0 -2
- package/dist/admin/assets/Builder-Do5KVHV9.js +0 -2
- package/dist/admin/assets/Builder-Do5KVHV9.js.map +0 -1
- package/dist/admin/assets/LinkTabs-Bn2JVqOL.js +0 -2
- package/dist/admin/assets/Match-DaYgKrk7.js +0 -2
- package/dist/admin/assets/Structure-D5-hCUuF.js +0 -2
- package/dist/admin/assets/SubNavLink-C5oN5mzB.js +0 -2
- package/dist/admin/assets/TextLink-B4a6j3r6.js +0 -2
- package/dist/admin/assets/UnsavedChangesGuard-BYwMTDsE.js +0 -2
- package/dist/admin/assets/auth-b3_9QbtL.js +0 -2
- package/dist/admin/assets/auth-b3_9QbtL.js.map +0 -1
- package/dist/admin/assets/badge-CMox6-v3.js +0 -2
- package/dist/admin/assets/chevron-left-DyqYjcMB.js +0 -2
- package/dist/admin/assets/cn-DnXL75B0.js +0 -2
- package/dist/admin/assets/cn-DnXL75B0.js.map +0 -1
- package/dist/admin/assets/coerce-COM3rk1i.js +0 -2
- package/dist/admin/assets/constants-CS1ziZO0.js +0 -2
- package/dist/admin/assets/constants-CS1ziZO0.js.map +0 -1
- package/dist/admin/assets/content-Dic2fof_.js +0 -3
- package/dist/admin/assets/content-Dic2fof_.js.map +0 -1
- package/dist/admin/assets/contentTypes-D4_Ax9rb.js +0 -2
- package/dist/admin/assets/contentTypes-D4_Ax9rb.js.map +0 -1
- package/dist/admin/assets/develop-Brnb5YPC.js +0 -11
- package/dist/admin/assets/develop-Brnb5YPC.js.map +0 -1
- package/dist/admin/assets/errors-DfoXUVDI.js +0 -2
- package/dist/admin/assets/errors-DfoXUVDI.js.map +0 -1
- package/dist/admin/assets/fileRoute-BYwireXG.js +0 -2
- package/dist/admin/assets/inbox-wDoqym--.js +0 -2
- package/dist/admin/assets/index-57Mn6XLO.js +0 -4
- package/dist/admin/assets/index-57Mn6XLO.js.map +0 -1
- package/dist/admin/assets/link-2-DhM2vi4v.js +0 -2
- package/dist/admin/assets/link-2-DhM2vi4v.js.map +0 -1
- package/dist/admin/assets/link-2-off-DpDOMsa-.js +0 -2
- package/dist/admin/assets/link-2-off-DpDOMsa-.js.map +0 -1
- package/dist/admin/assets/media-DjK3xGFN.js +0 -2
- package/dist/admin/assets/network-CAJ76ILr.js +0 -2
- package/dist/admin/assets/network-CAJ76ILr.js.map +0 -1
- package/dist/admin/assets/publishing-vCVjaSGF.js +0 -2
- package/dist/admin/assets/schema-KXXSPVJn.js +0 -2
- package/dist/admin/assets/schema-KXXSPVJn.js.map +0 -1
- package/dist/admin/assets/searchSchema-BGrRDBL_.js +0 -2
- package/dist/admin/assets/searchSchemas-ChN9hhuQ.js +0 -2
- package/dist/admin/assets/searchSchemas-ChN9hhuQ.js.map +0 -1
- package/dist/admin/assets/settings-68BAxrPM.js +0 -2
- package/dist/admin/assets/settings-68BAxrPM.js.map +0 -1
- package/dist/admin/assets/skeleton-DUvclBAr.js +0 -42
- package/dist/admin/assets/skeleton-DUvclBAr.js.map +0 -1
- package/dist/admin/assets/snapshots-CKjK-vkL.js +0 -2
- package/dist/admin/assets/src-D6DABe5J.js +0 -4
- package/dist/admin/assets/src-D6DABe5J.js.map +0 -1
- package/dist/admin/assets/tabs-YThoOiE3.js +0 -5
- package/dist/admin/assets/titles-DyCBLXue.js +0 -2
- package/dist/admin/assets/useConfirmTarget-9JmfiY2X.js +0 -2
- package/dist/admin/assets/useConfirmTarget-9JmfiY2X.js.map +0 -1
- package/dist/admin/assets/usePlaces-D1raoQ2s.js +0 -2
- package/dist/admin/assets/usePlaces-D1raoQ2s.js.map +0 -1
- package/dist/worker-C-MSYr4l.js.map +0 -1
package/dist/cli.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import { A as update, B as
|
|
2
|
+
import { $ as validateSchema, A as update, B as hashDefinition, C as BEFORE_EVENTS, D as listForAssets, E as buildEditorManifest, F as RESERVED_FIELD_API_KEYS, G as parseLockFile, H as lockEntriesForSite, I as RESERVED_TYPE_NAMES, J as serializeDefinition, K as schemaFilePath, L as SCHEMA_KIND_DIRECTORIES, M as describeError, O as listLiveByDriver, P as RESERVED_DEFINITION_API_KEYS, Q as upgradeLockFile, R as SITES_DIRECTORY, S as AFTER_EVENTS, T as EXTENSION_ROUTE_ROOT, U as mergePulledLock, V as lockCoversSite, W as parseDefinition, X as suggestPlural, Y as serializeLockFile, Z as toTypeName, _ as createLogger, a as loadConfig, at as createDb, b as SITE_KEY_PATTERN, c as getPendingMigrations, d as createMediaStorage, et as withSiteCovered, f as createSite, g as generateToken, h as SYSTEM_CLI_ACTOR, i as assertDatabaseReachable, it as validateRichText, j as STORAGE_DRIVERS, k as lockById, l as migrateToLatest, m as createAdminDirect, n as startServer, nt as SAFE_LINK_PATTERN, o as loadEnvFileIfPresent, ot as sqliteDriverOf, p as listAllSites, q as scopeDirectory, r as copyObjectVerified, rt as createStableId, t as startDedicatedWorker, tt as RICHTEXT_FORMAT, u as SHAPIO_VERSION, v as createUrlBuilder, w as EXTENSION_JOB_PREFIX, x as loadProjectConfig, y as loopbackUrl, z as foldApiKey } from "./worker-BLXy8aRW.js";
|
|
3
3
|
import { createDecipheriv, createHash, scryptSync } from "node:crypto";
|
|
4
4
|
import { createReadStream, createWriteStream, existsSync, openAsBlob } from "node:fs";
|
|
5
5
|
import { basename, dirname, extname, isAbsolute, join, posix, relative, resolve } from "node:path";
|
|
@@ -472,7 +472,8 @@ const DEFINITION_PATHS = {
|
|
|
472
472
|
const createDefinitionApi = (request, category) => {
|
|
473
473
|
const base = DEFINITION_PATHS[category];
|
|
474
474
|
return {
|
|
475
|
-
|
|
475
|
+
/** The site's view (shared definitions and its own); `{ scope: 'network' }` lists the shared ones. */
|
|
476
|
+
list: async (options = {}) => (await request(`${base}${toQueryString(options)}`)).items,
|
|
476
477
|
get: (id) => request(withId(base, id)),
|
|
477
478
|
/** Creates and activates a definition (`pending` when prerequisites must run first). */
|
|
478
479
|
create: (body) => request(base, {
|
|
@@ -480,9 +481,17 @@ const createDefinitionApi = (request, category) => {
|
|
|
480
481
|
body
|
|
481
482
|
}),
|
|
482
483
|
/** Plan preview of a create: classification and impact, nothing written. */
|
|
483
|
-
planCreate: (definition) => request(`${base}/plan`, {
|
|
484
|
+
planCreate: (definition, scope) => request(`${base}/plan`, {
|
|
484
485
|
method: "POST",
|
|
485
|
-
body:
|
|
486
|
+
body: scope ? {
|
|
487
|
+
definition,
|
|
488
|
+
scope
|
|
489
|
+
} : { definition }
|
|
490
|
+
}),
|
|
491
|
+
/** Shares a definition with all sites, or keeps it on one (needs schema.create on every site). */
|
|
492
|
+
changeScope: (id, body) => request(`${withId(base, id)}/scope`, {
|
|
493
|
+
method: "PUT",
|
|
494
|
+
body
|
|
486
495
|
}),
|
|
487
496
|
/** Changes a definition; 409 SCHEMA_VERSION_CONFLICT when `expectedVersion` is stale. */
|
|
488
497
|
update: (id, body) => request(withId(base, id), {
|
|
@@ -508,7 +517,7 @@ const createSchemaApi = (request) => ({
|
|
|
508
517
|
summary: () => request(ADMIN_PATHS.schema),
|
|
509
518
|
change: (changeId) => request(withId(ADMIN_PATHS.schemaChanges, changeId)),
|
|
510
519
|
/** Every definition in the pull format, with the schema version they come from (`shapio schema pull`). */
|
|
511
|
-
export: () => request(ADMIN_PATHS.schemaExport),
|
|
520
|
+
export: (options = {}) => request(`${ADMIN_PATHS.schemaExport}${toQueryString(options)}`),
|
|
512
521
|
/** Applies definition files live through the change planner; refuses when the base moved (409). */
|
|
513
522
|
apply: (body) => request(ADMIN_PATHS.schemaApply, {
|
|
514
523
|
method: "POST",
|
|
@@ -2802,41 +2811,48 @@ const writeOrder = (entries) => {
|
|
|
2802
2811
|
deferred
|
|
2803
2812
|
};
|
|
2804
2813
|
};
|
|
2805
|
-
/**
|
|
2806
|
-
const
|
|
2807
|
-
const definitionPath = (dir, definition) => join(dir, definition.kind === "component" ? "components" : "models", `${definition.apiKey}.json`);
|
|
2814
|
+
/** The file of a definition in a scope (`site`: its site key, null when shared). */
|
|
2815
|
+
const definitionPath = (dir, definition, site) => join(dir, ...schemaFilePath(definition, site).split("/"));
|
|
2808
2816
|
const isMissing = (error) => error.code === "ENOENT";
|
|
2809
|
-
|
|
2810
|
-
|
|
2811
|
-
|
|
2812
|
-
|
|
2813
|
-
|
|
2814
|
-
|
|
2815
|
-
names = (await readdir(join(dir, kindDir))).filter((name) => name.endsWith(".json")).sort();
|
|
2816
|
-
} catch (error) {
|
|
2817
|
-
if (isMissing(error)) continue;
|
|
2818
|
-
throw error;
|
|
2819
|
-
}
|
|
2820
|
-
for (const name of names) {
|
|
2821
|
-
const path = join(dir, kindDir, name);
|
|
2822
|
-
let raw;
|
|
2823
|
-
try {
|
|
2824
|
-
raw = JSON.parse(await readFile(path, "utf8"));
|
|
2825
|
-
} catch (error) {
|
|
2826
|
-
throw new Error(`${path} is not valid JSON: ${error instanceof Error ? error.message : String(error)}`, { cause: error });
|
|
2827
|
-
}
|
|
2828
|
-
const parsed = parseDefinition(raw);
|
|
2829
|
-
files.push(parsed.ok ? {
|
|
2830
|
-
path,
|
|
2831
|
-
raw,
|
|
2832
|
-
id: parsed.definition.id,
|
|
2833
|
-
hash: await hashDefinition(parsed.definition)
|
|
2834
|
-
} : {
|
|
2835
|
-
path,
|
|
2836
|
-
raw
|
|
2837
|
-
});
|
|
2838
|
-
}
|
|
2817
|
+
const listNames = async (path, filter) => {
|
|
2818
|
+
try {
|
|
2819
|
+
return (await readdir(path, { withFileTypes: true })).filter(filter).map((entry) => entry.name).sort();
|
|
2820
|
+
} catch (error) {
|
|
2821
|
+
if (isMissing(error)) return [];
|
|
2822
|
+
throw error;
|
|
2839
2823
|
}
|
|
2824
|
+
};
|
|
2825
|
+
const readLocalFile = async (path, site) => {
|
|
2826
|
+
let raw;
|
|
2827
|
+
try {
|
|
2828
|
+
raw = JSON.parse(await readFile(path, "utf8"));
|
|
2829
|
+
} catch (error) {
|
|
2830
|
+
throw new Error(`${path} is not valid JSON: ${error instanceof Error ? error.message : String(error)}`, { cause: error });
|
|
2831
|
+
}
|
|
2832
|
+
const parsed = parseDefinition(raw);
|
|
2833
|
+
return parsed.ok ? {
|
|
2834
|
+
path,
|
|
2835
|
+
raw,
|
|
2836
|
+
site,
|
|
2837
|
+
id: parsed.definition.id,
|
|
2838
|
+
hash: await hashDefinition(parsed.definition)
|
|
2839
|
+
} : {
|
|
2840
|
+
path,
|
|
2841
|
+
raw,
|
|
2842
|
+
site
|
|
2843
|
+
};
|
|
2844
|
+
};
|
|
2845
|
+
/** The files of one scope's folder (`models/` and `components/` under it). */
|
|
2846
|
+
const readScopeFiles = async (dir, site) => {
|
|
2847
|
+
const base = join(dir, ...scopeDirectory(site).split("/").filter(Boolean));
|
|
2848
|
+
const files = [];
|
|
2849
|
+
for (const kindDir of SCHEMA_KIND_DIRECTORIES) for (const name of await listNames(join(base, kindDir), (entry) => entry.isFile() && entry.name.endsWith(".json"))) files.push(await readLocalFile(join(base, kindDir, name), site));
|
|
2850
|
+
return files;
|
|
2851
|
+
};
|
|
2852
|
+
/** Every schema file under `dir`: the shared folders first, then each site folder by key. */
|
|
2853
|
+
const readLocalFiles = async (dir) => {
|
|
2854
|
+
const files = await readScopeFiles(dir, null);
|
|
2855
|
+
for (const siteKey of await listNames(join(dir, SITES_DIRECTORY), (entry) => entry.isDirectory() && !entry.name.startsWith("."))) files.push(...await readScopeFiles(dir, siteKey));
|
|
2840
2856
|
return files;
|
|
2841
2857
|
};
|
|
2842
2858
|
const readLockFile = async (path) => {
|
|
@@ -2851,8 +2867,8 @@ const writeLockFile = async (path, lock) => {
|
|
|
2851
2867
|
await mkdir(dirname(path), { recursive: true });
|
|
2852
2868
|
await writeFile(path, serializeLockFile(lock));
|
|
2853
2869
|
};
|
|
2854
|
-
const writeDefinitionFile = async (dir, definition) => {
|
|
2855
|
-
const path = definitionPath(dir, definition);
|
|
2870
|
+
const writeDefinitionFile = async (dir, definition, site) => {
|
|
2871
|
+
const path = definitionPath(dir, definition, site);
|
|
2856
2872
|
await mkdir(dirname(path), { recursive: true });
|
|
2857
2873
|
await writeFile(path, serializeDefinition(definition));
|
|
2858
2874
|
return path;
|
|
@@ -2905,23 +2921,103 @@ const formatItem = (item, names) => {
|
|
|
2905
2921
|
].filter(Boolean);
|
|
2906
2922
|
return [`${item.kind === "component" ? "component" : "model"} ${item.apiKey}: ${describeDecision(item)}${flags.length ? ` [${flags.join(", ")}]` : ""}`, ...item.changes.map((change) => ` ${formatChange(change, names)}`)].join("\n");
|
|
2907
2923
|
};
|
|
2908
|
-
|
|
2924
|
+
const FOLDER_OF = {
|
|
2925
|
+
network: "the shared folders",
|
|
2926
|
+
site: "the site’s folder"
|
|
2927
|
+
};
|
|
2928
|
+
const PLACE_OF = {
|
|
2929
|
+
network: "shared",
|
|
2930
|
+
site: "on one site"
|
|
2931
|
+
};
|
|
2932
|
+
const SCOPE_OF = {
|
|
2933
|
+
network: "shared",
|
|
2934
|
+
site: "site"
|
|
2935
|
+
};
|
|
2936
|
+
/** One line per item of a scope refusal (`SCOPE_MISMATCH`, `FORBIDDEN_SCOPE`). */
|
|
2937
|
+
const scopeItemLines = (code, items) => items.map((item) => {
|
|
2938
|
+
const name = item.apiKey ?? item.definitionId ?? "?";
|
|
2939
|
+
return code === "SCOPE_MISMATCH" ? ` ${name}: its file is in ${FOLDER_OF[item.local ?? ""] ?? "?"}, but on the instance it is ${PLACE_OF[item.remote ?? ""] ?? "?"}` : ` ${name} (${SCOPE_OF[item.scope ?? ""] ?? item.scope ?? "?"}): ${item.message ?? "not allowed"}`;
|
|
2940
|
+
});
|
|
2941
|
+
/** What to do next, per refusal. */
|
|
2942
|
+
const HINTS = {
|
|
2943
|
+
SCHEMA_CHANGE_NOT_ACKNOWLEDGED: "Review the changes with `shapio schema diff`, then re-run with --allow-breaking and/or --allow-destructive.",
|
|
2944
|
+
SCHEMA_SYNC_CONFLICT: "Commit your files, run `shapio schema pull --force`, reconcile with git, then apply again.",
|
|
2945
|
+
SCOPE_MISMATCH: "Sync never moves a definition between sites: run `shapio schema pull` to get the instance’s layout, or change the scope with `shapio schema scope`.",
|
|
2946
|
+
FORBIDDEN_SCOPE: "Shared definitions (in models/ and components/) need schema permission on every site: apply with a network token, or leave those files unchanged."
|
|
2947
|
+
};
|
|
2948
|
+
const issueWhere = (found, filePaths) => {
|
|
2949
|
+
const match = /^\/definitions\/(\d+)(.*)$/.exec(found.path ?? "");
|
|
2950
|
+
const where = match ? `${filePaths[Number(match[1])] ?? `definition ${match[1]}`} ${match[2] || "/"}` : found.path ?? "";
|
|
2951
|
+
return found.siteKey ? `${where} (site ${found.siteKey})` : where;
|
|
2952
|
+
};
|
|
2953
|
+
const siteCountLines = (sites) => (sites ?? []).flatMap((site) => typeof site === "object" && site.entries !== void 0 ? [` site ${site.key ?? site.siteId ?? "?"}: ${site.entries} entr${site.entries === 1 ? "y" : "ies"}`] : []);
|
|
2954
|
+
/** Explains a refused request: conflicts with diffs, invalid files, scope refusals, missing acknowledgements. */
|
|
2909
2955
|
const formatApiError = (error, filePaths, names) => {
|
|
2910
2956
|
const details = error.details ?? {};
|
|
2911
2957
|
const lines = [`${error.code}: ${error.message}`];
|
|
2912
2958
|
for (const conflict of details.conflicts ?? []) lines.push(formatItem(conflict, names));
|
|
2913
|
-
for (const found of details.issues ?? []) {
|
|
2914
|
-
|
|
2915
|
-
|
|
2916
|
-
|
|
2917
|
-
|
|
2918
|
-
if (error.code === "SCHEMA_CHANGE_NOT_ACKNOWLEDGED") lines.push("Review the changes with `shapio schema diff`, then re-run with --allow-breaking and/or --allow-destructive.");
|
|
2919
|
-
if (error.code === "SCHEMA_SYNC_CONFLICT") lines.push("Commit your files, run `shapio schema pull --force`, reconcile with git, then apply again.");
|
|
2959
|
+
for (const found of details.issues ?? []) lines.push(` ${issueWhere(found, filePaths)}: ${found.message ?? ""}`);
|
|
2960
|
+
lines.push(...scopeItemLines(error.code, details.items ?? []));
|
|
2961
|
+
if (error.code === "SCOPE_IN_USE") lines.push(...siteCountLines(details.sites));
|
|
2962
|
+
const hint = HINTS[error.code];
|
|
2963
|
+
if (hint) lines.push(hint);
|
|
2920
2964
|
return `${lines.join("\n")}\n`;
|
|
2921
2965
|
};
|
|
2966
|
+
/**
|
|
2967
|
+
* Which part of a schema tree one site's sync is about (plan site-schema): the shared folders and that site's
|
|
2968
|
+
* own folder. One tree may hold several sites (`sites/<key>/`); a pull or apply for one never reads, sends,
|
|
2969
|
+
* rewrites or removes another site's files or lock entries.
|
|
2970
|
+
*/
|
|
2971
|
+
const inView = (site, siteKey) => site === null || site === siteKey;
|
|
2972
|
+
/** The files an apply for `siteKey` sends: the shared ones and that site's. */
|
|
2973
|
+
const filesForSite = (files, siteKey) => files.filter((file) => inView(file.site, siteKey));
|
|
2974
|
+
/** Each sent file's scope, parallel to the files: its folder decides (only creates use it). */
|
|
2975
|
+
const scopesOf = (files) => files.map((file) => file.site === null ? "network" : "site");
|
|
2976
|
+
/**
|
|
2977
|
+
* The base an apply for `siteKey` sends: the lock in format 2 with only the shared entries and that site's,
|
|
2978
|
+
* so neither the three-way decision nor `--prune` can ever see another site's IDs. `sites` is kept: the
|
|
2979
|
+
* server refuses a tree that covers other sites only.
|
|
2980
|
+
*/
|
|
2981
|
+
const baseForSite = (lock, siteKey) => {
|
|
2982
|
+
const upgraded = upgradeLockFile(lock);
|
|
2983
|
+
return {
|
|
2984
|
+
...upgraded,
|
|
2985
|
+
definitions: lockEntriesForSite(upgraded, siteKey)
|
|
2986
|
+
};
|
|
2987
|
+
};
|
|
2988
|
+
/** Files in the site's view that differ from what was last pulled (or were never pulled). */
|
|
2989
|
+
const editedFilesForSite = (files, lock, siteKey) => {
|
|
2990
|
+
const base = lockEntriesForSite(lock, siteKey);
|
|
2991
|
+
if (Object.keys(base).length === 0) return [];
|
|
2992
|
+
return filesForSite(files, siteKey).filter((file) => {
|
|
2993
|
+
const entry = file.id ? base[file.id] : void 0;
|
|
2994
|
+
return !entry || file.hash !== entry.hash;
|
|
2995
|
+
});
|
|
2996
|
+
};
|
|
2997
|
+
/**
|
|
2998
|
+
* Files a pull of `siteKey` leaves stale: in the pulled scopes and not written (deleted or renamed on the
|
|
2999
|
+
* instance), plus any other file of a definition that was just written elsewhere (its scope changed on the
|
|
3000
|
+
* instance: it is the same definition, and two files with one ID would make the next apply fail).
|
|
3001
|
+
*/
|
|
3002
|
+
const staleFilesAfterPull = (files, siteKey, written) => {
|
|
3003
|
+
const writtenPaths = new Set(written.values());
|
|
3004
|
+
return files.filter((file) => {
|
|
3005
|
+
if (writtenPaths.has(file.path)) return false;
|
|
3006
|
+
return inView(file.site, siteKey) || file.id !== void 0 && written.has(file.id);
|
|
3007
|
+
});
|
|
3008
|
+
};
|
|
3009
|
+
/**
|
|
3010
|
+
* The lock after an apply for `siteKey` recorded its entries: the tree covers the site once it holds one of
|
|
3011
|
+
* the site's own definitions. A shared-only tree stays uncovered, so it still applies to every site.
|
|
3012
|
+
*/
|
|
3013
|
+
const coverSiteIfHeld = (lock, siteKey) => Object.values(lock.definitions).some((entry) => entry.site === siteKey) ? {
|
|
3014
|
+
...lock,
|
|
3015
|
+
sites: withSiteCovered(lock.sites, siteKey)
|
|
3016
|
+
} : lock;
|
|
2922
3017
|
const EMPTY_LOCK = {
|
|
2923
|
-
formatVersion:
|
|
3018
|
+
formatVersion: 2,
|
|
2924
3019
|
schemaVersion: 0,
|
|
3020
|
+
sites: [],
|
|
2925
3021
|
definitions: {}
|
|
2926
3022
|
};
|
|
2927
3023
|
/** Field and definition names by ID from the local files, for readable diffs. */
|
|
@@ -2942,17 +3038,45 @@ const readLocalState = async (options) => {
|
|
|
2942
3038
|
names: collectNames(files)
|
|
2943
3039
|
};
|
|
2944
3040
|
};
|
|
2945
|
-
/** The
|
|
2946
|
-
const
|
|
3041
|
+
/** The admin client for the command's site (`--site`, else the token's site, else the primary). */
|
|
3042
|
+
const clientFor = (options) => createClient({
|
|
2947
3043
|
baseUrl: options.baseUrl,
|
|
2948
|
-
token: options.token
|
|
2949
|
-
|
|
2950
|
-
|
|
3044
|
+
token: options.token,
|
|
3045
|
+
...options.site ? { site: options.site } : {}
|
|
3046
|
+
});
|
|
3047
|
+
/** The schema sync endpoints (`export`, `apply`, `change`) of @shapio/client. */
|
|
3048
|
+
const apiFor = (options) => clientFor(options).admin.schema;
|
|
3049
|
+
/** The key of the site the command works on, as the instance resolved it (an unnamed site is the default). */
|
|
3050
|
+
const resolveSiteKey = async (options) => {
|
|
3051
|
+
if (options.site) return options.site;
|
|
3052
|
+
const { site } = await apiFor(options).export({ scope: "network" });
|
|
3053
|
+
if (!site) throw new Error("The instance did not say which site this token works on; pass --site <key>");
|
|
3054
|
+
return site.key;
|
|
3055
|
+
};
|
|
3056
|
+
/**
|
|
3057
|
+
* The local tree narrowed to one site (shared files and `sites/<key>/`), or undefined (after explaining)
|
|
3058
|
+
* when the tree was pulled for other sites only.
|
|
3059
|
+
*/
|
|
3060
|
+
const readSiteState = async (options, io) => {
|
|
3061
|
+
const siteKey = await resolveSiteKey(options);
|
|
3062
|
+
const state = await readLocalState(options);
|
|
3063
|
+
if (!lockCoversSite(state.lock, siteKey)) {
|
|
3064
|
+
io.stderr(`${displayPath(options.lockPath)} covers the site(s) ${(state.lock.sites ?? []).join(", ")}, not "${siteKey}".\nApply it with --site <one of those>, or pull "${siteKey}" into this tree first: shapio schema pull --site ${siteKey}\n`);
|
|
3065
|
+
return;
|
|
3066
|
+
}
|
|
3067
|
+
return {
|
|
3068
|
+
...state,
|
|
3069
|
+
siteKey,
|
|
3070
|
+
sent: filesForSite(state.files, siteKey)
|
|
3071
|
+
};
|
|
3072
|
+
};
|
|
3073
|
+
/** Sends the site's files with their lock-file bases; the server decides per definition (three-way). */
|
|
2951
3074
|
const sendApply = async (options, state, dryRun, io) => {
|
|
2952
3075
|
try {
|
|
2953
3076
|
return await apiFor(options).apply({
|
|
2954
|
-
definitions: state.
|
|
2955
|
-
|
|
3077
|
+
definitions: state.sent.map((file) => file.raw),
|
|
3078
|
+
scopes: scopesOf(state.sent),
|
|
3079
|
+
base: baseForSite(state.lock, state.siteKey),
|
|
2956
3080
|
prune: options.prune,
|
|
2957
3081
|
dryRun,
|
|
2958
3082
|
acknowledgeBreaking: options.allowBreaking,
|
|
@@ -2960,7 +3084,7 @@ const sendApply = async (options, state, dryRun, io) => {
|
|
|
2960
3084
|
});
|
|
2961
3085
|
} catch (error) {
|
|
2962
3086
|
if (error instanceof ShapioApiError) {
|
|
2963
|
-
io.stderr(formatApiError(error, state.
|
|
3087
|
+
io.stderr(formatApiError(error, state.sent.map((file) => displayPath(file.path)), state.names));
|
|
2964
3088
|
return;
|
|
2965
3089
|
}
|
|
2966
3090
|
throw error;
|
|
@@ -3048,11 +3172,12 @@ const checkPlanDirectory = async (dir, force) => {
|
|
|
3048
3172
|
if (Object.keys(previous.state.entries).length > 0 || Object.keys(previous.state.media).length > 0) throw new Error(`${dir} holds an import that has started (${Object.keys(previous.state.entries).length} entries created): re-run --map to continue it, or plan into a new directory`);
|
|
3049
3173
|
if (!force) throw new Error(`${dir} already holds a plan: pass --force to replace it (new IDs), or use another directory`);
|
|
3050
3174
|
};
|
|
3051
|
-
const plannedMap = (source, info, ids) => ({
|
|
3175
|
+
const plannedMap = (source, info, ids, site) => ({
|
|
3052
3176
|
format: IMPORT_MAP_FORMAT,
|
|
3053
3177
|
formatVersion: 1,
|
|
3054
3178
|
source: info,
|
|
3055
3179
|
plannedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
3180
|
+
site: site ?? null,
|
|
3056
3181
|
definitions: ids,
|
|
3057
3182
|
media: Object.fromEntries(source.media.map((media) => [media.sourceId, {
|
|
3058
3183
|
filename: media.filename,
|
|
@@ -3070,9 +3195,11 @@ const plannedMap = (source, info, ids) => ({
|
|
|
3070
3195
|
/**
|
|
3071
3196
|
* `--plan`: writes one pull-format schema file per planned definition under `<dir>/schema`, an empty lock file
|
|
3072
3197
|
* beside them (so `schema apply` treats every definition as new and leaves the project's own lock alone), and
|
|
3073
|
-
* `import-map.json`. Nothing is sent to an instance.
|
|
3198
|
+
* `import-map.json`. Nothing is sent to an instance. With `site` (`--site` / SHAPIO_SITE) the files go under
|
|
3199
|
+
* `schema/sites/<site>/`, so `schema apply --site <site>` creates them on that site; without one they go in
|
|
3200
|
+
* the shared folders and are created shared with all sites.
|
|
3074
3201
|
*/
|
|
3075
|
-
const writePlan = async (dir, source, info, { force = false } = {}) => {
|
|
3202
|
+
const writePlan = async (dir, source, info, { force = false, site } = {}) => {
|
|
3076
3203
|
await checkPlanDirectory(dir, force);
|
|
3077
3204
|
const ids = assignIds(source.definitions);
|
|
3078
3205
|
const definitions = buildDefinitions(source, ids);
|
|
@@ -3081,9 +3208,9 @@ const writePlan = async (dir, source, info, { force = false } = {}) => {
|
|
|
3081
3208
|
recursive: true,
|
|
3082
3209
|
force: true
|
|
3083
3210
|
});
|
|
3084
|
-
for (const definition of definitions) await writeDefinitionFile(schemaDir, definition);
|
|
3211
|
+
for (const definition of definitions) await writeDefinitionFile(schemaDir, definition, site ?? null);
|
|
3085
3212
|
await writeLockFile(join(dir, PLAN_LOCK_FILE), EMPTY_LOCK);
|
|
3086
|
-
const map = plannedMap(source, info, ids);
|
|
3213
|
+
const map = plannedMap(source, info, ids, site);
|
|
3087
3214
|
await writeImportMap(dir, map);
|
|
3088
3215
|
return {
|
|
3089
3216
|
definitions,
|
|
@@ -3198,17 +3325,27 @@ var ImportRefusedError = class extends Error {
|
|
|
3198
3325
|
this.name = "ImportRefusedError";
|
|
3199
3326
|
}
|
|
3200
3327
|
};
|
|
3328
|
+
/**
|
|
3329
|
+
* The site `--map` writes to: `--site` (or SHAPIO_SITE), else the site the plan was made for. A requested site
|
|
3330
|
+
* that disagrees with the planned one is refused: the planned models exist on that site only.
|
|
3331
|
+
*/
|
|
3332
|
+
const resolveMapSite = (map, requested) => {
|
|
3333
|
+
const planned = map.site ?? void 0;
|
|
3334
|
+
if (requested !== void 0 && planned !== void 0 && requested !== planned) throw new ImportRefusedError(`This import was planned for site "${planned}", not "${requested}": run --map with --site ${planned}, or plan again with --site ${requested}`);
|
|
3335
|
+
return requested ?? planned;
|
|
3336
|
+
};
|
|
3201
3337
|
const messageOf = (error) => error instanceof Error ? error.message : String(error);
|
|
3202
|
-
const checkSourceAndSite = async (map,
|
|
3338
|
+
const checkSourceAndSite = async (map, site) => {
|
|
3203
3339
|
if (await sha256File(map.source.path).catch((error) => {
|
|
3204
3340
|
throw new ImportRefusedError(`The source ${map.source.path} cannot be read: ${messageOf(error)}`);
|
|
3205
3341
|
}) !== map.source.sha256) throw new ImportRefusedError(`${map.source.path} changed since it was planned: plan again into a new directory`);
|
|
3206
|
-
if ((Object.keys(map.state.entries).length > 0 || Object.keys(map.state.media).length > 0) && (map.state.site ?? null) !== (
|
|
3342
|
+
if ((Object.keys(map.state.entries).length > 0 || Object.keys(map.state.media).length > 0) && (map.state.site ?? null) !== (site ?? null)) throw new ImportRefusedError(`This import was started on site ${map.state.site ?? "(default)"}: re-run it with the same --site`);
|
|
3207
3343
|
};
|
|
3208
|
-
|
|
3344
|
+
/** The target site's view (the client names the site): its own definitions and the shared ones. */
|
|
3345
|
+
const loadLiveSchema = async (client, map, dir, site) => {
|
|
3209
3346
|
const exported = await client.admin.schema.export();
|
|
3210
3347
|
const live = resolveLiveSchema(map, exported.definitions.map((entry) => entry.definition));
|
|
3211
|
-
if (live.missing.length > 0) throw new ImportRefusedError(`The instance does not have the planned models yet: ${live.missing.join(", ")}.\nApply them first: shapio schema apply --dir ${join(dir, PLAN_SCHEMA_DIR)} --lock ${join(dir, PLAN_LOCK_FILE)}`);
|
|
3348
|
+
if (live.missing.length > 0) throw new ImportRefusedError(`The instance does not have the planned models yet: ${live.missing.join(", ")}.\nApply them first: shapio schema apply --dir ${join(dir, PLAN_SCHEMA_DIR)} --lock ${join(dir, PLAN_LOCK_FILE)}${site ? ` --site ${site}` : ""}`);
|
|
3212
3349
|
return live;
|
|
3213
3350
|
};
|
|
3214
3351
|
const checkLocales = async (client, source) => {
|
|
@@ -3362,17 +3499,18 @@ const printSummary = (run, source, changeSetFailures) => {
|
|
|
3362
3499
|
};
|
|
3363
3500
|
const runMap = async (options, io) => {
|
|
3364
3501
|
const map = await readImportMap(options.dir);
|
|
3365
|
-
|
|
3502
|
+
const site = resolveMapSite(map, options.site);
|
|
3503
|
+
await checkSourceAndSite(map, site);
|
|
3366
3504
|
const client = createClient({
|
|
3367
3505
|
baseUrl: options.baseUrl,
|
|
3368
3506
|
token: options.token,
|
|
3369
3507
|
fetch: createRateLimitedFetch(options.fetch),
|
|
3370
|
-
...
|
|
3508
|
+
...site ? { site } : {}
|
|
3371
3509
|
});
|
|
3372
|
-
const live = await loadLiveSchema(client, map, options.dir);
|
|
3510
|
+
const live = await loadLiveSchema(client, map, options.dir, site);
|
|
3373
3511
|
const source = await options.load(map);
|
|
3374
3512
|
await checkLocales(client, source);
|
|
3375
|
-
map.state.site =
|
|
3513
|
+
map.state.site = site ?? null;
|
|
3376
3514
|
map.state.baseUrl = options.baseUrl;
|
|
3377
3515
|
const run = {
|
|
3378
3516
|
options,
|
|
@@ -3396,7 +3534,7 @@ const display = (path) => {
|
|
|
3396
3534
|
return !shown ? "." : shown.startsWith("..") || isAbsolute(shown) ? path : shown;
|
|
3397
3535
|
};
|
|
3398
3536
|
/** What `--plan` wrote and what to do next. */
|
|
3399
|
-
const formatPlanSummary = (source, definitions, dir, command) => {
|
|
3537
|
+
const formatPlanSummary = (source, definitions, dir, command, site) => {
|
|
3400
3538
|
const keyOf = new Map(source.definitions.map((definition) => [definition.apiKey, definition.key]));
|
|
3401
3539
|
const lines = [`Planned ${definitions.length} definition(s) in ${display(`${dir}/${PLAN_SCHEMA_DIR}`)}:`];
|
|
3402
3540
|
for (const definition of definitions) {
|
|
@@ -3407,7 +3545,9 @@ const formatPlanSummary = (source, definitions, dir, command) => {
|
|
|
3407
3545
|
lines.push(`Media: ${source.media.length} file(s) to import.`);
|
|
3408
3546
|
lines.push("Every model has draft and publish on: nothing goes live until you ship the change set(s) the import opens.");
|
|
3409
3547
|
lines.push(...source.notes);
|
|
3410
|
-
lines.push(
|
|
3548
|
+
lines.push(site ? `The models and components will belong to site "${site}".` : "No --site given: the models and components will be shared with all sites. Plan again with --site <key> to keep them on one site.");
|
|
3549
|
+
const siteFlag = site ? ` --site ${site}` : "";
|
|
3550
|
+
lines.push("Next:", " 1. Review the files: rename API IDs or delete fields you do not want (entries follow the stable IDs).", ` 2. shapio schema apply --dir ${display(`${dir}/${PLAN_SCHEMA_DIR}`)} --lock ${display(`${dir}/${PLAN_LOCK_FILE}`)}${siteFlag}`, ` 3. shapio import ${command} --map ${display(dir)}${siteFlag}`);
|
|
3411
3551
|
return `${lines.join("\n")}\n`;
|
|
3412
3552
|
};
|
|
3413
3553
|
const parse = (args, spec) => {
|
|
@@ -3436,24 +3576,30 @@ const parse = (args, spec) => {
|
|
|
3436
3576
|
file: positionals[0]
|
|
3437
3577
|
};
|
|
3438
3578
|
};
|
|
3579
|
+
/** `--site`, else SHAPIO_SITE: the site the plan's schema belongs to and the map step writes to. */
|
|
3580
|
+
const siteOf = (values, io) => (values.site ?? io.env.SHAPIO_SITE)?.trim() || void 0;
|
|
3439
3581
|
const runPlan = async (spec, file, values, io) => {
|
|
3440
3582
|
const dir = resolve(String(values.plan));
|
|
3441
3583
|
const path = resolve(file);
|
|
3442
3584
|
await checkPlanDirectory(dir, values.force === true);
|
|
3443
3585
|
const source = await spec.plan(path, dir, values);
|
|
3586
|
+
const site = siteOf(values, io);
|
|
3444
3587
|
const { definitions } = await writePlan(dir, source, {
|
|
3445
3588
|
kind: source.kind,
|
|
3446
3589
|
path,
|
|
3447
3590
|
sha256: await sha256File(path)
|
|
3448
|
-
}, {
|
|
3449
|
-
|
|
3591
|
+
}, {
|
|
3592
|
+
force: values.force === true,
|
|
3593
|
+
site
|
|
3594
|
+
});
|
|
3595
|
+
io.stdout(formatPlanSummary(source, definitions, dir, spec.name, site));
|
|
3450
3596
|
return 0;
|
|
3451
3597
|
};
|
|
3452
3598
|
const runMapStep = (spec, values, io) => {
|
|
3453
3599
|
const token = values.token ?? io.env.SHAPIO_TOKEN;
|
|
3454
3600
|
if (!token) throw new UsageError$1("An admin API token is required: pass --token or set SHAPIO_TOKEN");
|
|
3455
3601
|
const dir = resolve(String(values.map));
|
|
3456
|
-
const site = values
|
|
3602
|
+
const site = siteOf(values, io);
|
|
3457
3603
|
return runMap({
|
|
3458
3604
|
dir,
|
|
3459
3605
|
baseUrl: values.url ?? io.env.SHAPIO_URL ?? "http://localhost:4300",
|
|
@@ -3492,7 +3638,7 @@ const importStrapiCommand = createImporterCommand({
|
|
|
3492
3638
|
name: "strapi",
|
|
3493
3639
|
label: "Strapi",
|
|
3494
3640
|
summary: "Import a Strapi 5 export: --plan writes schema files, --map creates drafts and change sets",
|
|
3495
|
-
usage: "shapio import strapi <export.tar.gz[.enc]> --plan <dir> [--key <encryption key>] [--force]\n shapio import strapi --map <dir> [--url <origin>] [--token <admin token>] [--site <key>]\n --plan unpacks the export into <dir>/source (--key for an encrypted export) and writes the planned models\n and components (<dir>/schema) and <dir>/import-map.json; it sends nothing. Apply the schema with\n `shapio schema apply --dir <dir>/schema --lock <dir>/schema-lock.json`, then run --map
|
|
3641
|
+
usage: "shapio import strapi <export.tar.gz[.enc]> --plan <dir> [--key <encryption key>] [--site <key>] [--force]\n shapio import strapi --map <dir> [--url <origin>] [--token <admin token>] [--site <key>]\n --plan unpacks the export into <dir>/source (--key for an encrypted export) and writes the planned models\n and components (<dir>/schema) and <dir>/import-map.json; it sends nothing. With --site (or SHAPIO_SITE)\n they belong to that site (<dir>/schema/sites/<key>/); without, they are shared (--map\n without --site imports into the planned site). Apply the schema with\n `shapio schema apply --dir <dir>/schema --lock <dir>/schema-lock.json [--site <key>]`, then run --map:\n it uploads the media, creates every document as a draft and opens change sets with the published ones.\n Strapi 5 only.",
|
|
3496
3642
|
options: ["key"],
|
|
3497
3643
|
plan: async (file, dir, values) => {
|
|
3498
3644
|
await extractStrapiExport(file, sourceDir(dir), typeof values.key === "string" ? values.key : void 0);
|
|
@@ -4086,7 +4232,7 @@ const importWordPressCommand = createImporterCommand({
|
|
|
4086
4232
|
name: "wordpress",
|
|
4087
4233
|
label: "WordPress",
|
|
4088
4234
|
summary: "Import a WordPress export (WXR): --plan writes schema files, --map creates drafts and change sets",
|
|
4089
|
-
usage: "shapio import wordpress <export.xml> --plan <dir> [--force]\n shapio import wordpress --map <dir> [--url <origin>] [--token <admin token>] [--site <key>] [--media-dir <uploads dir>]\n --plan reads the export and writes the planned models (<dir>/schema) and <dir>/import-map.json; it sends nothing.\n Apply the models with `shapio schema apply --dir <dir>/schema --lock <dir>/schema-lock.json`, then run --map:\n it uploads the media (downloaded from the site, or read from --media-dir, a copy of wp-content/uploads),\n creates every post and page as a draft, and opens change sets with the published ones. Re-run --map to resume.",
|
|
4235
|
+
usage: "shapio import wordpress <export.xml> --plan <dir> [--site <key>] [--force]\n shapio import wordpress --map <dir> [--url <origin>] [--token <admin token>] [--site <key>] [--media-dir <uploads dir>]\n --plan reads the export and writes the planned models (<dir>/schema) and <dir>/import-map.json; it sends nothing.\n With --site (or SHAPIO_SITE) the models belong to that site (<dir>/schema/sites/<key>/); without, they are shared;\n --map without --site then imports into the planned site.\n Apply the models with `shapio schema apply --dir <dir>/schema --lock <dir>/schema-lock.json [--site <key>]`, then run --map:\n it uploads the media (downloaded from the site, or read from --media-dir, a copy of wp-content/uploads),\n creates every post and page as a draft, and opens change sets with the published ones. Re-run --map to resume.",
|
|
4090
4236
|
options: ["media-dir"],
|
|
4091
4237
|
plan: async (file) => wordpressSource(await readWxr(file)),
|
|
4092
4238
|
load: async (map, _dir, values) => wordpressSource(await readWxr(map.source.path), mediaDirOf(values))
|
|
@@ -4268,13 +4414,28 @@ var UsageError = class extends Error {
|
|
|
4268
4414
|
this.name = "UsageError";
|
|
4269
4415
|
}
|
|
4270
4416
|
};
|
|
4271
|
-
|
|
4417
|
+
const CONNECTION_FLAGS = {
|
|
4418
|
+
url: { type: "string" },
|
|
4419
|
+
token: { type: "string" },
|
|
4420
|
+
site: { type: "string" }
|
|
4421
|
+
};
|
|
4422
|
+
/** URL, token and site from the flags, else SHAPIO_URL / SHAPIO_TOKEN / SHAPIO_SITE. */
|
|
4423
|
+
const resolveConnection = (values, io) => {
|
|
4424
|
+
const token = values.token ?? io.env.SHAPIO_TOKEN;
|
|
4425
|
+
if (!token) throw new UsageError("An admin API token is required: pass --token or set SHAPIO_TOKEN");
|
|
4426
|
+
const site = (values.site ?? io.env.SHAPIO_SITE)?.trim() || void 0;
|
|
4427
|
+
return {
|
|
4428
|
+
baseUrl: values.url ?? io.env.SHAPIO_URL ?? "http://localhost:4300",
|
|
4429
|
+
token,
|
|
4430
|
+
...site ? { site } : {}
|
|
4431
|
+
};
|
|
4432
|
+
};
|
|
4433
|
+
/** Shared flags of `shapio schema pull|diff|apply`. */
|
|
4272
4434
|
const parseSchemaOptions = (args, io) => {
|
|
4273
4435
|
const { values } = parseArgs({
|
|
4274
4436
|
args: [...args],
|
|
4275
4437
|
options: {
|
|
4276
|
-
|
|
4277
|
-
token: { type: "string" },
|
|
4438
|
+
...CONNECTION_FLAGS,
|
|
4278
4439
|
dir: { type: "string" },
|
|
4279
4440
|
lock: { type: "string" },
|
|
4280
4441
|
prune: {
|
|
@@ -4301,13 +4462,11 @@ const parseSchemaOptions = (args, io) => {
|
|
|
4301
4462
|
},
|
|
4302
4463
|
allowPositionals: false
|
|
4303
4464
|
});
|
|
4304
|
-
const
|
|
4305
|
-
if (!token) throw new UsageError("An admin API token is required: pass --token or set SHAPIO_TOKEN");
|
|
4465
|
+
const connection = resolveConnection(values, io);
|
|
4306
4466
|
const waitTimeoutSeconds = Number(values["wait-timeout"] ?? 600);
|
|
4307
4467
|
if (!Number.isFinite(waitTimeoutSeconds) || waitTimeoutSeconds <= 0) throw new UsageError("--wait-timeout must be a positive number of seconds");
|
|
4308
4468
|
return {
|
|
4309
|
-
|
|
4310
|
-
token,
|
|
4469
|
+
...connection,
|
|
4311
4470
|
dir: resolve(values.dir ?? "schema"),
|
|
4312
4471
|
lockPath: resolve(values.lock ?? ".shapio/schema-lock.json"),
|
|
4313
4472
|
prune: values.prune,
|
|
@@ -4318,7 +4477,7 @@ const parseSchemaOptions = (args, io) => {
|
|
|
4318
4477
|
waitTimeoutMs: waitTimeoutSeconds * 1e3
|
|
4319
4478
|
};
|
|
4320
4479
|
};
|
|
4321
|
-
const COMMON_USAGE =
|
|
4480
|
+
const COMMON_USAGE = `[--url <origin>] [--token <admin token>] [--site <key>] [--dir schema] [--lock .shapio/schema-lock.json]`;
|
|
4322
4481
|
const POLL_INTERVAL_MS = 500;
|
|
4323
4482
|
/** Waits for planned changes (prerequisite jobs) to activate or fail. Returns the failed ones. */
|
|
4324
4483
|
const waitForChanges = async (options, items, io) => {
|
|
@@ -4350,16 +4509,18 @@ const waitForChanges = async (options, items, io) => {
|
|
|
4350
4509
|
};
|
|
4351
4510
|
/**
|
|
4352
4511
|
* Records the new state in the lock file and rewrites the files of applied definitions in canonical form
|
|
4353
|
-
* (e.g. with server-assigned field IDs). Definitions skipped because they were
|
|
4354
|
-
* their old base, so a later apply still treats them as untouched.
|
|
4512
|
+
* (e.g. with server-assigned field IDs), in their scope's folder. Definitions skipped because they were
|
|
4513
|
+
* unchanged locally keep their old base, so a later apply still treats them as untouched. Other sites'
|
|
4514
|
+
* entries are kept as they are.
|
|
4355
4515
|
*/
|
|
4356
4516
|
const updateLocalState = async (options, state, response) => {
|
|
4357
4517
|
const exported = await apiFor(options).export();
|
|
4358
4518
|
const remote = new Map(exported.definitions.map((entry) => [entry.definition.id, entry]));
|
|
4519
|
+
const upgraded = upgradeLockFile(state.lock);
|
|
4359
4520
|
const lock = {
|
|
4360
|
-
...
|
|
4521
|
+
...upgraded,
|
|
4361
4522
|
schemaVersion: exported.schemaVersion,
|
|
4362
|
-
definitions: { ...
|
|
4523
|
+
definitions: { ...upgraded.definitions }
|
|
4363
4524
|
};
|
|
4364
4525
|
for (const item of response.results) {
|
|
4365
4526
|
if (!(item.outcome === "activated" || item.decision.action === "skip" && item.decision.reason === "alreadyApplied")) continue;
|
|
@@ -4368,97 +4529,152 @@ const updateLocalState = async (options, state, response) => {
|
|
|
4368
4529
|
delete lock.definitions[item.definitionId];
|
|
4369
4530
|
continue;
|
|
4370
4531
|
}
|
|
4371
|
-
const previous = state.
|
|
4372
|
-
const path = await writeDefinitionFile(options.dir, entry.definition);
|
|
4532
|
+
const previous = state.sent.find((file) => file.id === item.definitionId);
|
|
4533
|
+
const path = await writeDefinitionFile(options.dir, entry.definition, entry.site);
|
|
4373
4534
|
if (previous && previous.path !== path) await removeFile(previous.path);
|
|
4374
4535
|
lock.definitions[item.definitionId] = {
|
|
4375
4536
|
kind: entry.definition.kind,
|
|
4376
4537
|
apiKey: entry.definition.apiKey,
|
|
4377
4538
|
version: entry.version,
|
|
4378
|
-
hash: entry.hash
|
|
4539
|
+
hash: entry.hash,
|
|
4540
|
+
site: entry.site
|
|
4379
4541
|
};
|
|
4380
4542
|
}
|
|
4381
|
-
await writeLockFile(options.lockPath, lock);
|
|
4543
|
+
await writeLockFile(options.lockPath, coverSiteIfHeld(lock, state.siteKey));
|
|
4544
|
+
};
|
|
4545
|
+
/**
|
|
4546
|
+
* `shapio schema apply`: applies local schema files to a running instance live, through the same planner as
|
|
4547
|
+
* the admin UI. Three-way per definition against the lock file; refuses (and changes nothing) on conflicts.
|
|
4548
|
+
* It sends the shared files and the site's own (`sites/<key>/`), never another site's.
|
|
4549
|
+
*/
|
|
4550
|
+
const schemaApplyCommand = {
|
|
4551
|
+
summary: "Apply local schema files to the instance live (three-way, per model; refuses on conflicts)",
|
|
4552
|
+
usage: `shapio schema apply ${COMMON_USAGE} [--prune] [--allow-breaking] [--allow-destructive] [--no-wait] [--wait-timeout <s>]`,
|
|
4553
|
+
run: async (args, io) => {
|
|
4554
|
+
const options = parseSchemaOptions(args, io);
|
|
4555
|
+
const state = await readSiteState(options, io);
|
|
4556
|
+
if (!state) return 1;
|
|
4557
|
+
const response = await sendApply(options, state, false, io);
|
|
4558
|
+
if (!response) return 1;
|
|
4559
|
+
printResults(response, state, io, false);
|
|
4560
|
+
const pending = response.results.filter((item) => item.outcome === "pending");
|
|
4561
|
+
const failed = options.wait ? await waitForChanges(options, pending, io) : [];
|
|
4562
|
+
await updateLocalState(options, state, response);
|
|
4563
|
+
const applied = response.results.filter((item) => item.outcome === "activated").length;
|
|
4564
|
+
io.stdout(`Applied ${applied} definition(s) at schema version ${response.schemaVersion}.\n`);
|
|
4565
|
+
return failed.length > 0 ? 1 : 0;
|
|
4566
|
+
}
|
|
4567
|
+
};
|
|
4568
|
+
/** `shapio schema diff`: what `apply` would do, per definition, without changing anything. */
|
|
4569
|
+
const schemaDiffCommand = {
|
|
4570
|
+
summary: "Show what `shapio schema apply` would change on the instance (dry run)",
|
|
4571
|
+
usage: `shapio schema diff ${COMMON_USAGE} [--prune]`,
|
|
4572
|
+
run: async (args, io) => {
|
|
4573
|
+
const options = parseSchemaOptions(args, io);
|
|
4574
|
+
const state = await readSiteState(options, io);
|
|
4575
|
+
if (!state) return 1;
|
|
4576
|
+
const response = await sendApply(options, state, true, io);
|
|
4577
|
+
if (!response) return 1;
|
|
4578
|
+
printResults(response, state, io, false);
|
|
4579
|
+
const pending = response.results.filter((item) => [
|
|
4580
|
+
"create",
|
|
4581
|
+
"update",
|
|
4582
|
+
"delete"
|
|
4583
|
+
].includes(item.decision.action));
|
|
4584
|
+
io.stdout(pending.length === 0 ? "Nothing to apply.\n" : `${pending.length} definition(s) would change.\n`);
|
|
4585
|
+
return 0;
|
|
4586
|
+
}
|
|
4587
|
+
};
|
|
4588
|
+
/**
|
|
4589
|
+
* `shapio schema pull`: writes one site's view of the instance (the shared definitions in `models/` and
|
|
4590
|
+
* `components/`, the site's own under `sites/<key>/`) as canonical JSON, one file per model or component,
|
|
4591
|
+
* and records what was pulled in the lock file. Another site's folder and lock entries are left alone, so one
|
|
4592
|
+
* tree can hold several sites. Refuses to overwrite local edits in the pulled folders unless --force.
|
|
4593
|
+
*/
|
|
4594
|
+
const schemaPullCommand = {
|
|
4595
|
+
summary: "Write a site’s models and components (shared and its own) to schema files and the lock file",
|
|
4596
|
+
usage: `shapio schema pull ${COMMON_USAGE} [--force]`,
|
|
4597
|
+
run: async (args, io) => {
|
|
4598
|
+
const options = parseSchemaOptions(args, io);
|
|
4599
|
+
const exported = await apiFor(options).export();
|
|
4600
|
+
if (!exported.site) throw new Error("The instance did not say which site this view is; pass --site <key>");
|
|
4601
|
+
const siteKey = exported.site.key;
|
|
4602
|
+
const state = await readLocalState(options);
|
|
4603
|
+
const edited = editedFilesForSite(state.files, state.lock, siteKey);
|
|
4604
|
+
if (edited.length > 0 && !options.force) {
|
|
4605
|
+
io.stderr(`Local schema files have changes that are not on the instance:\n${edited.map((file) => ` ${displayPath(file.path)}`).join("\n")}\nApply them first, or commit them and re-run with --force to overwrite them with the instance’s schema.
|
|
4606
|
+
`);
|
|
4607
|
+
return 1;
|
|
4608
|
+
}
|
|
4609
|
+
const written = /* @__PURE__ */ new Map();
|
|
4610
|
+
for (const { definition, site } of exported.definitions) written.set(definition.id, await writeDefinitionFile(options.dir, definition, site));
|
|
4611
|
+
for (const file of staleFilesAfterPull(state.files, siteKey, written)) await removeFile(file.path);
|
|
4612
|
+
await writeLockFile(options.lockPath, mergePulledLock(state.lock, {
|
|
4613
|
+
schemaVersion: exported.schemaVersion,
|
|
4614
|
+
siteKey,
|
|
4615
|
+
definitions: exported.definitions
|
|
4616
|
+
}));
|
|
4617
|
+
io.stdout(`Pulled ${exported.definitions.length} definition(s) of site "${siteKey}" at schema version ${exported.schemaVersion} into ${displayPath(options.dir)}\n`);
|
|
4618
|
+
return 0;
|
|
4619
|
+
}
|
|
4620
|
+
};
|
|
4621
|
+
const parseScopeOptions = (args, io) => {
|
|
4622
|
+
const { values, positionals } = parseArgs({
|
|
4623
|
+
args: [...args],
|
|
4624
|
+
options: {
|
|
4625
|
+
...CONNECTION_FLAGS,
|
|
4626
|
+
shared: {
|
|
4627
|
+
type: "boolean",
|
|
4628
|
+
default: false
|
|
4629
|
+
},
|
|
4630
|
+
version: { type: "string" }
|
|
4631
|
+
},
|
|
4632
|
+
allowPositionals: true
|
|
4633
|
+
});
|
|
4634
|
+
const [apiKey, ...extra] = positionals;
|
|
4635
|
+
if (!apiKey || extra.length > 0) throw new UsageError("Name one model or component by its API ID");
|
|
4636
|
+
if (!values.shared && !values.site) throw new UsageError("Pass --site <key> to keep it on that site, or --shared to share it with all sites");
|
|
4637
|
+
const version = values.version === void 0 ? void 0 : Number(values.version);
|
|
4638
|
+
if (version !== void 0 && (!Number.isInteger(version) || version < 1)) throw new UsageError("--version must be a positive integer");
|
|
4639
|
+
return {
|
|
4640
|
+
...resolveConnection(values, io),
|
|
4641
|
+
apiKey,
|
|
4642
|
+
shared: values.shared,
|
|
4643
|
+
version
|
|
4644
|
+
};
|
|
4382
4645
|
};
|
|
4383
4646
|
const SUBCOMMANDS$1 = {
|
|
4384
|
-
pull:
|
|
4385
|
-
|
|
4386
|
-
|
|
4647
|
+
pull: schemaPullCommand,
|
|
4648
|
+
diff: schemaDiffCommand,
|
|
4649
|
+
apply: schemaApplyCommand,
|
|
4650
|
+
scope: {
|
|
4651
|
+
summary: "Keep a shared model or component on one site (--site), or share a site’s with all sites (--shared)",
|
|
4652
|
+
usage: "shapio schema scope <apiKey> (--site <key> | --shared [--site <key>]) [--url <origin>] [--token <admin token>] [--version <n>]",
|
|
4387
4653
|
run: async (args, io) => {
|
|
4388
|
-
const options =
|
|
4389
|
-
const
|
|
4390
|
-
const
|
|
4391
|
-
|
|
4392
|
-
|
|
4393
|
-
|
|
4394
|
-
|
|
4395
|
-
io.stderr(`Local schema files have changes that are not on the instance:\n${edited.map((file) => ` ${displayPath(file.path)}`).join("\n")}\nApply them first, or commit them and re-run with --force to overwrite them with the instance’s schema.
|
|
4396
|
-
`);
|
|
4654
|
+
const options = parseScopeOptions(args, io);
|
|
4655
|
+
const client = clientFor(options);
|
|
4656
|
+
const exported = await client.admin.schema.export();
|
|
4657
|
+
const siteKey = options.site ?? exported.site?.key ?? "(default)";
|
|
4658
|
+
const found = exported.definitions.find(({ definition }) => definition.apiKey === options.apiKey);
|
|
4659
|
+
if (!found) {
|
|
4660
|
+
io.stderr(`Site "${siteKey}" has no model or component with API ID "${options.apiKey}".\n`);
|
|
4397
4661
|
return 1;
|
|
4398
4662
|
}
|
|
4399
|
-
const
|
|
4400
|
-
|
|
4401
|
-
|
|
4402
|
-
|
|
4403
|
-
|
|
4404
|
-
};
|
|
4405
|
-
const written = /* @__PURE__ */ new Set();
|
|
4406
|
-
for (const { definition, version, hash } of exported.definitions) {
|
|
4407
|
-
written.add(await writeDefinitionFile(options.dir, definition));
|
|
4408
|
-
lock.definitions[definition.id] = {
|
|
4409
|
-
kind: definition.kind,
|
|
4410
|
-
apiKey: definition.apiKey,
|
|
4411
|
-
version,
|
|
4412
|
-
hash
|
|
4413
|
-
};
|
|
4414
|
-
}
|
|
4415
|
-
for (const file of state.files.filter((candidate) => !written.has(candidate.path))) await removeFile(file.path);
|
|
4416
|
-
await writeLockFile(options.lockPath, lock);
|
|
4417
|
-
io.stdout(`Pulled ${exported.definitions.length} definition(s) at schema version ${exported.schemaVersion} into ${displayPath(options.dir)}\n`);
|
|
4418
|
-
return 0;
|
|
4419
|
-
}
|
|
4420
|
-
},
|
|
4421
|
-
diff: {
|
|
4422
|
-
summary: "Show what `shapio schema apply` would change on the instance (dry run)",
|
|
4423
|
-
usage: `shapio schema diff ${COMMON_USAGE} [--prune]`,
|
|
4424
|
-
run: async (args, io) => {
|
|
4425
|
-
const options = parseSchemaOptions(args, io);
|
|
4426
|
-
const state = await readLocalState(options);
|
|
4427
|
-
const response = await sendApply(options, state, true, io);
|
|
4428
|
-
if (!response) return 1;
|
|
4429
|
-
printResults(response, state, io, false);
|
|
4430
|
-
const pending = response.results.filter((item) => [
|
|
4431
|
-
"create",
|
|
4432
|
-
"update",
|
|
4433
|
-
"delete"
|
|
4434
|
-
].includes(item.decision.action));
|
|
4435
|
-
io.stdout(pending.length === 0 ? "Nothing to apply.\n" : `${pending.length} definition(s) would change.\n`);
|
|
4663
|
+
const outcome = await (found.definition.kind === "component" ? client.admin.components : client.admin.models).changeScope(found.definition.id, {
|
|
4664
|
+
scope: options.shared ? "network" : "site",
|
|
4665
|
+
version: options.version ?? found.version
|
|
4666
|
+
});
|
|
4667
|
+
const where = outcome.scope === "network" ? "shared with all sites" : `on site "${siteKey}" only`;
|
|
4668
|
+
io.stdout(outcome.status === "unchanged" ? `${options.apiKey} is already ${where}.\n` : `${options.apiKey} is now ${where} (version ${outcome.version}, schema version ${outcome.schemaVersion}).\nPull to move its file: shapio schema pull --site ${siteKey}\n`);
|
|
4436
4669
|
return 0;
|
|
4437
4670
|
}
|
|
4438
|
-
},
|
|
4439
|
-
apply: {
|
|
4440
|
-
summary: "Apply local schema files to the instance live (three-way, per model; refuses on conflicts)",
|
|
4441
|
-
usage: `shapio schema apply ${COMMON_USAGE} [--prune] [--allow-breaking] [--allow-destructive] [--no-wait] [--wait-timeout <s>]`,
|
|
4442
|
-
run: async (args, io) => {
|
|
4443
|
-
const options = parseSchemaOptions(args, io);
|
|
4444
|
-
const state = await readLocalState(options);
|
|
4445
|
-
const response = await sendApply(options, state, false, io);
|
|
4446
|
-
if (!response) return 1;
|
|
4447
|
-
printResults(response, state, io, false);
|
|
4448
|
-
const pending = response.results.filter((item) => item.outcome === "pending");
|
|
4449
|
-
const failed = options.wait ? await waitForChanges(options, pending, io) : [];
|
|
4450
|
-
await updateLocalState(options, state, response);
|
|
4451
|
-
const applied = response.results.filter((item) => item.outcome === "activated").length;
|
|
4452
|
-
io.stdout(`Applied ${applied} definition(s) at schema version ${response.schemaVersion}.\n`);
|
|
4453
|
-
return failed.length > 0 ? 1 : 0;
|
|
4454
|
-
}
|
|
4455
4671
|
}
|
|
4456
4672
|
};
|
|
4457
4673
|
const help$1 = () => `Usage:\n${Object.values(SUBCOMMANDS$1).map((command) => ` ${command.usage}\n ${command.summary}`).join("\n")}\n`;
|
|
4458
|
-
/** `shapio schema <pull|diff|apply>`: git-like schema sync over HTTP with an admin API token. */
|
|
4674
|
+
/** `shapio schema <pull|diff|apply|scope>`: git-like schema sync over HTTP with an admin API token. */
|
|
4459
4675
|
const schemaCommand = {
|
|
4460
|
-
summary: "Sync models and components with schema files: pull | diff | apply",
|
|
4461
|
-
usage: "shapio schema <pull|diff|apply> [options]",
|
|
4676
|
+
summary: "Sync models and components with schema files: pull | diff | apply | scope",
|
|
4677
|
+
usage: "shapio schema <pull|diff|apply|scope> [options]",
|
|
4462
4678
|
run: async (args, io) => {
|
|
4463
4679
|
const [name, ...rest] = args;
|
|
4464
4680
|
const command = name ? SUBCOMMANDS$1[name] : void 0;
|
|
@@ -4473,6 +4689,10 @@ const schemaCommand = {
|
|
|
4473
4689
|
io.stderr(`shapio schema ${name}: ${error.message}\n`);
|
|
4474
4690
|
return 1;
|
|
4475
4691
|
}
|
|
4692
|
+
if (error instanceof ShapioApiError) {
|
|
4693
|
+
io.stderr(formatApiError(error, [], /* @__PURE__ */ new Map()));
|
|
4694
|
+
return 1;
|
|
4695
|
+
}
|
|
4476
4696
|
throw error;
|
|
4477
4697
|
}
|
|
4478
4698
|
}
|
|
@@ -5050,7 +5270,7 @@ const adminCommand = {
|
|
|
5050
5270
|
}
|
|
5051
5271
|
}
|
|
5052
5272
|
};
|
|
5053
|
-
const SITES_USAGE = "shapio sites list\nshapio sites create --key <key> --name <name>\n Lists or creates sites directly in the database (sites share the
|
|
5273
|
+
const SITES_USAGE = "shapio sites list\nshapio sites create --key <key> --name <name>\n Lists or creates sites directly in the database (sites share the admins, roles and shared content types;\n each has its own content types, content, media, tokens and snapshots). Keys are lower case and fixed once\n created.";
|
|
5054
5274
|
const SITE_KEY_RE = new RegExp(SITE_KEY_PATTERN);
|
|
5055
5275
|
const runSites = async (subcommand, options, io) => {
|
|
5056
5276
|
const config = loadConfig();
|