@shapio/cms 0.5.6 → 0.5.8
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-_qRYsivK.js → AssetTile-BrMzsUZD.js} +2 -2
- package/dist/admin/assets/{AssetTile-_qRYsivK.js.map → AssetTile-BrMzsUZD.js.map} +1 -1
- package/dist/admin/assets/AssistError-Cs-r9Ssc.js +2 -0
- package/dist/admin/assets/{AssistError-CMXQWiQo.js.map → AssistError-Cs-r9Ssc.js.map} +1 -1
- package/dist/admin/assets/{BlockMenuItems-WIrbyv1a.js → BlockMenuItems-DsccXMc_.js} +2 -2
- package/dist/admin/assets/{BlockMenuItems-WIrbyv1a.js.map → BlockMenuItems-DsccXMc_.js.map} +1 -1
- package/dist/admin/assets/Body-BzZD-TZT.js +2 -0
- package/dist/admin/assets/{Body-BYc1IVsQ.js.map → Body-BzZD-TZT.js.map} +1 -1
- package/dist/admin/assets/Builder-DW-GJA_q.js +2 -0
- package/dist/admin/assets/Builder-DW-GJA_q.js.map +1 -0
- package/dist/admin/assets/{CodeEditor-NMvrWgxT.js → CodeEditor-CBCR73Wd.js} +2 -2
- package/dist/admin/assets/{CodeEditor-NMvrWgxT.js.map → CodeEditor-CBCR73Wd.js.map} +1 -1
- package/dist/admin/assets/{CopyButton-B0RuxynJ.js → CopyButton-CxFsBHfF.js} +2 -2
- package/dist/admin/assets/{CopyButton-B0RuxynJ.js.map → CopyButton-CxFsBHfF.js.map} +1 -1
- package/dist/admin/assets/{CursorPager-CQZsKNxR.js → CursorPager-BW2U3v6l.js} +2 -2
- package/dist/admin/assets/{CursorPager-CQZsKNxR.js.map → CursorPager-BW2U3v6l.js.map} +1 -1
- package/dist/admin/assets/{ExternalLink-BNq7nAYL.js → ExternalLink-BITMgS1K.js} +2 -2
- package/dist/admin/assets/{ExternalLink-BNq7nAYL.js.map → ExternalLink-BITMgS1K.js.map} +1 -1
- package/dist/admin/assets/{FocalPoint-BYu2fOTb.js → FocalPoint-CpZTve1E.js} +2 -2
- package/dist/admin/assets/{FocalPoint-BYu2fOTb.js.map → FocalPoint-CpZTve1E.js.map} +1 -1
- package/dist/admin/assets/Form-lNrRHc0I.js +2 -0
- package/dist/admin/assets/Form-lNrRHc0I.js.map +1 -0
- package/dist/admin/assets/{FormCheckboxGroup-Bz8KERs1.js → FormCheckboxGroup-DeeaYnzB.js} +2 -2
- package/dist/admin/assets/FormCheckboxGroup-DeeaYnzB.js.map +1 -0
- package/dist/admin/assets/{FormRadioGroup-c-wyx7dq.js → FormRadioGroup-Cfx5pvzU.js} +2 -2
- package/dist/admin/assets/{FormRadioGroup-c-wyx7dq.js.map → FormRadioGroup-Cfx5pvzU.js.map} +1 -1
- package/dist/admin/assets/{FormSelectField-ijG9qPpb.js → FormSelectField-BzE9Lq9i.js} +2 -2
- package/dist/admin/assets/{FormSelectField-ijG9qPpb.js.map → FormSelectField-BzE9Lq9i.js.map} +1 -1
- package/dist/admin/assets/{FormSwitchField-Bp3hNpeP.js → FormSwitchField-BLOh7qei.js} +2 -2
- package/dist/admin/assets/{FormSwitchField-Bp3hNpeP.js.map → FormSwitchField-BLOh7qei.js.map} +1 -1
- package/dist/admin/assets/{FormTextareaField-BSKMqHcW.js → FormTextareaField-CO115n_u.js} +2 -2
- package/dist/admin/assets/{FormTextareaField-BSKMqHcW.js.map → FormTextareaField-CO115n_u.js.map} +1 -1
- package/dist/admin/assets/{HintedLabel-BrLH4NQW.js → HintedLabel-DzHnEdIK.js} +2 -2
- package/dist/admin/assets/{HintedLabel-BrLH4NQW.js.map → HintedLabel-DzHnEdIK.js.map} +1 -1
- package/dist/admin/assets/{InfoHint-Dyzyf59c.js → InfoHint-CSEtcHjL.js} +2 -2
- package/dist/admin/assets/{InfoHint-Dyzyf59c.js.map → InfoHint-CSEtcHjL.js.map} +1 -1
- package/dist/admin/assets/InlineConfirm-yW-iUKFC.js +2 -0
- package/dist/admin/assets/InlineConfirm-yW-iUKFC.js.map +1 -0
- package/dist/admin/assets/InsertMenuItem-CCr9e0qY.js +2 -0
- package/dist/admin/assets/InsertMenuItem-CCr9e0qY.js.map +1 -0
- package/dist/admin/assets/{LinkTabs-ByB2eCIr.js → LinkTabs-8SmS1vCd.js} +2 -2
- package/dist/admin/assets/{LinkTabs-ByB2eCIr.js.map → LinkTabs-8SmS1vCd.js.map} +1 -1
- package/dist/admin/assets/{Match-Bixf1ygj.js → Match-CcD9KxHH.js} +2 -2
- package/dist/admin/assets/{Match-Bixf1ygj.js.map → Match-CcD9KxHH.js.map} +1 -1
- package/dist/admin/assets/NoAccess-C8RLPN0I.js +2 -0
- package/dist/admin/assets/NoAccess-C8RLPN0I.js.map +1 -0
- package/dist/admin/assets/Panel-Bcl09TtM.js +2 -0
- package/dist/admin/assets/Panel-Bcl09TtM.js.map +1 -0
- package/dist/admin/assets/{QueryView--_vvV7dC.js → QueryView-xMP_uJ_t.js} +2 -2
- package/dist/admin/assets/{QueryView--_vvV7dC.js.map → QueryView-xMP_uJ_t.js.map} +1 -1
- package/dist/admin/assets/{RadioTile-BCp6auUz.js → RadioTile-DQFmni5A.js} +2 -2
- package/dist/admin/assets/{RadioTile-BCp6auUz.js.map → RadioTile-DQFmni5A.js.map} +1 -1
- package/dist/admin/assets/{RichTextField-fWNjndUc.js → RichTextField-CVHRIbnu.js} +5 -5
- package/dist/admin/assets/{RichTextField-fWNjndUc.js.map → RichTextField-CVHRIbnu.js.map} +1 -1
- package/dist/admin/assets/{RowTitle-B4CE8tt7.js → RowTitle-Bqt6evG9.js} +2 -2
- package/dist/admin/assets/{RowTitle-B4CE8tt7.js.map → RowTitle-Bqt6evG9.js.map} +1 -1
- package/dist/admin/assets/SecretReveal-Bm6nYg5J.js +2 -0
- package/dist/admin/assets/SecretReveal-Bm6nYg5J.js.map +1 -0
- package/dist/admin/assets/{SharedGlyph-71FTypoi.js → SharedGlyph-cUmTh0_C.js} +2 -2
- package/dist/admin/assets/{SharedGlyph-71FTypoi.js.map → SharedGlyph-cUmTh0_C.js.map} +1 -1
- package/dist/admin/assets/StepList-BXGYD9eJ.js +2 -0
- package/dist/admin/assets/StepList-BXGYD9eJ.js.map +1 -0
- package/dist/admin/assets/Structure-D8csgrIt.js +2 -0
- package/dist/admin/assets/{Structure-Dk87778W.js.map → Structure-D8csgrIt.js.map} +1 -1
- package/dist/admin/assets/{SubNavLink-CPJFIt1j.js → SubNavLink-CiCaVV8U.js} +2 -2
- package/dist/admin/assets/{SubNavLink-CPJFIt1j.js.map → SubNavLink-CiCaVV8U.js.map} +1 -1
- package/dist/admin/assets/{SuggestAltButton-CxS8IR6m.js → SuggestAltButton-CvIoirnz.js} +2 -2
- package/dist/admin/assets/{SuggestAltButton-CxS8IR6m.js.map → SuggestAltButton-CvIoirnz.js.map} +1 -1
- package/dist/admin/assets/{TextLink-DnrMaF2F.js → TextLink-HRn66VL1.js} +2 -2
- package/dist/admin/assets/{TextLink-DnrMaF2F.js.map → TextLink-HRn66VL1.js.map} +1 -1
- package/dist/admin/assets/Thumbnail-DNj5TRBI.js +2 -0
- package/dist/admin/assets/Thumbnail-DNj5TRBI.js.map +1 -0
- package/dist/admin/assets/UnsavedChangesGuard-CUiuMklN.js +2 -0
- package/dist/admin/assets/UnsavedChangesGuard-CUiuMklN.js.map +1 -0
- package/dist/admin/assets/{UserAvatar-D7IbSpsP.js → UserAvatar-p-jV-LoD.js} +2 -2
- package/dist/admin/assets/{UserAvatar-D7IbSpsP.js.map → UserAvatar-p-jV-LoD.js.map} +1 -1
- package/dist/admin/assets/auth-CQO4MBUj.js +2 -0
- package/dist/admin/assets/auth-CQO4MBUj.js.map +1 -0
- package/dist/admin/assets/badge-CqKF1pwz.js +2 -0
- package/dist/admin/assets/{badge-vLiQczOd.js.map → badge-CqKF1pwz.js.map} +1 -1
- package/dist/admin/assets/{boxes-D6Y4Cenx.js → boxes-CAygw8zF.js} +2 -2
- package/dist/admin/assets/{boxes-D6Y4Cenx.js.map → boxes-CAygw8zF.js.map} +1 -1
- package/dist/admin/assets/{calendar-clock-DFUgXWXg.js → calendar-clock-BZGtAvWR.js} +2 -2
- package/dist/admin/assets/{calendar-clock-DFUgXWXg.js.map → calendar-clock-BZGtAvWR.js.map} +1 -1
- package/dist/admin/assets/changeSets-8EburmT0.js +2 -0
- package/dist/admin/assets/changeSets-8EburmT0.js.map +1 -0
- package/dist/admin/assets/chevron-left-DGU3HGYG.js +2 -0
- package/dist/admin/assets/{chevron-left-CZXrLV99.js.map → chevron-left-DGU3HGYG.js.map} +1 -1
- package/dist/admin/assets/{circle-check-De27poaB.js → circle-check-C37MSJqX.js} +2 -2
- package/dist/admin/assets/{circle-check-De27poaB.js.map → circle-check-C37MSJqX.js.map} +1 -1
- package/dist/admin/assets/{clock-BGAXsuo4.js → clock-2arjsgZ4.js} +2 -2
- package/dist/admin/assets/{clock-BGAXsuo4.js.map → clock-2arjsgZ4.js.map} +1 -1
- package/dist/admin/assets/{constants-CKGh8uwT.js → constants-a_15vqOh.js} +2 -2
- package/dist/admin/assets/{constants-CKGh8uwT.js.map → constants-a_15vqOh.js.map} +1 -1
- package/dist/admin/assets/content-CAjkbZEY.js +3 -0
- package/dist/admin/assets/content-CAjkbZEY.js.map +1 -0
- package/dist/admin/assets/contentCounts-DP7YYeZZ.js +2 -0
- package/dist/admin/assets/{contentCounts-DknqJ4kh.js.map → contentCounts-DP7YYeZZ.js.map} +1 -1
- package/dist/admin/assets/{contentTypes-DzQ_0v36.js → contentTypes-84uc0bjR.js} +2 -2
- package/dist/admin/assets/{contentTypes-DzQ_0v36.js.map → contentTypes-84uc0bjR.js.map} +1 -1
- package/dist/admin/assets/context-IKYdzQJ-.js +2 -0
- package/dist/admin/assets/{context-fImO9k99.js.map → context-IKYdzQJ-.js.map} +1 -1
- package/dist/admin/assets/{copy-B5owk67M.js → copy-CsSRHgKZ.js} +2 -2
- package/dist/admin/assets/{copy-B5owk67M.js.map → copy-CsSRHgKZ.js.map} +1 -1
- package/dist/admin/assets/createLucideIcon-CLmh7Go-.js +2 -0
- package/dist/admin/assets/createLucideIcon-CLmh7Go-.js.map +1 -0
- package/dist/admin/assets/develop-BOqvnlgt.js +11 -0
- package/dist/admin/assets/develop-BOqvnlgt.js.map +1 -0
- package/dist/admin/assets/{dropdown-menu-CVAnm22s.js → dropdown-menu-_xfaEp5C.js} +2 -2
- package/dist/admin/assets/{dropdown-menu-CVAnm22s.js.map → dropdown-menu-_xfaEp5C.js.map} +1 -1
- package/dist/admin/assets/{ellipsis-BHtU4ov6.js → ellipsis-F91991on.js} +2 -2
- package/dist/admin/assets/{ellipsis-BHtU4ov6.js.map → ellipsis-F91991on.js.map} +1 -1
- package/dist/admin/assets/entryLink-CVB-TdIn.js +2 -0
- package/dist/admin/assets/entryLink-CVB-TdIn.js.map +1 -0
- package/dist/admin/assets/es2015-BHmI7wjK.js +42 -0
- package/dist/admin/assets/es2015-BHmI7wjK.js.map +1 -0
- package/dist/admin/assets/{external-link-nZp2VpKw.js → external-link-CdG6kHfA.js} +2 -2
- package/dist/admin/assets/{external-link-nZp2VpKw.js.map → external-link-CdG6kHfA.js.map} +1 -1
- package/dist/admin/assets/{field-Bg-JRgsB.js → field-COOzRptX.js} +2 -2
- package/dist/admin/assets/{field-Bg-JRgsB.js.map → field-COOzRptX.js.map} +1 -1
- package/dist/admin/assets/{file-stack-8rRouTJj.js → file-stack-28ZtO1xW.js} +2 -2
- package/dist/admin/assets/{file-stack-8rRouTJj.js.map → file-stack-28ZtO1xW.js.map} +1 -1
- package/dist/admin/assets/{fileRoute-DQCI1nMN.js → fileRoute-s7mCMYUJ.js} +2 -2
- package/dist/admin/assets/{fileRoute-DQCI1nMN.js.map → fileRoute-s7mCMYUJ.js.map} +1 -1
- package/dist/admin/assets/{folder-plus-B3L3b389.js → folder-plus-DIk0pWkP.js} +2 -2
- package/dist/admin/assets/{folder-plus-B3L3b389.js.map → folder-plus-DIk0pWkP.js.map} +1 -1
- package/dist/admin/assets/followPlural-Cm7v_Udv.js +2 -0
- package/dist/admin/assets/followPlural-Cm7v_Udv.js.map +1 -0
- package/dist/admin/assets/{globe-DKkjr9MZ.js → globe-DFr3Gd2w.js} +2 -2
- package/dist/admin/assets/{globe-DKkjr9MZ.js.map → globe-DFr3Gd2w.js.map} +1 -1
- package/dist/admin/assets/{image-B6aL7hP8.js → image-DT79QFa_.js} +2 -2
- package/dist/admin/assets/{image-B6aL7hP8.js.map → image-DT79QFa_.js.map} +1 -1
- package/dist/admin/assets/{image-off-TVxEyb74.js → image-off-DFs5upyX.js} +2 -2
- package/dist/admin/assets/{image-off-TVxEyb74.js.map → image-off-DFs5upyX.js.map} +1 -1
- package/dist/admin/assets/{inbox-BKqu1EfP.js → inbox-CySnQydm.js} +2 -2
- package/dist/admin/assets/{inbox-BKqu1EfP.js.map → inbox-CySnQydm.js.map} +1 -1
- package/dist/admin/assets/inbox-DGO2D8fa.js +2 -0
- package/dist/admin/assets/inbox-DGO2D8fa.js.map +1 -0
- package/dist/admin/assets/index-BIIU9ZI6.js +4 -0
- package/dist/admin/assets/index-BIIU9ZI6.js.map +1 -0
- package/dist/admin/assets/index-lxe7WimO.css +2 -0
- package/dist/admin/assets/{key-round-Dmdr1vP5.js → key-round-D36CePnN.js} +2 -2
- package/dist/admin/assets/{key-round-Dmdr1vP5.js.map → key-round-D36CePnN.js.map} +1 -1
- package/dist/admin/assets/{labels-BrwwGWnv.js → labels-DQckbLGW.js} +2 -2
- package/dist/admin/assets/{labels-BrwwGWnv.js.map → labels-DQckbLGW.js.map} +1 -1
- package/dist/admin/assets/{languages-BbfFIygP.js → languages-CzbTaQv9.js} +2 -2
- package/dist/admin/assets/{languages-BbfFIygP.js.map → languages-CzbTaQv9.js.map} +1 -1
- package/dist/admin/assets/{layers-B0jT4rc4.js → layers-BmcodiaH.js} +2 -2
- package/dist/admin/assets/{layers-B0jT4rc4.js.map → layers-BmcodiaH.js.map} +1 -1
- package/dist/admin/assets/{link-2-off-DC06jLDj.js → link-2-off-CoJNwrxm.js} +2 -2
- package/dist/admin/assets/{link-2-off-DC06jLDj.js.map → link-2-off-CoJNwrxm.js.map} +1 -1
- package/dist/admin/assets/{link-B3O0VUVT.js → link-Pyr2Y35S.js} +2 -2
- package/dist/admin/assets/{link-B3O0VUVT.js.map → link-Pyr2Y35S.js.map} +1 -1
- package/dist/admin/assets/locales-Bg3htKo8.js +2 -0
- package/dist/admin/assets/{locales-e7B5t6id.js.map → locales-Bg3htKo8.js.map} +1 -1
- package/dist/admin/assets/media-BCnVhaDH.js +2 -0
- package/dist/admin/assets/{media-VCJUbYzJ.js.map → media-BCnVhaDH.js.map} +1 -1
- package/dist/admin/assets/media-CURizGns.js +2 -0
- package/dist/admin/assets/media-CURizGns.js.map +1 -0
- package/dist/admin/assets/network-BixABr0o.js +2 -0
- package/dist/admin/assets/network-BixABr0o.js.map +1 -0
- package/dist/admin/assets/{plus-WfYKHW7G.js → plus-BoDtdLCo.js} +2 -2
- package/dist/admin/assets/{plus-WfYKHW7G.js.map → plus-BoDtdLCo.js.map} +1 -1
- package/dist/admin/assets/publishing-Dke9bSKp.js +2 -0
- package/dist/admin/assets/{publishing-CpSDO3M7.js.map → publishing-Dke9bSKp.js.map} +1 -1
- package/dist/admin/assets/{radio-group-DQ3sC1ol.js → radio-group-4ok5evXq.js} +2 -2
- package/dist/admin/assets/{radio-group-DQ3sC1ol.js.map → radio-group-4ok5evXq.js.map} +1 -1
- package/dist/admin/assets/{rotate-ccw-Cvc_uA58.js → rotate-ccw-DL6TzcZh.js} +2 -2
- package/dist/admin/assets/{rotate-ccw-Cvc_uA58.js.map → rotate-ccw-DL6TzcZh.js.map} +1 -1
- package/dist/admin/assets/schedules-BmB9Y73z.js +2 -0
- package/dist/admin/assets/{schedules-CBGpjEg7.js.map → schedules-BmB9Y73z.js.map} +1 -1
- package/dist/admin/assets/schema-D-qo7XSF.js +2 -0
- package/dist/admin/assets/schema-D-qo7XSF.js.map +1 -0
- package/dist/admin/assets/{scroll-text-gKYBbibb.js → scroll-text-PqeZm472.js} +2 -2
- package/dist/admin/assets/{scroll-text-gKYBbibb.js.map → scroll-text-PqeZm472.js.map} +1 -1
- package/dist/admin/assets/{search-CW3iBC4k.js → search-BdwIwOzC.js} +2 -2
- package/dist/admin/assets/{search-CW3iBC4k.js.map → search-BdwIwOzC.js.map} +1 -1
- package/dist/admin/assets/searchSchemas-CSScloG8.js +2 -0
- package/dist/admin/assets/{searchSchemas-D4S2ceA0.js.map → searchSchemas-CSScloG8.js.map} +1 -1
- package/dist/admin/assets/{sections-CN5fIoAr.js → sections-BTS683ur.js} +2 -2
- package/dist/admin/assets/{sections-CN5fIoAr.js.map → sections-BTS683ur.js.map} +1 -1
- package/dist/admin/assets/sections-DqBzSKMP.js +2 -0
- package/dist/admin/assets/{sections-Cl1LrzqH.js.map → sections-DqBzSKMP.js.map} +1 -1
- package/dist/admin/assets/{select-DjCAH45V.js → select-C0USI-Ox.js} +2 -2
- package/dist/admin/assets/{select-DjCAH45V.js.map → select-C0USI-Ox.js.map} +1 -1
- package/dist/admin/assets/{send-DRA-Pe46.js → send-XPWo3m4u.js} +2 -2
- package/dist/admin/assets/{send-DRA-Pe46.js.map → send-XPWo3m4u.js.map} +1 -1
- package/dist/admin/assets/seo-CceGYTIX.js +2 -0
- package/dist/admin/assets/{seo-DJ4k3LtY.js.map → seo-CceGYTIX.js.map} +1 -1
- package/dist/admin/assets/settings-B60vHpZd.js +2 -0
- package/dist/admin/assets/settings-B60vHpZd.js.map +1 -0
- package/dist/admin/assets/settle-CFU6YpQ0.js +2 -0
- package/dist/admin/assets/settle-CFU6YpQ0.js.map +1 -0
- package/dist/admin/assets/shapes-B5twqZcp.js +6 -0
- package/dist/admin/assets/shapes-B5twqZcp.js.map +1 -0
- package/dist/admin/assets/{skeleton-D4eOLKLY.js → skeleton-B5MP72Kw.js} +2 -2
- package/dist/admin/assets/{skeleton-D4eOLKLY.js.map → skeleton-B5MP72Kw.js.map} +1 -1
- package/dist/admin/assets/slugify-rYFum3Sc.js +2 -0
- package/dist/admin/assets/slugify-rYFum3Sc.js.map +1 -0
- package/dist/admin/assets/snapshots-DUI2t-qF.js +2 -0
- package/dist/admin/assets/snapshots-DUI2t-qF.js.map +1 -0
- package/dist/admin/assets/{sparkles-DCRAqbqD.js → sparkles-CvT-jxrW.js} +2 -2
- package/dist/admin/assets/{sparkles-DCRAqbqD.js.map → sparkles-CvT-jxrW.js.map} +1 -1
- package/dist/admin/assets/src-ndgTSYLX.js +7 -0
- package/dist/admin/assets/src-ndgTSYLX.js.map +1 -0
- package/dist/admin/assets/{stableId-iRkUbVIP.js → stableId-BrtQedPy.js} +2 -2
- package/dist/admin/assets/{stableId-iRkUbVIP.js.map → stableId-BrtQedPy.js.map} +1 -1
- package/dist/admin/assets/store-CdIFG90N.js +2 -0
- package/dist/admin/assets/{store-DknnssoQ.js.map → store-CdIFG90N.js.map} +1 -1
- package/dist/admin/assets/{switch-B2R13aVU.js → switch-Dp6WYNam.js} +2 -2
- package/dist/admin/assets/{switch-B2R13aVU.js.map → switch-Dp6WYNam.js.map} +1 -1
- package/dist/admin/assets/theme-65PB8uAu.js +2 -0
- package/dist/admin/assets/{theme-X-qeg74W.js.map → theme-65PB8uAu.js.map} +1 -1
- package/dist/admin/assets/titles-CQiqqDw-.js +2 -0
- package/dist/admin/assets/titles-CQiqqDw-.js.map +1 -0
- package/dist/admin/assets/tokens-ixHjAkDK.js +2 -0
- package/dist/admin/assets/{tokens-BlIDIMY9.js.map → tokens-ixHjAkDK.js.map} +1 -1
- package/dist/admin/assets/{tooltip-u2epXfJF.js → tooltip-BGP1DVBt.js} +2 -2
- package/dist/admin/assets/{tooltip-u2epXfJF.js.map → tooltip-BGP1DVBt.js.map} +1 -1
- package/dist/admin/assets/{undo-2-Zd1OT6qk.js → undo-2-BiTANHFz.js} +2 -2
- package/dist/admin/assets/{undo-2-Zd1OT6qk.js.map → undo-2-BiTANHFz.js.map} +1 -1
- package/dist/admin/assets/useContentSchema-DtYfhsd2.js +2 -0
- package/dist/admin/assets/{useContentSchema-DaQHlL19.js.map → useContentSchema-DtYfhsd2.js.map} +1 -1
- package/dist/admin/assets/useCursorPager-0zHjlm-7.js +2 -0
- package/dist/admin/assets/{useCursorPager-Dc-9B67j.js.map → useCursorPager-0zHjlm-7.js.map} +1 -1
- package/dist/admin/assets/useDiscardGuard-BskWSlbT.js +2 -0
- package/dist/admin/assets/useDiscardGuard-BskWSlbT.js.map +1 -0
- package/dist/admin/assets/useMediaPickerDialog-CU-ekPqX.js +2 -0
- package/dist/admin/assets/{useMediaPickerDialog-C23eOHQR.js.map → useMediaPickerDialog-CU-ekPqX.js.map} +1 -1
- package/dist/admin/assets/useMediaUploader-CBcq1ICg.js +2 -0
- package/dist/admin/assets/{useMediaUploader-CTViR0LX.js.map → useMediaUploader-CBcq1ICg.js.map} +1 -1
- package/dist/admin/assets/useNetworkPermission-Cts98h9d.js +2 -0
- package/dist/admin/assets/{useNetworkPermission-CegwqQXR.js.map → useNetworkPermission-Cts98h9d.js.map} +1 -1
- package/dist/admin/assets/usePaletteItems-DtReWmkd.js +2 -0
- package/dist/admin/assets/{usePaletteItems-B3y2t7Ly.js.map → usePaletteItems-DtReWmkd.js.map} +1 -1
- package/dist/admin/assets/usePlaces-DC47wVeU.js +2 -0
- package/dist/admin/assets/{usePlaces-CAXr-IO9.js.map → usePlaces-DC47wVeU.js.map} +1 -1
- package/dist/admin/assets/useQueries-CirW3Mvp.js +2 -0
- package/dist/admin/assets/{useQueries-CX6eFr24.js.map → useQueries-CirW3Mvp.js.map} +1 -1
- package/dist/admin/assets/{useResolvedScheme-Cg8TdO85.js → useResolvedScheme-C8vcQVko.js} +2 -2
- package/dist/admin/assets/{useResolvedScheme-Cg8TdO85.js.map → useResolvedScheme-C8vcQVko.js.map} +1 -1
- package/dist/admin/assets/{useSchemaScopeAccess-DyfiZnzs.js → useSchemaScopeAccess-ByrxIdKM.js} +2 -2
- package/dist/admin/assets/{useSchemaScopeAccess-DyfiZnzs.js.map → useSchemaScopeAccess-ByrxIdKM.js.map} +1 -1
- package/dist/admin/assets/users-2iJYwlJb.js +2 -0
- package/dist/admin/assets/users-2iJYwlJb.js.map +1 -0
- package/dist/admin/assets/{users-ohHZnBJW.js → users-DM7CXUBJ.js} +2 -2
- package/dist/admin/assets/{users-ohHZnBJW.js.map → users-DM7CXUBJ.js.map} +1 -1
- package/dist/admin/assets/{zod-D5i60ErJ.js → zod-Cry7YvLY.js} +2 -2
- package/dist/admin/assets/{zod-D5i60ErJ.js.map → zod-Cry7YvLY.js.map} +1 -1
- package/dist/admin/index.html +59 -60
- package/dist/cli.js +10 -5696
- package/dist/cli.js.map +1 -1
- package/dist/cliMain-papyXJDd.js +5771 -0
- package/dist/cliMain-papyXJDd.js.map +1 -0
- package/dist/config.d.ts +1 -1
- package/dist/config.js +1 -38
- package/dist/contentDisposition-DOL2Xt0l.js +90 -0
- package/dist/contentDisposition-DOL2Xt0l.js.map +1 -0
- package/dist/index.d.ts +23 -6
- package/dist/index.js +2 -2
- package/dist/public-B57h4F7Y.js +39 -0
- package/dist/public-B57h4F7Y.js.map +1 -0
- package/dist/{public-BO_wneBL.d.ts → public-COKbHR-N.d.ts} +47 -3
- package/dist/{s3Adapter-CtPzkzf0.js → s3Adapter-U01iEAcK.js} +2 -2
- package/dist/{s3Adapter-CtPzkzf0.js.map → s3Adapter-U01iEAcK.js.map} +1 -1
- package/dist/{worker-DRCCGGjl.js → worker-B-sC-eY2.js} +5735 -3982
- package/dist/worker-B-sC-eY2.js.map +1 -0
- package/package.json +5 -5
- package/dist/admin/assets/AssistError-CMXQWiQo.js +0 -2
- package/dist/admin/assets/Body-BYc1IVsQ.js +0 -2
- package/dist/admin/assets/Builder-CwHpRhZN.js +0 -2
- package/dist/admin/assets/Builder-CwHpRhZN.js.map +0 -1
- package/dist/admin/assets/ConfirmDialog-Rd6WDt6q.js +0 -2
- package/dist/admin/assets/ConfirmDialog-Rd6WDt6q.js.map +0 -1
- package/dist/admin/assets/Form-CiZUsLPp.js +0 -2
- package/dist/admin/assets/Form-CiZUsLPp.js.map +0 -1
- package/dist/admin/assets/FormCheckboxGroup-Bz8KERs1.js.map +0 -1
- package/dist/admin/assets/InsertMenuItem-BvRDuXtd.js +0 -2
- package/dist/admin/assets/InsertMenuItem-BvRDuXtd.js.map +0 -1
- package/dist/admin/assets/Panel-B1TkcP8V.js +0 -2
- package/dist/admin/assets/Panel-B1TkcP8V.js.map +0 -1
- package/dist/admin/assets/SecretReveal-BhSqdWqh.js +0 -2
- package/dist/admin/assets/SecretReveal-BhSqdWqh.js.map +0 -1
- package/dist/admin/assets/StepList-CZJmwy9e.js +0 -2
- package/dist/admin/assets/StepList-CZJmwy9e.js.map +0 -1
- package/dist/admin/assets/Structure-Dk87778W.js +0 -2
- package/dist/admin/assets/Thumbnail-BwbCNpgQ.js +0 -2
- package/dist/admin/assets/Thumbnail-BwbCNpgQ.js.map +0 -1
- package/dist/admin/assets/UnsavedChangesGuard-C6nD55Fn.js +0 -2
- package/dist/admin/assets/UnsavedChangesGuard-C6nD55Fn.js.map +0 -1
- package/dist/admin/assets/auth-C4fHG9Iu.js +0 -2
- package/dist/admin/assets/auth-C4fHG9Iu.js.map +0 -1
- package/dist/admin/assets/badge-vLiQczOd.js +0 -2
- package/dist/admin/assets/changeSets-D5VevASj.js +0 -2
- package/dist/admin/assets/changeSets-D5VevASj.js.map +0 -1
- package/dist/admin/assets/chevron-left-CZXrLV99.js +0 -2
- package/dist/admin/assets/content-Cbavyq0x.js +0 -3
- package/dist/admin/assets/content-Cbavyq0x.js.map +0 -1
- package/dist/admin/assets/contentCounts-DknqJ4kh.js +0 -2
- package/dist/admin/assets/context-fImO9k99.js +0 -2
- package/dist/admin/assets/createLucideIcon-CqygG5K6.js +0 -2
- package/dist/admin/assets/createLucideIcon-CqygG5K6.js.map +0 -1
- package/dist/admin/assets/develop-BDqMOEql.js +0 -11
- package/dist/admin/assets/develop-BDqMOEql.js.map +0 -1
- package/dist/admin/assets/es2015-BKfbx3rz.js +0 -42
- package/dist/admin/assets/es2015-BKfbx3rz.js.map +0 -1
- package/dist/admin/assets/followPlural-D0bENI5E.js +0 -2
- package/dist/admin/assets/followPlural-D0bENI5E.js.map +0 -1
- package/dist/admin/assets/inbox-Dfy4YBZ2.js +0 -2
- package/dist/admin/assets/inbox-Dfy4YBZ2.js.map +0 -1
- package/dist/admin/assets/index-BEM45u2w.css +0 -2
- package/dist/admin/assets/index-M4TUI1dl.js +0 -4
- package/dist/admin/assets/index-M4TUI1dl.js.map +0 -1
- package/dist/admin/assets/loader-circle-C-9trZPI.js +0 -2
- package/dist/admin/assets/loader-circle-C-9trZPI.js.map +0 -1
- package/dist/admin/assets/locales-e7B5t6id.js +0 -2
- package/dist/admin/assets/media-DBdx-UmR.js +0 -2
- package/dist/admin/assets/media-DBdx-UmR.js.map +0 -1
- package/dist/admin/assets/media-VCJUbYzJ.js +0 -2
- package/dist/admin/assets/network-BpbMYp6D.js +0 -2
- package/dist/admin/assets/network-BpbMYp6D.js.map +0 -1
- package/dist/admin/assets/pencil-BVSFlU14.js +0 -2
- package/dist/admin/assets/pencil-BVSFlU14.js.map +0 -1
- package/dist/admin/assets/publishing-CpSDO3M7.js +0 -2
- package/dist/admin/assets/schedules-CBGpjEg7.js +0 -2
- package/dist/admin/assets/schema-D9BgCVzZ.js +0 -2
- package/dist/admin/assets/schema-D9BgCVzZ.js.map +0 -1
- package/dist/admin/assets/searchSchemas-D4S2ceA0.js +0 -2
- package/dist/admin/assets/sections-Cl1LrzqH.js +0 -2
- package/dist/admin/assets/seo-DJ4k3LtY.js +0 -2
- package/dist/admin/assets/settings-DRZ33PTg.js +0 -2
- package/dist/admin/assets/settings-DRZ33PTg.js.map +0 -1
- package/dist/admin/assets/settle-LRKtTN_e.js +0 -2
- package/dist/admin/assets/settle-LRKtTN_e.js.map +0 -1
- package/dist/admin/assets/shapes-BJe3IMuj.js +0 -6
- package/dist/admin/assets/shapes-BJe3IMuj.js.map +0 -1
- package/dist/admin/assets/snapshots-CT-zs6Up.js +0 -2
- package/dist/admin/assets/snapshots-CT-zs6Up.js.map +0 -1
- package/dist/admin/assets/src-DUpL-qwG.js +0 -7
- package/dist/admin/assets/src-DUpL-qwG.js.map +0 -1
- package/dist/admin/assets/store-DknnssoQ.js +0 -2
- package/dist/admin/assets/theme-X-qeg74W.js +0 -2
- package/dist/admin/assets/titles-CLh5ftA2.js +0 -2
- package/dist/admin/assets/titles-CLh5ftA2.js.map +0 -1
- package/dist/admin/assets/tokens-BlIDIMY9.js +0 -2
- package/dist/admin/assets/useAuditLabels-DWBpLOTB.js +0 -2
- package/dist/admin/assets/useAuditLabels-DWBpLOTB.js.map +0 -1
- package/dist/admin/assets/useContentSchema-DaQHlL19.js +0 -2
- package/dist/admin/assets/useCursorPager-Dc-9B67j.js +0 -2
- package/dist/admin/assets/useDiscardGuard-BVJGUCiH.js +0 -2
- package/dist/admin/assets/useDiscardGuard-BVJGUCiH.js.map +0 -1
- package/dist/admin/assets/useMediaPickerDialog-C23eOHQR.js +0 -2
- package/dist/admin/assets/useMediaUploader-CTViR0LX.js +0 -2
- package/dist/admin/assets/useNetworkPermission-CegwqQXR.js +0 -2
- package/dist/admin/assets/usePaletteItems-B3y2t7Ly.js +0 -2
- package/dist/admin/assets/usePlaces-CAXr-IO9.js +0 -2
- package/dist/admin/assets/useQueries-CX6eFr24.js +0 -2
- package/dist/admin/assets/users-CDoJRL24.js +0 -2
- package/dist/admin/assets/users-CDoJRL24.js.map +0 -1
- package/dist/config.js.map +0 -1
- package/dist/worker-DRCCGGjl.js.map +0 -1
package/dist/config.d.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { A as ServiceFactoryContext, C as HookEvent, D as MediaUsage, E as MediaReferenceService, F as defineConfig, I as isHookError, M as ShapioServices, N as ThemeDefinition, O as ModelHooks, P as ThemeTokens, S as HookError, T as JobHandlerContext, _ as ExtensionRoute, a as BeforeHookContext, b as ExtensionSite, c as ContentReadOptions, d as EXTENSION_CONTRACT_VERSION, f as EnqueueOptions, g as ExtensionJobService, h as ExtensionJobHandler, i as BeforeHook, j as ShapioConfig, k as ServiceFactory, l as ContentReadService, m as ExtensionHostConfig, n as AfterHookContext, o as BeforeHookEvent, p as EntryData, r as AfterHookEvent, s as ContentReadEntry, t as AfterHook, u as CustomServices, v as ExtensionRouteOptions, w as HookModel, x as HookEntry, y as ExtensionServices } from "./public-
|
|
1
|
+
import { A as ServiceFactoryContext, C as HookEvent, D as MediaUsage, E as MediaReferenceService, F as defineConfig, I as isHookError, M as ShapioServices, N as ThemeDefinition, O as ModelHooks, P as ThemeTokens, S as HookError, T as JobHandlerContext, _ as ExtensionRoute, a as BeforeHookContext, b as ExtensionSite, c as ContentReadOptions, d as EXTENSION_CONTRACT_VERSION, f as EnqueueOptions, g as ExtensionJobService, h as ExtensionJobHandler, i as BeforeHook, j as ShapioConfig, k as ServiceFactory, l as ContentReadService, m as ExtensionHostConfig, n as AfterHookContext, o as BeforeHookEvent, p as EntryData, r as AfterHookEvent, s as ContentReadEntry, t as AfterHook, u as CustomServices, v as ExtensionRouteOptions, w as HookModel, x as HookEntry, y as ExtensionServices } from "./public-COKbHR-N.js";
|
|
2
2
|
export { AfterHook, AfterHookContext, AfterHookEvent, BeforeHook, BeforeHookContext, BeforeHookEvent, ContentReadEntry, ContentReadOptions, ContentReadService, CustomServices, EXTENSION_CONTRACT_VERSION, EnqueueOptions, EntryData, ExtensionHostConfig, ExtensionJobHandler, ExtensionJobService, ExtensionRoute, ExtensionRouteOptions, ExtensionServices, ExtensionSite, HookEntry, HookError, HookEvent, HookModel, JobHandlerContext, MediaReferenceService, MediaUsage, ModelHooks, ServiceFactory, ServiceFactoryContext, ShapioConfig, ShapioServices, ThemeDefinition, ThemeTokens, defineConfig, isHookError };
|
package/dist/config.js
CHANGED
|
@@ -1,39 +1,2 @@
|
|
|
1
|
-
|
|
2
|
-
/**
|
|
3
|
-
* The project extension contract (ADR 0009), imported by project authors from `@shapio/cms/config`:
|
|
4
|
-
*
|
|
5
|
-
* ```ts
|
|
6
|
-
* import { defineConfig } from '@shapio/cms/config';
|
|
7
|
-
* export const config = defineConfig({ hooks: { article: { beforePublish: (ctx) => { ... } } } });
|
|
8
|
-
* ```
|
|
9
|
-
*
|
|
10
|
-
* Extensions are code: changing them needs a restart of Shapio (never a rebuild). Content models are never
|
|
11
|
-
* configured here; they change live in the admin. This file has no runtime imports from the server, so a
|
|
12
|
-
* config that imports it stays cheap to load.
|
|
13
|
-
*
|
|
14
|
-
* Stability: everything exported here follows semver with `EXTENSION_CONTRACT_VERSION`; Shapio's database
|
|
15
|
-
* tables (reachable through `trx`) are internal and may change in any release.
|
|
16
|
-
*/
|
|
17
|
-
const EXTENSION_CONTRACT_VERSION = 1;
|
|
18
|
-
/** Identity helper for completion and type checking in `shapio.config.ts`. */
|
|
19
|
-
const defineConfig = (config) => config;
|
|
20
|
-
const HOOK_ERROR_BRAND = Symbol.for("shapio.HookError");
|
|
21
|
-
/**
|
|
22
|
-
* Thrown by a `before*` hook to reject a write: the API answers 422 with code `HOOK_REJECTED`, this message
|
|
23
|
-
* and the details. Recognised by a brand, not `instanceof`, so a copy of this class loaded from another
|
|
24
|
-
* path (a project's own `node_modules`) works the same.
|
|
25
|
-
*/
|
|
26
|
-
var HookError = class extends Error {
|
|
27
|
-
details;
|
|
28
|
-
[HOOK_ERROR_BRAND] = true;
|
|
29
|
-
constructor(message, details) {
|
|
30
|
-
super(message);
|
|
31
|
-
this.name = "HookError";
|
|
32
|
-
this.details = details;
|
|
33
|
-
}
|
|
34
|
-
};
|
|
35
|
-
const isHookError = (error) => typeof error === "object" && error !== null && error[HOOK_ERROR_BRAND] === true;
|
|
36
|
-
//#endregion
|
|
1
|
+
import { i as isHookError, n as HookError, r as defineConfig, t as EXTENSION_CONTRACT_VERSION } from "./public-B57h4F7Y.js";
|
|
37
2
|
export { EXTENSION_CONTRACT_VERSION, HookError, defineConfig, isHookError };
|
|
38
|
-
|
|
39
|
-
//# sourceMappingURL=config.js.map
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
import { randomBytes } from "node:crypto";
|
|
2
|
+
//#region src/media/keys.ts
|
|
3
|
+
const MAX_FILENAME_LENGTH = 200;
|
|
4
|
+
const MAX_SLUG_LENGTH = 80;
|
|
5
|
+
/** Characters Windows, macOS or shells treat specially, plus every control character. */
|
|
6
|
+
const UNSAFE_FILENAME_CHARACTERS = /[\u0000-\u001f\u007f<>:"/\\|?*]+/g;
|
|
7
|
+
const STORAGE_KEY_PATTERN = new RegExp(`^(public|private)(/[A-Za-z0-9][A-Za-z0-9._-]{0,127}){2,5}$`);
|
|
8
|
+
const splitExtension = (name) => {
|
|
9
|
+
const dot = name.lastIndexOf(".");
|
|
10
|
+
return dot > 0 && name.length - dot <= 16 ? {
|
|
11
|
+
stem: name.slice(0, dot),
|
|
12
|
+
extension: name.slice(dot)
|
|
13
|
+
} : {
|
|
14
|
+
stem: name,
|
|
15
|
+
extension: ""
|
|
16
|
+
};
|
|
17
|
+
};
|
|
18
|
+
/**
|
|
19
|
+
* The display name kept for an upload: the last path segment, NFC-normalised, without control or
|
|
20
|
+
* path characters, at most 200 characters with the extension preserved. Never used as a storage path.
|
|
21
|
+
*/
|
|
22
|
+
const sanitizeFilename = (input) => {
|
|
23
|
+
const cleaned = (input.split(/[/\\]/).pop() ?? "").normalize("NFC").replace(UNSAFE_FILENAME_CHARACTERS, "-").replace(/\s+/g, " ").replace(/^[\s.-]+|[\s.]+$/g, "");
|
|
24
|
+
if (cleaned === "") return "file";
|
|
25
|
+
if (cleaned.length <= MAX_FILENAME_LENGTH) return cleaned;
|
|
26
|
+
const { stem, extension } = splitExtension(cleaned);
|
|
27
|
+
return `${stem.slice(0, MAX_FILENAME_LENGTH - extension.length)}${extension}`;
|
|
28
|
+
};
|
|
29
|
+
/** An ASCII, lower-case, URL-safe version of a file name for storage keys: `Été 2026.JPG` → `ete-2026.jpg`. */
|
|
30
|
+
const toStorageSlug = (filename) => {
|
|
31
|
+
const { stem, extension } = splitExtension(filename);
|
|
32
|
+
const slugify = (value) => value.normalize("NFKD").replace(/[̀-ͯ]/g, "").toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "");
|
|
33
|
+
const slugStem = slugify(stem).slice(0, MAX_SLUG_LENGTH) || "file";
|
|
34
|
+
const slugExtension = slugify(extension).slice(0, 15);
|
|
35
|
+
return slugExtension ? `${slugStem}.${slugExtension}` : slugStem;
|
|
36
|
+
};
|
|
37
|
+
/** Relative keys only, made of safe segments under a visibility prefix: no `..`, no absolute paths. */
|
|
38
|
+
const isValidStorageKey = (key) => STORAGE_KEY_PATTERN.test(key);
|
|
39
|
+
/**
|
|
40
|
+
* `public/<assetId>/<token>/<slug>`. The visibility prefix lets an operator expose only `public/` through a
|
|
41
|
+
* CDN or bucket policy; the random token gives every upload (and replacement) a new, cacheable URL.
|
|
42
|
+
*/
|
|
43
|
+
const buildAssetKey = (visibility, assetId, filename) => `${visibility}/${assetId}/${randomBytes(12).toString("hex")}/${toStorageSlug(filename)}`;
|
|
44
|
+
/** Variants sit beside their original: `public/<assetId>/<token>/v/<name>.<extension>`. */
|
|
45
|
+
const buildVariantKey = (assetKey, name, extension) => `${assetKey.slice(0, assetKey.lastIndexOf("/"))}/v/${name}.${extension}`;
|
|
46
|
+
/** The same key under the other visibility prefix (visibility changes move objects). */
|
|
47
|
+
const withVisibility = (key, visibility) => `${visibility}${key.slice(key.indexOf("/"))}`;
|
|
48
|
+
const visibilityOfKey = (key) => {
|
|
49
|
+
const prefix = key.slice(0, key.indexOf("/"));
|
|
50
|
+
return prefix === "public" || prefix === "private" ? prefix : void 0;
|
|
51
|
+
};
|
|
52
|
+
/** Percent-encodes each segment for use in a URL path. */
|
|
53
|
+
const encodeKeyPath = (key) => key.split("/").map(encodeURIComponent).join("/");
|
|
54
|
+
//#endregion
|
|
55
|
+
//#region src/media/errors.ts
|
|
56
|
+
/** Thrown by adapters when a key has no object, so callers can tell "missing" from "storage is down". */
|
|
57
|
+
var ObjectNotFoundError = class extends Error {
|
|
58
|
+
constructor(key, options) {
|
|
59
|
+
super(`No stored object at ${key}`, options);
|
|
60
|
+
this.name = "ObjectNotFoundError";
|
|
61
|
+
}
|
|
62
|
+
};
|
|
63
|
+
var InvalidStorageKeyError = class extends Error {
|
|
64
|
+
constructor(key) {
|
|
65
|
+
super(`Not a valid media storage key: ${JSON.stringify(key)}`);
|
|
66
|
+
this.name = "InvalidStorageKeyError";
|
|
67
|
+
}
|
|
68
|
+
};
|
|
69
|
+
//#endregion
|
|
70
|
+
//#region src/media/contentDisposition.ts
|
|
71
|
+
/**
|
|
72
|
+
* A Content-Disposition value that names the file safely: an ASCII fallback plus the RFC 5987 UTF-8 form,
|
|
73
|
+
* so quotes, semicolons or line breaks in a filename can never inject header parameters.
|
|
74
|
+
*/
|
|
75
|
+
const contentDisposition = (filename, type = "inline") => {
|
|
76
|
+
return `${type}; filename="${filename.replace(/[^\x20-\x7e]/g, "_").replace(/["\\]/g, "_")}"; filename*=UTF-8''${encodeURIComponent(filename)}`;
|
|
77
|
+
};
|
|
78
|
+
/** Types a browser only ever displays passively: opening one directly cannot run script. */
|
|
79
|
+
const PASSIVE_INLINE_TYPE = /^(image\/(png|jpeg|gif|webp|avif|bmp|tiff|x-icon|vnd\.microsoft\.icon)|video\/.+|audio\/.+)$/;
|
|
80
|
+
/**
|
|
81
|
+
* Content-Disposition to store on an object in a bucket. Public objects can be served straight from the
|
|
82
|
+
* bucket or a CDN, where Shapio's sandboxing headers are absent; anything that could run as a page there
|
|
83
|
+
* (SVG, HTML, XML, PDF...) is stored as an attachment, so opening it downloads it. `<img>` tags still show
|
|
84
|
+
* an SVG, since embedding ignores Content-Disposition.
|
|
85
|
+
*/
|
|
86
|
+
const bucketContentDisposition = (contentType) => PASSIVE_INLINE_TYPE.test(contentType.toLowerCase()) ? void 0 : "attachment";
|
|
87
|
+
//#endregion
|
|
88
|
+
export { buildAssetKey as a, isValidStorageKey as c, withVisibility as d, ObjectNotFoundError as i, sanitizeFilename as l, contentDisposition as n, buildVariantKey as o, InvalidStorageKeyError as r, encodeKeyPath as s, bucketContentDisposition as t, visibilityOfKey as u };
|
|
89
|
+
|
|
90
|
+
//# sourceMappingURL=contentDisposition-DOL2Xt0l.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"contentDisposition-DOL2Xt0l.js","names":[],"sources":["../src/media/keys.ts","../src/media/errors.ts","../src/media/contentDisposition.ts"],"sourcesContent":["import { randomBytes } from 'node:crypto';\n\nexport type MediaVisibility = 'public' | 'private';\n\nconst MAX_FILENAME_LENGTH = 200;\nconst MAX_SLUG_LENGTH = 80;\n/** Characters Windows, macOS or shells treat specially, plus every control character. */\n// eslint-disable-next-line no-control-regex\nconst UNSAFE_FILENAME_CHARACTERS = /[\\u0000-\\u001f\\u007f<>:\"/\\\\|?*]+/g;\nconst SEGMENT = '[A-Za-z0-9][A-Za-z0-9._-]{0,127}';\nconst STORAGE_KEY_PATTERN = new RegExp(`^(public|private)(/${SEGMENT}){2,5}$`);\n\nconst splitExtension = (name: string): { stem: string; extension: string } => {\n const dot = name.lastIndexOf('.');\n return dot > 0 && name.length - dot <= 16\n ? { stem: name.slice(0, dot), extension: name.slice(dot) }\n : { stem: name, extension: '' };\n};\n\n/**\n * The display name kept for an upload: the last path segment, NFC-normalised, without control or\n * path characters, at most 200 characters with the extension preserved. Never used as a storage path.\n */\nexport const sanitizeFilename = (input: string): string => {\n const base = input.split(/[/\\\\]/).pop() ?? '';\n const cleaned = base\n .normalize('NFC')\n .replace(UNSAFE_FILENAME_CHARACTERS, '-')\n .replace(/\\s+/g, ' ')\n .replace(/^[\\s.-]+|[\\s.]+$/g, '');\n if (cleaned === '') {\n return 'file';\n }\n if (cleaned.length <= MAX_FILENAME_LENGTH) {\n return cleaned;\n }\n const { stem, extension } = splitExtension(cleaned);\n return `${stem.slice(0, MAX_FILENAME_LENGTH - extension.length)}${extension}`;\n};\n\n/** An ASCII, lower-case, URL-safe version of a file name for storage keys: `Été 2026.JPG` → `ete-2026.jpg`. */\nexport const toStorageSlug = (filename: string): string => {\n const { stem, extension } = splitExtension(filename);\n const slugify = (value: string) =>\n value\n .normalize('NFKD')\n .replace(/[̀-ͯ]/g, '')\n .toLowerCase()\n .replace(/[^a-z0-9]+/g, '-')\n .replace(/^-+|-+$/g, '');\n const slugStem = slugify(stem).slice(0, MAX_SLUG_LENGTH) || 'file';\n const slugExtension = slugify(extension).slice(0, 15);\n return slugExtension ? `${slugStem}.${slugExtension}` : slugStem;\n};\n\n/** Relative keys only, made of safe segments under a visibility prefix: no `..`, no absolute paths. */\nexport const isValidStorageKey = (key: string): boolean => STORAGE_KEY_PATTERN.test(key);\n\n/**\n * `public/<assetId>/<token>/<slug>`. The visibility prefix lets an operator expose only `public/` through a\n * CDN or bucket policy; the random token gives every upload (and replacement) a new, cacheable URL.\n */\nexport const buildAssetKey = (visibility: MediaVisibility, assetId: string, filename: string): string =>\n `${visibility}/${assetId}/${randomBytes(12).toString('hex')}/${toStorageSlug(filename)}`;\n\n/** Variants sit beside their original: `public/<assetId>/<token>/v/<name>.<extension>`. */\nexport const buildVariantKey = (assetKey: string, name: string, extension: string): string =>\n `${assetKey.slice(0, assetKey.lastIndexOf('/'))}/v/${name}.${extension}`;\n\n/** The same key under the other visibility prefix (visibility changes move objects). */\nexport const withVisibility = (key: string, visibility: MediaVisibility): string =>\n `${visibility}${key.slice(key.indexOf('/'))}`;\n\nexport const visibilityOfKey = (key: string): MediaVisibility | undefined => {\n const prefix = key.slice(0, key.indexOf('/'));\n return prefix === 'public' || prefix === 'private' ? prefix : undefined;\n};\n\n/** Percent-encodes each segment for use in a URL path. */\nexport const encodeKeyPath = (key: string): string => key.split('/').map(encodeURIComponent).join('/');\n","/** Thrown by adapters when a key has no object, so callers can tell \"missing\" from \"storage is down\". */\nexport class ObjectNotFoundError extends Error {\n constructor(key: string, options?: ErrorOptions) {\n super(`No stored object at ${key}`, options);\n this.name = 'ObjectNotFoundError';\n }\n}\n\nexport class InvalidStorageKeyError extends Error {\n constructor(key: string) {\n super(`Not a valid media storage key: ${JSON.stringify(key)}`);\n this.name = 'InvalidStorageKeyError';\n }\n}\n","/**\n * A Content-Disposition value that names the file safely: an ASCII fallback plus the RFC 5987 UTF-8 form,\n * so quotes, semicolons or line breaks in a filename can never inject header parameters.\n */\nexport const contentDisposition = (filename: string, type: 'inline' | 'attachment' = 'inline'): string => {\n const ascii = filename.replace(/[^\\x20-\\x7e]/g, '_').replace(/[\"\\\\]/g, '_');\n return `${type}; filename=\"${ascii}\"; filename*=UTF-8''${encodeURIComponent(filename)}`;\n};\n\n/** Types a browser only ever displays passively: opening one directly cannot run script. */\nconst PASSIVE_INLINE_TYPE =\n /^(image\\/(png|jpeg|gif|webp|avif|bmp|tiff|x-icon|vnd\\.microsoft\\.icon)|video\\/.+|audio\\/.+)$/;\n\n/**\n * Content-Disposition to store on an object in a bucket. Public objects can be served straight from the\n * bucket or a CDN, where Shapio's sandboxing headers are absent; anything that could run as a page there\n * (SVG, HTML, XML, PDF...) is stored as an attachment, so opening it downloads it. `<img>` tags still show\n * an SVG, since embedding ignores Content-Disposition.\n */\nexport const bucketContentDisposition = (contentType: string): string | undefined =>\n PASSIVE_INLINE_TYPE.test(contentType.toLowerCase()) ? undefined : 'attachment';\n"],"mappings":";;AAIA,MAAM,sBAAsB;AAC5B,MAAM,kBAAkB;;AAGxB,MAAM,6BAA6B;AAEnC,MAAM,sBAAsB,IAAI,OAAO,4DAAsC;AAE7E,MAAM,kBAAkB,SAAsD;CAC5E,MAAM,MAAM,KAAK,YAAY,GAAG;CAChC,OAAO,MAAM,KAAK,KAAK,SAAS,OAAO,KACnC;EAAE,MAAM,KAAK,MAAM,GAAG,GAAG;EAAG,WAAW,KAAK,MAAM,GAAG;CAAE,IACvD;EAAE,MAAM;EAAM,WAAW;CAAG;AAClC;;;;;AAMA,MAAa,oBAAoB,UAA0B;CAEzD,MAAM,WADO,MAAM,MAAM,OAAO,CAAC,CAAC,IAAI,KAAK,GAAA,CAExC,UAAU,KAAK,CAAC,CAChB,QAAQ,4BAA4B,GAAG,CAAC,CACxC,QAAQ,QAAQ,GAAG,CAAC,CACpB,QAAQ,qBAAqB,EAAE;CAClC,IAAI,YAAY,IACd,OAAO;CAET,IAAI,QAAQ,UAAU,qBACpB,OAAO;CAET,MAAM,EAAE,MAAM,cAAc,eAAe,OAAO;CAClD,OAAO,GAAG,KAAK,MAAM,GAAG,sBAAsB,UAAU,MAAM,IAAI;AACpE;;AAGA,MAAa,iBAAiB,aAA6B;CACzD,MAAM,EAAE,MAAM,cAAc,eAAe,QAAQ;CACnD,MAAM,WAAW,UACf,MACG,UAAU,MAAM,CAAC,CACjB,QAAQ,UAAU,EAAE,CAAC,CACrB,YAAY,CAAC,CACb,QAAQ,eAAe,GAAG,CAAC,CAC3B,QAAQ,YAAY,EAAE;CAC3B,MAAM,WAAW,QAAQ,IAAI,CAAC,CAAC,MAAM,GAAG,eAAe,KAAK;CAC5D,MAAM,gBAAgB,QAAQ,SAAS,CAAC,CAAC,MAAM,GAAG,EAAE;CACpD,OAAO,gBAAgB,GAAG,SAAS,GAAG,kBAAkB;AAC1D;;AAGA,MAAa,qBAAqB,QAAyB,oBAAoB,KAAK,GAAG;;;;;AAMvF,MAAa,iBAAiB,YAA6B,SAAiB,aAC1E,GAAG,WAAW,GAAG,QAAQ,GAAG,YAAY,EAAE,CAAC,CAAC,SAAS,KAAK,EAAE,GAAG,cAAc,QAAQ;;AAGvF,MAAa,mBAAmB,UAAkB,MAAc,cAC9D,GAAG,SAAS,MAAM,GAAG,SAAS,YAAY,GAAG,CAAC,EAAE,KAAK,KAAK,GAAG;;AAG/D,MAAa,kBAAkB,KAAa,eAC1C,GAAG,aAAa,IAAI,MAAM,IAAI,QAAQ,GAAG,CAAC;AAE5C,MAAa,mBAAmB,QAA6C;CAC3E,MAAM,SAAS,IAAI,MAAM,GAAG,IAAI,QAAQ,GAAG,CAAC;CAC5C,OAAO,WAAW,YAAY,WAAW,YAAY,SAAS,KAAA;AAChE;;AAGA,MAAa,iBAAiB,QAAwB,IAAI,MAAM,GAAG,CAAC,CAAC,IAAI,kBAAkB,CAAC,CAAC,KAAK,GAAG;;;;AC9ErG,IAAa,sBAAb,cAAyC,MAAM;CAC7C,YAAY,KAAa,SAAwB;EAC/C,MAAM,uBAAuB,OAAO,OAAO;EAC3C,KAAK,OAAO;CACd;AACF;AAEA,IAAa,yBAAb,cAA4C,MAAM;CAChD,YAAY,KAAa;EACvB,MAAM,kCAAkC,KAAK,UAAU,GAAG,GAAG;EAC7D,KAAK,OAAO;CACd;AACF;;;;;;;ACTA,MAAa,sBAAsB,UAAkB,OAAgC,aAAqB;CAExG,OAAO,GAAG,KAAK,cADD,SAAS,QAAQ,iBAAiB,GAAG,CAAC,CAAC,QAAQ,UAAU,GACtC,EAAE,sBAAsB,mBAAmB,QAAQ;AACtF;;AAGA,MAAM,sBACJ;;;;;;;AAQF,MAAa,4BAA4B,gBACvC,oBAAoB,KAAK,YAAY,YAAY,CAAC,IAAI,KAAA,IAAY"}
|
package/dist/index.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { A as ServiceFactoryContext, B as Principal, C as HookEvent, D as MediaUsage, E as MediaReferenceService, F as defineConfig, G as ComponentDefinition, H as DB, I as isHookError, J as ModelDefinition, K as DataType, L as KnownVersions, M as ShapioServices, N as ThemeDefinition, O as ModelHooks, P as ThemeTokens, R as PermissionEvaluator, S as HookError, T as JobHandlerContext, U as OutboxEvents, V as Database, W as ContentData, Y as
|
|
1
|
+
import { A as ServiceFactoryContext, B as Principal, C as HookEvent, D as MediaUsage, E as MediaReferenceService, F as defineConfig, G as ComponentDefinition, H as DB, I as isHookError, J as ModelDefinition, K as DataType, L as KnownVersions, M as ShapioServices, N as ThemeDefinition, O as ModelHooks, P as ThemeTokens, R as PermissionEvaluator, S as HookError, T as JobHandlerContext, U as OutboxEvents, V as Database, W as ContentData, Y as PlannedChange, _ as ExtensionRoute, a as BeforeHookContext, b as ExtensionSite, c as ContentReadOptions, d as EXTENSION_CONTRACT_VERSION, f as EnqueueOptions, g as ExtensionJobService, h as ExtensionJobHandler, i as BeforeHook, j as ShapioConfig, k as ServiceFactory, l as ContentReadService, m as ExtensionHostConfig, n as AfterHookContext, o as BeforeHookEvent, p as EntryData, q as JsonValue, r as AfterHookEvent, s as ContentReadEntry, t as AfterHook, u as CustomServices, v as ExtensionRouteOptions, w as HookModel, x as HookEntry, y as ExtensionServices, z as PermissionExecutor } from "./public-COKbHR-N.js";
|
|
2
2
|
import { FastifyBaseLogger, FastifyInstance } from "fastify";
|
|
3
3
|
import { Kysely, Selectable, Transaction } from "kysely";
|
|
4
4
|
import { Static, Type } from "typebox";
|
|
@@ -66,7 +66,10 @@ declare const configSchema: Type.TObject<{
|
|
|
66
66
|
SHUTDOWN_TIMEOUT_MS: Type.TInteger;
|
|
67
67
|
/**
|
|
68
68
|
* Days to keep finished bookkeeping: succeeded jobs, dispatched outbox events, after-hook run records,
|
|
69
|
-
* resolved content health findings
|
|
69
|
+
* resolved content health findings, finished webhook deliveries and deployment runs (each webhook's newest
|
|
70
|
+
* delivery and each connection's newest and live run are always kept), and credentials after they expire
|
|
71
|
+
* (admin sessions, invitations, password resets, app-user refresh tokens, login codes, email confirmations,
|
|
72
|
+
* preview tokens) or setup tokens after they are used.
|
|
70
73
|
*/
|
|
71
74
|
RETENTION_DAYS: Type.TInteger;
|
|
72
75
|
/** Days after which an untouched draft (or unpublished changes) shows up in the Inbox. */
|
|
@@ -645,7 +648,7 @@ type ContentStep = {
|
|
|
645
648
|
} | {
|
|
646
649
|
kind: 'convert';
|
|
647
650
|
ownerId: string;
|
|
648
|
-
change:
|
|
651
|
+
change: PlannedChange;
|
|
649
652
|
locations: ValueLocation[];
|
|
650
653
|
};
|
|
651
654
|
type IndexStep = {
|
|
@@ -665,7 +668,10 @@ type FollowUpStep = IndexStep | {
|
|
|
665
668
|
kind: 'releaseUnique';
|
|
666
669
|
fieldId: string;
|
|
667
670
|
} |
|
|
668
|
-
/**
|
|
671
|
+
/**
|
|
672
|
+
* Deletes a removed locale's heads, revisions and unique-registry rows, and moves non-localized entries stored
|
|
673
|
+
* in it to the default locale (content ports).
|
|
674
|
+
*/
|
|
669
675
|
{
|
|
670
676
|
kind: 'purgeLocale';
|
|
671
677
|
code: string;
|
|
@@ -734,6 +740,8 @@ type ContentMigrationPort = {
|
|
|
734
740
|
type StepImpact = {
|
|
735
741
|
affectedHeads: number;
|
|
736
742
|
invalidHeads?: number;
|
|
743
|
+
/** The distinct entries those failing heads belong to (a person counts entries; the check counts heads). */
|
|
744
|
+
invalidEntries?: number;
|
|
737
745
|
/** A type change Shapio cannot convert: live entries holding a value it drops (absent inside components). */
|
|
738
746
|
droppedEntries?: number;
|
|
739
747
|
};
|
|
@@ -745,8 +753,17 @@ type ContentImpactSource = {
|
|
|
745
753
|
* `steps` are the plan's content steps (a check's outcome can depend on another step, e.g. a dropped value).
|
|
746
754
|
*/
|
|
747
755
|
assess: (step: ContentStep, steps: readonly ContentStep[]) => Promise<StepImpact>;
|
|
748
|
-
/**
|
|
749
|
-
|
|
756
|
+
/** What deleting a locale would do to content. */
|
|
757
|
+
countLocaleRemoval: (code: string) => Promise<LocaleRemovalImpact>;
|
|
758
|
+
};
|
|
759
|
+
/** The content impact of deleting a locale (shown before acknowledging, and on the result). */
|
|
760
|
+
type LocaleRemovalImpact = {
|
|
761
|
+
/** Heads of localized models stored in the locale: purged. */
|
|
762
|
+
affectedHeads: number;
|
|
763
|
+
/** Entries that exist only in the locale: deleted. */
|
|
764
|
+
deletedEntries: number;
|
|
765
|
+
/** Entries of non-localized models stored in the locale: moved to the default locale, not deleted. */
|
|
766
|
+
movedEntries: number;
|
|
750
767
|
};
|
|
751
768
|
type SchemaContentPorts = {
|
|
752
769
|
migration: ContentMigrationPort;
|
package/dist/index.js
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
import { a as loadConfig,
|
|
2
|
-
import {
|
|
1
|
+
import { a as loadConfig, n as startServer, s as buildApp, t as startDedicatedWorker, u as SHAPIO_VERSION } from "./worker-B-sC-eY2.js";
|
|
2
|
+
import { i as isHookError, n as HookError, r as defineConfig, t as EXTENSION_CONTRACT_VERSION } from "./public-B57h4F7Y.js";
|
|
3
3
|
export { EXTENSION_CONTRACT_VERSION, HookError, SHAPIO_VERSION, buildApp, defineConfig, isHookError, loadConfig, startDedicatedWorker, startServer };
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
//#region src/extensions/public.ts
|
|
2
|
+
/**
|
|
3
|
+
* The project extension contract (ADR 0009), imported by project authors from `@shapio/cms/config`:
|
|
4
|
+
*
|
|
5
|
+
* ```ts
|
|
6
|
+
* import { defineConfig } from '@shapio/cms/config';
|
|
7
|
+
* export const config = defineConfig({ hooks: { article: { beforePublish: (ctx) => { ... } } } });
|
|
8
|
+
* ```
|
|
9
|
+
*
|
|
10
|
+
* Extensions are code: changing them needs a restart of Shapio (never a rebuild). Content models are never
|
|
11
|
+
* configured here; they change live in the admin. This file has no runtime imports from the server, so a
|
|
12
|
+
* config that imports it stays cheap to load.
|
|
13
|
+
*
|
|
14
|
+
* Stability: everything exported here follows semver with `EXTENSION_CONTRACT_VERSION`; Shapio's database
|
|
15
|
+
* tables (reachable through `trx`) are internal and may change in any release.
|
|
16
|
+
*/
|
|
17
|
+
const EXTENSION_CONTRACT_VERSION = 1;
|
|
18
|
+
/** Identity helper for completion and type checking in `shapio.config.ts`. */
|
|
19
|
+
const defineConfig = (config) => config;
|
|
20
|
+
const HOOK_ERROR_BRAND = Symbol.for("shapio.HookError");
|
|
21
|
+
/**
|
|
22
|
+
* Thrown by a `before*` hook to reject a write: the API answers 422 with code `HOOK_REJECTED`, this message
|
|
23
|
+
* and the details. Recognised by a brand, not `instanceof`, so a copy of this class loaded from another
|
|
24
|
+
* path (a project's own `node_modules`) works the same.
|
|
25
|
+
*/
|
|
26
|
+
var HookError = class extends Error {
|
|
27
|
+
details;
|
|
28
|
+
[HOOK_ERROR_BRAND] = true;
|
|
29
|
+
constructor(message, details) {
|
|
30
|
+
super(message);
|
|
31
|
+
this.name = "HookError";
|
|
32
|
+
this.details = details;
|
|
33
|
+
}
|
|
34
|
+
};
|
|
35
|
+
const isHookError = (error) => typeof error === "object" && error !== null && error[HOOK_ERROR_BRAND] === true;
|
|
36
|
+
//#endregion
|
|
37
|
+
export { isHookError as i, HookError as n, defineConfig as r, EXTENSION_CONTRACT_VERSION as t };
|
|
38
|
+
|
|
39
|
+
//# sourceMappingURL=public-B57h4F7Y.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"public-B57h4F7Y.js","names":[],"sources":["../src/extensions/public.ts"],"sourcesContent":["import type { ThemeToken } from '@shapio/schema';\nimport type { FastifyBaseLogger, FastifyPluginAsync, preHandlerAsyncHookHandler } from 'fastify';\nimport type { Kysely, Transaction } from 'kysely';\nimport type { DB } from '../db/types.js';\nimport type { PermissionEvaluator, Principal } from '../permissions/types.js';\nimport type { RouteAuditConfig } from '../plugins/auditDeclaration.js';\n\n// What Shapio adds to Fastify, repeated here so custom route code is typed without the server's internals.\ndeclare module 'fastify' {\n interface FastifyRequest {\n /** Who is calling. Anonymous unless a session cookie or API token resolved. Never null after onRequest. */\n principal: Principal;\n /**\n * The request's site on a site route (custom routes are site routes): the credential's site, else the\n * `Shapio-Site` header or `?site=`, else the primary site. Undefined on a route declaring\n * `config.site = 'network'`.\n */\n site: { id: string; key: string } | undefined;\n }\n interface FastifyContextConfig {\n /** Required on every mutating route: the audit action recorded on success, or `{ exempt: '<why>' }`. */\n audit?: RouteAuditConfig;\n /** `'network'` for a custom route that is about the whole instance rather than one site. */\n site?: 'site' | 'network';\n }\n}\n\n/**\n * The project extension contract (ADR 0009), imported by project authors from `@shapio/cms/config`:\n *\n * ```ts\n * import { defineConfig } from '@shapio/cms/config';\n * export const config = defineConfig({ hooks: { article: { beforePublish: (ctx) => { ... } } } });\n * ```\n *\n * Extensions are code: changing them needs a restart of Shapio (never a rebuild). Content models are never\n * configured here; they change live in the admin. This file has no runtime imports from the server, so a\n * config that imports it stays cheap to load.\n *\n * Stability: everything exported here follows semver with `EXTENSION_CONTRACT_VERSION`; Shapio's database\n * tables (reachable through `trx`) are internal and may change in any release.\n */\nexport const EXTENSION_CONTRACT_VERSION = 1;\n\nexport type BeforeHookEvent = 'beforeCreate' | 'beforeUpdate' | 'beforePublish' | 'beforeDelete';\nexport type AfterHookEvent = 'afterCreate' | 'afterUpdate' | 'afterPublish' | 'afterDelete';\nexport type HookEvent = BeforeHookEvent | AfterHookEvent;\n\n/** A site of a multi-site instance: its stable ID and its key (sites share the schema, not content). */\nexport type ExtensionSite = { id: string; key: string };\n\n/** Entry data keyed by field API key (the admin API's shape; media and relations are IDs). */\nexport type EntryData = Readonly<Record<string, unknown>>;\n\nexport type HookModel = {\n /** Stable model ID (never changes). */\n id: string;\n apiKey: string;\n label: string;\n kind: 'collection' | 'singleton';\n localized: boolean;\n draftAndPublish: boolean;\n};\n\nexport type HookEntry = {\n id: string;\n locale: string | null;\n /** Which head the change is about: the draft (create/update), the live version (publish), or a delete. */\n state: 'draft' | 'published' | 'deleted';\n};\n\nexport type ContentReadOptions = {\n locale?: string;\n /** Read as this principal (its permissions apply). Default: Shapio itself (everything). */\n principal?: Principal;\n};\n\nexport type ContentReadEntry = {\n id: string;\n locale: string;\n status: string;\n data: Record<string, unknown>;\n};\n\n/** Read-only access to content (drafts, as the admin API shows them). Reads committed data. */\nexport type ContentReadService = {\n get: (modelKey: string, id: string, options?: ContentReadOptions) => Promise<ContentReadEntry>;\n /** `query` is a delivery-style querystring, e.g. `filters[title][$contains]=a&pageSize=10`. */\n list: (\n modelKey: string,\n query?: string,\n options?: Omit<ContentReadOptions, 'locale'>,\n ) => Promise<{ items: ContentReadEntry[]; total: number }>;\n /** Number of (non-deleted) entries of a model. */\n count: (modelKey: string) => Promise<number>;\n /** The active content models (collections and singletons) of this site: shared ones and its own. */\n models: () => Promise<HookModel[]>;\n};\n\nexport type MediaUsage = {\n entryId: string;\n modelId: string;\n fieldId: string;\n locale: string;\n state: string;\n};\n\nexport type MediaReferenceService = {\n /** Where an asset is used (up to 100 references, plus the total). */\n usages: (assetId: string) => Promise<{ items: MediaUsage[]; total: number }>;\n};\n\nexport type EnqueueOptions = {\n runAt?: Date;\n /** Enqueueing the same key twice creates one job. */\n idempotencyKey?: string;\n maxAttempts?: number;\n};\n\nexport type ExtensionJobService = {\n /** Enqueues one of the project's own jobs (`jobs` in the config), by its name without the `ext.` prefix. */\n enqueue: (\n name: string,\n payload?: Record<string, unknown>,\n options?: EnqueueOptions,\n ) => Promise<{ id: string; created: boolean }>;\n};\n\n/**\n * What Shapio offers extensions. Deliberately small; everything else goes through `trx` or HTTP.\n *\n * Content and media are per site. The services handed to a hook read the hook's site; the services given to\n * routes, jobs and service factories read the primary site. Use `forSite` for another one (in a custom\n * route: `services.forSite(request.site)`).\n */\nexport type ShapioServices = {\n /** The site `content` and `media` read. */\n site: ExtensionSite;\n /** The same services reading another site. */\n forSite: (site: ExtensionSite) => ShapioServices;\n content: ContentReadService;\n media: MediaReferenceService;\n jobs: ExtensionJobService;\n logger: FastifyBaseLogger;\n};\n\n/**\n * Your own services, by name. Augment it for typed access everywhere services appear:\n *\n * ```ts\n * declare module '@shapio/cms/config' {\n * interface CustomServices { stats: StatsService }\n * }\n * ```\n */\n// eslint-disable-next-line @typescript-eslint/no-empty-object-type -- augmented by projects\nexport interface CustomServices {}\n\nexport type ExtensionServices = ShapioServices & CustomServices;\n\ntype HookContextBase = {\n /** The site the entry belongs to; `services` read this site. */\n site: ExtensionSite;\n model: HookModel;\n entry: HookEntry;\n locale: string | null;\n /** The document after the change (absent for deletes). */\n data: EntryData | undefined;\n /** The document before the change: the previous draft (update) or the live version (publish). */\n before: EntryData | undefined;\n /** Who made the change (an admin, an API token, an app user, or Shapio itself for scheduled work). */\n principal: Principal;\n services: ExtensionServices;\n logger: FastifyBaseLogger;\n /** Aborted when Shapio shuts down. */\n signal: AbortSignal;\n};\n\n/**\n * `before*` hooks run INSIDE the write's transaction, before it commits. Throw `HookError` (or call\n * `reject`) to abort the write with 422 `HOOK_REJECTED`; nothing of the write is kept. Other errors abort it\n * too, as a 500. Database work through `trx` commits or rolls back with the write.\n */\nexport type BeforeHookContext = HookContextBase & {\n event: BeforeHookEvent;\n trx: Transaction<DB>;\n reject: (message: string, details?: Record<string, unknown>) => never;\n};\n\n/**\n * `after*` hooks run AFTER the write committed, as a job (retried with backoff on error, never rolling the\n * write back). Database work through `trx` is exactly once: it commits together with the record that the\n * hook ran. Other side effects (HTTP calls) are at least once: make them idempotent with `idempotencyKey`.\n */\nexport type AfterHookContext = HookContextBase & {\n event: AfterHookEvent;\n trx: Transaction<DB>;\n /** The outbox event the hook runs for. */\n eventId: string;\n /** `<eventId>:<hook name>`: stable across retries. */\n idempotencyKey: string;\n attempt: number;\n};\n\nexport type BeforeHook = (context: BeforeHookContext) => Promise<void> | void;\nexport type AfterHook = (context: AfterHookContext) => Promise<void> | void;\n\nexport type ModelHooks = { [E in BeforeHookEvent]?: BeforeHook } & { [E in AfterHookEvent]?: AfterHook };\n\nexport type ServiceFactoryContext = {\n /** Kysely on Shapio's database. Shapio's own tables are internal and may change between releases. */\n db: Kysely<DB>;\n config: ExtensionHostConfig;\n logger: FastifyBaseLogger;\n /** Shapio's services plus the custom services declared before this one. */\n services: ExtensionServices;\n};\n\nexport type ExtensionHostConfig = {\n nodeEnv: 'development' | 'production' | 'test';\n /** PUBLIC_URL origin, without a trailing slash. */\n publicUrl: string;\n basePath: string;\n /** The directory holding shapio.config and extensions/. */\n projectDir: string;\n};\n\nexport type ServiceFactory = (context: ServiceFactoryContext) => unknown;\n\n/** Options every custom route plugin receives (also available as `app.ext`). */\nexport type ExtensionRouteOptions = {\n services: ExtensionServices;\n /** Shapio's permission evaluator: `permissions.evaluate(request.principal, { action, modelId })`. */\n permissions: PermissionEvaluator;\n logger: FastifyBaseLogger;\n /** preHandler: 401/403 unless the caller is an admin user or an admin API token. */\n requireAdmin: preHandlerAsyncHookHandler;\n};\n\nexport type ExtensionRoute = {\n /** Mounted at `/api/ext/<prefix>` (under BASE_PATH). Lower-case letters, digits and dashes. */\n prefix: string;\n plugin: FastifyPluginAsync<ExtensionRouteOptions>;\n};\n\nexport type JobHandlerContext = {\n jobId: string;\n payload: Record<string, unknown>;\n attempt: number;\n maxAttempts: number;\n idempotencyKey: string | null;\n services: ExtensionServices;\n logger: FastifyBaseLogger;\n signal: AbortSignal;\n};\n\n/** Throw to retry with backoff; the return value (JSON) is stored as the job result. */\nexport type ExtensionJobHandler = (context: JobHandlerContext) => Promise<unknown>;\n\n/**\n * A colour theme for the admin: token values for a light variant, a dark variant, or both. Every UI token is\n * required in a variant; the `brand-*` tokens may be left out (Shapio's are used). Values are `#rrggbb`\n * (contrast is checked by `shapio extensions check`), `#rgb`, `#rrggbbaa`, or `rgb()`, `hsl()`, `oklch()`,\n * `oklab()` with plain arguments.\n */\nexport type ThemeTokens = Partial<Record<ThemeToken, string>>;\n\nexport type ThemeDefinition = {\n /** Lower-case letters, digits and dashes; not a built-in theme's key. Saved in each browser's setting. */\n key: string;\n /** Shown in the theme menu (not translated). */\n name: string;\n description?: string;\n light?: ThemeTokens;\n dark?: ThemeTokens;\n};\n\nexport type ShapioConfig = {\n /** Lifecycle hooks by model API ID (or stable model UUID); `*` runs for every model. */\n hooks?: Record<string, ModelHooks>;\n routes?: ExtensionRoute[];\n /** Constructed once at startup, in order, and shared by hooks, routes and jobs. */\n services?: Record<string, ServiceFactory>;\n /** Custom field editor modules: file names inside `extensions/editors/` (built ES modules). */\n editors?: string[];\n /** Job handlers by name; registered as `ext.<name>`. */\n jobs?: Record<string, ExtensionJobHandler>;\n /** Admin colour themes, listed after the built-in ones in the theme menu. */\n themes?: ThemeDefinition[];\n};\n\n/** Identity helper for completion and type checking in `shapio.config.ts`. */\nexport const defineConfig = (config: ShapioConfig): ShapioConfig => config;\n\nconst HOOK_ERROR_BRAND = Symbol.for('shapio.HookError');\n\n/**\n * Thrown by a `before*` hook to reject a write: the API answers 422 with code `HOOK_REJECTED`, this message\n * and the details. Recognised by a brand, not `instanceof`, so a copy of this class loaded from another\n * path (a project's own `node_modules`) works the same.\n */\nexport class HookError extends Error {\n readonly details: Record<string, unknown> | undefined;\n readonly [HOOK_ERROR_BRAND] = true;\n\n constructor(message: string, details?: Record<string, unknown>) {\n super(message);\n this.name = 'HookError';\n this.details = details;\n }\n}\n\nexport const isHookError = (error: unknown): error is HookError =>\n typeof error === 'object' &&\n error !== null &&\n (error as Record<symbol, unknown>)[HOOK_ERROR_BRAND] === true;\n"],"mappings":";;;;;;;;;;;;;;;;AA0CA,MAAa,6BAA6B;;AA0P1C,MAAa,gBAAgB,WAAuC;AAEpE,MAAM,mBAAmB,OAAO,IAAI,kBAAkB;;;;;;AAOtD,IAAa,YAAb,cAA+B,MAAM;CACnC;CACA,CAAU,oBAAoB;CAE9B,YAAY,SAAiB,SAAmC;EAC9D,MAAM,OAAO;EACb,KAAK,OAAO;EACZ,KAAK,UAAU;CACjB;AACF;AAEA,MAAa,eAAe,UAC1B,OAAO,UAAU,YACjB,UAAU,QACT,MAAkC,sBAAsB"}
|
|
@@ -246,6 +246,12 @@ type SchemaChange = {
|
|
|
246
246
|
from?: JsonValue$1;
|
|
247
247
|
to?: JsonValue$1;
|
|
248
248
|
};
|
|
249
|
+
/**
|
|
250
|
+
* A change as a stored plan step carries it: classified since 0.5.6, plain before (no drops existed then).
|
|
251
|
+
*/
|
|
252
|
+
type PlannedChange = SchemaChange & {
|
|
253
|
+
dropsValues?: boolean;
|
|
254
|
+
};
|
|
249
255
|
declare const THEME_TOKENS: readonly ["background", "foreground", "card", "card-foreground", "popover", "popover-foreground", "primary", "primary-foreground", "primary-hover", "secondary", "secondary-foreground", "muted", "muted-foreground", "accent", "accent-foreground", "destructive", "destructive-foreground", "destructive-muted", "success", "success-muted", "warning", "warning-muted", "info", "info-muted", "border", "input", "ring", "link", "overlay", "sidebar", "sidebar-foreground", "sidebar-primary", "sidebar-primary-foreground", "sidebar-accent", "sidebar-accent-foreground", "sidebar-border", "sidebar-ring", "brand-logo", "brand-logo-foreground", "brand-letters", "brand-panel-from", "brand-panel-to", "brand-panel-foreground", "brand-panel-mark"];
|
|
250
256
|
type ThemeToken = (typeof THEME_TOKENS)[number];
|
|
251
257
|
//#endregion
|
|
@@ -1134,12 +1140,22 @@ type DeliveryAction = (typeof DELIVERY_ACTIONS)[number];
|
|
|
1134
1140
|
type ModelAction = ContentAction | DeliveryAction;
|
|
1135
1141
|
declare const GLOBAL_ACTIONS: readonly ["schema.create", "users.manage", "roles.manage", "audit.read", "sites.manage", "tokens.manage", "media.read", "media.write", "media.manage", "publishing.manage", "webhooks.manage", "deployments.manage", "deployments.trigger", "changes.manage", "changes.ship", "site.settings"];
|
|
1136
1142
|
type GlobalAction = (typeof GLOBAL_ACTIONS)[number];
|
|
1137
|
-
/**
|
|
1143
|
+
/**
|
|
1144
|
+
* Which fields of a component (at any depth) a principal sees: `all`, or only those with `public: true`. Grants
|
|
1145
|
+
* name model field IDs only, never a component's fields, so delivery audiences see a component's
|
|
1146
|
+
* `public: false` fields under no grant.
|
|
1147
|
+
*/
|
|
1148
|
+
type ComponentFieldVisibility = 'all' | 'public';
|
|
1149
|
+
/**
|
|
1150
|
+
* Field visibility by stable field ID. `all` means every field the schema exposes to this principal kind,
|
|
1151
|
+
* a component's fields included. `only`: these top-level fields, and `componentFields` inside components.
|
|
1152
|
+
*/
|
|
1138
1153
|
type FieldMask = {
|
|
1139
1154
|
mode: 'all';
|
|
1140
1155
|
} | {
|
|
1141
1156
|
mode: 'only';
|
|
1142
1157
|
fieldIds: readonly string[];
|
|
1158
|
+
componentFields: ComponentFieldVisibility;
|
|
1143
1159
|
};
|
|
1144
1160
|
/** Enumerated row conditions; compiled to SQL only by content/compiler. Never free-form expressions. */
|
|
1145
1161
|
type RowCondition = {
|
|
@@ -1152,12 +1168,40 @@ type RowFilter = RowCondition | {
|
|
|
1152
1168
|
kind: 'or';
|
|
1153
1169
|
filters: readonly RowFilter[];
|
|
1154
1170
|
};
|
|
1171
|
+
/**
|
|
1172
|
+
* Field masks that differ by row: `everyRow` applies to every row the principal may act on, and each `when`
|
|
1173
|
+
* entry adds its mask on the rows matching its condition (a grant limited to the principal's own entries
|
|
1174
|
+
* that names more fields than the grants reaching every row).
|
|
1175
|
+
*/
|
|
1176
|
+
type RowFieldMasks = {
|
|
1177
|
+
everyRow: FieldMask;
|
|
1178
|
+
when: ReadonlyArray<{
|
|
1179
|
+
condition: RowCondition;
|
|
1180
|
+
mask: FieldMask;
|
|
1181
|
+
}>;
|
|
1182
|
+
};
|
|
1183
|
+
/** Read masks per row (issue #75). */
|
|
1184
|
+
type RowReadMasks = RowFieldMasks;
|
|
1185
|
+
/** Write masks per row (issue #80). */
|
|
1186
|
+
type RowWriteMasks = RowFieldMasks;
|
|
1155
1187
|
type Policy = {
|
|
1156
1188
|
allowed: boolean;
|
|
1157
1189
|
/** Extra restriction on which rows the principal may act on. `null` means no restriction. */
|
|
1158
1190
|
rowFilter: RowFilter | null;
|
|
1191
|
+
/**
|
|
1192
|
+
* Every field the principal may read on some row (the shape of what it can see, e.g. a GraphQL schema).
|
|
1193
|
+
* Values are shown per row: see `rowReadMasks`.
|
|
1194
|
+
*/
|
|
1159
1195
|
readMask: FieldMask;
|
|
1196
|
+
/** null: `readMask` applies to every row. Otherwise readers apply these per row (never `readMask`). */
|
|
1197
|
+
rowReadMasks: RowReadMasks | null;
|
|
1198
|
+
/**
|
|
1199
|
+
* Every field the principal may write on some row (the shape of what it can send, e.g. GraphQL inputs).
|
|
1200
|
+
* Writes are checked per row: see `rowWriteMasks`.
|
|
1201
|
+
*/
|
|
1160
1202
|
writeMask: FieldMask;
|
|
1203
|
+
/** null: `writeMask` applies to every row. Otherwise writes check these per row (never `writeMask`). */
|
|
1204
|
+
rowWriteMasks: RowWriteMasks | null;
|
|
1161
1205
|
};
|
|
1162
1206
|
type PolicyRequest = {
|
|
1163
1207
|
action: ModelAction;
|
|
@@ -1485,5 +1529,5 @@ declare class HookError extends Error {
|
|
|
1485
1529
|
}
|
|
1486
1530
|
declare const isHookError: (error: unknown) => error is HookError;
|
|
1487
1531
|
//#endregion
|
|
1488
|
-
export { ServiceFactoryContext as A, Principal as B, HookEvent as C, MediaUsage as D, MediaReferenceService as E, defineConfig as F, ComponentDefinition as G, DB as H, isHookError as I, ModelDefinition as J, DataType as K, KnownVersions as L, ShapioServices as M, ThemeDefinition as N, ModelHooks as O, ThemeTokens as P, PermissionEvaluator as R, HookError as S, JobHandlerContext as T, OutboxEvents as U, Database as V, ContentData as W,
|
|
1489
|
-
//# sourceMappingURL=public-
|
|
1532
|
+
export { ServiceFactoryContext as A, Principal as B, HookEvent as C, MediaUsage as D, MediaReferenceService as E, defineConfig as F, ComponentDefinition as G, DB as H, isHookError as I, ModelDefinition as J, DataType as K, KnownVersions as L, ShapioServices as M, ThemeDefinition as N, ModelHooks as O, ThemeTokens as P, PermissionEvaluator as R, HookError as S, JobHandlerContext as T, OutboxEvents as U, Database as V, ContentData as W, PlannedChange as Y, ExtensionRoute as _, BeforeHookContext as a, ExtensionSite as b, ContentReadOptions as c, EXTENSION_CONTRACT_VERSION as d, EnqueueOptions as f, ExtensionJobService as g, ExtensionJobHandler as h, BeforeHook as i, ShapioConfig as j, ServiceFactory as k, ContentReadService as l, ExtensionHostConfig as m, AfterHookContext as n, BeforeHookEvent as o, EntryData as p, JsonValue$1 as q, AfterHookEvent as r, ContentReadEntry as s, AfterHook as t, CustomServices as u, ExtensionRouteOptions as v, HookModel as w, HookEntry as x, ExtensionServices as y, PermissionExecutor as z };
|
|
1533
|
+
//# sourceMappingURL=public-COKbHR-N.d.ts.map
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { c as isValidStorageKey, i as ObjectNotFoundError, n as contentDisposition, r as InvalidStorageKeyError, s as encodeKeyPath, t as bucketContentDisposition } from "./contentDisposition-DOL2Xt0l.js";
|
|
2
2
|
import { DeleteObjectCommand, GetObjectCommand, HeadObjectCommand, PutObjectCommand, S3Client, S3ServiceException } from "@aws-sdk/client-s3";
|
|
3
3
|
import { createPresignedPost } from "@aws-sdk/s3-presigned-post";
|
|
4
4
|
import { getSignedUrl } from "@aws-sdk/s3-request-presigner";
|
|
@@ -122,4 +122,4 @@ const createS3Adapter = ({ config, publicBaseUrl, client }) => {
|
|
|
122
122
|
//#endregion
|
|
123
123
|
export { createS3Adapter };
|
|
124
124
|
|
|
125
|
-
//# sourceMappingURL=s3Adapter-
|
|
125
|
+
//# sourceMappingURL=s3Adapter-U01iEAcK.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"s3Adapter-
|
|
1
|
+
{"version":3,"file":"s3Adapter-U01iEAcK.js","names":[],"sources":["../src/media/s3Adapter.ts"],"sourcesContent":["import type { Readable } from 'node:stream';\nimport {\n DeleteObjectCommand,\n GetObjectCommand,\n HeadObjectCommand,\n PutObjectCommand,\n S3Client,\n S3ServiceException,\n} from '@aws-sdk/client-s3';\nimport { createPresignedPost } from '@aws-sdk/s3-presigned-post';\nimport { getSignedUrl } from '@aws-sdk/s3-request-presigner';\nimport type { S3StorageConfig } from '../config/index.js';\nimport { bucketContentDisposition, contentDisposition } from './contentDisposition.js';\nimport { InvalidStorageKeyError, ObjectNotFoundError } from './errors.js';\nimport { encodeKeyPath, isValidStorageKey } from './keys.js';\nimport type { StorageAdapter } from './types.js';\n\n/** R2 accepts any region name (\"auto\" by convention); AWS needs the bucket's real region. */\nconst DEFAULT_REGION = 'us-east-1';\n\nconst isNotFound = (error: unknown): boolean =>\n error instanceof S3ServiceException &&\n (error.$metadata.httpStatusCode === 404 || error.name === 'NotFound' || error.name === 'NoSuchKey');\n\nexport const createS3Client = (config: S3StorageConfig): S3Client =>\n new S3Client({\n region: config.region ?? DEFAULT_REGION,\n ...(config.endpoint ? { endpoint: config.endpoint } : {}),\n forcePathStyle: config.forcePathStyle,\n ...(config.accessKeyId && config.secretAccessKey\n ? { credentials: { accessKeyId: config.accessKeyId, secretAccessKey: config.secretAccessKey } }\n : {}),\n // Only send/validate checksums when an operation requires them: several S3-compatible services\n // (R2, B2 and other gateways) reject the SDK's default streaming CRC32 trailers.\n requestChecksumCalculation: 'WHEN_REQUIRED',\n responseChecksumValidation: 'WHEN_REQUIRED',\n });\n\nexport type S3AdapterOptions = {\n config: S3StorageConfig;\n publicBaseUrl: string | undefined;\n /** Injected in tests; created from `config` otherwise. */\n client?: S3Client;\n};\n\n/**\n * Any S3-compatible service (AWS S3, Cloudflare R2, B2, Spaces, Wasabi, versitygw). Private objects are read\n * through presigned GET URLs; browsers upload straight to the bucket with a presigned POST whose policy\n * limits size and content type, so Shapio never streams upload bytes.\n */\nexport const createS3Adapter = ({ config, publicBaseUrl, client }: S3AdapterOptions): StorageAdapter => {\n const s3 = client ?? createS3Client(config);\n const Bucket = config.bucket;\n const checkKey = (key: string) => {\n if (!isValidStorageKey(key)) {\n throw new InvalidStorageKeyError(key);\n }\n return key;\n };\n\n const head = async (key: string) => {\n try {\n const result = await s3.send(new HeadObjectCommand({ Bucket, Key: checkKey(key) }));\n return { size: result.ContentLength ?? 0, contentType: result.ContentType };\n } catch (error) {\n if (isNotFound(error)) {\n return undefined;\n }\n throw error;\n }\n };\n\n return {\n driver: 's3',\n put: async (key, body, { contentType, contentLength }) => {\n await s3.send(\n new PutObjectCommand({\n Bucket,\n Key: checkKey(key),\n Body: body,\n ContentType: contentType,\n ContentLength: Buffer.isBuffer(body) ? body.length : contentLength,\n ContentDisposition: bucketContentDisposition(contentType),\n }),\n );\n },\n getStream: async (key, range) => {\n try {\n const result = await s3.send(\n new GetObjectCommand({\n Bucket,\n Key: checkKey(key),\n ...(range ? { Range: `bytes=${range.start}-${range.end}` } : {}),\n }),\n );\n if (!result.Body) {\n throw new ObjectNotFoundError(key);\n }\n return result.Body as Readable;\n } catch (error) {\n throw isNotFound(error) ? new ObjectNotFoundError(key, { cause: error }) : error;\n }\n },\n head,\n exists: async (key) => (await head(key)) !== undefined,\n delete: async (key) => {\n await s3.send(new DeleteObjectCommand({ Bucket, Key: checkKey(key) }));\n },\n signedGetUrl: async (key, { expiresInSeconds, filename, contentType }) =>\n getSignedUrl(\n s3,\n new GetObjectCommand({\n Bucket,\n Key: checkKey(key),\n ResponseContentType: contentType,\n ResponseContentDisposition: contentDisposition(filename),\n }),\n { expiresIn: expiresInSeconds },\n ),\n publicUrl: (key) => (publicBaseUrl ? `${publicBaseUrl}/${encodeKeyPath(checkKey(key))}` : undefined),\n presignedUpload: async ({ key, contentType, maxSizeBytes, expiresInSeconds }) => {\n const disposition = bucketContentDisposition(contentType);\n const { url, fields } = await createPresignedPost(s3, {\n Bucket,\n Key: checkKey(key),\n Conditions: [\n ['content-length-range', 1, maxSizeBytes],\n ['eq', '$Content-Type', contentType],\n ...(disposition ? [['eq', '$Content-Disposition', disposition] as ['eq', string, string]] : []),\n ],\n Fields: {\n 'Content-Type': contentType,\n ...(disposition ? { 'Content-Disposition': disposition } : {}),\n },\n Expires: expiresInSeconds,\n });\n return { url, fields };\n },\n };\n};\n"],"mappings":";;;;;;AAkBA,MAAM,iBAAiB;AAEvB,MAAM,cAAc,UAClB,iBAAiB,uBAChB,MAAM,UAAU,mBAAmB,OAAO,MAAM,SAAS,cAAc,MAAM,SAAS;AAEzF,MAAa,kBAAkB,WAC7B,IAAI,SAAS;CACX,QAAQ,OAAO,UAAU;CACzB,GAAI,OAAO,WAAW,EAAE,UAAU,OAAO,SAAS,IAAI,CAAC;CACvD,gBAAgB,OAAO;CACvB,GAAI,OAAO,eAAe,OAAO,kBAC7B,EAAE,aAAa;EAAE,aAAa,OAAO;EAAa,iBAAiB,OAAO;CAAgB,EAAE,IAC5F,CAAC;CAGL,4BAA4B;CAC5B,4BAA4B;AAC9B,CAAC;;;;;;AAcH,MAAa,mBAAmB,EAAE,QAAQ,eAAe,aAA+C;CACtG,MAAM,KAAK,UAAU,eAAe,MAAM;CAC1C,MAAM,SAAS,OAAO;CACtB,MAAM,YAAY,QAAgB;EAChC,IAAI,CAAC,kBAAkB,GAAG,GACxB,MAAM,IAAI,uBAAuB,GAAG;EAEtC,OAAO;CACT;CAEA,MAAM,OAAO,OAAO,QAAgB;EAClC,IAAI;GACF,MAAM,SAAS,MAAM,GAAG,KAAK,IAAI,kBAAkB;IAAE;IAAQ,KAAK,SAAS,GAAG;GAAE,CAAC,CAAC;GAClF,OAAO;IAAE,MAAM,OAAO,iBAAiB;IAAG,aAAa,OAAO;GAAY;EAC5E,SAAS,OAAO;GACd,IAAI,WAAW,KAAK,GAClB;GAEF,MAAM;EACR;CACF;CAEA,OAAO;EACL,QAAQ;EACR,KAAK,OAAO,KAAK,MAAM,EAAE,aAAa,oBAAoB;GACxD,MAAM,GAAG,KACP,IAAI,iBAAiB;IACnB;IACA,KAAK,SAAS,GAAG;IACjB,MAAM;IACN,aAAa;IACb,eAAe,OAAO,SAAS,IAAI,IAAI,KAAK,SAAS;IACrD,oBAAoB,yBAAyB,WAAW;GAC1D,CAAC,CACH;EACF;EACA,WAAW,OAAO,KAAK,UAAU;GAC/B,IAAI;IACF,MAAM,SAAS,MAAM,GAAG,KACtB,IAAI,iBAAiB;KACnB;KACA,KAAK,SAAS,GAAG;KACjB,GAAI,QAAQ,EAAE,OAAO,SAAS,MAAM,MAAM,GAAG,MAAM,MAAM,IAAI,CAAC;IAChE,CAAC,CACH;IACA,IAAI,CAAC,OAAO,MACV,MAAM,IAAI,oBAAoB,GAAG;IAEnC,OAAO,OAAO;GAChB,SAAS,OAAO;IACd,MAAM,WAAW,KAAK,IAAI,IAAI,oBAAoB,KAAK,EAAE,OAAO,MAAM,CAAC,IAAI;GAC7E;EACF;EACA;EACA,QAAQ,OAAO,QAAS,MAAM,KAAK,GAAG,MAAO,KAAA;EAC7C,QAAQ,OAAO,QAAQ;GACrB,MAAM,GAAG,KAAK,IAAI,oBAAoB;IAAE;IAAQ,KAAK,SAAS,GAAG;GAAE,CAAC,CAAC;EACvE;EACA,cAAc,OAAO,KAAK,EAAE,kBAAkB,UAAU,kBACtD,aACE,IACA,IAAI,iBAAiB;GACnB;GACA,KAAK,SAAS,GAAG;GACjB,qBAAqB;GACrB,4BAA4B,mBAAmB,QAAQ;EACzD,CAAC,GACD,EAAE,WAAW,iBAAiB,CAChC;EACF,YAAY,QAAS,gBAAgB,GAAG,cAAc,GAAG,cAAc,SAAS,GAAG,CAAC,MAAM,KAAA;EAC1F,iBAAiB,OAAO,EAAE,KAAK,aAAa,cAAc,uBAAuB;GAC/E,MAAM,cAAc,yBAAyB,WAAW;GACxD,MAAM,EAAE,KAAK,WAAW,MAAM,oBAAoB,IAAI;IACpD;IACA,KAAK,SAAS,GAAG;IACjB,YAAY;KACV;MAAC;MAAwB;MAAG;KAAY;KACxC;MAAC;MAAM;MAAiB;KAAW;KACnC,GAAI,cAAc,CAAC;MAAC;MAAM;MAAwB;KAAW,CAA2B,IAAI,CAAC;IAC/F;IACA,QAAQ;KACN,gBAAgB;KAChB,GAAI,cAAc,EAAE,uBAAuB,YAAY,IAAI,CAAC;IAC9D;IACA,SAAS;GACX,CAAC;GACD,OAAO;IAAE;IAAK;GAAO;EACvB;CACF;AACF"}
|