@phtngyn/cms 0.2.0-beta.7 → 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/LICENSE +18 -10
- package/README.md +59 -401
- package/drizzle/20261003215543_initial/migration.sql +251 -0
- package/drizzle/20261003215543_initial/snapshot.json +1941 -0
- package/package.json +75 -71
- package/src/Authoring.d.ts +41 -49
- package/src/Authoring.js +1 -1
- package/src/Blocks-BrxSemnd.js +40 -0
- package/src/Client.d.ts +8186 -0
- package/src/Client.js +41 -0
- package/src/Collections.d.ts +142 -0
- package/src/Collections.js +142 -0
- package/src/Config-CMiwciub.js +130 -0
- package/src/Config.d.ts +172 -0
- package/src/Config.js +2 -0
- package/src/Configuration-Dk2k3OIc.js +73 -0
- package/src/DataTransfer-BmECvPHB.js +488 -0
- package/src/Database-DSsNCGft.d.ts +3 -0
- package/src/Delivery.d.ts +28 -0
- package/src/Delivery.js +7 -0
- package/src/Document-CKXMSEf1.js +293 -0
- package/src/Document-TgwYKJZM.d.ts +220 -0
- package/src/DocumentRenderer-Wz2xaNyf.js +394 -0
- package/src/EditorSchema-wrDv-id6.js +296 -0
- package/src/Fields-BegSgYhj.d.ts +166 -0
- package/src/Fields-ioGaMEh9.js +130 -0
- package/src/Forms-BuKAXQxr.d.ts +203 -0
- package/src/Forms.d.ts +48 -11
- package/src/Forms.js +342 -7
- package/src/I18n-Ckf9h0rC.js +154 -0
- package/src/I18n.d.ts +45 -2
- package/src/I18n.js +2 -1
- package/src/Image-CJWPLnhP.js +110 -0
- package/src/Links-CJYyy7rC.js +28 -0
- package/src/Links-Dx1yOni8.d.ts +28 -0
- package/src/Locales-Ch7a5xuA.js +67 -0
- package/src/Locales-jwbmJaOp.d.ts +43 -0
- package/src/Locales.d.ts +3 -0
- package/src/Locales.js +3 -0
- package/src/Media-BQ0uL4w7.d.ts +15 -0
- package/src/Media-DSyvd14o.js +87 -0
- package/src/Module.d.ts +2 -10
- package/src/Module.js +1039 -162
- package/src/Operations.d.ts +57 -0
- package/src/Operations.js +263 -0
- package/src/People-DvNZauWw.js +69 -0
- package/src/PreviewFocus-C_EelZO5.js +104 -0
- package/src/Query-C0kGJF5_.d.ts +261 -0
- package/src/RevisionPreview-IVwbJ9Wy.js +133 -0
- package/src/Routes-BaZvm2LE.js +126 -0
- package/src/Routes-DM1rRp3r.d.ts +15 -0
- package/src/S3MediaObjects-y-WacEi9.js +193 -0
- package/src/Seo-BcpqxoAs.d.ts +57 -0
- package/src/Seo-CjNUtUkj.js +254 -0
- package/src/StudioApi-CXLwwocX.js +833 -0
- package/src/StudioErrors-T5zLGQ1M.js +117 -0
- package/src/StudioErrors-kq-E44lQ.d.ts +104 -0
- package/src/StudioServer.d.ts +20 -0
- package/src/StudioServer.js +34 -0
- package/src/answers-DcTg0Xv2.js +41 -0
- package/src/cli.js +681 -187
- package/src/contracts-rprW3ZOB.js +130 -0
- package/src/forms-3xuf0Ym7.d.ts +206 -0
- package/src/localeConfiguration-BPbkLi7-.js +32 -0
- package/src/localeContext-DhF3SPvM.js +59 -0
- package/src/locales-6OD4XGIZ.js +12 -0
- package/src/nuxtDelivery-BYX_Cddb.js +466 -0
- package/src/plugin-DTYuDaQu.js +7171 -0
- package/src/previewContext-dt3ZUh-w.js +4 -0
- package/src/previewRegions-CXjk5cbP.js +145 -0
- package/src/previewSource-fb-q3ESM.js +144 -0
- package/src/rendering-D9LVeEKX.js +47 -0
- package/src/rolldown-runtime-8H4AJuhK.js +14 -0
- package/src/runtime/CmsImage.js +38 -0
- package/src/runtime/DocumentPage.vue +10 -0
- package/src/runtime/DocumentPageContent.js +48 -0
- package/src/runtime/DocumentRenderer.d.ts +129 -0
- package/src/runtime/DocumentRenderer.js +2 -0
- package/src/runtime/api.js +48 -6
- package/src/runtime/delivery/useCmsDocument.js +2 -0
- package/src/runtime/delivery/useCmsDocumentQuery.js +2 -0
- package/src/runtime/delivery/useCmsDocumentSeo.js +2 -114
- package/src/runtime/delivery/useCmsLocale.js +10 -0
- package/src/runtime/plugin.js +2 -40
- package/src/runtime/preview.css +85 -0
- package/src/runtime/preview.js +277 -0
- package/src/runtime/previewSource.js +82 -0
- package/src/runtime/revisionPrivacy.js +13 -0
- package/src/runtime/studio.js +10 -0
- package/src/runtime/studioIcons.js +36 -0
- package/src/validation-3pggwcnm.js +396 -0
- package/src/validation-DpUwPC8Y.js +224 -0
- package/studio/THIRD-PARTY-LICENSES.md +2406 -0
- package/studio/chunks/AccountPage-DL3DitDM.js +288 -0
- package/studio/chunks/AccountPage-DL3DitDM.js.br +0 -0
- package/studio/chunks/AccountPage-DL3DitDM.js.gz +0 -0
- package/studio/chunks/ActivityPage-CLqVUqTh.js +584 -0
- package/studio/chunks/ActivityPage-CLqVUqTh.js.br +0 -0
- package/studio/chunks/ActivityPage-CLqVUqTh.js.gz +0 -0
- package/studio/chunks/Alert-D0D24z_a.js +335 -0
- package/studio/chunks/Alert-D0D24z_a.js.br +0 -0
- package/studio/chunks/Alert-D0D24z_a.js.gz +0 -0
- package/studio/chunks/Badge-BBFs88TI.js +346 -0
- package/studio/chunks/Badge-BBFs88TI.js.br +0 -0
- package/studio/chunks/Badge-BBFs88TI.js.gz +0 -0
- package/studio/chunks/Button-BT3ztSPx.js +14319 -0
- package/studio/chunks/Button-BT3ztSPx.js.br +0 -0
- package/studio/chunks/Button-BT3ztSPx.js.gz +0 -0
- package/studio/chunks/Collapsible-CKnEYIlp.js +246 -0
- package/studio/chunks/Collapsible-CKnEYIlp.js.br +0 -0
- package/studio/chunks/Collapsible-CKnEYIlp.js.gz +0 -0
- package/studio/chunks/ContentInventory-D7nsFA6U.js +1745 -0
- package/studio/chunks/ContentInventory-D7nsFA6U.js.br +0 -0
- package/studio/chunks/ContentInventory-D7nsFA6U.js.gz +0 -0
- package/studio/chunks/ContentPage-DCxt6BeD.js +18 -0
- package/studio/chunks/ContentPage-DCxt6BeD.js.br +0 -0
- package/studio/chunks/ContentPage-DCxt6BeD.js.gz +0 -0
- package/studio/chunks/DashboardSearch-DjyMjJwF.js +2413 -0
- package/studio/chunks/DashboardSearch-DjyMjJwF.js.br +0 -0
- package/studio/chunks/DashboardSearch-DjyMjJwF.js.gz +0 -0
- package/studio/chunks/DocumentLocaleMenu-0EkkOr6_.js +26063 -0
- package/studio/chunks/DocumentLocaleMenu-0EkkOr6_.js.br +0 -0
- package/studio/chunks/DocumentLocaleMenu-0EkkOr6_.js.gz +0 -0
- package/studio/chunks/DropdownMenu-CA9fB0uZ.js +4400 -0
- package/studio/chunks/DropdownMenu-CA9fB0uZ.js.br +0 -0
- package/studio/chunks/DropdownMenu-CA9fB0uZ.js.gz +0 -0
- package/studio/chunks/EditorPage-D_PAYEE4.js +7799 -0
- package/studio/chunks/EditorPage-D_PAYEE4.js.br +0 -0
- package/studio/chunks/EditorPage-D_PAYEE4.js.gz +0 -0
- package/studio/chunks/FormField-CgM6l2Yn.js +198 -0
- package/studio/chunks/FormField-CgM6l2Yn.js.br +0 -0
- package/studio/chunks/FormField-CgM6l2Yn.js.gz +0 -0
- package/studio/chunks/HelpPage-C-vrFcT_.js +552 -0
- package/studio/chunks/HelpPage-C-vrFcT_.js.br +0 -0
- package/studio/chunks/HelpPage-C-vrFcT_.js.gz +0 -0
- package/studio/chunks/Kbd-Ot7TIhVZ.js +271 -0
- package/studio/chunks/Kbd-Ot7TIhVZ.js.br +0 -0
- package/studio/chunks/Kbd-Ot7TIhVZ.js.gz +0 -0
- package/studio/chunks/MediaFolderDialog-DYu-eu-q.js +101 -0
- package/studio/chunks/MediaFolderDialog-DYu-eu-q.js.br +0 -0
- package/studio/chunks/MediaFolderDialog-DYu-eu-q.js.gz +0 -0
- package/studio/chunks/MediaPage-D-jaWtdl.js +923 -0
- package/studio/chunks/MediaPage-D-jaWtdl.js.br +0 -0
- package/studio/chunks/MediaPage-D-jaWtdl.js.gz +0 -0
- package/studio/chunks/MediaPicker-BZs2wUFz.js +837 -0
- package/studio/chunks/MediaPicker-BZs2wUFz.js.br +0 -0
- package/studio/chunks/MediaPicker-BZs2wUFz.js.gz +0 -0
- package/studio/chunks/MediaUploadPanel-C7Kyg6aR.js +1173 -0
- package/studio/chunks/MediaUploadPanel-C7Kyg6aR.js.br +0 -0
- package/studio/chunks/MediaUploadPanel-C7Kyg6aR.js.gz +0 -0
- package/studio/chunks/Modal-D6hSvxHd.js +265 -0
- package/studio/chunks/Modal-D6hSvxHd.js.br +0 -0
- package/studio/chunks/Modal-D6hSvxHd.js.gz +0 -0
- package/studio/chunks/NewDocumentDialog-C8B6_r3J.js +277 -0
- package/studio/chunks/NewDocumentDialog-C8B6_r3J.js.br +0 -0
- package/studio/chunks/NewDocumentDialog-C8B6_r3J.js.gz +0 -0
- package/studio/chunks/Pagination-D9BSo5H2.js +573 -0
- package/studio/chunks/Pagination-D9BSo5H2.js.br +0 -0
- package/studio/chunks/Pagination-D9BSo5H2.js.gz +0 -0
- package/studio/chunks/PeoplePage-CWIXitBD.js +783 -0
- package/studio/chunks/PeoplePage-CWIXitBD.js.br +0 -0
- package/studio/chunks/PeoplePage-CWIXitBD.js.gz +0 -0
- package/studio/chunks/Popover-B63bkTMS.js +128 -0
- package/studio/chunks/Popover-B63bkTMS.js.br +0 -0
- package/studio/chunks/Popover-B63bkTMS.js.gz +0 -0
- package/studio/chunks/PublicationActionDialog-Cm_P0C3I.js +255 -0
- package/studio/chunks/PublicationActionDialog-Cm_P0C3I.js.br +0 -0
- package/studio/chunks/PublicationActionDialog-Cm_P0C3I.js.gz +0 -0
- package/studio/chunks/Routes-DLYHmulE.js +102 -0
- package/studio/chunks/Routes-DLYHmulE.js.br +0 -0
- package/studio/chunks/Routes-DLYHmulE.js.gz +0 -0
- package/studio/chunks/RovingFocusItem-QZNg-wWF.js +95 -0
- package/studio/chunks/RovingFocusItem-QZNg-wWF.js.br +0 -0
- package/studio/chunks/RovingFocusItem-QZNg-wWF.js.gz +0 -0
- package/studio/chunks/ScheduledPage-C0hqrkr5.js +332 -0
- package/studio/chunks/ScheduledPage-C0hqrkr5.js.br +0 -0
- package/studio/chunks/ScheduledPage-C0hqrkr5.js.gz +0 -0
- package/studio/chunks/Search-BEgCe9Aj.js +14646 -0
- package/studio/chunks/Search-BEgCe9Aj.js.br +0 -0
- package/studio/chunks/Search-BEgCe9Aj.js.gz +0 -0
- package/studio/chunks/Select-B50WZMW-.js +2145 -0
- package/studio/chunks/Select-B50WZMW-.js.br +0 -0
- package/studio/chunks/Select-B50WZMW-.js.gz +0 -0
- package/studio/chunks/SelectMenu-DSweWGMz.js +2109 -0
- package/studio/chunks/SelectMenu-DSweWGMz.js.br +0 -0
- package/studio/chunks/SelectMenu-DSweWGMz.js.gz +0 -0
- package/studio/chunks/SeoPage-CNNxGe4h.js +846 -0
- package/studio/chunks/SeoPage-CNNxGe4h.js.br +0 -0
- package/studio/chunks/SeoPage-CNNxGe4h.js.gz +0 -0
- package/studio/chunks/Skeleton-COz8dcrw.js +39 -0
- package/studio/chunks/Skeleton-COz8dcrw.js.br +2 -0
- package/studio/chunks/Skeleton-COz8dcrw.js.gz +0 -0
- package/studio/chunks/Slideover-QMMHAAys.js +289 -0
- package/studio/chunks/Slideover-QMMHAAys.js.br +0 -0
- package/studio/chunks/Slideover-QMMHAAys.js.gz +0 -0
- package/studio/chunks/StudioPage-ngEIDr5d.js +80 -0
- package/studio/chunks/StudioPage-ngEIDr5d.js.br +0 -0
- package/studio/chunks/StudioPage-ngEIDr5d.js.gz +0 -0
- package/studio/chunks/StudioPageToolbar-BwHnqyr6.js +2524 -0
- package/studio/chunks/StudioPageToolbar-BwHnqyr6.js.br +0 -0
- package/studio/chunks/StudioPageToolbar-BwHnqyr6.js.gz +0 -0
- package/studio/chunks/Switch-qKl1aDn7.js +484 -0
- package/studio/chunks/Switch-qKl1aDn7.js.br +0 -0
- package/studio/chunks/Switch-qKl1aDn7.js.gz +0 -0
- package/studio/chunks/ToolPage-DxoVAJVk.js +29 -0
- package/studio/chunks/ToolPage-DxoVAJVk.js.br +0 -0
- package/studio/chunks/ToolPage-DxoVAJVk.js.gz +0 -0
- package/studio/chunks/Tooltip-Bu15m_DB.js +693 -0
- package/studio/chunks/Tooltip-Bu15m_DB.js.br +0 -0
- package/studio/chunks/Tooltip-Bu15m_DB.js.gz +0 -0
- package/studio/chunks/TrashPage-lhqLLdoG.js +12 -0
- package/studio/chunks/TrashPage-lhqLLdoG.js.br +0 -0
- package/studio/chunks/TrashPage-lhqLLdoG.js.gz +0 -0
- package/studio/chunks/VersionsPage-Cqy6UAp9.js +2349 -0
- package/studio/chunks/VersionsPage-Cqy6UAp9.js.br +0 -0
- package/studio/chunks/VersionsPage-Cqy6UAp9.js.gz +0 -0
- package/studio/chunks/VisuallyHiddenInput-Cu8hQLRf.js +113 -0
- package/studio/chunks/VisuallyHiddenInput-Cu8hQLRf.js.br +0 -0
- package/studio/chunks/VisuallyHiddenInput-Cu8hQLRf.js.gz +0 -0
- package/studio/chunks/arrays-CUJkmV4I.js +10 -0
- package/studio/chunks/arrays-CUJkmV4I.js.br +0 -0
- package/studio/chunks/arrays-CUJkmV4I.js.gz +0 -0
- package/studio/chunks/base-DkTekJe8.js +213 -0
- package/studio/chunks/base-DkTekJe8.js.br +0 -0
- package/studio/chunks/base-DkTekJe8.js.gz +0 -0
- package/studio/chunks/content-DUGl3N4d.js +6012 -0
- package/studio/chunks/content-DUGl3N4d.js.br +0 -0
- package/studio/chunks/content-DUGl3N4d.js.gz +0 -0
- package/studio/chunks/destinations-DPIQVQa6.js +227 -0
- package/studio/chunks/destinations-DPIQVQa6.js.br +0 -0
- package/studio/chunks/destinations-DPIQVQa6.js.gz +0 -0
- package/studio/chunks/en-073cjKW4.js +152 -0
- package/studio/chunks/en-073cjKW4.js.br +0 -0
- package/studio/chunks/en-073cjKW4.js.gz +0 -0
- package/studio/chunks/en-Bn8mxPuf.js +134 -0
- package/studio/chunks/en-Bn8mxPuf.js.br +0 -0
- package/studio/chunks/en-Bn8mxPuf.js.gz +0 -0
- package/studio/chunks/en-C9OiaUDZ.js +251 -0
- package/studio/chunks/en-C9OiaUDZ.js.br +0 -0
- package/studio/chunks/en-C9OiaUDZ.js.gz +0 -0
- package/studio/chunks/en-CHAR6jzx.js +147 -0
- package/studio/chunks/en-CHAR6jzx.js.br +0 -0
- package/studio/chunks/en-CHAR6jzx.js.gz +0 -0
- package/studio/chunks/en-Cq4N1vEF.js +93 -0
- package/studio/chunks/en-Cq4N1vEF.js.br +2 -0
- package/studio/chunks/en-Cq4N1vEF.js.gz +0 -0
- package/studio/chunks/en-D2hRqlse.js +140 -0
- package/studio/chunks/en-D2hRqlse.js.br +0 -0
- package/studio/chunks/en-D2hRqlse.js.gz +0 -0
- package/studio/chunks/en-DiUC3-j6.js +144 -0
- package/studio/chunks/en-DiUC3-j6.js.br +0 -0
- package/studio/chunks/en-DiUC3-j6.js.gz +0 -0
- package/studio/chunks/english-Cs_Adu-u.js +8 -0
- package/studio/chunks/english-Cs_Adu-u.js.br +0 -0
- package/studio/chunks/english-Cs_Adu-u.js.gz +0 -0
- package/studio/chunks/esm-D6DqSiL1.js +752 -0
- package/studio/chunks/esm-D6DqSiL1.js.br +0 -0
- package/studio/chunks/esm-D6DqSiL1.js.gz +0 -0
- package/studio/chunks/externalRequest-CTzr2nDq.js +23 -0
- package/studio/chunks/externalRequest-CTzr2nDq.js.br +0 -0
- package/studio/chunks/externalRequest-CTzr2nDq.js.gz +0 -0
- package/studio/chunks/iconify-DR9ryCPv.js +1007 -0
- package/studio/chunks/iconify-DR9ryCPv.js.br +0 -0
- package/studio/chunks/iconify-DR9ryCPv.js.gz +0 -0
- package/studio/chunks/icons-D2MsAaXq.js +183 -0
- package/studio/chunks/icons-D2MsAaXq.js.br +0 -0
- package/studio/chunks/icons-D2MsAaXq.js.gz +0 -0
- package/studio/chunks/leaveGuards-D22fTGgr.js +26 -0
- package/studio/chunks/leaveGuards-D22fTGgr.js.br +0 -0
- package/studio/chunks/leaveGuards-D22fTGgr.js.gz +0 -0
- package/studio/chunks/lucideIcons-EyqyPBsX.js +238 -0
- package/studio/chunks/lucideIcons-EyqyPBsX.js.br +0 -0
- package/studio/chunks/lucideIcons-EyqyPBsX.js.gz +0 -0
- package/studio/chunks/mediaRoute--8cY8rUe.js +17 -0
- package/studio/chunks/mediaRoute--8cY8rUe.js.br +0 -0
- package/studio/chunks/mediaRoute--8cY8rUe.js.gz +0 -0
- package/studio/chunks/newDocumentPlanning-C26DHpvh.js +77 -0
- package/studio/chunks/newDocumentPlanning-C26DHpvh.js.br +0 -0
- package/studio/chunks/newDocumentPlanning-C26DHpvh.js.gz +0 -0
- package/studio/chunks/notifications-OKOLc40v.js +110 -0
- package/studio/chunks/notifications-OKOLc40v.js.br +0 -0
- package/studio/chunks/notifications-OKOLc40v.js.gz +0 -0
- package/studio/chunks/operations-CjNHyrEX.js +57 -0
- package/studio/chunks/operations-CjNHyrEX.js.br +0 -0
- package/studio/chunks/operations-CjNHyrEX.js.gz +0 -0
- package/studio/chunks/overlay-DnqFLZTc.js +1733 -0
- package/studio/chunks/overlay-DnqFLZTc.js.br +0 -0
- package/studio/chunks/overlay-DnqFLZTc.js.gz +0 -0
- package/studio/chunks/presentation-DF83w0hE.js +57 -0
- package/studio/chunks/presentation-DF83w0hE.js.br +0 -0
- package/studio/chunks/presentation-DF83w0hE.js.gz +0 -0
- package/studio/chunks/runtime-core.esm-bundler-DKFA9Rep.js +4557 -0
- package/studio/chunks/runtime-core.esm-bundler-DKFA9Rep.js.br +0 -0
- package/studio/chunks/runtime-core.esm-bundler-DKFA9Rep.js.gz +0 -0
- package/studio/chunks/searchPresentation-DFwxQkt3.js +76 -0
- package/studio/chunks/searchPresentation-DFwxQkt3.js.br +0 -0
- package/studio/chunks/searchPresentation-DFwxQkt3.js.gz +0 -0
- package/studio/chunks/status-DQv6ihkU.js +38 -0
- package/studio/chunks/status-DQv6ihkU.js.br +0 -0
- package/studio/chunks/status-DQv6ihkU.js.gz +0 -0
- package/studio/chunks/studioContext-I8HozGU1.js +4953 -0
- package/studio/chunks/studioContext-I8HozGU1.js.br +0 -0
- package/studio/chunks/studioContext-I8HozGU1.js.gz +0 -0
- package/studio/chunks/studioQueries-BR-9NT5F.js +73 -0
- package/studio/chunks/studioQueries-BR-9NT5F.js.br +0 -0
- package/studio/chunks/studioQueries-BR-9NT5F.js.gz +0 -0
- package/studio/chunks/studioSearch-ByaL-QpM.js +1095 -0
- package/studio/chunks/studioSearch-ByaL-QpM.js.br +0 -0
- package/studio/chunks/studioSearch-ByaL-QpM.js.gz +0 -0
- package/studio/chunks/useAcknowledgedDraft-0_c9sWI6.js +62 -0
- package/studio/chunks/useAcknowledgedDraft-0_c9sWI6.js.br +0 -0
- package/studio/chunks/useAcknowledgedDraft-0_c9sWI6.js.gz +0 -0
- package/studio/chunks/useApi-CUWMwLLw-B3Q3g2nf.js +189 -0
- package/studio/chunks/useApi-CUWMwLLw-B3Q3g2nf.js.br +0 -0
- package/studio/chunks/useApi-CUWMwLLw-B3Q3g2nf.js.gz +0 -0
- package/studio/chunks/useDocumentMessage-BAWvc38w.js +16 -0
- package/studio/chunks/useDocumentMessage-BAWvc38w.js.br +3 -0
- package/studio/chunks/useDocumentMessage-BAWvc38w.js.gz +0 -0
- package/studio/chunks/useFilter-DzyiTR7f.js +87 -0
- package/studio/chunks/useFilter-DzyiTR7f.js.br +0 -0
- package/studio/chunks/useFilter-DzyiTR7f.js.gz +0 -0
- package/studio/chunks/useFormControl-CL7sSCUo.js +8 -0
- package/studio/chunks/useFormControl-CL7sSCUo.js.br +0 -0
- package/studio/chunks/useFormControl-CL7sSCUo.js.gz +0 -0
- package/studio/chunks/useGraceArea-Chcy25IQ.js +154 -0
- package/studio/chunks/useGraceArea-Chcy25IQ.js.br +0 -0
- package/studio/chunks/useGraceArea-Chcy25IQ.js.gz +0 -0
- package/studio/chunks/useLeaveConfirmation-_iCSnKEp.js +44 -0
- package/studio/chunks/useLeaveConfirmation-_iCSnKEp.js.br +8 -0
- package/studio/chunks/useLeaveConfirmation-_iCSnKEp.js.gz +0 -0
- package/studio/chunks/useLinkCopy-CMjQteCy.js +35 -0
- package/studio/chunks/useLinkCopy-CMjQteCy.js.br +0 -0
- package/studio/chunks/useLinkCopy-CMjQteCy.js.gz +0 -0
- package/studio/chunks/usePointerMotion-DwRcwBNQ.js +16 -0
- package/studio/chunks/usePointerMotion-DwRcwBNQ.js.br +0 -0
- package/studio/chunks/usePointerMotion-DwRcwBNQ.js.gz +0 -0
- package/studio/chunks/useStudioNavigation-CLwtSYpb.js +298 -0
- package/studio/chunks/useStudioNavigation-CLwtSYpb.js.br +0 -0
- package/studio/chunks/useStudioNavigation-CLwtSYpb.js.gz +0 -0
- package/studio/chunks/useStudioPages-DR9qmYLg.js +79 -0
- package/studio/chunks/useStudioPages-DR9qmYLg.js.br +0 -0
- package/studio/chunks/useStudioPages-DR9qmYLg.js.gz +0 -0
- package/studio/chunks/utils-mdScC0v0.js +59 -0
- package/studio/chunks/utils-mdScC0v0.js.br +0 -0
- package/studio/chunks/utils-mdScC0v0.js.gz +0 -0
- package/studio/chunks/virtualizer-D1S0bZ4t.js +781 -0
- package/studio/chunks/virtualizer-D1S0bZ4t.js.br +0 -0
- package/studio/chunks/virtualizer-D1S0bZ4t.js.gz +0 -0
- package/studio/help/64f767fe29c2-save-and-publish.svg +7 -0
- package/studio/host.css +1 -1
- package/studio/host.css.br +0 -0
- package/studio/host.css.gz +0 -0
- package/studio/host.js +8757 -39178
- package/studio/host.js.br +0 -0
- package/studio/host.js.gz +0 -0
- package/CHANGELOG.md +0 -13
- package/bin/cms.mjs +0 -2
- package/src/ApplicationTypes.d.ts +0 -84
- package/src/ApplicationTypes.js +0 -1
- package/src/Configuration-Da5B2PVH.js +0 -1191
- package/src/Configuration-Da5B2PVH.js.map +0 -1
- package/src/Configuration.d.ts +0 -82
- package/src/Configuration.js +0 -8
- package/src/Configuration.js.map +0 -1
- package/src/Content.d.ts +0 -68
- package/src/Content.js +0 -373
- package/src/Content.js.map +0 -1
- package/src/ContentTransfer-BxwswWn3.js +0 -86
- package/src/ContentTransfer-BxwswWn3.js.map +0 -1
- package/src/ContentTransfer-Z9FHyLez.d.ts +0 -72
- package/src/DocumentEngine-hh_IGPXO.js +0 -978
- package/src/DocumentEngine-hh_IGPXO.js.map +0 -1
- package/src/DocumentModel.d.ts +0 -52
- package/src/DocumentModel.js +0 -66
- package/src/DocumentModel.js.map +0 -1
- package/src/Forms-CX-hwmJF.js +0 -391
- package/src/Forms-CX-hwmJF.js.map +0 -1
- package/src/Forms-CfNPTiCr.js +0 -110
- package/src/Forms-CfNPTiCr.js.map +0 -1
- package/src/Forms-R0HoTR-o.d.ts +0 -92
- package/src/Forms.js.map +0 -1
- package/src/HttpPaths-c9nLZ9H2.js +0 -21
- package/src/HttpPaths-c9nLZ9H2.js.map +0 -1
- package/src/I18n-zbqpWxki.d.ts +0 -29
- package/src/Media-j1bTritO.js +0 -112
- package/src/Media-j1bTritO.js.map +0 -1
- package/src/Module.js.map +0 -1
- package/src/References-CCPDAPve.js +0 -45
- package/src/References-CCPDAPve.js.map +0 -1
- package/src/S3MediaObjects-Dwhl2deX.js +0 -2742
- package/src/S3MediaObjects-Dwhl2deX.js.map +0 -1
- package/src/Seo-402YumpT.d.ts +0 -198
- package/src/cli/content.js +0 -101
- package/src/cli/content.js.map +0 -1
- package/src/cli.js.map +0 -1
- package/src/connection-BP80q4d-.js +0 -92
- package/src/connection-BP80q4d-.js.map +0 -1
- package/src/dev-lifecycle-CjDq63Ft.js +0 -535
- package/src/dev-lifecycle-CjDq63Ft.js.map +0 -1
- package/src/installation-DYNQQBD3.js +0 -9114
- package/src/installation-DYNQQBD3.js.map +0 -1
- package/src/internal/application-types.js +0 -43
- package/src/internal/application-types.js.map +0 -1
- package/src/internal/authoring-catalog.js +0 -158
- package/src/internal/authoring-catalog.js.map +0 -1
- package/src/internal/authoring-compiler.js +0 -146
- package/src/internal/authoring-compiler.js.map +0 -1
- package/src/internal/authoring-metadata.js +0 -191
- package/src/internal/authoring-metadata.js.map +0 -1
- package/src/internal/cms-config.js +0 -45
- package/src/internal/cms-config.js.map +0 -1
- package/src/internal/configuration.js +0 -228
- package/src/internal/configuration.js.map +0 -1
- package/src/internal/dev-lifecycle.js +0 -3
- package/src/internal/diagnostics.js +0 -47
- package/src/internal/diagnostics.js.map +0 -1
- package/src/internal/document-model.js +0 -376
- package/src/internal/document-model.js.map +0 -1
- package/src/internal/field-metadata.js +0 -7
- package/src/internal/field-metadata.js.map +0 -1
- package/src/internal/form-capabilities.js +0 -12
- package/src/internal/form-capabilities.js.map +0 -1
- package/src/internal/i18n.js +0 -73
- package/src/internal/i18n.js.map +0 -1
- package/src/internal/studio-app.js +0 -68
- package/src/internal/studio-app.js.map +0 -1
- package/src/location-CMNGO3lU.js +0 -35
- package/src/location-CMNGO3lU.js.map +0 -1
- package/src/metadata-DN9_K6Yl.js +0 -201
- package/src/metadata-DN9_K6Yl.js.map +0 -1
- package/src/models-5j67LMqW.js +0 -131
- package/src/models-5j67LMqW.js.map +0 -1
- package/src/models-VmGmG19-.js +0 -628
- package/src/models-VmGmG19-.js.map +0 -1
- package/src/runtime/api.js.map +0 -1
- package/src/runtime/blocks.js +0 -30
- package/src/runtime/blocks.js.map +0 -1
- package/src/runtime/collaboration.js +0 -45
- package/src/runtime/collaboration.js.map +0 -1
- package/src/runtime/delivery/DocumentField.js +0 -23
- package/src/runtime/delivery/DocumentField.js.map +0 -1
- package/src/runtime/delivery/DocumentRenderer.js +0 -61
- package/src/runtime/delivery/DocumentRenderer.js.map +0 -1
- package/src/runtime/delivery/DocumentScope.js +0 -41
- package/src/runtime/delivery/DocumentScope.js.map +0 -1
- package/src/runtime/delivery/blocks.js +0 -8
- package/src/runtime/delivery/blocks.js.map +0 -1
- package/src/runtime/delivery/context.js +0 -12
- package/src/runtime/delivery/context.js.map +0 -1
- package/src/runtime/delivery/document-page.js +0 -21
- package/src/runtime/delivery/document-page.js.map +0 -1
- package/src/runtime/delivery/document.js +0 -43
- package/src/runtime/delivery/document.js.map +0 -1
- package/src/runtime/delivery/error.js +0 -11
- package/src/runtime/delivery/error.js.map +0 -1
- package/src/runtime/delivery/plugin.js +0 -99
- package/src/runtime/delivery/plugin.js.map +0 -1
- package/src/runtime/delivery/preview.d.ts +0 -11
- package/src/runtime/delivery/preview.js +0 -6
- package/src/runtime/delivery/preview.js.map +0 -1
- package/src/runtime/delivery/types.d.ts +0 -2
- package/src/runtime/delivery/types.js +0 -1
- package/src/runtime/delivery/useCmsDocumentSeo.d.ts +0 -67
- package/src/runtime/delivery/useCmsDocumentSeo.js.map +0 -1
- package/src/runtime/delivery/useDocument.d.ts +0 -6
- package/src/runtime/delivery/useDocument.js +0 -23
- package/src/runtime/delivery/useDocument.js.map +0 -1
- package/src/runtime/delivery/useDocumentQuery.d.ts +0 -7
- package/src/runtime/delivery/useDocumentQuery.js +0 -29
- package/src/runtime/delivery/useDocumentQuery.js.map +0 -1
- package/src/runtime/forms/document.js +0 -38
- package/src/runtime/forms/document.js.map +0 -1
- package/src/runtime/forms/useCmsForm.js +0 -257
- package/src/runtime/forms/useCmsForm.js.map +0 -1
- package/src/runtime/i18n/translator.js +0 -51
- package/src/runtime/i18n/translator.js.map +0 -1
- package/src/runtime/i18n/useCmsI18n.d.ts +0 -13
- package/src/runtime/i18n/useCmsI18n.js +0 -38
- package/src/runtime/i18n/useCmsI18n.js.map +0 -1
- package/src/runtime/installation.js +0 -3
- package/src/runtime/plugin.js.map +0 -1
- package/src/runtime/preview/CmsStudioPreviewMarker.js +0 -29
- package/src/runtime/preview/CmsStudioPreviewMarker.js.map +0 -1
- package/src/runtime/preview/comark-document.js +0 -37
- package/src/runtime/preview/comark-document.js.map +0 -1
- package/src/runtime/preview/connection.js +0 -3
- package/src/runtime/preview/controller.js +0 -265
- package/src/runtime/preview/controller.js.map +0 -1
- package/src/runtime/preview/crypto.js +0 -16
- package/src/runtime/preview/crypto.js.map +0 -1
- package/src/runtime/preview/overlay.js +0 -122
- package/src/runtime/preview/overlay.js.map +0 -1
- package/src/runtime/preview/plugin.client.js +0 -68
- package/src/runtime/preview/plugin.client.js.map +0 -1
- package/src/runtime/preview/preview.css +0 -91
- package/src/runtime/preview/protocol.d.ts +0 -16
- package/src/runtime/preview/protocol.js +0 -23
- package/src/runtime/preview/protocol.js.map +0 -1
- package/src/runtime/preview/regions.js +0 -142
- package/src/runtime/preview/regions.js.map +0 -1
- package/src/runtime/preview/store.js +0 -4
- package/src/runtime/sitemap-entries.js +0 -17
- package/src/runtime/sitemap-entries.js.map +0 -1
- package/src/runtime/sitemap.js +0 -23
- package/src/runtime/sitemap.js.map +0 -1
- package/src/runtime/studio-app.js +0 -17
- package/src/runtime/studio-app.js.map +0 -1
- package/src/runtime/studio-document.js +0 -46
- package/src/runtime/studio-document.js.map +0 -1
- package/src/runtime/studio-entry.js +0 -19
- package/src/runtime/studio-entry.js.map +0 -1
- package/src/runtime/studio-navigation.js +0 -11
- package/src/runtime/studio-navigation.js.map +0 -1
- package/src/scalars-CA6kyipS.d.ts +0 -7
- package/src/scalars-CVZqT3L0.js +0 -22
- package/src/scalars-CVZqT3L0.js.map +0 -1
- package/src/store-X1e1o_MF.js +0 -209
- package/src/store-X1e1o_MF.js.map +0 -1
- package/src/types-DZ0IV-Ow.d.ts +0 -101
- package/studio/CreateDocumentDialog-BpjBYGfI.js +0 -335
- package/studio/SelectMenu-KiXwx4Y_.js +0 -34032
- package/studio/collaboration-DcK2F6v9.js +0 -4566
- package/studio/editor-P2rB7Csp.js +0 -30128
- package/studio/rolldown-runtime-Dy4uBu1J.js +0 -11
package/src/Module.js
CHANGED
|
@@ -1,170 +1,1047 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
7
|
-
import {
|
|
8
|
-
import { Effect,
|
|
9
|
-
import {
|
|
10
|
-
import {
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
1
|
+
import { r as defineLocales } from "./Locales-Ch7a5xuA.js";
|
|
2
|
+
import { r as validateBlockConfiguration } from "./validation-3pggwcnm.js";
|
|
3
|
+
import { n as FieldDefinition, t as CollectionDefinition } from "./Fields-ioGaMEh9.js";
|
|
4
|
+
import { r as BlockSlot, t as BlockDefinition } from "./Blocks-BrxSemnd.js";
|
|
5
|
+
import { c as defineStudioModules } from "./People-DvNZauWw.js";
|
|
6
|
+
import { t as load } from "./Configuration-Dk2k3OIc.js";
|
|
7
|
+
import { t as blockComponentName } from "./rendering-D9LVeEKX.js";
|
|
8
|
+
import { Effect, Schema } from "effect";
|
|
9
|
+
import { readFile, readdir, stat } from "node:fs/promises";
|
|
10
|
+
import { dirname, join, relative, resolve, sep } from "node:path";
|
|
11
|
+
import { existsSync, readFileSync, statSync } from "node:fs";
|
|
12
|
+
import { fileURLToPath, pathToFileURL } from "node:url";
|
|
13
|
+
import { addComponent, addDevServerHandler, addImports, addNitroPlugin, addPluginTemplate, addServerHandler, addServerTemplate, addTypeTemplate, addVitePlugin, createResolver, defineNuxtModule, extendPages, extendRouteRules } from "@nuxt/kit";
|
|
14
|
+
import { MagicString, parse } from "@vue/compiler-sfc";
|
|
15
|
+
import ts from "typescript";
|
|
16
|
+
//#region src/internal/authoringProgram.ts
|
|
17
|
+
const options = {
|
|
18
|
+
strict: true,
|
|
19
|
+
noEmit: true,
|
|
20
|
+
skipLibCheck: true,
|
|
21
|
+
target: ts.ScriptTarget.ESNext,
|
|
22
|
+
module: ts.ModuleKind.ESNext,
|
|
23
|
+
moduleResolution: ts.ModuleResolutionKind.Bundler
|
|
24
|
+
};
|
|
25
|
+
/** One installation shares parsed dependencies and a checker across its block catalog. */
|
|
26
|
+
function createAuthoringProgram() {
|
|
27
|
+
const scripts = /* @__PURE__ */ new Map();
|
|
28
|
+
const files = /* @__PURE__ */ new Map();
|
|
29
|
+
let dependencyStamps = /* @__PURE__ */ new Map();
|
|
30
|
+
const host = ts.createCompilerHost(options);
|
|
31
|
+
const getSourceFile = host.getSourceFile.bind(host);
|
|
32
|
+
const fileExists = host.fileExists.bind(host);
|
|
33
|
+
const readFile = host.readFile.bind(host);
|
|
34
|
+
let program;
|
|
35
|
+
let dirty = true;
|
|
36
|
+
host.getSourceFile = (filename, languageVersion, onError, shouldCreateNewSourceFile) => {
|
|
37
|
+
const cached = files.get(filename);
|
|
38
|
+
if (cached) return cached;
|
|
39
|
+
const source = scripts.get(filename);
|
|
40
|
+
const file = source === void 0 ? getSourceFile(filename, languageVersion, onError, shouldCreateNewSourceFile) : ts.createSourceFile(filename, source, languageVersion, true, ts.ScriptKind.TS);
|
|
41
|
+
if (file) files.set(filename, file);
|
|
42
|
+
return file;
|
|
43
|
+
};
|
|
44
|
+
host.fileExists = (filename) => scripts.has(filename) || fileExists(filename);
|
|
45
|
+
host.readFile = (filename) => scripts.get(filename) ?? readFile(filename);
|
|
46
|
+
function register(filename, source) {
|
|
47
|
+
if (scripts.get(filename) === source) return;
|
|
48
|
+
scripts.set(filename, source);
|
|
49
|
+
files.delete(filename);
|
|
50
|
+
dirty = true;
|
|
31
51
|
}
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
});
|
|
78
|
-
registerDeliveryUi(nuxt);
|
|
79
|
-
yield* registerStudioApp(nuxt, resolver);
|
|
80
|
-
configureNitro(nuxt);
|
|
81
|
-
addServerPlugin(installationPluginTemplate.filename);
|
|
82
|
-
addServerHandler({
|
|
83
|
-
handler: resolver.resolve("./runtime/api"),
|
|
84
|
-
route: `${CMS_AUTHENTICATION_PATH}/**:path`
|
|
85
|
-
});
|
|
86
|
-
addServerHandler({
|
|
87
|
-
handler: resolver.resolve("./runtime/collaboration"),
|
|
88
|
-
route: STUDIO_COLLABORATION_PATH
|
|
89
|
-
});
|
|
90
|
-
addServerHandler({
|
|
91
|
-
handler: resolver.resolve("./runtime/api"),
|
|
92
|
-
route: `${STUDIO_API_PATH}/**:path`
|
|
93
|
-
});
|
|
94
|
-
});
|
|
95
|
-
function configureSitemap(options) {
|
|
96
|
-
if (options.sitemap === false) return;
|
|
97
|
-
const sitemap = options.sitemap ?? {};
|
|
98
|
-
const sources = sitemap.sources ?? [];
|
|
99
|
-
if (!sources.includes(CMS_SITEMAP_SOURCE_PATH)) sitemap.sources = [...sources, CMS_SITEMAP_SOURCE_PATH];
|
|
100
|
-
options.sitemap = sitemap;
|
|
101
|
-
}
|
|
102
|
-
function registerDeliveryUi(nuxt) {
|
|
103
|
-
addPlugin(resolver.resolve("./runtime/blocks"));
|
|
104
|
-
nuxt.options.css.push(resolver.resolve("./runtime/preview/preview.css"));
|
|
105
|
-
addComponent({
|
|
106
|
-
name: "DocumentField",
|
|
107
|
-
filePath: resolver.resolve("./runtime/delivery/DocumentField")
|
|
108
|
-
});
|
|
109
|
-
addComponent({
|
|
110
|
-
name: "DocumentRenderer",
|
|
111
|
-
filePath: resolver.resolve("./runtime/delivery/DocumentRenderer")
|
|
112
|
-
});
|
|
113
|
-
addComponent({
|
|
114
|
-
name: "DocumentScope",
|
|
115
|
-
filePath: resolver.resolve("./runtime/delivery/DocumentScope")
|
|
52
|
+
function check(filename, source) {
|
|
53
|
+
register(filename, source);
|
|
54
|
+
if (dirty || !program) {
|
|
55
|
+
program = ts.createProgram([...scripts.keys()], options, host, program);
|
|
56
|
+
dirty = false;
|
|
57
|
+
dependencyStamps = new Map(program.getSourceFiles().flatMap((file) => !scripts.has(file.fileName) && !file.fileName.includes("/node_modules/") ? [[file.fileName, fileStamp(file.fileName)]] : []));
|
|
58
|
+
}
|
|
59
|
+
const file = program.getSourceFile(filename);
|
|
60
|
+
if (!file) throw new Error(`${filename}: Vue type information is unavailable.`);
|
|
61
|
+
return {
|
|
62
|
+
file,
|
|
63
|
+
checker: program.getTypeChecker()
|
|
64
|
+
};
|
|
65
|
+
}
|
|
66
|
+
function dependencies() {
|
|
67
|
+
return [...dependencyStamps.keys()];
|
|
68
|
+
}
|
|
69
|
+
function refreshDependencies() {
|
|
70
|
+
let changed = false;
|
|
71
|
+
for (const [filename, stamp] of dependencyStamps) {
|
|
72
|
+
if (fileStamp(filename) === stamp) continue;
|
|
73
|
+
invalidate(filename);
|
|
74
|
+
changed = true;
|
|
75
|
+
}
|
|
76
|
+
return changed;
|
|
77
|
+
}
|
|
78
|
+
function invalidate(filename) {
|
|
79
|
+
files.delete(filename);
|
|
80
|
+
files.delete(`${filename}.ts`);
|
|
81
|
+
dependencyStamps.delete(filename);
|
|
82
|
+
program = void 0;
|
|
83
|
+
dirty = true;
|
|
84
|
+
}
|
|
85
|
+
return {
|
|
86
|
+
register,
|
|
87
|
+
check,
|
|
88
|
+
dependencies,
|
|
89
|
+
refreshDependencies,
|
|
90
|
+
invalidate
|
|
91
|
+
};
|
|
92
|
+
}
|
|
93
|
+
function fileStamp(filename) {
|
|
94
|
+
const stat = statSync(filename, {
|
|
95
|
+
bigint: true,
|
|
96
|
+
throwIfNoEntry: false
|
|
116
97
|
});
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
98
|
+
return stat ? `${stat.mtimeNs}:${stat.size}` : "missing";
|
|
99
|
+
}
|
|
100
|
+
//#endregion
|
|
101
|
+
//#region src/internal/authoring/metadata.ts
|
|
102
|
+
/** Static declarations are read from syntax; site code is never evaluated. */
|
|
103
|
+
function vueDefaults(calls, editable, fail) {
|
|
104
|
+
const values = {};
|
|
105
|
+
const has = /* @__PURE__ */ new Set();
|
|
106
|
+
const call = calls.find((candidate) => candidate.arguments[0] && ts.isCallExpression(candidate.arguments[0]) && ts.isIdentifier(candidate.arguments[0].expression) && candidate.arguments[0].expression.text === "defineProps");
|
|
107
|
+
if (!call) return {
|
|
108
|
+
values,
|
|
109
|
+
has
|
|
110
|
+
};
|
|
111
|
+
const value = call.arguments[1];
|
|
112
|
+
if (!value || !ts.isObjectLiteralExpression(value)) fail(call, "withDefaults needs a static object for CMS props.");
|
|
113
|
+
for (const property of value.properties) {
|
|
114
|
+
if (!ts.isPropertyAssignment(property) || !staticName(property.name)) fail(property, "withDefaults needs literal prop names for CMS blocks.");
|
|
115
|
+
const name = staticName(property.name);
|
|
116
|
+
if (!name) fail(property, "withDefaults needs literal prop names for CMS blocks.");
|
|
117
|
+
has.add(name);
|
|
118
|
+
if (editable.has(name)) values[name] = jsonValue(property.initializer, fail);
|
|
119
|
+
}
|
|
120
|
+
return {
|
|
121
|
+
values,
|
|
122
|
+
has
|
|
123
|
+
};
|
|
124
|
+
}
|
|
125
|
+
function objectValue(node, fail) {
|
|
126
|
+
const value = {};
|
|
127
|
+
for (const property of node.properties) {
|
|
128
|
+
if (!ts.isPropertyAssignment(property) || !property.name || !staticName(property.name)) fail(property, "CMS metadata needs literal named properties; spreads and methods are unsupported.");
|
|
129
|
+
const name = staticName(property.name);
|
|
130
|
+
if (!name) fail(property, "CMS metadata needs literal property names.");
|
|
131
|
+
if (Object.hasOwn(value, name)) fail(property, `Duplicate CMS property "${name}".`);
|
|
132
|
+
value[name] = jsonValue(property.initializer, fail);
|
|
133
|
+
}
|
|
134
|
+
return Schema.decodeSync(Schema.JsonObject)(value);
|
|
135
|
+
}
|
|
136
|
+
function jsonValue(node, fail) {
|
|
137
|
+
if (ts.isAsExpression(node) || ts.isSatisfiesExpression(node) || ts.isParenthesizedExpression(node)) return jsonValue(node.expression, fail);
|
|
138
|
+
if (ts.isArrowFunction(node) && !ts.isBlock(node.body)) return jsonValue(node.body, fail);
|
|
139
|
+
if (ts.isStringLiteral(node) || ts.isNoSubstitutionTemplateLiteral(node)) return node.text;
|
|
140
|
+
if (ts.isNumericLiteral(node)) return Number(node.text);
|
|
141
|
+
if (node.kind === ts.SyntaxKind.TrueKeyword) return true;
|
|
142
|
+
if (node.kind === ts.SyntaxKind.FalseKeyword) return false;
|
|
143
|
+
if (node.kind === ts.SyntaxKind.NullKeyword) return null;
|
|
144
|
+
if (ts.isPrefixUnaryExpression(node) && node.operator === ts.SyntaxKind.MinusToken && ts.isNumericLiteral(node.operand)) return -Number(node.operand.text);
|
|
145
|
+
if (ts.isArrayLiteralExpression(node)) return node.elements.map((element) => jsonValue(element, fail));
|
|
146
|
+
if (ts.isObjectLiteralExpression(node)) return objectValue(node, fail);
|
|
147
|
+
return fail(node, "CMS metadata must contain static JSON values.");
|
|
148
|
+
}
|
|
149
|
+
function staticName(node) {
|
|
150
|
+
return ts.isIdentifier(node) || ts.isStringLiteral(node) || ts.isNumericLiteral(node) ? node.text : void 0;
|
|
151
|
+
}
|
|
152
|
+
function record(value, node, fail, label) {
|
|
153
|
+
if (!Schema.is(Schema.JsonObject)(value)) fail(node, `${label} must be an object.`);
|
|
154
|
+
return value;
|
|
155
|
+
}
|
|
156
|
+
function string(value, node, fail, label) {
|
|
157
|
+
if (!Schema.is(Schema.NonEmptyString)(value)) fail(node, `${label} must be a nonempty string.`);
|
|
158
|
+
return value;
|
|
159
|
+
}
|
|
160
|
+
function strings(value, node, fail) {
|
|
161
|
+
if (!Schema.is(Schema.Array(Schema.String))(value)) fail(node, "Expected a string array.");
|
|
162
|
+
return value;
|
|
163
|
+
}
|
|
164
|
+
function keys(value, allowed, node, fail) {
|
|
165
|
+
for (const key of Object.keys(value)) if (!allowed.includes(key)) fail(node, `Unknown CMS metadata key "${key}".`);
|
|
166
|
+
}
|
|
167
|
+
//#endregion
|
|
168
|
+
//#region src/internal/authoring/fields.ts
|
|
169
|
+
/** Editable fields must agree with the component's checked Vue prop types. */
|
|
170
|
+
function fieldFromType(name, metadata, rawType, required, defaultValue, checker, node, fail) {
|
|
171
|
+
keys(metadata, [
|
|
172
|
+
"label",
|
|
173
|
+
"description",
|
|
174
|
+
"input",
|
|
175
|
+
"optionLabels",
|
|
176
|
+
"mediaKind",
|
|
177
|
+
"collections",
|
|
178
|
+
"fields"
|
|
179
|
+
], node, fail);
|
|
180
|
+
const label = string(metadata.label, node, fail, `${name}.label`);
|
|
181
|
+
const description = metadata.description === void 0 ? void 0 : string(metadata.description, node, fail, "description");
|
|
182
|
+
const common = {
|
|
183
|
+
name,
|
|
184
|
+
label,
|
|
185
|
+
required
|
|
186
|
+
};
|
|
187
|
+
if (description !== void 0) Object.assign(common, { description });
|
|
188
|
+
const type = checker.getNonNullableType(rawType);
|
|
189
|
+
const members = type.isUnion() ? type.types : [type];
|
|
190
|
+
const choices = literalChoices(type);
|
|
191
|
+
const input = metadata.input === void 0 ? inferInput(type, checker) : string(metadata.input, node, fail, "input");
|
|
192
|
+
if (input === "select" || input === "multi-select") {
|
|
193
|
+
if (input === "select" && !stringType(type)) fail(node, `${name} needs a string Vue prop for select.`);
|
|
194
|
+
const item = input === "multi-select" ? checker.getIndexTypeOfType(type, ts.IndexKind.Number) : void 0;
|
|
195
|
+
if (input === "multi-select" && (!item || !stringType(item))) fail(node, `${name} needs a string array Vue prop for multi-select.`);
|
|
196
|
+
const labels = record(metadata.optionLabels ?? {}, node, fail, "optionLabels");
|
|
197
|
+
const inferredChoices = input === "multi-select" && item ? literalChoices(item) : choices;
|
|
198
|
+
const values = inferredChoices.length ? inferredChoices : Object.keys(labels);
|
|
199
|
+
if (input === "select" && !values.length) fail(node, `${name} needs literal string choices or optionLabels.`);
|
|
200
|
+
for (const key of Object.keys(labels)) if (!values.includes(key)) fail(node, `${name} has unknown choice "${key}".`);
|
|
201
|
+
const options = values.map((value) => ({
|
|
202
|
+
value,
|
|
203
|
+
label: labels[value] === void 0 ? humanize(value) : string(labels[value], node, fail, "option label")
|
|
204
|
+
}));
|
|
205
|
+
const field = {
|
|
206
|
+
...common,
|
|
207
|
+
kind: input,
|
|
208
|
+
options
|
|
209
|
+
};
|
|
210
|
+
if (defaultValue !== void 0) Object.assign(field, { defaultValue });
|
|
211
|
+
return decodeField(field, node, fail);
|
|
212
|
+
}
|
|
213
|
+
if (input === "object" || input === "list") {
|
|
214
|
+
const nested = record(metadata.fields, node, fail, `${name}.fields`);
|
|
215
|
+
const item = input === "list" ? checker.getIndexTypeOfType(type, ts.IndexKind.Number) : type;
|
|
216
|
+
if (!item || !(item.flags & ts.TypeFlags.Object)) fail(node, `${name} needs an object${input === "list" ? " list" : ""} Vue type.`);
|
|
217
|
+
if (input === "list") {
|
|
218
|
+
const id = item.getProperty("id");
|
|
219
|
+
const idType = id && checker.getTypeOfSymbolAtLocation(id, id.valueDeclaration ?? node);
|
|
220
|
+
if (!id || id.flags & ts.SymbolFlags.Optional || !idType || !stringType(idType)) fail(node, `${name} list items need a required string id.`);
|
|
221
|
+
if (Object.hasOwn(nested, "id")) fail(node, `${name}.id is managed by Studio.`);
|
|
139
222
|
}
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
name
|
|
145
|
-
path: "/:contentPath(.*)*",
|
|
146
|
-
meta: { cmsDocument: true }
|
|
223
|
+
const fields = Object.entries(nested).map(([key, raw]) => {
|
|
224
|
+
const property = item.getProperty(key);
|
|
225
|
+
if (!property) fail(node, `${name}.${key} does not exist in the Vue type.`);
|
|
226
|
+
const member = checker.getTypeOfSymbolAtLocation(property, property.valueDeclaration ?? node);
|
|
227
|
+
return fieldFromType(key, record(raw, node, fail, `${name}.${key}`), member, !(property.flags & ts.SymbolFlags.Optional), void 0, checker, node, fail);
|
|
147
228
|
});
|
|
148
|
-
|
|
229
|
+
for (const property of item.getProperties()) if (property.name !== "id" && !(property.flags & ts.SymbolFlags.Optional) && !Object.hasOwn(nested, property.name)) fail(node, `${name}.${property.name} is required by Vue and needs an authoring declaration.`);
|
|
230
|
+
return decodeField({
|
|
231
|
+
...common,
|
|
232
|
+
kind: input,
|
|
233
|
+
fields
|
|
234
|
+
}, node, fail);
|
|
235
|
+
}
|
|
236
|
+
if (input === "image") {
|
|
237
|
+
if (!(type.flags & ts.TypeFlags.Object)) fail(node, `${name} needs an image object Vue prop.`);
|
|
238
|
+
return decodeField({
|
|
239
|
+
...common,
|
|
240
|
+
kind: "image"
|
|
241
|
+
}, node, fail);
|
|
242
|
+
}
|
|
243
|
+
if (input === "link") {
|
|
244
|
+
if (!stringType(type)) fail(node, `${name} needs a string Vue prop for resolved links.`);
|
|
245
|
+
if (defaultValue !== void 0 && !Schema.is(Schema.String)(defaultValue)) fail(node, `${name} needs a string Vue default.`);
|
|
246
|
+
const field = {
|
|
247
|
+
...common,
|
|
248
|
+
kind: "link"
|
|
249
|
+
};
|
|
250
|
+
if (defaultValue !== void 0) Object.assign(field, { defaultValue: {
|
|
251
|
+
kind: "url",
|
|
252
|
+
href: defaultValue
|
|
253
|
+
} });
|
|
254
|
+
return decodeField(field, node, fail);
|
|
255
|
+
}
|
|
256
|
+
if (input === "media") {
|
|
257
|
+
if (!stringType(type)) fail(node, `${name} needs a string Vue prop for resolved media.`);
|
|
258
|
+
const mediaKind = string(metadata.mediaKind, node, fail, `${name}.mediaKind`);
|
|
259
|
+
return decodeField({
|
|
260
|
+
...common,
|
|
261
|
+
kind: "media",
|
|
262
|
+
mediaKind
|
|
263
|
+
}, node, fail);
|
|
264
|
+
}
|
|
265
|
+
if (input === "document") {
|
|
266
|
+
if (!stringType(type)) fail(node, `${name} needs a string Vue prop for document IDs.`);
|
|
267
|
+
const field = {
|
|
268
|
+
...common,
|
|
269
|
+
kind: "document"
|
|
270
|
+
};
|
|
271
|
+
if (metadata.collections !== void 0) Object.assign(field, { collections: strings(metadata.collections, node, fail) });
|
|
272
|
+
return decodeField(field, node, fail);
|
|
273
|
+
}
|
|
274
|
+
if (![
|
|
275
|
+
"text",
|
|
276
|
+
"textarea",
|
|
277
|
+
"date",
|
|
278
|
+
"icon",
|
|
279
|
+
"number",
|
|
280
|
+
"boolean"
|
|
281
|
+
].includes(input)) fail(node, `${name} has unsupported input "${input}".`);
|
|
282
|
+
if (!(input === "number" && members.every((item) => item.flags & ts.TypeFlags.NumberLike) || input === "boolean" && members.every((item) => item.flags & ts.TypeFlags.BooleanLike) || [
|
|
283
|
+
"text",
|
|
284
|
+
"textarea",
|
|
285
|
+
"date",
|
|
286
|
+
"icon"
|
|
287
|
+
].includes(input) && stringType(type))) fail(node, `${name} uses ${input}, which does not match its Vue prop type.`);
|
|
288
|
+
const field = {
|
|
289
|
+
...common,
|
|
290
|
+
kind: input
|
|
291
|
+
};
|
|
292
|
+
if (defaultValue !== void 0) Object.assign(field, { defaultValue });
|
|
293
|
+
return decodeField(field, node, fail);
|
|
294
|
+
}
|
|
295
|
+
function decodeField(field, node, fail) {
|
|
296
|
+
try {
|
|
297
|
+
return Schema.decodeUnknownSync(FieldDefinition)(field);
|
|
298
|
+
} catch (cause) {
|
|
299
|
+
return fail(node, `Invalid prop "${field.name}": ${String(cause)}`);
|
|
300
|
+
}
|
|
301
|
+
}
|
|
302
|
+
function inferInput(type, checker) {
|
|
303
|
+
if (literalChoices(type).length) return "select";
|
|
304
|
+
const members = type.isUnion() ? type.types : [type];
|
|
305
|
+
if (stringType(type)) return "text";
|
|
306
|
+
if (members.every((item) => item.flags & ts.TypeFlags.NumberLike)) return "number";
|
|
307
|
+
if (members.every((item) => item.flags & ts.TypeFlags.BooleanLike)) return "boolean";
|
|
308
|
+
const item = checker.getIndexTypeOfType(type, ts.IndexKind.Number);
|
|
309
|
+
if (item && stringType(item)) return "multi-select";
|
|
310
|
+
return "";
|
|
149
311
|
}
|
|
150
|
-
function
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
312
|
+
function stringType(type) {
|
|
313
|
+
return (type.isUnion() ? type.types : [type]).every((member) => Boolean(member.flags & ts.TypeFlags.StringLike));
|
|
314
|
+
}
|
|
315
|
+
function literalChoices(type) {
|
|
316
|
+
const members = type.isUnion() ? type.types : [type];
|
|
317
|
+
return members.every((member) => member.isStringLiteral()) ? members.flatMap((member) => member.isStringLiteral() ? [member.value] : []) : [];
|
|
318
|
+
}
|
|
319
|
+
function humanize(value) {
|
|
320
|
+
return value.replaceAll("-", " ").replace(/\b\w/gu, (letter) => letter.toUpperCase());
|
|
321
|
+
}
|
|
322
|
+
//#endregion
|
|
323
|
+
//#region src/internal/authoringCompiler.ts
|
|
324
|
+
const authoringImport = "@phtngyn/cms/Authoring";
|
|
325
|
+
function parseBlock(source, filename) {
|
|
326
|
+
const parsed = parse(source, { filename });
|
|
327
|
+
if (parsed.errors.length) throw new Error(`${filename}: ${parsed.errors.join("\n")}`);
|
|
328
|
+
const setup = parsed.descriptor.scriptSetup;
|
|
329
|
+
if (!setup || setup.lang !== "ts") throw new Error(`${filename}: CMS blocks need <script setup lang="ts">.`);
|
|
330
|
+
return {
|
|
331
|
+
parsed,
|
|
332
|
+
setup
|
|
333
|
+
};
|
|
334
|
+
}
|
|
335
|
+
function createAuthoringCompiler() {
|
|
336
|
+
const program = createAuthoringProgram();
|
|
337
|
+
const results = /* @__PURE__ */ new Map();
|
|
338
|
+
function invalidate(filename) {
|
|
339
|
+
program.invalidate(filename);
|
|
340
|
+
results.clear();
|
|
341
|
+
}
|
|
342
|
+
function compile(source, filename) {
|
|
343
|
+
if (program.refreshDependencies()) results.clear();
|
|
344
|
+
const cached = results.get(filename);
|
|
345
|
+
if (cached?.source === source) return cached.compiled;
|
|
346
|
+
const compiled = compileBlock(source, filename, program);
|
|
347
|
+
results.set(filename, {
|
|
348
|
+
source,
|
|
349
|
+
compiled
|
|
350
|
+
});
|
|
351
|
+
return compiled;
|
|
352
|
+
}
|
|
353
|
+
function compileMany(entries) {
|
|
354
|
+
for (const entry of entries) program.register(`${entry.filename}.ts`, parseBlock(entry.source, entry.filename).setup.content);
|
|
355
|
+
return entries.map((entry) => compile(entry.source, entry.filename));
|
|
356
|
+
}
|
|
357
|
+
function trackDependencies(filename, source) {
|
|
358
|
+
program.check(filename, source);
|
|
359
|
+
}
|
|
360
|
+
return {
|
|
361
|
+
compile,
|
|
362
|
+
compileMany,
|
|
363
|
+
invalidate,
|
|
364
|
+
trackDependencies,
|
|
365
|
+
dependencies: program.dependencies
|
|
366
|
+
};
|
|
367
|
+
}
|
|
368
|
+
function compileBlock(source, filename, program) {
|
|
369
|
+
const { parsed, setup } = parseBlock(source, filename);
|
|
370
|
+
const { file, checker } = program.check(`${filename}.ts`, setup.content);
|
|
371
|
+
const fail = (node, message) => {
|
|
372
|
+
const offset = setup.loc.start.offset + node.getStart(file);
|
|
373
|
+
const before = source.slice(0, offset);
|
|
374
|
+
const line = before.split("\n").length;
|
|
375
|
+
const column = offset - before.lastIndexOf("\n");
|
|
376
|
+
throw new Error(`${filename}:${line}:${column}: ${message}`);
|
|
377
|
+
};
|
|
378
|
+
const imports = file.statements.filter((node) => ts.isImportDeclaration(node) && ts.isStringLiteral(node.moduleSpecifier) && node.moduleSpecifier.text === authoringImport);
|
|
379
|
+
const importNode = imports[0];
|
|
380
|
+
if (imports.length !== 1 || !importNode?.importClause?.namedBindings || !ts.isNamedImports(importNode.importClause.namedBindings) || importNode.importClause.namedBindings.elements.length !== 1 || importNode.importClause.namedBindings.elements[0]?.name.text !== "defineCmsBlock" || importNode.importClause.namedBindings.elements[0]?.propertyName) return fail(file, "Import only { defineCmsBlock } from @phtngyn/cms/Authoring.");
|
|
381
|
+
const statements = file.statements.filter((node) => ts.isExpressionStatement(node) && ts.isCallExpression(node.expression) && ts.isIdentifier(node.expression.expression) && node.expression.expression.text === "defineCmsBlock");
|
|
382
|
+
const statement = statements[0];
|
|
383
|
+
if (statements.length !== 1 || !statement || !ts.isCallExpression(statement.expression)) return fail(file, "Call defineCmsBlock exactly once as a top-level statement.");
|
|
384
|
+
const call = statement.expression;
|
|
385
|
+
const argument = call.arguments[0];
|
|
386
|
+
if (call.arguments.length !== 1 || !argument || !ts.isObjectLiteralExpression(argument)) return fail(call, "defineCmsBlock needs one static object literal.");
|
|
387
|
+
if (call.typeArguments?.length !== 1 && call.typeArguments?.length !== 2) return fail(call, "Share named Props and optional Slots types with defineProps and defineSlots.");
|
|
388
|
+
const propsTypeNode = call.typeArguments[0];
|
|
389
|
+
const slotsTypeNode = call.typeArguments[1];
|
|
390
|
+
if (!propsTypeNode || !ts.isTypeReferenceNode(propsTypeNode) || slotsTypeNode && !ts.isTypeReferenceNode(slotsTypeNode)) return fail(call, "defineCmsBlock type arguments must be named types.");
|
|
391
|
+
const vueCalls = /* @__PURE__ */ new Map();
|
|
392
|
+
const walk = (node) => {
|
|
393
|
+
if (ts.isCallExpression(node) && ts.isIdentifier(node.expression)) {
|
|
394
|
+
const calls = vueCalls.get(node.expression.text) ?? [];
|
|
395
|
+
calls.push(node);
|
|
396
|
+
vueCalls.set(node.expression.text, calls);
|
|
397
|
+
}
|
|
398
|
+
ts.forEachChild(node, walk);
|
|
399
|
+
};
|
|
400
|
+
walk(file);
|
|
401
|
+
const authoringCalls = vueCalls.get("defineCmsBlock") ?? [];
|
|
402
|
+
if (authoringCalls.length !== 1 || authoringCalls[0] !== call) fail(call, "defineCmsBlock may only be used in its top-level declaration.");
|
|
403
|
+
const vueProps = vueCalls.get("defineProps") ?? [];
|
|
404
|
+
const vueSlots = vueCalls.get("defineSlots") ?? [];
|
|
405
|
+
if (vueProps.length !== 1 || vueProps[0]?.typeArguments?.[0]?.getText(file) !== propsTypeNode.getText(file)) fail(call, "defineProps must use the same Props type as defineCmsBlock.");
|
|
406
|
+
if (slotsTypeNode && (vueSlots.length !== 1 || vueSlots[0]?.typeArguments?.[0]?.getText(file) !== slotsTypeNode.getText(file))) fail(call, "defineSlots must use the same Slots type as defineCmsBlock.");
|
|
407
|
+
if (!slotsTypeNode && vueSlots.length) fail(call, "Pass the defineSlots type to defineCmsBlock.");
|
|
408
|
+
const declaration = objectValue(argument, fail);
|
|
409
|
+
keys(declaration, [
|
|
410
|
+
"name",
|
|
411
|
+
"label",
|
|
412
|
+
"description",
|
|
413
|
+
"group",
|
|
414
|
+
"icon",
|
|
415
|
+
"props",
|
|
416
|
+
"slots",
|
|
417
|
+
"form",
|
|
418
|
+
"handler"
|
|
419
|
+
], call, fail);
|
|
420
|
+
const name = string(declaration.name, call, fail, "name");
|
|
421
|
+
const label = string(declaration.label, call, fail, "label");
|
|
422
|
+
const propMetadata = record(declaration.props ?? {}, call, fail, "props");
|
|
423
|
+
const slotMetadata = record(declaration.slots ?? {}, call, fail, "slots");
|
|
424
|
+
const defaults = vueDefaults(vueCalls.get("withDefaults") ?? [], new Set(Object.keys(propMetadata)), fail);
|
|
425
|
+
const propsType = checker.getTypeFromTypeNode(propsTypeNode);
|
|
426
|
+
const slotsType = slotsTypeNode ? checker.getTypeFromTypeNode(slotsTypeNode) : void 0;
|
|
427
|
+
const fields = [];
|
|
428
|
+
const slots = [];
|
|
429
|
+
for (const [key, raw] of Object.entries(propMetadata)) {
|
|
430
|
+
const property = propsType.getProperty(key);
|
|
431
|
+
if (!property) return fail(call, `Editable prop "${key}" does not exist in Props.`);
|
|
432
|
+
const metadata = record(raw, call, fail, `props.${key}`);
|
|
433
|
+
const type = checker.getTypeOfSymbolAtLocation(property, property.valueDeclaration ?? propsTypeNode);
|
|
434
|
+
const required = !(property.flags & ts.SymbolFlags.Optional);
|
|
435
|
+
fields.push(fieldFromType(key, metadata, type, required, defaults.values[key], checker, call, fail));
|
|
436
|
+
}
|
|
437
|
+
for (const property of propsType.getProperties()) if (!(property.flags & ts.SymbolFlags.Optional) && !defaults.has.has(property.name) && !Object.hasOwn(propMetadata, property.name) && !(declaration.form && property.name === "cmsForm")) fail(call, `Required prop "${property.name}" needs an authoring declaration or a Vue default.`);
|
|
438
|
+
for (const [key, raw] of Object.entries(slotMetadata)) {
|
|
439
|
+
const property = slotsType?.getProperty(key);
|
|
440
|
+
if (!property) return fail(call, `Editable slot "${key}" does not exist in Slots.`);
|
|
441
|
+
const slotType = checker.getNonNullableType(checker.getTypeOfSymbolAtLocation(property, property.valueDeclaration ?? slotsTypeNode ?? call));
|
|
442
|
+
const signatures = checker.getSignaturesOfType(slotType, ts.SignatureKind.Call);
|
|
443
|
+
if (signatures.length !== 1 || signatures[0]?.parameters.length) fail(call, `Editable slot "${key}" must be an unscoped Vue slot.`);
|
|
444
|
+
const metadata = record(raw, call, fail, `slots.${key}`);
|
|
445
|
+
keys(metadata, [
|
|
446
|
+
"label",
|
|
447
|
+
"input",
|
|
448
|
+
"features",
|
|
449
|
+
"blocks",
|
|
450
|
+
"groups",
|
|
451
|
+
"initial"
|
|
452
|
+
], call, fail);
|
|
453
|
+
const initial = metadata.initial;
|
|
454
|
+
const slot = {
|
|
455
|
+
name: key,
|
|
456
|
+
label: string(metadata.label, call, fail, `slots.${key}.label`),
|
|
457
|
+
kind: string(metadata.input, call, fail, `slots.${key}.input`),
|
|
458
|
+
required: !(property.flags & ts.SymbolFlags.Optional)
|
|
158
459
|
};
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
460
|
+
if (metadata.features !== void 0) Object.assign(slot, { features: strings(metadata.features, call, fail) });
|
|
461
|
+
if (metadata.blocks !== void 0) Object.assign(slot, { blocks: strings(metadata.blocks, call, fail) });
|
|
462
|
+
if (metadata.groups !== void 0) Object.assign(slot, { groups: strings(metadata.groups, call, fail) });
|
|
463
|
+
if (initial !== void 0) Object.assign(slot, { initial: slotInitial(initial, call, fail) });
|
|
464
|
+
try {
|
|
465
|
+
slots.push(Schema.decodeUnknownSync(BlockSlot)(slot));
|
|
466
|
+
} catch (cause) {
|
|
467
|
+
fail(call, `Invalid slot "${key}": ${String(cause)}`);
|
|
468
|
+
}
|
|
469
|
+
}
|
|
470
|
+
for (const property of slotsType?.getProperties() ?? []) if (!(property.flags & ts.SymbolFlags.Optional) && !Object.hasOwn(slotMetadata, property.name)) fail(call, `Required slot "${property.name}" needs an authoring declaration.`);
|
|
471
|
+
validateSlotOutlets(parsed.descriptor.template?.ast, new Set(slots.map((slot) => slot.name)), filename);
|
|
472
|
+
const block = {
|
|
473
|
+
name,
|
|
474
|
+
label,
|
|
475
|
+
fields,
|
|
476
|
+
slots
|
|
477
|
+
};
|
|
478
|
+
if (declaration.description !== void 0) Object.assign(block, { description: string(declaration.description, call, fail, "description") });
|
|
479
|
+
if (declaration.group !== void 0) Object.assign(block, { group: string(declaration.group, call, fail, "group") });
|
|
480
|
+
if (declaration.icon !== void 0) Object.assign(block, { icon: string(declaration.icon, call, fail, "icon") });
|
|
481
|
+
if (declaration.form !== void 0) Object.assign(block, { form: declaration.form });
|
|
482
|
+
const definition = (() => {
|
|
483
|
+
try {
|
|
484
|
+
return Schema.decodeSync(BlockDefinition)(block);
|
|
485
|
+
} catch (cause) {
|
|
486
|
+
return fail(call, `Invalid block declaration: ${String(cause)}`);
|
|
487
|
+
}
|
|
488
|
+
})();
|
|
489
|
+
const handler = declaration.handler === void 0 ? void 0 : string(declaration.handler, call, fail, "handler");
|
|
490
|
+
if (handler && !declaration.form) fail(call, "A handler requires a form declaration.");
|
|
491
|
+
const code = new MagicString(source);
|
|
492
|
+
code.remove(setup.loc.start.offset + importNode.getStart(file), setup.loc.start.offset + importNode.end);
|
|
493
|
+
code.remove(setup.loc.start.offset + statement.getStart(file), setup.loc.start.offset + statement.end);
|
|
494
|
+
return {
|
|
495
|
+
filename,
|
|
496
|
+
definition,
|
|
497
|
+
handler,
|
|
498
|
+
code: code.toString(),
|
|
499
|
+
map: code.generateMap({
|
|
500
|
+
source: filename,
|
|
501
|
+
hires: true
|
|
502
|
+
})
|
|
503
|
+
};
|
|
504
|
+
}
|
|
505
|
+
function slotInitial(value, node, fail) {
|
|
506
|
+
if (Schema.is(Schema.String)(value)) return [{
|
|
507
|
+
type: "paragraph",
|
|
508
|
+
content: [{
|
|
509
|
+
type: "text",
|
|
510
|
+
text: value
|
|
511
|
+
}]
|
|
512
|
+
}];
|
|
513
|
+
if (!Schema.is(Schema.Array(Schema.JsonObject))(value)) fail(node, "Slot initial content must be text or an array of ProseMirror nodes.");
|
|
514
|
+
return value;
|
|
515
|
+
}
|
|
516
|
+
function validateSlotOutlets(template, names, filename) {
|
|
517
|
+
if (!names.size) return;
|
|
518
|
+
const found = /* @__PURE__ */ new Set();
|
|
519
|
+
function visit(node) {
|
|
520
|
+
const element = node.type === 1 ? node : void 0;
|
|
521
|
+
if (element?.tag === "slot") {
|
|
522
|
+
if (element.props.some((property) => property.type === 7 && property.name === "bind" && property.arg?.type === 4 && property.arg.isStatic && property.arg.content === "name")) throw new Error(`${filename}: authored slot outlets need a static name.`);
|
|
523
|
+
const attribute = element.props.find((property) => property.type === 6 && property.name === "name");
|
|
524
|
+
found.add(attribute?.value?.content ?? "default");
|
|
525
|
+
}
|
|
526
|
+
if (node.type === 0 || node.type === 1) for (const child of node.children) visit(child);
|
|
527
|
+
}
|
|
528
|
+
if (template) visit(template);
|
|
529
|
+
for (const name of names) if (!found.has(name)) throw new Error(`${filename}: authored slot "${name}" needs a <slot name="${name}"> outlet.`);
|
|
530
|
+
}
|
|
531
|
+
//#endregion
|
|
532
|
+
//#region src/internal/blockCatalog.ts
|
|
533
|
+
/** app/cms/blocks is the sole site-level block registry. */
|
|
534
|
+
async function discoverBlocks(rootDir, compiler = createAuthoringCompiler()) {
|
|
535
|
+
const directory = resolve(rootDir, "app/cms/blocks");
|
|
536
|
+
const blocks = [];
|
|
537
|
+
const names = /* @__PURE__ */ new Map();
|
|
538
|
+
const files = [];
|
|
539
|
+
if (!existsSync(directory)) return blocks;
|
|
540
|
+
async function visit(path) {
|
|
541
|
+
for (const entry of await readdir(path, { withFileTypes: true })) {
|
|
542
|
+
const filename = join(path, entry.name);
|
|
543
|
+
if (entry.isDirectory()) {
|
|
544
|
+
await visit(filename);
|
|
545
|
+
continue;
|
|
546
|
+
}
|
|
547
|
+
if (!entry.isFile() || !entry.name.endsWith(".vue")) continue;
|
|
548
|
+
files.push(filename);
|
|
549
|
+
}
|
|
550
|
+
}
|
|
551
|
+
await visit(directory);
|
|
552
|
+
const entries = await Promise.all(files.map(async (filename) => ({
|
|
553
|
+
filename,
|
|
554
|
+
source: await readFile(filename, "utf8")
|
|
555
|
+
})));
|
|
556
|
+
const compiledBlocks = compiler.compileMany(entries);
|
|
557
|
+
for (const compiled of compiledBlocks) {
|
|
558
|
+
const { filename } = compiled;
|
|
559
|
+
const previous = names.get(compiled.definition.name);
|
|
560
|
+
if (previous) throw new Error(`CMS block "${compiled.definition.name}" is declared in both ${previous} and ${filename}.`);
|
|
561
|
+
names.set(compiled.definition.name, filename);
|
|
562
|
+
if (compiled.handler && !existsSync(resolve(rootDir, compiled.handler))) throw new Error(`${filename}: form handler does not exist: ${compiled.handler}`);
|
|
563
|
+
const block = Object.assign({ component: `./${relative(rootDir, filename)}` }, compiled.definition);
|
|
564
|
+
if (compiled.handler !== void 0) Object.assign(block, { handler: compiled.handler });
|
|
565
|
+
blocks.push(block);
|
|
566
|
+
}
|
|
567
|
+
blocks.sort((first, second) => first.name.localeCompare(second.name));
|
|
568
|
+
return blocks;
|
|
166
569
|
}
|
|
167
|
-
|
|
168
570
|
//#endregion
|
|
169
|
-
|
|
170
|
-
|
|
571
|
+
//#region src/internal/previewCompiler.ts
|
|
572
|
+
/** Add preview-only provenance bindings without changing the site's authored values or markup layout. */
|
|
573
|
+
function compilePreviewTemplate(source, filename, runtime) {
|
|
574
|
+
const { descriptor, errors } = parse(source, { filename });
|
|
575
|
+
if (errors.length || !descriptor.template?.ast || descriptor.script && !descriptor.scriptSetup) return null;
|
|
576
|
+
const setup = descriptor.scriptSetup;
|
|
577
|
+
const file = ts.createSourceFile(filename, setup?.content ?? "", ts.ScriptTarget.ESNext, true, ts.ScriptKind.TS);
|
|
578
|
+
const propAliases = /* @__PURE__ */ new Set();
|
|
579
|
+
const propNames = /* @__PURE__ */ new Map();
|
|
580
|
+
function findProps(node) {
|
|
581
|
+
if (ts.isCallExpression(node) && ts.isIdentifier(node.expression) && node.expression.text === "defineProps") {
|
|
582
|
+
let parent = node.parent;
|
|
583
|
+
if (ts.isCallExpression(parent)) parent = parent.parent;
|
|
584
|
+
if (ts.isVariableDeclaration(parent)) {
|
|
585
|
+
if (ts.isIdentifier(parent.name)) propAliases.add(parent.name.text);
|
|
586
|
+
else if (ts.isObjectBindingPattern(parent.name)) {
|
|
587
|
+
for (const element of parent.name.elements) if (ts.isIdentifier(element.name)) propNames.set(element.name.text, element.propertyName?.getText(file) ?? element.name.text);
|
|
588
|
+
}
|
|
589
|
+
}
|
|
590
|
+
const type = node.typeArguments?.[0];
|
|
591
|
+
const members = type && ts.isTypeLiteralNode(type) ? type.members : type && ts.isTypeReferenceNode(type) ? file.statements.flatMap((statement) => ts.isInterfaceDeclaration(statement) && statement.name.text === type.typeName.getText(file) ? [...statement.members] : ts.isTypeAliasDeclaration(statement) && statement.name.text === type.typeName.getText(file) && ts.isTypeLiteralNode(statement.type) ? [...statement.type.members] : []) : [];
|
|
592
|
+
for (const member of members) if (ts.isPropertySignature(member) && member.name && (ts.isIdentifier(member.name) || ts.isStringLiteral(member.name))) propNames.set(member.name.text, member.name.text);
|
|
593
|
+
}
|
|
594
|
+
ts.forEachChild(node, findProps);
|
|
595
|
+
}
|
|
596
|
+
findProps(file);
|
|
597
|
+
function expressionSources(expression) {
|
|
598
|
+
const expressionFile = ts.createSourceFile("expression.ts", `(${expression})`, ts.ScriptTarget.ESNext, true, ts.ScriptKind.TS);
|
|
599
|
+
const found = /* @__PURE__ */ new Set();
|
|
600
|
+
function access(node) {
|
|
601
|
+
return ts.isIdentifier(node) || ts.isPropertyAccessExpression(node) && access(node.expression) || ts.isElementAccessExpression(node) && access(node.expression) && !!node.argumentExpression && (ts.isIdentifier(node.argumentExpression) || ts.isStringLiteral(node.argumentExpression) || ts.isNumericLiteral(node.argumentExpression));
|
|
602
|
+
}
|
|
603
|
+
function read(node) {
|
|
604
|
+
if (ts.isPropertyAccessExpression(node)) return `${read(node.expression)}?.${node.name.text}`;
|
|
605
|
+
if (ts.isElementAccessExpression(node) && node.argumentExpression) return `${read(node.expression)}?.[${node.argumentExpression.getText(expressionFile)}]`;
|
|
606
|
+
return node.getText(expressionFile);
|
|
607
|
+
}
|
|
608
|
+
function visit(node) {
|
|
609
|
+
if (ts.isBinaryExpression(node) && access(node.left) && [
|
|
610
|
+
ts.SyntaxKind.QuestionQuestionToken,
|
|
611
|
+
ts.SyntaxKind.BarBarToken,
|
|
612
|
+
ts.SyntaxKind.AmpersandAmpersandToken
|
|
613
|
+
].includes(node.operatorToken.kind)) {
|
|
614
|
+
const left = expressionSources(node.left.getText(expressionFile)).join(", ");
|
|
615
|
+
const right = expressionSources(node.right.getText(expressionFile)).join(", ");
|
|
616
|
+
const condition = node.operatorToken.kind === ts.SyntaxKind.QuestionQuestionToken ? `${read(node.left)} != null` : read(node.left);
|
|
617
|
+
const first = node.operatorToken.kind === ts.SyntaxKind.AmpersandAmpersandToken ? right : left;
|
|
618
|
+
const second = node.operatorToken.kind === ts.SyntaxKind.AmpersandAmpersandToken ? left : right;
|
|
619
|
+
if (left || right) found.add(`cmsPreviewSource.combine(${condition} ? [${first}] : [${second}])`);
|
|
620
|
+
return;
|
|
621
|
+
}
|
|
622
|
+
if (ts.isCallExpression(node)) {
|
|
623
|
+
if (ts.isPropertyAccessExpression(node.expression)) visit(node.expression.expression);
|
|
624
|
+
for (const argument of node.arguments) visit(argument);
|
|
625
|
+
return;
|
|
626
|
+
}
|
|
627
|
+
if (ts.isPropertyAccessExpression(node)) {
|
|
628
|
+
const base = node.expression;
|
|
629
|
+
if (!access(base)) {
|
|
630
|
+
visit(base);
|
|
631
|
+
return;
|
|
632
|
+
}
|
|
633
|
+
if (ts.isIdentifier(base) && propAliases.has(base.text)) found.add(`cmsPreviewSource.prop(${JSON.stringify(node.name.text)})`);
|
|
634
|
+
else found.add(`cmsPreviewSource.property(${read(base)}, ${JSON.stringify(node.name.text)})`);
|
|
635
|
+
return;
|
|
636
|
+
}
|
|
637
|
+
if (ts.isElementAccessExpression(node) && node.argumentExpression && ts.isStringLiteral(node.argumentExpression)) {
|
|
638
|
+
if (access(node.expression)) found.add(`cmsPreviewSource.property(${read(node.expression)}, ${JSON.stringify(node.argumentExpression.text)})`);
|
|
639
|
+
return;
|
|
640
|
+
}
|
|
641
|
+
if (ts.isIdentifier(node) && propNames.has(node.text)) found.add(`cmsPreviewSource.prop(${JSON.stringify(propNames.get(node.text))})`);
|
|
642
|
+
else ts.forEachChild(node, visit);
|
|
643
|
+
}
|
|
644
|
+
visit(expressionFile);
|
|
645
|
+
return [...found];
|
|
646
|
+
}
|
|
647
|
+
const code = new MagicString(source);
|
|
648
|
+
let changed = false;
|
|
649
|
+
function visit(node) {
|
|
650
|
+
if (node.type !== 0 && node.type !== 1) return;
|
|
651
|
+
if (node.type === 1 && ![
|
|
652
|
+
"template",
|
|
653
|
+
"slot",
|
|
654
|
+
"Teleport",
|
|
655
|
+
"Suspense",
|
|
656
|
+
"KeepAlive",
|
|
657
|
+
"Transition",
|
|
658
|
+
"TransitionGroup"
|
|
659
|
+
].includes(node.tag)) {
|
|
660
|
+
const sources = /* @__PURE__ */ new Set();
|
|
661
|
+
const properties = [];
|
|
662
|
+
const loop = node.props.find((property) => property.type === 7 && property.name === "for");
|
|
663
|
+
const alias = loop?.type === 7 && loop.exp?.type === 4 ? /^\s*\(?\s*([A-Za-z_$][\w$]*)\s*(?:[,)]|\s+(?:in|of)\b)/u.exec(loop.exp.content)?.[1] : null;
|
|
664
|
+
if (alias) sources.add(`cmsPreviewSource.object(${alias})`);
|
|
665
|
+
for (const property of node.props) {
|
|
666
|
+
if (property.type !== 7 || property.name !== "bind" || property.exp?.type !== 4 || property.arg?.type !== 4 || !property.arg.isStatic || property.arg.content === "key") continue;
|
|
667
|
+
const candidates = expressionSources(property.exp.content);
|
|
668
|
+
for (const candidate of candidates) sources.add(candidate);
|
|
669
|
+
if (candidates.length) properties.push(`${JSON.stringify(property.arg.content.replace(/-([a-z])/gu, (_match, letter) => letter.toUpperCase()))}: cmsPreviewSource.combine([${candidates.join(", ")}])`);
|
|
670
|
+
}
|
|
671
|
+
for (const child of node.children) {
|
|
672
|
+
if (child.type !== 5 || child.content.type !== 4) continue;
|
|
673
|
+
if (node.props.some((property) => property.type === 7 && property.name === "slot" && property.exp)) continue;
|
|
674
|
+
for (const candidate of expressionSources(child.content.content)) sources.add(candidate);
|
|
675
|
+
}
|
|
676
|
+
if (sources.size) {
|
|
677
|
+
changed = true;
|
|
678
|
+
const candidates = [...sources].join(", ");
|
|
679
|
+
if (node.tagType === 1) wrapComponent(node, candidates, properties);
|
|
680
|
+
else code.appendLeft(node.loc.start.offset + 1 + node.tag.length, ` :data-cms-source="cmsPreviewSource.encode([${escapeAttribute(candidates)}])"`);
|
|
681
|
+
}
|
|
682
|
+
}
|
|
683
|
+
for (const child of node.children) visit(child);
|
|
684
|
+
}
|
|
685
|
+
function wrapComponent(node, candidates, properties) {
|
|
686
|
+
const controls = node.props.filter((property) => property.type === 7 && ([
|
|
687
|
+
"if",
|
|
688
|
+
"else-if",
|
|
689
|
+
"else",
|
|
690
|
+
"for"
|
|
691
|
+
].includes(property.name) || property.name === "bind" && property.arg?.type === 4 && property.arg.content === "key"));
|
|
692
|
+
for (const control of controls) code.remove(control.loc.start.offset, control.loc.end.offset);
|
|
693
|
+
const directives = controls.map((control) => control.loc.source).join(" ");
|
|
694
|
+
code.appendLeft(node.loc.start.offset, `<CmsPreviewSourceRegion ${directives} :source="cmsPreviewSource.combine([${escapeAttribute(candidates)}])" :properties="{${escapeAttribute(properties.join(", "))}}">`);
|
|
695
|
+
code.appendRight(node.loc.end.offset, "</CmsPreviewSourceRegion>");
|
|
696
|
+
}
|
|
697
|
+
visit(descriptor.template.ast);
|
|
698
|
+
if (!changed) return null;
|
|
699
|
+
const helper = `\nimport { CmsPreviewRegion as CmsPreviewSourceRegion, useCmsPreviewSource as useCmsPreviewSourceGenerated } from ${JSON.stringify(runtime)}\nconst cmsPreviewSource = useCmsPreviewSourceGenerated()\n`;
|
|
700
|
+
if (setup) code.appendLeft(setup.loc.start.offset, helper);
|
|
701
|
+
else code.appendLeft(0, `<script setup lang="ts">${helper}<\/script>\n`);
|
|
702
|
+
return {
|
|
703
|
+
code: code.toString(),
|
|
704
|
+
map: code.generateMap({
|
|
705
|
+
source: filename,
|
|
706
|
+
hires: true
|
|
707
|
+
})
|
|
708
|
+
};
|
|
709
|
+
}
|
|
710
|
+
function escapeAttribute(value) {
|
|
711
|
+
return value.replaceAll("&", "&").replaceAll("\"", """);
|
|
712
|
+
}
|
|
713
|
+
//#endregion
|
|
714
|
+
//#region src/internal/siteTypes.ts
|
|
715
|
+
/** Types come from the authored fields; retained saved content may need readable recovery. */
|
|
716
|
+
function generateSiteTypes(collections, blocks, collectionsFile) {
|
|
717
|
+
const blockNames = union(blocks.map((block) => block.name));
|
|
718
|
+
const collectionNames = union(collections.map((collection) => collection.collection));
|
|
719
|
+
const fields = collections.map((collection) => ` readonly ${JSON.stringify(collection.collection)}: import('@phtngyn/cms/Collections').CmsCollectionFields<Extract<SiteCollections[number], { readonly collection: ${JSON.stringify(collection.collection)} }>>`).join("\n");
|
|
720
|
+
return [
|
|
721
|
+
"/* Generated by @phtngyn/cms from the site catalog. */",
|
|
722
|
+
`type SiteCollections = typeof import(${JSON.stringify(collectionsFile)})['default']`,
|
|
723
|
+
`export type CmsBlockName = ${blockNames}`,
|
|
724
|
+
`export type CmsCollectionName = ${collectionNames}`,
|
|
725
|
+
"export interface CmsPublishedFieldsByCollection {",
|
|
726
|
+
fields,
|
|
727
|
+
"}",
|
|
728
|
+
"export type CmsPublishedFields<Collection extends CmsCollectionName> = CmsPublishedFieldsByCollection[Collection]",
|
|
729
|
+
"export type CmsDraftFields<Collection extends CmsCollectionName> = { readonly [Key in keyof CmsPublishedFields<Collection>]?: unknown }",
|
|
730
|
+
""
|
|
731
|
+
].join("\n");
|
|
732
|
+
}
|
|
733
|
+
function union(values, fallback = "never") {
|
|
734
|
+
return values.length ? [...new Set(values)].map((value) => JSON.stringify(value)).join(" | ") : fallback;
|
|
735
|
+
}
|
|
736
|
+
//#endregion
|
|
737
|
+
//#region src/internal/collectionCatalog.ts
|
|
738
|
+
/** Collection authoring owns the catalog; Nuxt only decodes the serializable installation input. */
|
|
739
|
+
function collectionCatalog(collections) {
|
|
740
|
+
return collections.map((collection) => Schema.decodeSync(CollectionDefinition)(collection));
|
|
741
|
+
}
|
|
742
|
+
//#endregion
|
|
743
|
+
//#region src/internal/studioAssets.ts
|
|
744
|
+
/** Nitro's dev static server recompresses each request; Studio already ships compressed files. */
|
|
745
|
+
function createStudioAssetHandler(directory) {
|
|
746
|
+
const root = resolve(directory);
|
|
747
|
+
const baseURL = "/_cms/assets/";
|
|
748
|
+
const contentTypes = /* @__PURE__ */ new Map([
|
|
749
|
+
["js", "text/javascript; charset=utf-8"],
|
|
750
|
+
["css", "text/css; charset=utf-8"],
|
|
751
|
+
["png", "image/png"],
|
|
752
|
+
["jpg", "image/jpeg"],
|
|
753
|
+
["jpeg", "image/jpeg"],
|
|
754
|
+
["webp", "image/webp"],
|
|
755
|
+
["gif", "image/gif"],
|
|
756
|
+
["svg", "image/svg+xml"]
|
|
757
|
+
]);
|
|
758
|
+
return async (request) => {
|
|
759
|
+
if (request.method !== "GET" && request.method !== "HEAD") return new Response(null, { status: 405 });
|
|
760
|
+
let path;
|
|
761
|
+
try {
|
|
762
|
+
const pathname = new URL(request.url).pathname;
|
|
763
|
+
if (!pathname.startsWith(baseURL)) return new Response(null, { status: 404 });
|
|
764
|
+
path = resolve(root, decodeURIComponent(pathname.slice(13)));
|
|
765
|
+
} catch {
|
|
766
|
+
return new Response(null, { status: 400 });
|
|
767
|
+
}
|
|
768
|
+
const contentType = contentTypes.get(path.split(".").at(-1) ?? "");
|
|
769
|
+
if (!path.startsWith(`${root}${sep}`) || !contentType) return new Response(null, { status: 404 });
|
|
770
|
+
const candidates = [...(request.headers.get("accept-encoding") ?? "").split(",").map((entry) => {
|
|
771
|
+
const [encoding, ...parameters] = entry.trim().split(";");
|
|
772
|
+
const quality = parameters.find((value) => value.trim().startsWith("q="))?.trim().slice(2);
|
|
773
|
+
return {
|
|
774
|
+
encoding,
|
|
775
|
+
quality: quality === void 0 ? 1 : Number(quality)
|
|
776
|
+
};
|
|
777
|
+
}).filter(({ encoding, quality }) => (encoding === "br" || encoding === "gzip") && quality > 0).sort((left, right) => right.quality - left.quality || (left.encoding === "br" ? -1 : 1)).map(({ encoding }) => ({
|
|
778
|
+
encoding,
|
|
779
|
+
path: `${path}.${encoding === "br" ? "br" : "gz"}`
|
|
780
|
+
})), {
|
|
781
|
+
encoding: "",
|
|
782
|
+
path
|
|
783
|
+
}];
|
|
784
|
+
for (const candidate of candidates) {
|
|
785
|
+
const file = await stat(candidate.path).catch(() => null);
|
|
786
|
+
if (!file?.isFile()) continue;
|
|
787
|
+
const headers = new Headers({
|
|
788
|
+
"content-type": contentType,
|
|
789
|
+
"content-length": String(file.size),
|
|
790
|
+
"cache-control": "no-cache",
|
|
791
|
+
vary: "Accept-Encoding",
|
|
792
|
+
etag: `"${file.size}-${file.mtimeMs}"`
|
|
793
|
+
});
|
|
794
|
+
if (candidate.encoding) headers.set("content-encoding", candidate.encoding);
|
|
795
|
+
if (request.headers.get("if-none-match") === headers.get("etag")) {
|
|
796
|
+
headers.delete("content-length");
|
|
797
|
+
return new Response(null, {
|
|
798
|
+
status: 304,
|
|
799
|
+
headers
|
|
800
|
+
});
|
|
801
|
+
}
|
|
802
|
+
return new Response(request.method === "HEAD" ? null : await readFile(candidate.path), { headers });
|
|
803
|
+
}
|
|
804
|
+
return new Response(null, { status: 404 });
|
|
805
|
+
};
|
|
806
|
+
}
|
|
807
|
+
//#endregion
|
|
808
|
+
//#region src/Module.ts
|
|
809
|
+
const resolver = createResolver(import.meta.url);
|
|
810
|
+
const packageRoot = resolve(dirname(fileURLToPath(import.meta.url)), "..");
|
|
811
|
+
const packagedStudio = resolve(packageRoot, "studio");
|
|
812
|
+
const studioDirectory = existsSync(packagedStudio) ? packagedStudio : resolve(packageRoot, "../studio/dist");
|
|
813
|
+
const packagedMigrations = resolve(packageRoot, "drizzle");
|
|
814
|
+
const migrationsFolder = existsSync(packagedMigrations) ? packagedMigrations : resolve(packageRoot, "../server/drizzle");
|
|
815
|
+
var Module_default = defineNuxtModule({
|
|
816
|
+
meta: {
|
|
817
|
+
name: "@phtngyn/cms",
|
|
818
|
+
compatibility: { nuxt: ">=5.0.0-0 <6" }
|
|
819
|
+
},
|
|
820
|
+
async setup(_options, nuxt) {
|
|
821
|
+
const { configuration: options } = await Effect.runPromise(load(nuxt.options.rootDir, nuxt.options.envName, false));
|
|
822
|
+
const locales = options.locales === void 0 ? void 0 : defineLocales(options.locales);
|
|
823
|
+
const collectionsFile = resolve(nuxt.options.rootDir, "app/cms/collections.ts");
|
|
824
|
+
if (!existsSync(collectionsFile)) throw new Error("CMS needs app/cms/collections.ts.");
|
|
825
|
+
const loaded = (await import(`${pathToFileURL(collectionsFile).href}?modified=${statSync(collectionsFile).mtimeMs}`)).default;
|
|
826
|
+
if (!Array.isArray(loaded)) throw new Error("app/cms/collections.ts must export a collection array.");
|
|
827
|
+
const collections = collectionCatalog(loaded);
|
|
828
|
+
if (collections.length === 0) throw new Error("CMS needs at least one collection route.");
|
|
829
|
+
const compiler = createAuthoringCompiler();
|
|
830
|
+
const blocks = await discoverBlocks(nuxt.options.rootDir, compiler);
|
|
831
|
+
const blockFiles = new Set(blocks.map((block) => resolve(nuxt.options.rootDir, block.component)));
|
|
832
|
+
const blockIssues = validateBlockConfiguration(blocks, collections);
|
|
833
|
+
if (blockIssues.length) throw new Error(`CMS block configuration is invalid:\n${blockIssues.join("\n")}`);
|
|
834
|
+
const siteTypes = addTypeTemplate({
|
|
835
|
+
filename: "types/cms-site.d.ts",
|
|
836
|
+
getContents: () => generateSiteTypes(collections, blocks, collectionsFile)
|
|
837
|
+
});
|
|
838
|
+
nuxt.options.alias["#cms/types"] = siteTypes.dst;
|
|
839
|
+
if (nuxt.options.dev) {
|
|
840
|
+
const configurationFile = resolve(nuxt.options.rootDir, "cms.config.ts");
|
|
841
|
+
const blocksDirectory = resolve(nuxt.options.rootDir, "app/cms/blocks");
|
|
842
|
+
compiler.trackDependencies(configurationFile, readFileSync(configurationFile, "utf8"));
|
|
843
|
+
const watchedPaths = /* @__PURE__ */ new Set([
|
|
844
|
+
configurationFile,
|
|
845
|
+
collectionsFile,
|
|
846
|
+
blocksDirectory,
|
|
847
|
+
...compiler.dependencies()
|
|
848
|
+
]);
|
|
849
|
+
nuxt.options.watch.push(...watchedPaths);
|
|
850
|
+
nuxt.hook("builder:watch", async (_event, filename) => {
|
|
851
|
+
const changed = resolve(nuxt.options.srcDir, filename);
|
|
852
|
+
if (watchedPaths.has(changed) || changed.startsWith(`${blocksDirectory}/`)) await nuxt.callHook("restart", { hard: true });
|
|
853
|
+
});
|
|
854
|
+
}
|
|
855
|
+
addVitePlugin({
|
|
856
|
+
name: "cms:authoring",
|
|
857
|
+
enforce: "pre",
|
|
858
|
+
watchChange(id) {
|
|
859
|
+
compiler.invalidate(id);
|
|
860
|
+
},
|
|
861
|
+
transform(source, id) {
|
|
862
|
+
if (!id.endsWith(".vue") || !id.startsWith(`${resolve(nuxt.options.srcDir)}/`)) return void 0;
|
|
863
|
+
const compiled = blockFiles.has(id) ? compiler.compile(source, id) : null;
|
|
864
|
+
return compilePreviewTemplate(compiled?.code ?? source, id, resolver.resolve("./runtime/previewSource")) ?? (compiled ? {
|
|
865
|
+
code: compiled.code,
|
|
866
|
+
map: compiled.map
|
|
867
|
+
} : void 0);
|
|
868
|
+
}
|
|
869
|
+
});
|
|
870
|
+
const studioModules = defineStudioModules(options.studio.modules);
|
|
871
|
+
if (!["host.js", "host.css"].every((asset) => existsSync(resolve(studioDirectory, asset)))) throw new Error("Build CMS Studio before starting Nuxt.");
|
|
872
|
+
nuxt.options.runtimeConfig.cms = {
|
|
873
|
+
...options.runtime,
|
|
874
|
+
s3: { ...options.runtime.s3 }
|
|
875
|
+
};
|
|
876
|
+
if (locales) nuxt.options.runtimeConfig.public.cmsLocales = {
|
|
877
|
+
defaultLocale: locales.defaultLocale,
|
|
878
|
+
supported: locales.supported.map((definition) => ({ ...definition })),
|
|
879
|
+
prefixDefault: locales.prefixDefault
|
|
880
|
+
};
|
|
881
|
+
else Reflect.deleteProperty(nuxt.options.runtimeConfig.public, "cmsLocales");
|
|
882
|
+
const handlers = blocks.flatMap((block) => block.form && block.handler ? [{
|
|
883
|
+
name: block.name,
|
|
884
|
+
file: resolve(nuxt.options.rootDir, block.handler)
|
|
885
|
+
}] : []);
|
|
886
|
+
const plugin = addServerTemplate({
|
|
887
|
+
filename: resolver.resolve("./runtime/plugin.virtual.mjs"),
|
|
888
|
+
getContents: () => [
|
|
889
|
+
`import { createCmsPlugin } from ${JSON.stringify(resolver.resolve("./runtime/plugin"))}`,
|
|
890
|
+
`import cmsCollections from ${JSON.stringify(collectionsFile)}`,
|
|
891
|
+
...handlers.map((handler, index) => `import formHandler${index} from ${JSON.stringify(handler.file)}`),
|
|
892
|
+
`export default createCmsPlugin(${JSON.stringify({
|
|
893
|
+
collections,
|
|
894
|
+
blocks,
|
|
895
|
+
seo: options.seo,
|
|
896
|
+
studioModules,
|
|
897
|
+
rootDir: nuxt.options.rootDir,
|
|
898
|
+
migrationsFolder
|
|
899
|
+
})}, { ${handlers.map((handler, index) => `${JSON.stringify(handler.name)}: formHandler${index}`).join(", ")} }, Object.fromEntries(cmsCollections.flatMap(({ collection, schema }) => schema ? [[collection, schema]] : [])))`
|
|
900
|
+
].join("\n")
|
|
901
|
+
});
|
|
902
|
+
addNitroPlugin(plugin.filename);
|
|
903
|
+
nuxt.options.css.push(resolver.resolve("./runtime/preview.css"));
|
|
904
|
+
addPluginTemplate({
|
|
905
|
+
filename: "cms-preview.mjs",
|
|
906
|
+
getContents: () => `import { createCmsPreviewPlugin } from ${JSON.stringify(resolver.resolve("./runtime/preview"))}\nexport default createCmsPreviewPlugin(${JSON.stringify(collections)}, ${JSON.stringify(blocks)})`
|
|
907
|
+
});
|
|
908
|
+
for (const asset of ["host.js", "host.css"]) extendRouteRules(`/_cms/assets/${asset}`, { headers: { "cache-control": "public, max-age=0, must-revalidate" } }, { override: true });
|
|
909
|
+
addServerHandler({
|
|
910
|
+
handler: resolver.resolve("./runtime/studio"),
|
|
911
|
+
route: "/_cms/app"
|
|
912
|
+
});
|
|
913
|
+
addServerHandler({
|
|
914
|
+
handler: resolver.resolve("./runtime/studio"),
|
|
915
|
+
route: "/_cms/app/**:path"
|
|
916
|
+
});
|
|
917
|
+
if (nuxt.options.dev) {
|
|
918
|
+
const serve = createStudioAssetHandler(studioDirectory);
|
|
919
|
+
addDevServerHandler({
|
|
920
|
+
route: "/_cms/assets/**",
|
|
921
|
+
middleware: true,
|
|
922
|
+
handler: (event) => serve(event.req)
|
|
923
|
+
});
|
|
924
|
+
}
|
|
925
|
+
nuxt.hook("nitro:config", (configuration) => {
|
|
926
|
+
const assets = "publicAssets" in configuration && Array.isArray(configuration.publicAssets) ? configuration.publicAssets : [];
|
|
927
|
+
Object.assign(configuration, { publicAssets: [
|
|
928
|
+
...assets,
|
|
929
|
+
{
|
|
930
|
+
dir: studioDirectory,
|
|
931
|
+
baseURL: "/_cms/assets",
|
|
932
|
+
maxAge: 0,
|
|
933
|
+
ignore: ["chunks/**"]
|
|
934
|
+
},
|
|
935
|
+
{
|
|
936
|
+
dir: resolve(studioDirectory, "chunks"),
|
|
937
|
+
baseURL: "/_cms/assets/chunks",
|
|
938
|
+
maxAge: 31536e3
|
|
939
|
+
}
|
|
940
|
+
] });
|
|
941
|
+
});
|
|
942
|
+
addServerHandler({
|
|
943
|
+
handler: resolver.resolve("./runtime/studioIcons"),
|
|
944
|
+
route: "/_cms/icons/lucide"
|
|
945
|
+
});
|
|
946
|
+
addServerHandler({
|
|
947
|
+
handler: resolver.resolve("./runtime/revisionPrivacy"),
|
|
948
|
+
middleware: true
|
|
949
|
+
});
|
|
950
|
+
addServerHandler({
|
|
951
|
+
handler: resolver.resolve("./runtime/api"),
|
|
952
|
+
route: "/_cms/health/ready"
|
|
953
|
+
});
|
|
954
|
+
addServerHandler({
|
|
955
|
+
handler: resolver.resolve("./runtime/api"),
|
|
956
|
+
route: "/_cms/delivery"
|
|
957
|
+
});
|
|
958
|
+
addServerHandler({
|
|
959
|
+
handler: resolver.resolve("./runtime/api"),
|
|
960
|
+
route: "/_cms/query"
|
|
961
|
+
});
|
|
962
|
+
addServerHandler({
|
|
963
|
+
handler: resolver.resolve("./runtime/api"),
|
|
964
|
+
route: "/_cms/revision-preview/delivery"
|
|
965
|
+
});
|
|
966
|
+
addServerHandler({
|
|
967
|
+
handler: resolver.resolve("./runtime/api"),
|
|
968
|
+
route: "/_cms/revision-preview/query"
|
|
969
|
+
});
|
|
970
|
+
addServerHandler({
|
|
971
|
+
handler: resolver.resolve("./runtime/api"),
|
|
972
|
+
route: "/_cms/seo/published"
|
|
973
|
+
});
|
|
974
|
+
if (options.robots) addServerHandler({
|
|
975
|
+
handler: resolver.resolve("./runtime/api"),
|
|
976
|
+
route: "/robots.txt"
|
|
977
|
+
});
|
|
978
|
+
if (options.sitemap) addServerHandler({
|
|
979
|
+
handler: resolver.resolve("./runtime/api"),
|
|
980
|
+
route: "/sitemap.xml"
|
|
981
|
+
});
|
|
982
|
+
addServerHandler({
|
|
983
|
+
handler: resolver.resolve("./runtime/api"),
|
|
984
|
+
route: "/_cms/media/**:path"
|
|
985
|
+
});
|
|
986
|
+
addServerHandler({
|
|
987
|
+
handler: resolver.resolve("./runtime/api"),
|
|
988
|
+
route: "/_cms/image/**:path"
|
|
989
|
+
});
|
|
990
|
+
addServerHandler({
|
|
991
|
+
handler: resolver.resolve("./runtime/api"),
|
|
992
|
+
route: "/_cms/auth/**:path"
|
|
993
|
+
});
|
|
994
|
+
addServerHandler({
|
|
995
|
+
handler: resolver.resolve("./runtime/api"),
|
|
996
|
+
route: "/_cms/api/**:path"
|
|
997
|
+
});
|
|
998
|
+
addComponent({
|
|
999
|
+
name: "CmsDocumentRenderer",
|
|
1000
|
+
filePath: resolver.resolve("./runtime/DocumentRenderer")
|
|
1001
|
+
});
|
|
1002
|
+
addComponent({
|
|
1003
|
+
name: "CmsImage",
|
|
1004
|
+
filePath: resolver.resolve("./runtime/CmsImage")
|
|
1005
|
+
});
|
|
1006
|
+
addImports([
|
|
1007
|
+
{
|
|
1008
|
+
name: "useCmsDocument",
|
|
1009
|
+
from: resolver.resolve("./runtime/delivery/useCmsDocument")
|
|
1010
|
+
},
|
|
1011
|
+
{
|
|
1012
|
+
name: "useCmsDocumentQuery",
|
|
1013
|
+
from: resolver.resolve("./runtime/delivery/useCmsDocumentQuery")
|
|
1014
|
+
},
|
|
1015
|
+
{
|
|
1016
|
+
name: "useCmsDocumentSeo",
|
|
1017
|
+
from: resolver.resolve("./runtime/delivery/useCmsDocumentSeo")
|
|
1018
|
+
},
|
|
1019
|
+
{
|
|
1020
|
+
name: "useCmsLocale",
|
|
1021
|
+
from: resolver.resolve("./runtime/delivery/useCmsLocale")
|
|
1022
|
+
}
|
|
1023
|
+
]);
|
|
1024
|
+
for (const block of blocks) {
|
|
1025
|
+
const filePath = resolve(nuxt.options.rootDir, block.component);
|
|
1026
|
+
addComponent({
|
|
1027
|
+
name: blockComponentName(block.name),
|
|
1028
|
+
filePath,
|
|
1029
|
+
global: true
|
|
1030
|
+
});
|
|
1031
|
+
}
|
|
1032
|
+
extendPages((pages) => {
|
|
1033
|
+
pages.push({
|
|
1034
|
+
file: resolver.resolve("./runtime/DocumentPage.vue"),
|
|
1035
|
+
name: "cms-revision-preview",
|
|
1036
|
+
path: "/_cms/revision-preview"
|
|
1037
|
+
});
|
|
1038
|
+
pages.push({
|
|
1039
|
+
file: resolver.resolve("./runtime/DocumentPage.vue"),
|
|
1040
|
+
name: "cms-document",
|
|
1041
|
+
path: "/:contentPath(.*)*"
|
|
1042
|
+
});
|
|
1043
|
+
});
|
|
1044
|
+
}
|
|
1045
|
+
});
|
|
1046
|
+
//#endregion
|
|
1047
|
+
export { Module_default as default };
|