@shapio/cms 0.5.9 → 0.5.10
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-Da76KsyX.js → AssetTile-DecaDqjj.js} +2 -2
- package/dist/admin/assets/{AssetTile-Da76KsyX.js.map → AssetTile-DecaDqjj.js.map} +1 -1
- package/dist/admin/assets/{AssistError-Wr62cDj3.js → AssistError-rslPtgWB.js} +2 -2
- package/dist/admin/assets/{AssistError-Wr62cDj3.js.map → AssistError-rslPtgWB.js.map} +1 -1
- package/dist/admin/assets/{BlockMenuItems-BMiEVCIT.js → BlockMenuItems-JHFue7Qt.js} +2 -2
- package/dist/admin/assets/{BlockMenuItems-BMiEVCIT.js.map → BlockMenuItems-JHFue7Qt.js.map} +1 -1
- package/dist/admin/assets/{Body-BEW1sAAB.js → Body-7NgJl9Pi.js} +2 -2
- package/dist/admin/assets/Body-7NgJl9Pi.js.map +1 -0
- package/dist/admin/assets/Builder-DmlYcgiP.js +2 -0
- package/dist/admin/assets/Builder-DmlYcgiP.js.map +1 -0
- package/dist/admin/assets/{CodeEditor-Ck7ggv6w.js → CodeEditor-Dv1FtkvI.js} +2 -2
- package/dist/admin/assets/{CodeEditor-Ck7ggv6w.js.map → CodeEditor-Dv1FtkvI.js.map} +1 -1
- package/dist/admin/assets/{CopyButton-WMWuSVsk.js → CopyButton-Brnpfqe0.js} +2 -2
- package/dist/admin/assets/{CopyButton-WMWuSVsk.js.map → CopyButton-Brnpfqe0.js.map} +1 -1
- package/dist/admin/assets/{CursorPager-CsnzX1P8.js → CursorPager-C7cAK5Qe.js} +2 -2
- package/dist/admin/assets/{CursorPager-CsnzX1P8.js.map → CursorPager-C7cAK5Qe.js.map} +1 -1
- package/dist/admin/assets/{FocalPoint-CstZuVmt.js → FocalPoint-Bhtb1gUa.js} +2 -2
- package/dist/admin/assets/{FocalPoint-CstZuVmt.js.map → FocalPoint-Bhtb1gUa.js.map} +1 -1
- package/dist/admin/assets/{Form-CEOW2OFF.js → Form-Cf1ephPH.js} +2 -2
- package/dist/admin/assets/{Form-CEOW2OFF.js.map → Form-Cf1ephPH.js.map} +1 -1
- package/dist/admin/assets/FormCheckboxGroup-BzVZFR3W.js +2 -0
- package/dist/admin/assets/FormCheckboxGroup-BzVZFR3W.js.map +1 -0
- package/dist/admin/assets/{FormRadioGroup-BQurJa8M.js → FormRadioGroup-BzmLzRnI.js} +2 -2
- package/dist/admin/assets/{FormRadioGroup-BQurJa8M.js.map → FormRadioGroup-BzmLzRnI.js.map} +1 -1
- package/dist/admin/assets/{FormSelectField-B4sjP-pj.js → FormSelectField-Cl7EjXc3.js} +2 -2
- package/dist/admin/assets/{FormSelectField-B4sjP-pj.js.map → FormSelectField-Cl7EjXc3.js.map} +1 -1
- package/dist/admin/assets/{FormSheet-V99zdfQe.js → FormSheet-CLZpd_7B.js} +2 -2
- package/dist/admin/assets/FormSheet-CLZpd_7B.js.map +1 -0
- package/dist/admin/assets/{FormSwitchField-RZgoP--n.js → FormSwitchField-BbqQ3tx_.js} +2 -2
- package/dist/admin/assets/{FormSwitchField-RZgoP--n.js.map → FormSwitchField-BbqQ3tx_.js.map} +1 -1
- package/dist/admin/assets/{FormTextareaField-CzXgoQzf.js → FormTextareaField-9RN5Pt3B.js} +2 -2
- package/dist/admin/assets/{FormTextareaField-CzXgoQzf.js.map → FormTextareaField-9RN5Pt3B.js.map} +1 -1
- package/dist/admin/assets/{HintedLabel-Cd9nuSqV.js → HintedLabel-D9IVF0EE.js} +2 -2
- package/dist/admin/assets/{HintedLabel-Cd9nuSqV.js.map → HintedLabel-D9IVF0EE.js.map} +1 -1
- package/dist/admin/assets/{InfoHint-ymRmHKMr.js → InfoHint-tlSeZB9U.js} +2 -2
- package/dist/admin/assets/{InfoHint-ymRmHKMr.js.map → InfoHint-tlSeZB9U.js.map} +1 -1
- package/dist/admin/assets/{InlineConfirm-A4IqkrGp.js → InlineConfirm-Kj9AOIFO.js} +2 -2
- package/dist/admin/assets/{InlineConfirm-A4IqkrGp.js.map → InlineConfirm-Kj9AOIFO.js.map} +1 -1
- package/dist/admin/assets/{InsertMenuItem-Bf7S7qbm.js → InsertMenuItem-CHAp2tH7.js} +2 -2
- package/dist/admin/assets/{InsertMenuItem-Bf7S7qbm.js.map → InsertMenuItem-CHAp2tH7.js.map} +1 -1
- package/dist/admin/assets/{Match-DJq8wn3e.js → Match-BfNRwPfR.js} +2 -2
- package/dist/admin/assets/{Match-DJq8wn3e.js.map → Match-BfNRwPfR.js.map} +1 -1
- package/dist/admin/assets/{NoAccess-CZufdbPI.js → NoAccess-DnEpYj9l.js} +2 -2
- package/dist/admin/assets/{NoAccess-CZufdbPI.js.map → NoAccess-DnEpYj9l.js.map} +1 -1
- package/dist/admin/assets/Panel-Bcl09TtM.js.map +1 -1
- package/dist/admin/assets/{QueryView-DO9TFWYE.js → QueryView-B86NcRt5.js} +2 -2
- package/dist/admin/assets/{QueryView-DO9TFWYE.js.map → QueryView-B86NcRt5.js.map} +1 -1
- package/dist/admin/assets/{RadioTile-DmKBFkpy.js → RadioTile-Bwd2Pmlk.js} +2 -2
- package/dist/admin/assets/RadioTile-Bwd2Pmlk.js.map +1 -0
- package/dist/admin/assets/{RichTextField-BpxyusP4.js → RichTextField-Dou79MHF.js} +2 -2
- package/dist/admin/assets/RichTextField-Dou79MHF.js.map +1 -0
- package/dist/admin/assets/{RowTitle-DVOfgxOd.js → RowTitle-DH9OZs3g.js} +2 -2
- package/dist/admin/assets/{RowTitle-DVOfgxOd.js.map → RowTitle-DH9OZs3g.js.map} +1 -1
- package/dist/admin/assets/{SecretReveal-DRCqVEFF.js → SecretReveal-D95oACLj.js} +2 -2
- package/dist/admin/assets/{SecretReveal-DRCqVEFF.js.map → SecretReveal-D95oACLj.js.map} +1 -1
- package/dist/admin/assets/{SharedGlyph-nsXJPCew.js → SharedGlyph-Chwb1EIS.js} +2 -2
- package/dist/admin/assets/{SharedGlyph-nsXJPCew.js.map → SharedGlyph-Chwb1EIS.js.map} +1 -1
- package/dist/admin/assets/{StepList-CDZPRd3-.js → StepList-D9iHsUZJ.js} +2 -2
- package/dist/admin/assets/StepList-D9iHsUZJ.js.map +1 -0
- package/dist/admin/assets/Structure-CewJL1b3.js +2 -0
- package/dist/admin/assets/{Structure-CL51Bvbm.js.map → Structure-CewJL1b3.js.map} +1 -1
- package/dist/admin/assets/SubNavLink-7Cs1LqMv.js.map +1 -1
- package/dist/admin/assets/{SuggestAltButton-4SaZQOJu.js → SuggestAltButton-BK1uo4yC.js} +2 -2
- package/dist/admin/assets/{SuggestAltButton-4SaZQOJu.js.map → SuggestAltButton-BK1uo4yC.js.map} +1 -1
- package/dist/admin/assets/{Thumbnail-DauHAkh8.js → Thumbnail-C2A_Ub77.js} +2 -2
- package/dist/admin/assets/{Thumbnail-DauHAkh8.js.map → Thumbnail-C2A_Ub77.js.map} +1 -1
- package/dist/admin/assets/{Trans-B3UWiZaU.js → Trans-CPoNNUK1.js} +2 -2
- package/dist/admin/assets/{Trans-B3UWiZaU.js.map → Trans-CPoNNUK1.js.map} +1 -1
- package/dist/admin/assets/{UnsavedChangesGuard-DPgih7BX.js → UnsavedChangesGuard-BsEyn9oH.js} +2 -2
- package/dist/admin/assets/{UnsavedChangesGuard-DPgih7BX.js.map → UnsavedChangesGuard-BsEyn9oH.js.map} +1 -1
- package/dist/admin/assets/{UserAvatar-If-zlQNY.js → UserAvatar-CgGKOFfP.js} +2 -2
- package/dist/admin/assets/{UserAvatar-If-zlQNY.js.map → UserAvatar-CgGKOFfP.js.map} +1 -1
- package/dist/admin/assets/{badge-DEe9tqLS.js → badge-DGqA_yr_.js} +2 -2
- package/dist/admin/assets/{badge-DEe9tqLS.js.map → badge-DGqA_yr_.js.map} +1 -1
- package/dist/admin/assets/baseExtensions-TVKN1UwW.js.map +1 -1
- package/dist/admin/assets/{changeSets-D5i2SgFV.js → changeSets-B6HxCJ4A.js} +2 -2
- package/dist/admin/assets/{changeSets-D5i2SgFV.js.map → changeSets-B6HxCJ4A.js.map} +1 -1
- package/dist/admin/assets/cn-DVhJ55Mo.js.map +1 -1
- package/dist/admin/assets/{constants-FKg_ke3y.js → constants-DY3YJAKH.js} +2 -2
- package/dist/admin/assets/{constants-FKg_ke3y.js.map → constants-DY3YJAKH.js.map} +1 -1
- package/dist/admin/assets/content-BNZF26Ve.js +3 -0
- package/dist/admin/assets/content-BNZF26Ve.js.map +1 -0
- package/dist/admin/assets/{contentTypes-B5taZv3y.js → contentTypes-Bz2xpqGf.js} +2 -2
- package/dist/admin/assets/{contentTypes-B5taZv3y.js.map → contentTypes-Bz2xpqGf.js.map} +1 -1
- package/dist/admin/assets/createLucideIcon-BOsNKleB.js.map +1 -1
- package/dist/admin/assets/{develop-CFlv7IdP.js → develop-D6CtwuYj.js} +2 -2
- package/dist/admin/assets/develop-D6CtwuYj.js.map +1 -0
- package/dist/admin/assets/{dropdown-menu-B7dJyA8h.js → dropdown-menu-Bz7CLcRK.js} +2 -2
- package/dist/admin/assets/{dropdown-menu-B7dJyA8h.js.map → dropdown-menu-Bz7CLcRK.js.map} +1 -1
- package/dist/admin/assets/es2015-Cv57ynE1.js +42 -0
- package/dist/admin/assets/es2015-Cv57ynE1.js.map +1 -0
- package/dist/admin/assets/{field-BDCHXkZE.js → field-D-xWW2E7.js} +2 -2
- package/dist/admin/assets/{field-BDCHXkZE.js.map → field-D-xWW2E7.js.map} +1 -1
- package/dist/admin/assets/{fileRoute-c9UMUr9b.js → fileRoute-DMal-zYL.js} +2 -2
- package/dist/admin/assets/{fileRoute-c9UMUr9b.js.map → fileRoute-DMal-zYL.js.map} +1 -1
- package/dist/admin/assets/{followPlural-CHpz-yo4.js → followPlural-CsgeALTW.js} +2 -2
- package/dist/admin/assets/{followPlural-CHpz-yo4.js.map → followPlural-CsgeALTW.js.map} +1 -1
- package/dist/admin/assets/{inbox-Daw10v5C.js → inbox-C0PVc6UI.js} +2 -2
- package/dist/admin/assets/{inbox-Daw10v5C.js.map → inbox-C0PVc6UI.js.map} +1 -1
- package/dist/admin/assets/{index-BRx5mel0.js → index-BqtCXB0u.js} +4 -4
- package/dist/admin/assets/{index-BRx5mel0.js.map → index-BqtCXB0u.js.map} +1 -1
- package/dist/admin/assets/{labels-B83cEX9w.js → labels-BtktCNGw.js} +2 -2
- package/dist/admin/assets/{labels-B83cEX9w.js.map → labels-BtktCNGw.js.map} +1 -1
- package/dist/admin/assets/{media-CgxriwNL.js → media-CeZGDGh7.js} +2 -2
- package/dist/admin/assets/{media-CgxriwNL.js.map → media-CeZGDGh7.js.map} +1 -1
- package/dist/admin/assets/{network-Cc1TAyal.js → network-BflLSKFO.js} +2 -2
- package/dist/admin/assets/{network-Cc1TAyal.js.map → network-BflLSKFO.js.map} +1 -1
- package/dist/admin/assets/publishing-BkxBplUZ.js +2 -0
- package/dist/admin/assets/publishing-BkxBplUZ.js.map +1 -0
- package/dist/admin/assets/{radio-group-Btmx7dlD.js → radio-group-CRuWQnuV.js} +2 -2
- package/dist/admin/assets/{radio-group-Btmx7dlD.js.map → radio-group-CRuWQnuV.js.map} +1 -1
- package/dist/admin/assets/schema-6eUoC8fJ.js +2 -0
- package/dist/admin/assets/schema-6eUoC8fJ.js.map +1 -0
- package/dist/admin/assets/{searchSchemas-fO_49fDI.js → searchSchemas-DAnwh3I3.js} +2 -2
- package/dist/admin/assets/{searchSchemas-fO_49fDI.js.map → searchSchemas-DAnwh3I3.js.map} +1 -1
- package/dist/admin/assets/{sections-SX-oiQoE.js → sections-CWL-XD6m.js} +2 -2
- package/dist/admin/assets/sections-CWL-XD6m.js.map +1 -0
- package/dist/admin/assets/{select-JB2Vv7ep.js → select-DVrPV1b3.js} +2 -2
- package/dist/admin/assets/{select-JB2Vv7ep.js.map → select-DVrPV1b3.js.map} +1 -1
- package/dist/admin/assets/{settings-CrRFxhSo.js → settings-CqnrPmzR.js} +2 -2
- package/dist/admin/assets/{settings-CrRFxhSo.js.map → settings-CqnrPmzR.js.map} +1 -1
- package/dist/admin/assets/{shapes-EMjfYsXV.js → shapes-ZAkMBB-Z.js} +4 -4
- package/dist/admin/assets/shapes-ZAkMBB-Z.js.map +1 -0
- package/dist/admin/assets/{skeleton-Dk-qdg0z.js → skeleton-CiX26LnL.js} +2 -2
- package/dist/admin/assets/{skeleton-Dk-qdg0z.js.map → skeleton-CiX26LnL.js.map} +1 -1
- package/dist/admin/assets/src-CMor9izq.js.map +1 -1
- package/dist/admin/assets/{switch-DyCRGDs7.js → switch-CiVf05NF.js} +2 -2
- package/dist/admin/assets/{switch-DyCRGDs7.js.map → switch-CiVf05NF.js.map} +1 -1
- package/dist/admin/assets/theme-Cv-MfOv8.js.map +1 -1
- package/dist/admin/assets/{tooltip-CCOeMqiL.js → tooltip-Bqf3oyqC.js} +2 -2
- package/dist/admin/assets/{tooltip-CCOeMqiL.js.map → tooltip-Bqf3oyqC.js.map} +1 -1
- package/dist/admin/assets/{useContentSchema-uXOfT985.js → useContentSchema-B_q1rMrG.js} +2 -2
- package/dist/admin/assets/{useContentSchema-uXOfT985.js.map → useContentSchema-B_q1rMrG.js.map} +1 -1
- package/dist/admin/assets/useCursorPager-BHYqHb3M.js.map +1 -1
- package/dist/admin/assets/{useDiscardGuard-DvBI3VIz.js → useDiscardGuard-C4QTfiU4.js} +2 -2
- package/dist/admin/assets/{useDiscardGuard-DvBI3VIz.js.map → useDiscardGuard-C4QTfiU4.js.map} +1 -1
- package/dist/admin/assets/{useMediaPickerDialog-CehOsykG.js → useMediaPickerDialog-BLrVV1Kn.js} +2 -2
- package/dist/admin/assets/{useMediaPickerDialog-CehOsykG.js.map → useMediaPickerDialog-BLrVV1Kn.js.map} +1 -1
- package/dist/admin/assets/{useMediaUploader-DvtxYXxD.js → useMediaUploader-CFy6lasO.js} +2 -2
- package/dist/admin/assets/useMediaUploader-CFy6lasO.js.map +1 -0
- package/dist/admin/assets/{useModelIndex-D8Q0oM4M.js → useModelIndex-NU-WlHQY.js} +2 -2
- package/dist/admin/assets/{useModelIndex-D8Q0oM4M.js.map → useModelIndex-NU-WlHQY.js.map} +1 -1
- package/dist/admin/assets/{usePlaces-CySN2Vwz.js → usePlaces-BA4x6503.js} +2 -2
- package/dist/admin/assets/{usePlaces-CySN2Vwz.js.map → usePlaces-BA4x6503.js.map} +1 -1
- package/dist/admin/assets/{useResolvedDefinitions-C279ueCH.js → useResolvedDefinitions-30lnwFQ1.js} +2 -2
- package/dist/admin/assets/{useResolvedDefinitions-C279ueCH.js.map → useResolvedDefinitions-30lnwFQ1.js.map} +1 -1
- package/dist/admin/assets/{useResolvedScheme-DEq7P4R5.js → useResolvedScheme-BVM4qLct.js} +2 -2
- package/dist/admin/assets/{useResolvedScheme-DEq7P4R5.js.map → useResolvedScheme-BVM4qLct.js.map} +1 -1
- package/dist/admin/assets/{zod-vPzaNsuW.js → zod-ZaQjjiAq.js} +2 -2
- package/dist/admin/assets/{zod-vPzaNsuW.js.map → zod-ZaQjjiAq.js.map} +1 -1
- package/dist/admin/index.html +29 -29
- package/dist/cli.js +1 -1
- package/dist/{cliMain-DzBXO7Oa.js → cliMain-CTntiVc2.js} +11 -11
- package/dist/cliMain-CTntiVc2.js.map +1 -0
- package/dist/config.d.ts +1 -1
- package/dist/config.js +1 -1
- package/dist/{contentDisposition-DOL2Xt0l.js → contentDisposition-DzhPhncr.js} +2 -2
- package/dist/{contentDisposition-DOL2Xt0l.js.map → contentDisposition-DzhPhncr.js.map} +1 -1
- package/dist/index.d.ts +2 -2
- package/dist/index.js +2 -2
- package/dist/{public-jttKsns_.d.ts → public-CMFaGDyf.d.ts} +4 -4
- package/dist/{public-B57h4F7Y.js → public-sJCQaNaP.js} +2 -2
- package/dist/{public-B57h4F7Y.js.map → public-sJCQaNaP.js.map} +1 -1
- package/dist/{s3Adapter-U01iEAcK.js → s3Adapter-CZcCl0sy.js} +2 -2
- package/dist/{s3Adapter-U01iEAcK.js.map → s3Adapter-CZcCl0sy.js.map} +1 -1
- package/dist/{worker-6ru1tYBs.js → worker-DHm2JwMZ.js} +353 -232
- package/dist/worker-DHm2JwMZ.js.map +1 -0
- package/package.json +5 -5
- package/dist/admin/assets/Body-BEW1sAAB.js.map +0 -1
- package/dist/admin/assets/Builder-Tk_5Orrl.js +0 -2
- package/dist/admin/assets/Builder-Tk_5Orrl.js.map +0 -1
- package/dist/admin/assets/FormCheckboxGroup-VjWVMiF3.js +0 -2
- package/dist/admin/assets/FormCheckboxGroup-VjWVMiF3.js.map +0 -1
- package/dist/admin/assets/FormSheet-V99zdfQe.js.map +0 -1
- package/dist/admin/assets/RadioTile-DmKBFkpy.js.map +0 -1
- package/dist/admin/assets/RichTextField-BpxyusP4.js.map +0 -1
- package/dist/admin/assets/StepList-CDZPRd3-.js.map +0 -1
- package/dist/admin/assets/Structure-CL51Bvbm.js +0 -2
- package/dist/admin/assets/content-DKT2ziPH.js +0 -3
- package/dist/admin/assets/content-DKT2ziPH.js.map +0 -1
- package/dist/admin/assets/develop-CFlv7IdP.js.map +0 -1
- package/dist/admin/assets/es2015-1nJWBurR.js +0 -42
- package/dist/admin/assets/es2015-1nJWBurR.js.map +0 -1
- package/dist/admin/assets/publishing-RQUj-CyN.js +0 -2
- package/dist/admin/assets/publishing-RQUj-CyN.js.map +0 -1
- package/dist/admin/assets/schema-BMQEabwO.js +0 -2
- package/dist/admin/assets/schema-BMQEabwO.js.map +0 -1
- package/dist/admin/assets/sections-SX-oiQoE.js.map +0 -1
- package/dist/admin/assets/shapes-EMjfYsXV.js.map +0 -1
- package/dist/admin/assets/useMediaUploader-DvtxYXxD.js.map +0 -1
- package/dist/cliMain-DzBXO7Oa.js.map +0 -1
- package/dist/worker-6ru1tYBs.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 ThemeDefinition, I as ThemeTokens, L as defineConfig, M as ServiceModel, N as ShapioConfig, O as ModelHooks, P as ShapioServices, R as isHookError, 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 ServiceField, 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 ThemeDefinition, I as ThemeTokens, L as defineConfig, M as ServiceModel, N as ShapioConfig, O as ModelHooks, P as ShapioServices, R as isHookError, 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 ServiceField, 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-CMFaGDyf.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, ServiceField, ServiceModel, ShapioConfig, ShapioServices, ThemeDefinition, ThemeTokens, defineConfig, isHookError };
|
package/dist/config.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { i as isHookError, n as HookError, r as defineConfig, t as EXTENSION_CONTRACT_VERSION } from "./public-
|
|
1
|
+
import { i as isHookError, n as HookError, r as defineConfig, t as EXTENSION_CONTRACT_VERSION } from "./public-sJCQaNaP.js";
|
|
2
2
|
export { EXTENSION_CONTRACT_VERSION, HookError, defineConfig, isHookError };
|
|
@@ -16,7 +16,7 @@ const splitExtension = (name) => {
|
|
|
16
16
|
};
|
|
17
17
|
};
|
|
18
18
|
/**
|
|
19
|
-
* The display name kept for an upload: the last path segment, NFC-
|
|
19
|
+
* The display name kept for an upload: the last path segment, NFC-normalized, without control or
|
|
20
20
|
* path characters, at most 200 characters with the extension preserved. Never used as a storage path.
|
|
21
21
|
*/
|
|
22
22
|
const sanitizeFilename = (input) => {
|
|
@@ -87,4 +87,4 @@ const bucketContentDisposition = (contentType) => PASSIVE_INLINE_TYPE.test(conte
|
|
|
87
87
|
//#endregion
|
|
88
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
89
|
|
|
90
|
-
//# sourceMappingURL=contentDisposition-
|
|
90
|
+
//# sourceMappingURL=contentDisposition-DzhPhncr.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"contentDisposition-
|
|
1
|
+
{"version":3,"file":"contentDisposition-DzhPhncr.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-normalized, 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 PermissionEvaluator, C as HookEvent, D as MediaUsage, E as MediaReferenceService, F as ThemeDefinition, G as OutboxEvents, H as Principal, I as ThemeTokens, J as DataType, K as ContentData, L as defineConfig, M as ServiceModel, N as ShapioConfig, O as ModelHooks, P as ShapioServices, R as isHookError, S as HookError, T as JobHandlerContext, U as Database, V as PermissionExecutor, W as DB, X as PlannedChange, Y as JsonValue, Z as ResolvedModelDefinition, _ 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 ServiceField, k as ServiceFactory, l as ContentReadService, m as ExtensionHostConfig, n as AfterHookContext, o as BeforeHookEvent, p as EntryData, q as ComponentDefinition, 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 KnownVersions } from "./public-
|
|
1
|
+
import { A as ServiceFactoryContext, B as PermissionEvaluator, C as HookEvent, D as MediaUsage, E as MediaReferenceService, F as ThemeDefinition, G as OutboxEvents, H as Principal, I as ThemeTokens, J as DataType, K as ContentData, L as defineConfig, M as ServiceModel, N as ShapioConfig, O as ModelHooks, P as ShapioServices, R as isHookError, S as HookError, T as JobHandlerContext, U as Database, V as PermissionExecutor, W as DB, X as PlannedChange, Y as JsonValue, Z as ResolvedModelDefinition, _ 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 ServiceField, k as ServiceFactory, l as ContentReadService, m as ExtensionHostConfig, n as AfterHookContext, o as BeforeHookEvent, p as EntryData, q as ComponentDefinition, 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 KnownVersions } from "./public-CMFaGDyf.js";
|
|
2
2
|
import { FastifyBaseLogger, FastifyInstance } from "fastify";
|
|
3
3
|
import { Kysely, Selectable, Transaction } from "kysely";
|
|
4
4
|
import { Static, Type } from "typebox";
|
|
@@ -537,7 +537,7 @@ type JobContext = {
|
|
|
537
537
|
signal: AbortSignal;
|
|
538
538
|
log: JobLogger;
|
|
539
539
|
};
|
|
540
|
-
/** Returns an optional JSON-
|
|
540
|
+
/** Returns an optional JSON-serializable result. Throw to fail the attempt; the queue retries with backoff. */
|
|
541
541
|
type JobHandler = (context: JobContext) => Promise<unknown>;
|
|
542
542
|
/**
|
|
543
543
|
* Turns an outbox event into follow-up work (usually by enqueueing jobs) inside the relay's transaction.
|
package/dist/index.js
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
import { a as loadConfig, n as startServer, s as buildApp, t as startDedicatedWorker, u as SHAPIO_VERSION } from "./worker-
|
|
2
|
-
import { i as isHookError, n as HookError, r as defineConfig, t as EXTENSION_CONTRACT_VERSION } from "./public-
|
|
1
|
+
import { a as loadConfig, n as startServer, s as buildApp, t as startDedicatedWorker, u as SHAPIO_VERSION } from "./worker-DHm2JwMZ.js";
|
|
2
|
+
import { i as isHookError, n as HookError, r as defineConfig, t as EXTENSION_CONTRACT_VERSION } from "./public-sJCQaNaP.js";
|
|
3
3
|
export { EXTENSION_CONTRACT_VERSION, HookError, SHAPIO_VERSION, buildApp, defineConfig, isHookError, loadConfig, startDedicatedWorker, startServer };
|
|
@@ -1528,7 +1528,7 @@ type JobHandlerContext = {
|
|
|
1528
1528
|
/** Throw to retry with backoff; the return value (JSON) is stored as the job result. */
|
|
1529
1529
|
type ExtensionJobHandler = (context: JobHandlerContext) => Promise<unknown>;
|
|
1530
1530
|
/**
|
|
1531
|
-
* A
|
|
1531
|
+
* A color theme for the admin: token values for a light variant, a dark variant, or both. Every UI token is
|
|
1532
1532
|
* required in a variant; the `brand-*` tokens may be left out (Shapio's are used). Values are `#rrggbb`
|
|
1533
1533
|
* (contrast is checked by `shapio extensions check`), `#rgb`, `#rrggbbaa`, or `rgb()`, `hsl()`, `oklch()`,
|
|
1534
1534
|
* `oklab()` with plain arguments.
|
|
@@ -1553,7 +1553,7 @@ type ShapioConfig = {
|
|
|
1553
1553
|
editors?: string[];
|
|
1554
1554
|
/** Job handlers by name; registered as `ext.<name>`. */
|
|
1555
1555
|
jobs?: Record<string, ExtensionJobHandler>;
|
|
1556
|
-
/** Admin
|
|
1556
|
+
/** Admin color themes, listed after the built-in ones in the theme menu. */
|
|
1557
1557
|
themes?: ThemeDefinition[];
|
|
1558
1558
|
};
|
|
1559
1559
|
/** Identity helper for completion and type checking in `shapio.config.ts`. */
|
|
@@ -1561,7 +1561,7 @@ declare const defineConfig: (config: ShapioConfig) => ShapioConfig;
|
|
|
1561
1561
|
declare const HOOK_ERROR_BRAND: unique symbol;
|
|
1562
1562
|
/**
|
|
1563
1563
|
* Thrown by a `before*` hook to reject a write: the API answers 422 with code `HOOK_REJECTED`, this message
|
|
1564
|
-
* and the details.
|
|
1564
|
+
* and the details. Recognized by a brand, not `instanceof`, so a copy of this class loaded from another
|
|
1565
1565
|
* path (a project's own `node_modules`) works the same.
|
|
1566
1566
|
*/
|
|
1567
1567
|
declare class HookError extends Error {
|
|
@@ -1572,4 +1572,4 @@ declare class HookError extends Error {
|
|
|
1572
1572
|
declare const isHookError: (error: unknown) => error is HookError;
|
|
1573
1573
|
//#endregion
|
|
1574
1574
|
export { ServiceFactoryContext as A, PermissionEvaluator as B, HookEvent as C, MediaUsage as D, MediaReferenceService as E, ThemeDefinition as F, OutboxEvents as G, Principal as H, ThemeTokens as I, DataType as J, ContentData as K, defineConfig as L, ServiceModel as M, ShapioConfig as N, ModelHooks as O, ShapioServices as P, isHookError as R, HookError as S, JobHandlerContext as T, Database as U, PermissionExecutor as V, DB as W, PlannedChange as X, JsonValue$1 as Y, ResolvedModelDefinition as Z, 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, ServiceField as j, ServiceFactory as k, ContentReadService as l, ExtensionHostConfig as m, AfterHookContext as n, BeforeHookEvent as o, EntryData as p, ComponentDefinition 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, KnownVersions as z };
|
|
1575
|
-
//# sourceMappingURL=public-
|
|
1575
|
+
//# sourceMappingURL=public-CMFaGDyf.d.ts.map
|
|
@@ -20,7 +20,7 @@ const defineConfig = (config) => config;
|
|
|
20
20
|
const HOOK_ERROR_BRAND = Symbol.for("shapio.HookError");
|
|
21
21
|
/**
|
|
22
22
|
* Thrown by a `before*` hook to reject a write: the API answers 422 with code `HOOK_REJECTED`, this message
|
|
23
|
-
* and the details.
|
|
23
|
+
* and the details. Recognized by a brand, not `instanceof`, so a copy of this class loaded from another
|
|
24
24
|
* path (a project's own `node_modules`) works the same.
|
|
25
25
|
*/
|
|
26
26
|
var HookError = class extends Error {
|
|
@@ -36,4 +36,4 @@ const isHookError = (error) => typeof error === "object" && error !== null && er
|
|
|
36
36
|
//#endregion
|
|
37
37
|
export { isHookError as i, HookError as n, defineConfig as r, EXTENSION_CONTRACT_VERSION as t };
|
|
38
38
|
|
|
39
|
-
//# sourceMappingURL=public-
|
|
39
|
+
//# sourceMappingURL=public-sJCQaNaP.js.map
|
|
@@ -1 +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 /** The API ID of the model this one extends; absent for a model that extends nothing. */\n extends?: string;\n};\n\n/** A field of a model as `content.models()` describes it (its effective fields, inherited ones first). */\nexport type ServiceField = {\n /** Stable field ID (never changes; an inherited field keeps the declaring model's ID). */\n id: string;\n apiKey: string;\n label: string;\n type: string;\n required: boolean;\n localized: boolean;\n /** The API ID of the model that declares the field, when it is inherited; absent for the model's own. */\n inheritedFrom?: string;\n};\n\n/** A content model with its effective fields and where the delivery API serves it. */\nexport type ServiceModel = HookModel & {\n /** The delivery route key: the plural API ID, nested under the models it extends (`posts/guides`). */\n routeKey: string;\n fields: ServiceField[];\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 /**\n * The active content models (collections and singletons) of this site: shared ones and its own, each with\n * its effective fields (a model that extends another lists the inherited fields first) and route key.\n */\n models: () => Promise<ServiceModel[]>;\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;;AAmR1C,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"}
|
|
1
|
+
{"version":3,"file":"public-sJCQaNaP.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 /** The API ID of the model this one extends; absent for a model that extends nothing. */\n extends?: string;\n};\n\n/** A field of a model as `content.models()` describes it (its effective fields, inherited ones first). */\nexport type ServiceField = {\n /** Stable field ID (never changes; an inherited field keeps the declaring model's ID). */\n id: string;\n apiKey: string;\n label: string;\n type: string;\n required: boolean;\n localized: boolean;\n /** The API ID of the model that declares the field, when it is inherited; absent for the model's own. */\n inheritedFrom?: string;\n};\n\n/** A content model with its effective fields and where the delivery API serves it. */\nexport type ServiceModel = HookModel & {\n /** The delivery route key: the plural API ID, nested under the models it extends (`posts/guides`). */\n routeKey: string;\n fields: ServiceField[];\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 /**\n * The active content models (collections and singletons) of this site: shared ones and its own, each with\n * its effective fields (a model that extends another lists the inherited fields first) and route key.\n */\n models: () => Promise<ServiceModel[]>;\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 color 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 color 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. Recognized 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;;AAmR1C,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"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { c as isValidStorageKey, i as ObjectNotFoundError, n as contentDisposition, r as InvalidStorageKeyError, s as encodeKeyPath, t as bucketContentDisposition } from "./contentDisposition-
|
|
1
|
+
import { c as isValidStorageKey, i as ObjectNotFoundError, n as contentDisposition, r as InvalidStorageKeyError, s as encodeKeyPath, t as bucketContentDisposition } from "./contentDisposition-DzhPhncr.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-CZcCl0sy.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"s3Adapter-
|
|
1
|
+
{"version":3,"file":"s3Adapter-CZcCl0sy.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"}
|