@velora-cms/server 0.11.0 → 0.12.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.
Files changed (75) hide show
  1. package/dist/admin/sync-admin-bundle.d.ts +9 -0
  2. package/dist/admin/sync-admin-bundle.js +120 -0
  3. package/dist/admin-bundle/.velora-version +1 -0
  4. package/dist/admin-bundle/assets/{_virtual_mf-localSharedImportMap___mfe_internal__velora_admin__mf_owner__1-DOKdWYyj.js → _virtual_mf-localSharedImportMap___mfe_internal__velora_admin__mf_owner__1-DlIgIuFP.js} +1 -1
  5. package/dist/admin-bundle/assets/{_virtual_mf___mfe_internal__velora_admin__mf_owner__1__loadShare___mf_0_velora_mf_2_cms_mf_1_plugin_mf_2_sdk__loadShare__.js-C1-ZAxwO.js → _virtual_mf___mfe_internal__velora_admin__mf_owner__1__loadShare___mf_0_velora_mf_2_cms_mf_1_plugin_mf_2_sdk__loadShare__.js-Bm9EahCG.js} +2 -2
  6. package/dist/admin-bundle/assets/{content-trash.schema-DfXHkC-w.js → content-trash.schema-tvJ4Lbos.js} +5 -5
  7. package/dist/admin-bundle/assets/{hostInit--C4xK6nj.js → hostInit-B-6-34XY.js} +1 -1
  8. package/dist/admin-bundle/assets/{index-DhMY-0sC.js → index-CHCGuSbb.js} +1 -1
  9. package/dist/admin-bundle/assets/{index-BIAF0ShP.js → index-DYO7-IK8.js} +33 -33
  10. package/dist/admin-bundle/assets/{mf-entry-bootstrap-0-aef015cd.js → mf-entry-bootstrap-0-7b0ce2fe.js} +2 -2
  11. package/dist/admin-bundle/assets/{remoteEntry-CNyN68bc.js → remoteEntry-J2yJXsGB.js} +2 -2
  12. package/dist/admin-bundle/index.html +4 -4
  13. package/dist/app.d.ts +16 -1
  14. package/dist/app.js +63 -4
  15. package/dist/auth/api-keys.d.ts +1 -0
  16. package/dist/auth/api-keys.js +5 -1
  17. package/dist/auth/route-rate-limits.d.ts +4 -0
  18. package/dist/auth/route-rate-limits.js +13 -0
  19. package/dist/bin-sync-admin.d.ts +2 -0
  20. package/dist/bin-sync-admin.js +39 -0
  21. package/dist/bundled-templates/com.velora.blog/package.tar.gz +0 -0
  22. package/dist/config/public-url.d.ts +3 -0
  23. package/dist/config/public-url.js +45 -0
  24. package/dist/db/core-migrations/steps.js +95 -16
  25. package/dist/docs-bundle/pagefind/fragment/en_42f5356.pf_fragment +0 -0
  26. package/dist/docs-bundle/pagefind/fragment/en_67dccf8.pf_fragment +0 -0
  27. package/dist/docs-bundle/pagefind/fragment/en_80941b8.pf_fragment +0 -0
  28. package/dist/docs-bundle/pagefind/fragment/en_a64440b.pf_fragment +0 -0
  29. package/dist/docs-bundle/pagefind/fragment/en_eb168aa.pf_fragment +0 -0
  30. package/dist/docs-bundle/pagefind/index/en_8450ec7.pf_index +0 -0
  31. package/dist/docs-bundle/pagefind/index/en_c285f7b.pf_index +0 -0
  32. package/dist/docs-bundle/pagefind/index/en_e8cada7.pf_index +0 -0
  33. package/dist/docs-bundle/pagefind/pagefind-entry.json +1 -1
  34. package/dist/docs-bundle/pagefind/pagefind.en_57d2f8922f.pf_meta +0 -0
  35. package/dist/docs-bundle/v1/using-velora/getting-started/index.html +5 -3
  36. package/dist/docs-bundle/v1/using-velora/headless-api/index.html +10 -4
  37. package/dist/docs-bundle/v1/using-velora/index.html +6 -4
  38. package/dist/docs-bundle/v1/using-velora/installation/index.html +73 -15
  39. package/dist/docs-bundle/v1/using-velora/media/index.html +118 -34
  40. package/dist/graphql/schema.d.ts +1 -0
  41. package/dist/graphql/schema.js +5 -2
  42. package/dist/lib.d.ts +1 -0
  43. package/dist/lib.js +45 -11
  44. package/dist/media/media-service.d.ts +14 -15
  45. package/dist/media/media-service.js +121 -59
  46. package/dist/media/media-tokens.d.ts +6 -0
  47. package/dist/media/media-tokens.js +88 -0
  48. package/dist/media/storage/local.d.ts +16 -0
  49. package/dist/media/storage/local.js +99 -0
  50. package/dist/media/storage/s3.d.ts +25 -0
  51. package/dist/media/storage/s3.js +134 -0
  52. package/dist/media/storage/types.d.ts +21 -0
  53. package/dist/media/storage/types.js +44 -0
  54. package/dist/routes/admin-static.d.ts +2 -0
  55. package/dist/routes/admin-static.js +42 -4
  56. package/dist/routes/media-public.d.ts +6 -0
  57. package/dist/routes/media-public.js +265 -0
  58. package/dist/routes/media.d.ts +2 -1
  59. package/dist/routes/media.js +95 -5
  60. package/dist/routes/plugin-storage.js +5 -1
  61. package/dist/routes/public-api.js +5 -3
  62. package/dist/routes/published-item.d.ts +2 -1
  63. package/dist/routes/published-item.js +28 -5
  64. package/dist/scripts/copy-admin-bundle.js +9 -1
  65. package/package.json +7 -6
  66. package/prisma/schema.prisma +16 -3
  67. package/dist/docs-bundle/pagefind/fragment/en_1d9eb24.pf_fragment +0 -0
  68. package/dist/docs-bundle/pagefind/fragment/en_3099406.pf_fragment +0 -0
  69. package/dist/docs-bundle/pagefind/fragment/en_9aa652e.pf_fragment +0 -0
  70. package/dist/docs-bundle/pagefind/fragment/en_d855550.pf_fragment +0 -0
  71. package/dist/docs-bundle/pagefind/fragment/en_e6d88d8.pf_fragment +0 -0
  72. package/dist/docs-bundle/pagefind/index/en_5feeed7.pf_index +0 -0
  73. package/dist/docs-bundle/pagefind/index/en_c6981f9.pf_index +0 -0
  74. package/dist/docs-bundle/pagefind/index/en_ce4f6bf.pf_index +0 -0
  75. package/dist/docs-bundle/pagefind/pagefind.en_1e94abd852.pf_meta +0 -0
@@ -27,7 +27,7 @@ const __mfImport = (src) =>
27
27
 
28
28
 
29
29
  (async () => {
30
- const __mfHostInit = await __mfImport("./hostInit--C4xK6nj.js");
30
+ const __mfHostInit = await __mfImport("./hostInit-B-6-34XY.js");
31
31
  await __mfHostInit.__tla;
32
32
  const { initHost } = __mfHostInit;
33
33
  await initHost();
@@ -38,4 +38,4 @@ const __mfImport = (src) =>
38
38
  if (__mfReactServerModuleCache?.pendingShareLoads) {
39
39
  await Promise.all(__mfReactServerModuleCache.pendingShareLoads);
40
40
  }
41
- })().then(() => __mfImport("./index-BIAF0ShP.js"));
41
+ })().then(() => __mfImport("./index-DYO7-IK8.js"));
@@ -1,9 +1,9 @@
1
1
  const __vite__mapDeps=(i,m=__vite__mapDeps,d=(m.f||(m.f=["assets/index-Do71v6NZ.js"])))=>i.map(i=>d[i]);
2
- import{_ as xe}from"./vite-preload-helper-Cgledu0r.js";import{h as ct,i as lt}from"./index-Do71v6NZ.js";const dt=ct.share;typeof __VUE_HMR_RUNTIME__>"u"&&(globalThis.__VUE_HMR_RUNTIME__={createRecord(){},rerender(){},reload(){}});const Ne="__mf_init__virtual:mf:__mfe_internal__velora_admin__mf_owner__1__mf_v__runtimeInit__mf_v__.js__";let de=globalThis[Ne];if(!de){let s,f;const u=new Promise((h,C)=>{s=h,f=C});de=globalThis[Ne]={initPromise:u,initResolve:s,initReject:f}}const ut=de.initResolve,re="__mf_module_cache__";globalThis[re]||={share:{},remote:{}};globalThis[re].share||={};globalThis[re].remote||={};const d=globalThis[re];for(const s of Object.keys(d.share))if(s.startsWith("default:")){const f=s.slice(8);d.share[f]===void 0&&(d.share[f]=d.share[s])}else if(!s.includes(":")){const f="default:"+s;d.share[f]===void 0&&(d.share[f]=d.share[s])}const Te={},mt=Array.isArray("default")?"default":["default"],Fe="default",A="velora_admin",ce=[["react"],["react/jsx-runtime","react-dom","@velora-cms/plugin-sdk"],["react-dom/client"]];let ee,te,ue;async function _e(s){for(let f=0;;f++)try{return await s()}catch(u){throw u}}const Le=Symbol("mf.originalSharedProvider"),_t={emit:s=>s},ht=(s,f)=>{if(f!=="version-first")return s;const u={};for(const[h,C]of Object.entries(s))u[h]=Object.assign({},C,{[Le]:C});return u},le=(s,f)=>{if(!f)return;const u=Object.entries(s||{}),h=u.find(([,p])=>p===f);if(h)return{version:h[0],provider:f,registered:!0};if(typeof f.version=="string"&&f.version)return{version:f.version,provider:f,registered:!1};const C=u.filter(([,p])=>p===f||!!(f.from&&(p==null?void 0:p.from)===f.from));if(C.length===1)return{version:C[0][0],provider:f,registered:!1}},me=(s,f,u,h)=>{var E;if(!s||!u)return;const C=Array.isArray(u.scope)?u.scope:[u.scope||"default"],p=ht(s,h),x={};for(const D of C)x[D||"default"]={[f]:p};const P=(E=dt.getRegisteredShare(x,f,{...u,scope:C,strategy:h},_t))==null?void 0:E.shared;return(P==null?void 0:P[Le])||P},U=(s,f,u,h)=>{var P;const C=E=>k(E,u),p=Object.fromEntries(Object.entries(s||{}).filter(([,E])=>!C(E)));u!=null&&u.version&&((P=u.shareConfig)==null?void 0:P.import)!==!1&&(p[u.version]||(p[u.version]=u));const x=me(p,f,u,h);return C(x)?void 0:x},k=(s,f)=>s===f||!!(f!=null&&f.from&&(s==null?void 0:s.from)===f.from),gt=(s,f,u,h,C,p,x,P,E)=>{var B,J,W;if(!P)return;const D=(J=(B=f==null?void 0:f.options)==null?void 0:B.shared)==null?void 0:J[C],K=Array.isArray(D)?D.find(N=>(N==null?void 0:N.version)===p):void 0,V=((P==null?void 0:P.from)===((W=f==null?void 0:f.options)==null?void 0:W.name)?P:void 0)||(k(K,P)?K:f?void 0:P);return V&&s.some(N=>{var q,M;return N!==f&&((q=N==null?void 0:N.options)==null?void 0:q.name)===(x==null?void 0:x.from)&&((M=N==null?void 0:N.shareScopeMap)==null?void 0:M[h])===u})?V:void 0},vt=(s,f,u,h,C,p,x,P,E)=>{const D=p.registered?gt(s,f,u,h,C,p.version,p.provider,P):void 0,K=D||x;if(K&&!(p.registered&&!k(K,P)))return{provider:K,scopeRootProvider:D}};async function bt(){return ee||(ee=_e(()=>xe(()=>import("./_virtual_mf-localSharedImportMap___mfe_internal__velora_admin__mf_owner__1-DOKdWYyj.js"),__vite__mapDeps([0]))).catch(s=>{throw ee=void 0,s})),ee}async function yt(){return te||(te=_e(()=>xe(()=>import("./virtualExposes-BDCSo5OS.js"),[])).then(s=>s.default??s).catch(s=>{throw te=void 0,s})),te}async function Pt(s={},f=[]){var we,je,Re,Ce,Ee;const u=(t,e,r,n)=>{const o=(Array.isArray(n)?n[0]:n)||"default",c=e||!r?t:t+"@"+r,a={canonical:o+":"+c};return o==="default"&&(a.aliases=[c]),a},h=(t,e)=>{const r=t[e.canonical];if(r!==void 0)return r;const n=e.aliases||[];for(const i of n){if(!Object.prototype.hasOwnProperty.call(t,i))continue;const o=t[i];if(o!==void 0)return t[e.canonical]=o,o}},C=Symbol.for("module-federation.shared-cache-listeners"),p=Symbol.for("module-federation.shared-cache-owners"),x=t=>{let e=t[p];return e===void 0&&(e=Object.create(null),Object.defineProperty(t,p,{value:e,enumerable:!1,configurable:!1,writable:!1})),e},P=(t,e)=>{var r;return(r=t[p])==null?void 0:r[e.canonical]},E=(t,e,r,n)=>{var a;t[e.canonical]=r;const i=e.aliases||[];for(const l of i)Object.defineProperty(t,l,{value:r,enumerable:!0,configurable:!0,writable:!0});const o=t[p];n===void 0?o&&delete o[e.canonical]:x(t)[e.canonical]=n;const c=(a=t[C])==null?void 0:a[e.canonical];if(c)for(const l of c)l(r);return r},D=Symbol.for("module-federation.tree-shaking-shared-cache"),K=t=>{let e=t[D];return e===void 0&&(e=Object.create(null),Object.defineProperty(t,D,{value:e,enumerable:!1,configurable:!1,writable:!1})),e},he=(t,e,r,n)=>{if(!Array.isArray(r))return n;const i=[...new Set(r)].sort(),o=K(t),c=o[e.canonical]||=[],a=c.find(l=>l.providedExports.length===i.length&&l.providedExports.every((b,m)=>b===i[m]));return a?a.value=n:c.push({providedExports:i,value:n}),n},V=Symbol.for("module-federation.tree-shaking-shared-selection-cache"),ge=t=>{let e=t[V];return e===void 0&&(e=Object.create(null),Object.defineProperty(t,V,{value:e,enumerable:!1,configurable:!1,writable:!1})),e},B=(t,e,r)=>{var i,o;const n=h(t,e);return n!==void 0?n:(o=(i=t[V])==null?void 0:i[e.canonical])==null?void 0:o[r]},J=(t,e,r,n)=>{const i=ge(t),o=i[e.canonical]||=Object.create(null);return o[r]=n,n},W=((we=globalThis.__FEDERATION__)==null?void 0:we.__INSTANCES__)||[],N=(je=f.find(t=>t==null?void 0:t.from))==null?void 0:je.from,q=W.find(t=>{var e,r;return((e=t==null?void 0:t.options)==null?void 0:e.name)===N&&((r=t==null?void 0:t.shareScopeMap)==null?void 0:r.default)===s})||W.find(t=>{var e,r;return((e=t==null?void 0:t.options)==null?void 0:e.name)!==A&&((r=t==null?void 0:t.shareScopeMap)==null?void 0:r.default)===s}),M=Object.create(null),Ae=t=>{const e=Object.create(null);for(const[r,n]of Object.entries(t||{}))e[r]=Object.assign(Object.create(null),n);return e},ke=(t,e)=>{const r=!q&&Object.values(e||{}).some(i=>Object.values(i||{}).some(Q)),n=r?Ae(e):e;return M[t]={host:e,runtime:n,isWebpackScope:r},n},De=()=>{const t=Object.values(M).filter(({isWebpackScope:e})=>e);if(t.length!==0)for(const{host:e,runtime:r}of t)for(const[n,i]of Object.entries(e||{})){const o=r[n]||=Object.create(null);for(const[c,a]of Object.entries(i||{}))o[c]=a}},z=Object.create(null);for(const[t,e]of Object.entries(s)){const r=z[t]=Object.create(null);for(const[n,i]of Object.entries(e))r[n]=Object.assign({},i)}const{usedShared:I,usedRemotes:ze}=await bt();function Q(t){if(typeof(t==null?void 0:t.get)!="function")return!1;const e=Function.prototype.toString.call(t.get);return e.includes("__webpack_require__")||/\.\s*e\s*\([^)]*\)\s*\.then\s*\(/.test(e)}const Ke=Object.values(z).some(t=>Object.values(t||{}).some(Q)),Be=t=>{const e=t.split("/");return t.startsWith("@")?e.slice(0,2).join("/"):e[0]},ne=(t,e,r)=>{if(typeof U!="function")return;const n=Be(t),i=n===t?[[t,e]]:[[t,e],[n,I[n]]];for(const[o,c]of i){if(!c)continue;const a=r?o===t?r:z[o]:s[o],l=U(a,o,c,"version-first");if(l&&Q(l)&&!l.lib&&!l.loaded)return l}};var X=Te[Fe];if(X||(X=Te[Fe]={from:A}),f.indexOf(X)>=0)return;f.push(X);const ve=t=>{let e=t;for(let r=0;r<5;r++){const n=e==null?void 0:e.default;if(!n||typeof n!="object"||Object.keys(n).length===0)break;const i=Object.keys(e).filter(o=>o!=="default").map(o=>e[o]);if(i.length>0&&i.some(o=>o!==void 0))break;e=n}return e},Ge=[],Ve=typeof globalThis.window>"u"?await Promise.all([]):[],oe="__mf_vite_runtime_share_load_id__";let We=0;const ie=new Map,se=new Map,H=lt({name:A,remotes:ze,shared:I,plugins:[He(),Ue(),...Ge,...Ve],shareStrategy:"version-first"});H.initShareScopeMap("default",ke("default",s));function He(){return{name:"vite-share-pin-lifecycle-plugin",resolveShare(t){var i;const e=(i=t.shareInfo)==null?void 0:i[oe],r=e===void 0?void 0:se.get(e);if(!r)return t;const n=t.resolver;return t.resolver=(...o)=>(r.pinned.reapply(),n(...o)),r.pinned.reveal(),t}}}function Ue(){return{name:"vite-real-name-snapshot-plugin",afterLoadSnapshot(t){const e=t&&t.remoteSnapshot,r=e&&e.globalName,n=e&&e.version;if(!r||!n||!e.remoteEntry)return t;const i=globalThis.__FEDERATION__&&globalThis.__FEDERATION__.moduleInfo,o=r+":"+n;return i&&!i[o]&&(i[o]=e),t}}}const qe=H.sharedHandler.hooks.lifecycle.resolveShare,Y=new WeakMap;qe.on(t=>{var i;const e=(i=t.shareInfo)==null?void 0:i[oe],r=t.resolver;if(typeof r!="function")return t;const n=(...o)=>{const c=r(...o),a=c==null?void 0:c.shared;return a&&(typeof a=="object"||typeof a=="function")&&!Y.has(a)&&Y.set(a,{from:a.from}),e!==void 0&&a&&ie.set(e,a),c};return t.resolver=n,t});const Me=(t,e,r,n)=>{if(!t||t[e]!==r)return;const i=Object.assign({},n,{version:n.version??e,scope:n.scope??(r==null?void 0:r.scope)??["default"],strategy:"loaded-first"}),o=n.from;t[e]=i;const c=()=>r===void 0?t[e]===void 0:t[e]===r;return{provider:i,reveal(){return t[e]!==i?!1:(r===void 0?delete t[e]:t[e]=r,!0)},reapply(){return c()?(t[e]=i,!0):!1},release(a,l=!0){return n.from=o,t[e]!==i?!l&&c():l?a?(i.from=o,a&&i.lib&&(i.loaded=!0),n.strategy===void 0?delete i.strategy:i.strategy=n.strategy,!0):(r===void 0?delete t[e]:t[e]=r,!1):(r===void 0?delete t[e]:t[e]=r,!0)}}},Je=t=>Object.entries(t||{}).map(([e,r])=>({provider:r,version:e,from:r.from,registered:!0})),Qe=(t,e)=>{if(e===void 0)return;let r;for(const n of t){const i=n.provider,o=i.treeShaking||i;if(!(n.loadedFactory!==e&&i.lib!==e&&o.lib!==e)){if(r)return;r=n}}return r},Xe=async(t,e,r)=>{const n=++We;se.set(n,{pinned:r});try{const i=await H.loadShare(t,{customShareInfo:{shareConfig:e,[oe]:n}});return{factory:i===!1?void 0:i,selectedProvider:ie.get(n)}}finally{ie.delete(n),se.delete(n)}},be=async(t,e,r,n,i,o,c=!0)=>{const a=o.from,l=Me(r,n,i,o);if(!l)return;let b;try{b=await Xe(t,e,l)}catch(j){throw l.release(!1),j}const m=b==null?void 0:b.factory;if(m===void 0){l.release(!1);return}const _=Je(r),g=l.provider.treeShaking||l.provider,R=l.provider.lib===m||g.lib===m;if(!c&&R){const j=_.findIndex(S=>S.provider===l.provider);j!==-1&&_.splice(j,1)}!c&&!_.some(j=>j.provider===o)&&_.push({provider:o,version:n,from:a,registered:!1,loadedFactory:R?m:void 0});const O=!c&&b.selectedProvider===l.provider&&R?o:b.selectedProvider;if(O&&!_.some(j=>j.provider===O)){const j=Y.get(O),S=typeof O.version=="string"&&O.version?O.version:n;_.push({provider:O,version:S,from:j?j.from:O.from,registered:(r==null?void 0:r[S])===O,loadedFactory:m})}const v=_.find(j=>j.provider===O)??Qe(_,m);if(!l.release(!0,(v==null?void 0:v.provider)===l.provider)||!v)return;const y=Y.get(v.provider);v.from=v.provider===o?a:y?y.from:v.provider.from,y&&(v.provider.from=y.from);const L=typeof m=="function"?m():m,w=await Promise.resolve(L);if(!(v.registered&&(r==null?void 0:r[v.version])!==v.provider))return{provider:v.provider,selection:v,resolved:w}},fe=new Set,ae=new Map,Ye=async(t,e,r)=>{var i;const n=!!((i=e.shareConfig)!=null&&i.singleton);if(!n&&e.canLiveRebind!==!1)try{const o=U(r,t,e,"version-first"),c=le(r,o);if(!c)return;const{version:a}=c;if(!n&&a!==e.version||!o.lib&&!o.loading&&!(o.loaded&&typeof o.get=="function"))return;const l=u(t,n,e.version,e.scope);if(h(d.share,l)!==void 0)return;const b=s[t],m=b==null?void 0:b[a];if(c.registered&&!k(m,o))return;let _,g=o.lib;if(!g&&Q(o)||(!g&&o.loading&&(g=await o.loading),!g&&o.loaded&&typeof o.get=="function"&&(g=await o.get()),!g))return;const R=typeof g=="function"?g():g,O=await Promise.resolve(R),v=c.registered?m:o;_={provider:v,selection:{provider:v,version:a,from:o.from,registered:c.registered},resolved:O};const T=_==null?void 0:_.provider,y=_==null?void 0:_.selection;if(!y)return;const L=_==null?void 0:_.resolved;if(L===void 0||h(d.share,l)!==void 0||y.registered&&(b==null?void 0:b[y.version])!==T)return;E(d.share,l,ve(L),y.from),fe.add(T)}catch(o){console.error('[Module Federation] Failed to bridge materialized shared module "'+t+'"',o)}},ye=async(t,e,r,n,i)=>{var o,c;try{const a=u(t,(o=e.shareConfig)==null?void 0:o.singleton,e.version,e.scope),l=h(d.share,a),b=P(d.share,a),m=U(r,t,e,"version-first"),_=m||me(r,t,e,"version-first")||e,g=le(r,_);if(!g)return;const R=k(_,e),{version:O}=g;if(!((c=e.shareConfig)!=null&&c.singleton)&&O!==e.version)return;const v=n==null?void 0:n[O],T=vt(W,q,s,"default",t,g,m,v,"version-first");if(!T&&!R)return;const{provider:y,scopeRootProvider:L}=T||{provider:_,scopeRootProvider:void 0};if(e.canLiveRebind===!1||l!==void 0&&b!==A)return;const w=s[t],j=w==null?void 0:w[O];if(g.registered&&!L&&!k(j,y))return;const S=await be(t,e.shareConfig,w,O,j,y,g.registered&&!R),G=S==null?void 0:S.provider,F=S==null?void 0:S.selection;if(!F||k(G,e)||i&&(i.version!==F.version||!k({from:F.from},i.provider))||fe.has(G))return;const Ie=S==null?void 0:S.resolved;if(Ie===void 0)return;const st=h(d.share,a),ft=P(d.share,a);if(st!==void 0&&ft!==A||F.registered&&(w==null?void 0:w[F.version])!==G)return;i||ae.set(t,{version:F.version,provider:{from:F.from}}),fe.add(G);const at=ve(Ie);E(d.share,a,at,F.from)}catch(a){console.error('[Module Federation] Failed to bridge external shared module "'+t+'"',a)}};for(const t of ce)await Promise.all(t.map(async e=>{const r=I[e];!r||r.materialize===!1||r.treeShaking||await Ye(e,r,z[e])}));for(const[t,e]of Object.entries(I)){if(e.treeShaking)continue;const r=u(t,(Re=e.shareConfig)==null?void 0:Re.singleton,e.version,e.scope);if(h(d.share,r)!==void 0)continue;const n=u(t,!0,e.version,e.scope),i=h(d.share,n);i!==void 0&&E(d.share,r,i,P(d.share,n))}const Ze=["react","react/jsx-runtime","react-dom","@velora-cms/plugin-sdk","react-dom/client"],$e=[["react"],["react/jsx-runtime","react-dom","@velora-cms/plugin-sdk"],["react-dom/client"]],Z=Ze.filter(t=>{var e;return I[t]&&(I[t].materialize!==!1||((e=I[t].shareConfig)==null?void 0:e.import)===!1)});d.providerInit||=new Map;const et=(t,e)=>{const r=d.providerInit.get(t);if(r)return r;const n=Promise.resolve().then(e);return d.providerInit.set(t,n),n.catch(()=>d.providerInit.delete(t)),n};var Se=async t=>{const e=new Set(t);for(const r of $e)await Promise.all(r.filter(n=>e.has(n)).map(async n=>{var O,v;const i=I[n],o=u(n,(O=i.shareConfig)==null?void 0:O.singleton,i.version,i.scope);if(((v=i.shareConfig)==null?void 0:v.import)===!1||i.treeShaking||h(d.share,o)!==void 0)return;const c=u(n,!0,i.version,i.scope),a=h(d.share,c);if(a!==void 0){E(d.share,o,a,P(d.share,c));return}const l=typeof ne=="function"?ne(n,i):void 0;if(l&&!l.lib&&!l.loaded)return;const b=o.canonical,m=await et(b,async()=>{const T=await i.get(),y=typeof T=="function"?T():T;return Promise.resolve(y)}),g=(T=>{let y=T;for(let L=0;L<5;L++){const w=y==null?void 0:y.default;if(!w||typeof w!="object"||Object.keys(w).length===0)break;const j=Object.keys(y).filter(S=>S!=="default").map(S=>y[S]);if(j.length>0&&j.some(S=>S!==void 0))break;y=w}return y})(m),R=g===m?{...m}:g;R.__esModule!==!0&&Object.defineProperty(R,"__esModule",{value:!0,enumerable:!1}),E(d.share,o,R,A)}))};const pe=t=>{var n,i;const e=I[t];if(!e.treeShaking&&((n=e.shareConfig)==null?void 0:n.import)!==!1)return!1;const r=u(t,(i=e.shareConfig)==null?void 0:i.singleton,e.version,e.scope);return e.treeShaking?B(d.share,r,A)===void 0&&h(d.share,r)===void 0:h(d.share,r)===void 0},tt=t=>{var i,o;const e=I[t],r=u(t,(i=e.shareConfig)==null?void 0:i.singleton,e.version,e.scope);return(e.treeShaking?B(d.share,r,A)??h(d.share,r):h(d.share,r))!==void 0?!1:e.treeShaking||((o=e.shareConfig)==null?void 0:o.import)===!1?!0:typeof U!="function"?!1:!!U(z[t],t,e,"version-first")},$=Z.findIndex(tt),rt=$===-1?Z:Z.slice(0,$);var nt=$===-1?[]:Z.slice($);await Se(rt);try{await _e(async()=>{await Promise.all(await H.initializeSharing("default",{strategy:"version-first",from:"build",initScope:f}))})}catch(t){console.error("[Module Federation]",t)}De();const Pe=async()=>{for(const t of ce)await Promise.all(t.map(async e=>{const r=I[e];!r||r.materialize===!1||r.treeShaking||await ye(e,r,s[e],z[e],void 0)}))};await Pe(),Ke&&(ue=Pe);try{const t=(Ce=globalThis.__FEDERATION__)==null?void 0:Ce.__SHARE__,e=Object.create(null);if(t)for(const[,r]of Object.entries(t))for(const n of mt){const i=r==null?void 0:r[n];if(i)for(const[o,c]of Object.entries(i)){const a=I==null?void 0:I[o],l=z[o],b=ae.get(o);if(!a||!l||!b||a.treeShaking)continue;const m=e[o]||(e[o]=Object.create(null));for(const[_,g]of Object.entries(c)){if(!g.lib||b.version!==_||!k(g,b.provider))continue;const R=l[_];(g===R||R!=null&&R.from&&g.from===R.from)&&(g===a||a.from&&g.from===a.from||m[_]===void 0&&(m[_]=g))}}}for(const r of ce)await Promise.all(r.map(async n=>{const i=e[n];i&&await ye(n,I[n],i,z[n],ae.get(n))}))}catch(t){console.error("[Module Federation] Failed to bridge external shared modules",t)}const ot=async()=>{},it=async(t,e)=>{var T,y;const r=u(t,(T=e.shareConfig)==null?void 0:T.singleton,e.version,e.scope),n=e.treeShaking?B(d.share,r,A):h(d.share,r);if(((y=e.shareConfig)==null?void 0:y.import)!==!1||n!==void 0||ne(t,e,z[t]))return;const i=L=>{let w=L;for(let j=0;j<5;j++){const S=w==null?void 0:w.default;if(!S||typeof S!="object"||Object.keys(S).length===0)break;const G=Object.keys(w).filter(F=>F!=="default").map(F=>w[F]);if(G.length>0&&G.some(F=>F!==void 0))break;w=S}return w},o=s==null?void 0:s[t],c=me(o,t,e,"version-first")||e,a=le(o,c);if(!a)return;const{version:l}=a,b=o==null?void 0:o[l],m=await be(t,e.shareConfig,o,l,b,c,a.registered&&!k(c,e)),_=m==null?void 0:m.selection,g=m==null?void 0:m.provider,R=m==null?void 0:m.resolved;if(!_||k(g,e)||R===void 0||(e.treeShaking?B(d.share,r,A):h(d.share,r))!==void 0||_.registered&&(o==null?void 0:o[_.version])!==g)return;const v=i(R);if(e.treeShaking){const L=e.treeShaking.providedExports??e.treeShaking.usedExports??[];he(d.share,r,L,v),J(d.share,r,A,v)}else E(d.share,r,v,_.from)},Oe=[];for(const t of nt){const e=I[t];if(pe(t))try{e.treeShaking?await ot(t,e):((Ee=e.shareConfig)==null?void 0:Ee.import)===!1&&await it(t,e)}catch(r){console.error(`[Module Federation] Failed to resolve runtime-only shared module "${t}"`,r);break}if(pe(t))break;Oe.push(t)}return await Se(Oe),ut(H),H}async function Ot(s){const f=await yt();if(!(s in f))throw new Error(`[Module Federation] Module ${s} does not exist in container.`);return ue&&await ue(),d.pendingShareLoads&&await Promise.all(d.pendingShareLoads),f[s]().then(u=>()=>u)}export{Ot as get,Pt as init};
2
+ import{_ as xe}from"./vite-preload-helper-Cgledu0r.js";import{h as ct,i as lt}from"./index-Do71v6NZ.js";const dt=ct.share;typeof __VUE_HMR_RUNTIME__>"u"&&(globalThis.__VUE_HMR_RUNTIME__={createRecord(){},rerender(){},reload(){}});const Ne="__mf_init__virtual:mf:__mfe_internal__velora_admin__mf_owner__1__mf_v__runtimeInit__mf_v__.js__";let de=globalThis[Ne];if(!de){let s,f;const u=new Promise((h,C)=>{s=h,f=C});de=globalThis[Ne]={initPromise:u,initResolve:s,initReject:f}}const ut=de.initResolve,re="__mf_module_cache__";globalThis[re]||={share:{},remote:{}};globalThis[re].share||={};globalThis[re].remote||={};const d=globalThis[re];for(const s of Object.keys(d.share))if(s.startsWith("default:")){const f=s.slice(8);d.share[f]===void 0&&(d.share[f]=d.share[s])}else if(!s.includes(":")){const f="default:"+s;d.share[f]===void 0&&(d.share[f]=d.share[s])}const Te={},mt=Array.isArray("default")?"default":["default"],Fe="default",A="velora_admin",ce=[["react"],["react/jsx-runtime","react-dom","@velora-cms/plugin-sdk"],["react-dom/client"]];let ee,te,ue;async function _e(s){for(let f=0;;f++)try{return await s()}catch(u){throw u}}const Le=Symbol("mf.originalSharedProvider"),_t={emit:s=>s},ht=(s,f)=>{if(f!=="version-first")return s;const u={};for(const[h,C]of Object.entries(s))u[h]=Object.assign({},C,{[Le]:C});return u},le=(s,f)=>{if(!f)return;const u=Object.entries(s||{}),h=u.find(([,p])=>p===f);if(h)return{version:h[0],provider:f,registered:!0};if(typeof f.version=="string"&&f.version)return{version:f.version,provider:f,registered:!1};const C=u.filter(([,p])=>p===f||!!(f.from&&(p==null?void 0:p.from)===f.from));if(C.length===1)return{version:C[0][0],provider:f,registered:!1}},me=(s,f,u,h)=>{var E;if(!s||!u)return;const C=Array.isArray(u.scope)?u.scope:[u.scope||"default"],p=ht(s,h),x={};for(const D of C)x[D||"default"]={[f]:p};const P=(E=dt.getRegisteredShare(x,f,{...u,scope:C,strategy:h},_t))==null?void 0:E.shared;return(P==null?void 0:P[Le])||P},U=(s,f,u,h)=>{var P;const C=E=>k(E,u),p=Object.fromEntries(Object.entries(s||{}).filter(([,E])=>!C(E)));u!=null&&u.version&&((P=u.shareConfig)==null?void 0:P.import)!==!1&&(p[u.version]||(p[u.version]=u));const x=me(p,f,u,h);return C(x)?void 0:x},k=(s,f)=>s===f||!!(f!=null&&f.from&&(s==null?void 0:s.from)===f.from),gt=(s,f,u,h,C,p,x,P,E)=>{var B,J,W;if(!P)return;const D=(J=(B=f==null?void 0:f.options)==null?void 0:B.shared)==null?void 0:J[C],K=Array.isArray(D)?D.find(N=>(N==null?void 0:N.version)===p):void 0,V=((P==null?void 0:P.from)===((W=f==null?void 0:f.options)==null?void 0:W.name)?P:void 0)||(k(K,P)?K:f?void 0:P);return V&&s.some(N=>{var q,M;return N!==f&&((q=N==null?void 0:N.options)==null?void 0:q.name)===(x==null?void 0:x.from)&&((M=N==null?void 0:N.shareScopeMap)==null?void 0:M[h])===u})?V:void 0},vt=(s,f,u,h,C,p,x,P,E)=>{const D=p.registered?gt(s,f,u,h,C,p.version,p.provider,P):void 0,K=D||x;if(K&&!(p.registered&&!k(K,P)))return{provider:K,scopeRootProvider:D}};async function bt(){return ee||(ee=_e(()=>xe(()=>import("./_virtual_mf-localSharedImportMap___mfe_internal__velora_admin__mf_owner__1-DlIgIuFP.js"),__vite__mapDeps([0]))).catch(s=>{throw ee=void 0,s})),ee}async function yt(){return te||(te=_e(()=>xe(()=>import("./virtualExposes-BDCSo5OS.js"),[])).then(s=>s.default??s).catch(s=>{throw te=void 0,s})),te}async function Pt(s={},f=[]){var we,je,Re,Ce,Ee;const u=(t,e,r,n)=>{const o=(Array.isArray(n)?n[0]:n)||"default",c=e||!r?t:t+"@"+r,a={canonical:o+":"+c};return o==="default"&&(a.aliases=[c]),a},h=(t,e)=>{const r=t[e.canonical];if(r!==void 0)return r;const n=e.aliases||[];for(const i of n){if(!Object.prototype.hasOwnProperty.call(t,i))continue;const o=t[i];if(o!==void 0)return t[e.canonical]=o,o}},C=Symbol.for("module-federation.shared-cache-listeners"),p=Symbol.for("module-federation.shared-cache-owners"),x=t=>{let e=t[p];return e===void 0&&(e=Object.create(null),Object.defineProperty(t,p,{value:e,enumerable:!1,configurable:!1,writable:!1})),e},P=(t,e)=>{var r;return(r=t[p])==null?void 0:r[e.canonical]},E=(t,e,r,n)=>{var a;t[e.canonical]=r;const i=e.aliases||[];for(const l of i)Object.defineProperty(t,l,{value:r,enumerable:!0,configurable:!0,writable:!0});const o=t[p];n===void 0?o&&delete o[e.canonical]:x(t)[e.canonical]=n;const c=(a=t[C])==null?void 0:a[e.canonical];if(c)for(const l of c)l(r);return r},D=Symbol.for("module-federation.tree-shaking-shared-cache"),K=t=>{let e=t[D];return e===void 0&&(e=Object.create(null),Object.defineProperty(t,D,{value:e,enumerable:!1,configurable:!1,writable:!1})),e},he=(t,e,r,n)=>{if(!Array.isArray(r))return n;const i=[...new Set(r)].sort(),o=K(t),c=o[e.canonical]||=[],a=c.find(l=>l.providedExports.length===i.length&&l.providedExports.every((b,m)=>b===i[m]));return a?a.value=n:c.push({providedExports:i,value:n}),n},V=Symbol.for("module-federation.tree-shaking-shared-selection-cache"),ge=t=>{let e=t[V];return e===void 0&&(e=Object.create(null),Object.defineProperty(t,V,{value:e,enumerable:!1,configurable:!1,writable:!1})),e},B=(t,e,r)=>{var i,o;const n=h(t,e);return n!==void 0?n:(o=(i=t[V])==null?void 0:i[e.canonical])==null?void 0:o[r]},J=(t,e,r,n)=>{const i=ge(t),o=i[e.canonical]||=Object.create(null);return o[r]=n,n},W=((we=globalThis.__FEDERATION__)==null?void 0:we.__INSTANCES__)||[],N=(je=f.find(t=>t==null?void 0:t.from))==null?void 0:je.from,q=W.find(t=>{var e,r;return((e=t==null?void 0:t.options)==null?void 0:e.name)===N&&((r=t==null?void 0:t.shareScopeMap)==null?void 0:r.default)===s})||W.find(t=>{var e,r;return((e=t==null?void 0:t.options)==null?void 0:e.name)!==A&&((r=t==null?void 0:t.shareScopeMap)==null?void 0:r.default)===s}),M=Object.create(null),Ae=t=>{const e=Object.create(null);for(const[r,n]of Object.entries(t||{}))e[r]=Object.assign(Object.create(null),n);return e},ke=(t,e)=>{const r=!q&&Object.values(e||{}).some(i=>Object.values(i||{}).some(Q)),n=r?Ae(e):e;return M[t]={host:e,runtime:n,isWebpackScope:r},n},De=()=>{const t=Object.values(M).filter(({isWebpackScope:e})=>e);if(t.length!==0)for(const{host:e,runtime:r}of t)for(const[n,i]of Object.entries(e||{})){const o=r[n]||=Object.create(null);for(const[c,a]of Object.entries(i||{}))o[c]=a}},z=Object.create(null);for(const[t,e]of Object.entries(s)){const r=z[t]=Object.create(null);for(const[n,i]of Object.entries(e))r[n]=Object.assign({},i)}const{usedShared:I,usedRemotes:ze}=await bt();function Q(t){if(typeof(t==null?void 0:t.get)!="function")return!1;const e=Function.prototype.toString.call(t.get);return e.includes("__webpack_require__")||/\.\s*e\s*\([^)]*\)\s*\.then\s*\(/.test(e)}const Ke=Object.values(z).some(t=>Object.values(t||{}).some(Q)),Be=t=>{const e=t.split("/");return t.startsWith("@")?e.slice(0,2).join("/"):e[0]},ne=(t,e,r)=>{if(typeof U!="function")return;const n=Be(t),i=n===t?[[t,e]]:[[t,e],[n,I[n]]];for(const[o,c]of i){if(!c)continue;const a=r?o===t?r:z[o]:s[o],l=U(a,o,c,"version-first");if(l&&Q(l)&&!l.lib&&!l.loaded)return l}};var X=Te[Fe];if(X||(X=Te[Fe]={from:A}),f.indexOf(X)>=0)return;f.push(X);const ve=t=>{let e=t;for(let r=0;r<5;r++){const n=e==null?void 0:e.default;if(!n||typeof n!="object"||Object.keys(n).length===0)break;const i=Object.keys(e).filter(o=>o!=="default").map(o=>e[o]);if(i.length>0&&i.some(o=>o!==void 0))break;e=n}return e},Ge=[],Ve=typeof globalThis.window>"u"?await Promise.all([]):[],oe="__mf_vite_runtime_share_load_id__";let We=0;const ie=new Map,se=new Map,H=lt({name:A,remotes:ze,shared:I,plugins:[He(),Ue(),...Ge,...Ve],shareStrategy:"version-first"});H.initShareScopeMap("default",ke("default",s));function He(){return{name:"vite-share-pin-lifecycle-plugin",resolveShare(t){var i;const e=(i=t.shareInfo)==null?void 0:i[oe],r=e===void 0?void 0:se.get(e);if(!r)return t;const n=t.resolver;return t.resolver=(...o)=>(r.pinned.reapply(),n(...o)),r.pinned.reveal(),t}}}function Ue(){return{name:"vite-real-name-snapshot-plugin",afterLoadSnapshot(t){const e=t&&t.remoteSnapshot,r=e&&e.globalName,n=e&&e.version;if(!r||!n||!e.remoteEntry)return t;const i=globalThis.__FEDERATION__&&globalThis.__FEDERATION__.moduleInfo,o=r+":"+n;return i&&!i[o]&&(i[o]=e),t}}}const qe=H.sharedHandler.hooks.lifecycle.resolveShare,Y=new WeakMap;qe.on(t=>{var i;const e=(i=t.shareInfo)==null?void 0:i[oe],r=t.resolver;if(typeof r!="function")return t;const n=(...o)=>{const c=r(...o),a=c==null?void 0:c.shared;return a&&(typeof a=="object"||typeof a=="function")&&!Y.has(a)&&Y.set(a,{from:a.from}),e!==void 0&&a&&ie.set(e,a),c};return t.resolver=n,t});const Me=(t,e,r,n)=>{if(!t||t[e]!==r)return;const i=Object.assign({},n,{version:n.version??e,scope:n.scope??(r==null?void 0:r.scope)??["default"],strategy:"loaded-first"}),o=n.from;t[e]=i;const c=()=>r===void 0?t[e]===void 0:t[e]===r;return{provider:i,reveal(){return t[e]!==i?!1:(r===void 0?delete t[e]:t[e]=r,!0)},reapply(){return c()?(t[e]=i,!0):!1},release(a,l=!0){return n.from=o,t[e]!==i?!l&&c():l?a?(i.from=o,a&&i.lib&&(i.loaded=!0),n.strategy===void 0?delete i.strategy:i.strategy=n.strategy,!0):(r===void 0?delete t[e]:t[e]=r,!1):(r===void 0?delete t[e]:t[e]=r,!0)}}},Je=t=>Object.entries(t||{}).map(([e,r])=>({provider:r,version:e,from:r.from,registered:!0})),Qe=(t,e)=>{if(e===void 0)return;let r;for(const n of t){const i=n.provider,o=i.treeShaking||i;if(!(n.loadedFactory!==e&&i.lib!==e&&o.lib!==e)){if(r)return;r=n}}return r},Xe=async(t,e,r)=>{const n=++We;se.set(n,{pinned:r});try{const i=await H.loadShare(t,{customShareInfo:{shareConfig:e,[oe]:n}});return{factory:i===!1?void 0:i,selectedProvider:ie.get(n)}}finally{ie.delete(n),se.delete(n)}},be=async(t,e,r,n,i,o,c=!0)=>{const a=o.from,l=Me(r,n,i,o);if(!l)return;let b;try{b=await Xe(t,e,l)}catch(j){throw l.release(!1),j}const m=b==null?void 0:b.factory;if(m===void 0){l.release(!1);return}const _=Je(r),g=l.provider.treeShaking||l.provider,R=l.provider.lib===m||g.lib===m;if(!c&&R){const j=_.findIndex(S=>S.provider===l.provider);j!==-1&&_.splice(j,1)}!c&&!_.some(j=>j.provider===o)&&_.push({provider:o,version:n,from:a,registered:!1,loadedFactory:R?m:void 0});const O=!c&&b.selectedProvider===l.provider&&R?o:b.selectedProvider;if(O&&!_.some(j=>j.provider===O)){const j=Y.get(O),S=typeof O.version=="string"&&O.version?O.version:n;_.push({provider:O,version:S,from:j?j.from:O.from,registered:(r==null?void 0:r[S])===O,loadedFactory:m})}const v=_.find(j=>j.provider===O)??Qe(_,m);if(!l.release(!0,(v==null?void 0:v.provider)===l.provider)||!v)return;const y=Y.get(v.provider);v.from=v.provider===o?a:y?y.from:v.provider.from,y&&(v.provider.from=y.from);const L=typeof m=="function"?m():m,w=await Promise.resolve(L);if(!(v.registered&&(r==null?void 0:r[v.version])!==v.provider))return{provider:v.provider,selection:v,resolved:w}},fe=new Set,ae=new Map,Ye=async(t,e,r)=>{var i;const n=!!((i=e.shareConfig)!=null&&i.singleton);if(!n&&e.canLiveRebind!==!1)try{const o=U(r,t,e,"version-first"),c=le(r,o);if(!c)return;const{version:a}=c;if(!n&&a!==e.version||!o.lib&&!o.loading&&!(o.loaded&&typeof o.get=="function"))return;const l=u(t,n,e.version,e.scope);if(h(d.share,l)!==void 0)return;const b=s[t],m=b==null?void 0:b[a];if(c.registered&&!k(m,o))return;let _,g=o.lib;if(!g&&Q(o)||(!g&&o.loading&&(g=await o.loading),!g&&o.loaded&&typeof o.get=="function"&&(g=await o.get()),!g))return;const R=typeof g=="function"?g():g,O=await Promise.resolve(R),v=c.registered?m:o;_={provider:v,selection:{provider:v,version:a,from:o.from,registered:c.registered},resolved:O};const T=_==null?void 0:_.provider,y=_==null?void 0:_.selection;if(!y)return;const L=_==null?void 0:_.resolved;if(L===void 0||h(d.share,l)!==void 0||y.registered&&(b==null?void 0:b[y.version])!==T)return;E(d.share,l,ve(L),y.from),fe.add(T)}catch(o){console.error('[Module Federation] Failed to bridge materialized shared module "'+t+'"',o)}},ye=async(t,e,r,n,i)=>{var o,c;try{const a=u(t,(o=e.shareConfig)==null?void 0:o.singleton,e.version,e.scope),l=h(d.share,a),b=P(d.share,a),m=U(r,t,e,"version-first"),_=m||me(r,t,e,"version-first")||e,g=le(r,_);if(!g)return;const R=k(_,e),{version:O}=g;if(!((c=e.shareConfig)!=null&&c.singleton)&&O!==e.version)return;const v=n==null?void 0:n[O],T=vt(W,q,s,"default",t,g,m,v,"version-first");if(!T&&!R)return;const{provider:y,scopeRootProvider:L}=T||{provider:_,scopeRootProvider:void 0};if(e.canLiveRebind===!1||l!==void 0&&b!==A)return;const w=s[t],j=w==null?void 0:w[O];if(g.registered&&!L&&!k(j,y))return;const S=await be(t,e.shareConfig,w,O,j,y,g.registered&&!R),G=S==null?void 0:S.provider,F=S==null?void 0:S.selection;if(!F||k(G,e)||i&&(i.version!==F.version||!k({from:F.from},i.provider))||fe.has(G))return;const Ie=S==null?void 0:S.resolved;if(Ie===void 0)return;const st=h(d.share,a),ft=P(d.share,a);if(st!==void 0&&ft!==A||F.registered&&(w==null?void 0:w[F.version])!==G)return;i||ae.set(t,{version:F.version,provider:{from:F.from}}),fe.add(G);const at=ve(Ie);E(d.share,a,at,F.from)}catch(a){console.error('[Module Federation] Failed to bridge external shared module "'+t+'"',a)}};for(const t of ce)await Promise.all(t.map(async e=>{const r=I[e];!r||r.materialize===!1||r.treeShaking||await Ye(e,r,z[e])}));for(const[t,e]of Object.entries(I)){if(e.treeShaking)continue;const r=u(t,(Re=e.shareConfig)==null?void 0:Re.singleton,e.version,e.scope);if(h(d.share,r)!==void 0)continue;const n=u(t,!0,e.version,e.scope),i=h(d.share,n);i!==void 0&&E(d.share,r,i,P(d.share,n))}const Ze=["react","react/jsx-runtime","react-dom","@velora-cms/plugin-sdk","react-dom/client"],$e=[["react"],["react/jsx-runtime","react-dom","@velora-cms/plugin-sdk"],["react-dom/client"]],Z=Ze.filter(t=>{var e;return I[t]&&(I[t].materialize!==!1||((e=I[t].shareConfig)==null?void 0:e.import)===!1)});d.providerInit||=new Map;const et=(t,e)=>{const r=d.providerInit.get(t);if(r)return r;const n=Promise.resolve().then(e);return d.providerInit.set(t,n),n.catch(()=>d.providerInit.delete(t)),n};var Se=async t=>{const e=new Set(t);for(const r of $e)await Promise.all(r.filter(n=>e.has(n)).map(async n=>{var O,v;const i=I[n],o=u(n,(O=i.shareConfig)==null?void 0:O.singleton,i.version,i.scope);if(((v=i.shareConfig)==null?void 0:v.import)===!1||i.treeShaking||h(d.share,o)!==void 0)return;const c=u(n,!0,i.version,i.scope),a=h(d.share,c);if(a!==void 0){E(d.share,o,a,P(d.share,c));return}const l=typeof ne=="function"?ne(n,i):void 0;if(l&&!l.lib&&!l.loaded)return;const b=o.canonical,m=await et(b,async()=>{const T=await i.get(),y=typeof T=="function"?T():T;return Promise.resolve(y)}),g=(T=>{let y=T;for(let L=0;L<5;L++){const w=y==null?void 0:y.default;if(!w||typeof w!="object"||Object.keys(w).length===0)break;const j=Object.keys(y).filter(S=>S!=="default").map(S=>y[S]);if(j.length>0&&j.some(S=>S!==void 0))break;y=w}return y})(m),R=g===m?{...m}:g;R.__esModule!==!0&&Object.defineProperty(R,"__esModule",{value:!0,enumerable:!1}),E(d.share,o,R,A)}))};const pe=t=>{var n,i;const e=I[t];if(!e.treeShaking&&((n=e.shareConfig)==null?void 0:n.import)!==!1)return!1;const r=u(t,(i=e.shareConfig)==null?void 0:i.singleton,e.version,e.scope);return e.treeShaking?B(d.share,r,A)===void 0&&h(d.share,r)===void 0:h(d.share,r)===void 0},tt=t=>{var i,o;const e=I[t],r=u(t,(i=e.shareConfig)==null?void 0:i.singleton,e.version,e.scope);return(e.treeShaking?B(d.share,r,A)??h(d.share,r):h(d.share,r))!==void 0?!1:e.treeShaking||((o=e.shareConfig)==null?void 0:o.import)===!1?!0:typeof U!="function"?!1:!!U(z[t],t,e,"version-first")},$=Z.findIndex(tt),rt=$===-1?Z:Z.slice(0,$);var nt=$===-1?[]:Z.slice($);await Se(rt);try{await _e(async()=>{await Promise.all(await H.initializeSharing("default",{strategy:"version-first",from:"build",initScope:f}))})}catch(t){console.error("[Module Federation]",t)}De();const Pe=async()=>{for(const t of ce)await Promise.all(t.map(async e=>{const r=I[e];!r||r.materialize===!1||r.treeShaking||await ye(e,r,s[e],z[e],void 0)}))};await Pe(),Ke&&(ue=Pe);try{const t=(Ce=globalThis.__FEDERATION__)==null?void 0:Ce.__SHARE__,e=Object.create(null);if(t)for(const[,r]of Object.entries(t))for(const n of mt){const i=r==null?void 0:r[n];if(i)for(const[o,c]of Object.entries(i)){const a=I==null?void 0:I[o],l=z[o],b=ae.get(o);if(!a||!l||!b||a.treeShaking)continue;const m=e[o]||(e[o]=Object.create(null));for(const[_,g]of Object.entries(c)){if(!g.lib||b.version!==_||!k(g,b.provider))continue;const R=l[_];(g===R||R!=null&&R.from&&g.from===R.from)&&(g===a||a.from&&g.from===a.from||m[_]===void 0&&(m[_]=g))}}}for(const r of ce)await Promise.all(r.map(async n=>{const i=e[n];i&&await ye(n,I[n],i,z[n],ae.get(n))}))}catch(t){console.error("[Module Federation] Failed to bridge external shared modules",t)}const ot=async()=>{},it=async(t,e)=>{var T,y;const r=u(t,(T=e.shareConfig)==null?void 0:T.singleton,e.version,e.scope),n=e.treeShaking?B(d.share,r,A):h(d.share,r);if(((y=e.shareConfig)==null?void 0:y.import)!==!1||n!==void 0||ne(t,e,z[t]))return;const i=L=>{let w=L;for(let j=0;j<5;j++){const S=w==null?void 0:w.default;if(!S||typeof S!="object"||Object.keys(S).length===0)break;const G=Object.keys(w).filter(F=>F!=="default").map(F=>w[F]);if(G.length>0&&G.some(F=>F!==void 0))break;w=S}return w},o=s==null?void 0:s[t],c=me(o,t,e,"version-first")||e,a=le(o,c);if(!a)return;const{version:l}=a,b=o==null?void 0:o[l],m=await be(t,e.shareConfig,o,l,b,c,a.registered&&!k(c,e)),_=m==null?void 0:m.selection,g=m==null?void 0:m.provider,R=m==null?void 0:m.resolved;if(!_||k(g,e)||R===void 0||(e.treeShaking?B(d.share,r,A):h(d.share,r))!==void 0||_.registered&&(o==null?void 0:o[_.version])!==g)return;const v=i(R);if(e.treeShaking){const L=e.treeShaking.providedExports??e.treeShaking.usedExports??[];he(d.share,r,L,v),J(d.share,r,A,v)}else E(d.share,r,v,_.from)},Oe=[];for(const t of nt){const e=I[t];if(pe(t))try{e.treeShaking?await ot(t,e):((Ee=e.shareConfig)==null?void 0:Ee.import)===!1&&await it(t,e)}catch(r){console.error(`[Module Federation] Failed to resolve runtime-only shared module "${t}"`,r);break}if(pe(t))break;Oe.push(t)}return await Se(Oe),ut(H),H}async function Ot(s){const f=await yt();if(!(s in f))throw new Error(`[Module Federation] Module ${s} does not exist in container.`);return ue&&await ue(),d.pendingShareLoads&&await Promise.all(d.pendingShareLoads),f[s]().then(u=>()=>u)}export{Ot as get,Pt as init};
3
3
 
4
4
  if (typeof document !== 'undefined' && document.head) {
5
5
  try {
6
- for (const __mfWarmupPath of ["./virtualExposes-BDCSo5OS.js","./_virtual_mf-localSharedImportMap___mfe_internal__velora_admin__mf_owner__1-DOKdWYyj.js","./vite-preload-helper-Cgledu0r.js","./index-Do71v6NZ.js"]) {
6
+ for (const __mfWarmupPath of ["./virtualExposes-BDCSo5OS.js","./_virtual_mf-localSharedImportMap___mfe_internal__velora_admin__mf_owner__1-DlIgIuFP.js","./vite-preload-helper-Cgledu0r.js","./index-Do71v6NZ.js"]) {
7
7
  const __mfWarmupLink = document.createElement('link');
8
8
  __mfWarmupLink.rel = 'modulepreload';
9
9
  __mfWarmupLink.crossOrigin = '';
@@ -4,12 +4,12 @@
4
4
  <meta charset="UTF-8" />
5
5
  <meta name="viewport" content="width=device-width, initial-scale=1.0" />
6
6
  <title>Velora Admin</title>
7
- <script type="module" crossorigin src="/velora/assets/mf-entry-bootstrap-0-aef015cd.js"></script>
7
+ <script type="module" crossorigin src="/velora/assets/mf-entry-bootstrap-0-7b0ce2fe.js"></script>
8
8
  <link rel="modulepreload" crossorigin href="/velora/assets/index-Do71v6NZ.js">
9
- <link rel="modulepreload" crossorigin href="/velora/assets/remoteEntry-CNyN68bc.js">
10
- <link rel="modulepreload" crossorigin href="/velora/assets/content-trash.schema-DfXHkC-w.js">
9
+ <link rel="modulepreload" crossorigin href="/velora/assets/remoteEntry-J2yJXsGB.js">
10
+ <link rel="modulepreload" crossorigin href="/velora/assets/content-trash.schema-tvJ4Lbos.js">
11
11
  <link rel="stylesheet" crossorigin href="/velora/assets/index-DnZV_gsg.css">
12
- <link rel="modulepreload" crossorigin href="/velora/assets/_virtual_mf___mfe_internal__velora_admin__mf_owner__1__loadShare__react_mf_1_jsx_mf_2_runtime__loadShare__.js-DMaku-HC.js"><link rel="modulepreload" crossorigin href="/velora/assets/_virtual_mf___mfe_internal__velora_admin__mf_owner__1__loadShare__react__loadShare__.js-BuUBskgj.js"><link rel="modulepreload" crossorigin href="/velora/assets/__virtual_mf___mfe_internal__velora_admin__mf_owner__1__loadShare__react__loadShare__.js_commonjs-proxy-Ng0fOpdU.js"><link rel="modulepreload" crossorigin href="/velora/assets/__virtual_mf___mfe_internal__velora_admin__mf_owner__1__loadShare__react_mf_2_dom__loadShare__.js_commonjs-proxy-oc1i_iBU.js"><link rel="modulepreload" crossorigin href="/velora/assets/_virtual_mf___mfe_internal__velora_admin__mf_owner__1__loadShare__react_mf_2_dom_mf_1_client__loadShare__.js-BPoj3DC9.js"><link rel="modulepreload" crossorigin href="/velora/assets/_virtual_mf___mfe_internal__velora_admin__mf_owner__1__loadShare___mf_0_velora_mf_2_cms_mf_1_plugin_mf_2_sdk__loadShare__.js-C1-ZAxwO.js"><link rel="modulepreload" crossorigin href="/velora/assets/_virtual_mf___mfe_internal__velora_admin__mf_owner__1__loadShare__react_mf_2_dom__loadShare__.js-DYfqn12F.js"><link rel="modulepreload" crossorigin href="/velora/assets/hostInit--C4xK6nj.js"><link rel="modulepreload" crossorigin href="/velora/assets/index-BIAF0ShP.js"><link rel="modulepreload" crossorigin href="/velora/assets/virtualExposes-BDCSo5OS.js"><link rel="modulepreload" crossorigin href="/velora/assets/_virtual_mf-localSharedImportMap___mfe_internal__velora_admin__mf_owner__1-DOKdWYyj.js"><link rel="modulepreload" crossorigin href="/velora/assets/index-DhMY-0sC.js"><link rel="modulepreload" crossorigin href="/velora/assets/vite-preload-helper-Cgledu0r.js"></head>
12
+ <link rel="modulepreload" crossorigin href="/velora/assets/_virtual_mf___mfe_internal__velora_admin__mf_owner__1__loadShare__react_mf_1_jsx_mf_2_runtime__loadShare__.js-DMaku-HC.js"><link rel="modulepreload" crossorigin href="/velora/assets/_virtual_mf___mfe_internal__velora_admin__mf_owner__1__loadShare__react__loadShare__.js-BuUBskgj.js"><link rel="modulepreload" crossorigin href="/velora/assets/__virtual_mf___mfe_internal__velora_admin__mf_owner__1__loadShare__react__loadShare__.js_commonjs-proxy-Ng0fOpdU.js"><link rel="modulepreload" crossorigin href="/velora/assets/__virtual_mf___mfe_internal__velora_admin__mf_owner__1__loadShare__react_mf_2_dom__loadShare__.js_commonjs-proxy-oc1i_iBU.js"><link rel="modulepreload" crossorigin href="/velora/assets/_virtual_mf___mfe_internal__velora_admin__mf_owner__1__loadShare__react_mf_2_dom_mf_1_client__loadShare__.js-BPoj3DC9.js"><link rel="modulepreload" crossorigin href="/velora/assets/_virtual_mf___mfe_internal__velora_admin__mf_owner__1__loadShare___mf_0_velora_mf_2_cms_mf_1_plugin_mf_2_sdk__loadShare__.js-Bm9EahCG.js"><link rel="modulepreload" crossorigin href="/velora/assets/_virtual_mf___mfe_internal__velora_admin__mf_owner__1__loadShare__react_mf_2_dom__loadShare__.js-DYfqn12F.js"><link rel="modulepreload" crossorigin href="/velora/assets/hostInit-B-6-34XY.js"><link rel="modulepreload" crossorigin href="/velora/assets/index-DYO7-IK8.js"><link rel="modulepreload" crossorigin href="/velora/assets/virtualExposes-BDCSo5OS.js"><link rel="modulepreload" crossorigin href="/velora/assets/_virtual_mf-localSharedImportMap___mfe_internal__velora_admin__mf_owner__1-DlIgIuFP.js"><link rel="modulepreload" crossorigin href="/velora/assets/index-CHCGuSbb.js"><link rel="modulepreload" crossorigin href="/velora/assets/vite-preload-helper-Cgledu0r.js"></head>
13
13
  <body>
14
14
  <div id="root"></div>
15
15
  </body>
package/dist/app.d.ts CHANGED
@@ -1,8 +1,23 @@
1
- import { type FastifyInstance } from "fastify";
1
+ import { type FastifyInstance, type FastifyRequest } from "fastify";
2
2
  import { PluginRegistryService } from "./plugins/plugin-registry-service.js";
3
3
  declare module "fastify" {
4
4
  interface FastifyInstance {
5
5
  pluginRegistry: PluginRegistryService;
6
6
  }
7
7
  }
8
+ export declare function redactSensitiveQueryParams(url: string): string;
9
+ declare function redactingReqSerializer(request: FastifyRequest): {
10
+ method: string;
11
+ url: string;
12
+ version: string | undefined;
13
+ host: string;
14
+ remoteAddress: string;
15
+ remotePort: number | undefined;
16
+ };
17
+ export declare const requestLoggerOptions: {
18
+ serializers: {
19
+ req: typeof redactingReqSerializer;
20
+ };
21
+ };
8
22
  export declare function buildApp(): Promise<FastifyInstance>;
23
+ export {};
package/dist/app.js CHANGED
@@ -15,7 +15,7 @@ import { prisma, resolvePrismaDialect } from "./db/prisma.js";
15
15
  import { resolveClientDir } from "./db/resolve-client-dir.js";
16
16
  import { filterPublicApiSpec } from "./docs/filter-public-api-spec.js";
17
17
  import { startLicenseRevalidation } from "./marketplace/license-revalidation-job.js";
18
- import { MediaService, mediaStorageConfigFromEnv } from "./media/media-service.js";
18
+ import { MediaService, resolveMediaStorage } from "./media/media-service.js";
19
19
  import { bootInstalledPlugins } from "./plugins/boot-plugin-loader.js";
20
20
  import { createHookDispatcher } from "./plugins/hook-dispatcher.js";
21
21
  import { PluginRegistryService } from "./plugins/plugin-registry-service.js";
@@ -33,6 +33,7 @@ import { createFrameworkErrorHandler, registerHeadlessBridge } from "./routes/he
33
33
  import { healthRoutes } from "./routes/health.js";
34
34
  import { marketplaceProxyRoutes } from "./routes/marketplace-proxy.js";
35
35
  import { mediaRoutes } from "./routes/media.js";
36
+ import { mediaPublicRoutes } from "./routes/media-public.js";
36
37
  import { dataTypeRoutes } from "./routes/data-types.js";
37
38
  import { pluginRoutes } from "./routes/plugins.js";
38
39
  import { themeRoutes } from "./routes/themes.js";
@@ -45,6 +46,54 @@ import { snapshotRoutes } from "./routes/snapshots.js";
45
46
  import { setupRoutes } from "./routes/setup.js";
46
47
  import { usersRoutes } from "./routes/users.js";
47
48
  import { templateRoutes } from "./routes/templates.js";
49
+ // S186c Task 3 fix wave, M2: signed media/preview links (media-tokens.ts's
50
+ // `?token=`, preview-tokens.ts's `?previewToken=`) ride in the URL, and
51
+ // Fastify's request logging (logger: true below) logs `req.url` verbatim
52
+ // on every single request — meaning both land in cleartext in the access
53
+ // log, a persistent, usually-shipped-off-box artifact, even though each
54
+ // token is itself short-lived and scoped. Only the VALUE is masked; the
55
+ // param NAME stays visible (worth keeping for triage — "was a token even
56
+ // presented" is still answerable from the log line).
57
+ const REDACTED_QUERY_PARAMS = new Set(["token", "previewToken"]);
58
+ export function redactSensitiveQueryParams(url) {
59
+ const [path, query] = url.split("?", 2);
60
+ if (!query)
61
+ return url;
62
+ const redactedQuery = query
63
+ .split("&")
64
+ .map((pair) => {
65
+ const eqIndex = pair.indexOf("=");
66
+ const key = eqIndex === -1 ? pair : pair.slice(0, eqIndex);
67
+ return REDACTED_QUERY_PARAMS.has(key) ? `${key}=[redacted]` : pair;
68
+ })
69
+ .join("&");
70
+ return `${path}?${redactedQuery}`;
71
+ }
72
+ // Field-for-field the same shape as Fastify's own default req serializer
73
+ // (fastify/lib/logger-pino.js's `serializers.req`) — method, url, version,
74
+ // host, remoteAddress, remotePort — with `url` swapped for the redacted
75
+ // version above. Fastify calls this with the real (decorated) request
76
+ // object, not the raw Node one, hence `.host`/`.ip`/`.socket` rather than
77
+ // header-parsing by hand here.
78
+ function redactingReqSerializer(request) {
79
+ // accept-version, like any header, can legally repeat (string[]) — the
80
+ // default serializer this mirrors (fastify/lib/logger-pino.js) doesn't
81
+ // account for that either, so this narrows to Fastify's own declared
82
+ // `string | undefined` serializer shape rather than widening it.
83
+ const acceptVersion = request.headers?.["accept-version"];
84
+ return {
85
+ method: request.method,
86
+ url: redactSensitiveQueryParams(request.url),
87
+ version: typeof acceptVersion === "string" ? acceptVersion : undefined,
88
+ host: request.host,
89
+ remoteAddress: request.ip,
90
+ remotePort: request.socket ? request.socket.remotePort : undefined,
91
+ };
92
+ }
93
+ // Exported so a test can wire this exact serializer into its own minimal
94
+ // Fastify instance (with a capturable `stream`) rather than duplicating
95
+ // the redaction logic or standing up the full buildApp() + database.
96
+ export const requestLoggerOptions = { serializers: { req: redactingReqSerializer } };
48
97
  export async function buildApp() {
49
98
  // frameworkErrors (S156): the only hook into find-my-way's own
50
99
  // pre-routing FST_ERR_BAD_URL/FST_ERR_ASYNC_CONSTRAINT responses — it's
@@ -63,7 +112,13 @@ export async function buildApp() {
63
112
  // byte-for-byte for every deployment that hasn't opted in.
64
113
  const trustProxy = trustProxyFromEnv();
65
114
  const app = Fastify({
66
- logger: true,
115
+ // M2 (S186c Task 3 fix wave): logger: true previously used Fastify's
116
+ // default req serializer verbatim, which logs req.url unredacted —
117
+ // requestLoggerOptions above swaps in the one field that needs
118
+ // masking and otherwise matches the default exactly, so this is
119
+ // still "logger: true" in every other respect (level, timestamps,
120
+ // etc. all default).
121
+ logger: requestLoggerOptions,
67
122
  frameworkErrors: createFrameworkErrorHandler(),
68
123
  ...(trustProxy !== undefined ? { trustProxy } : {}),
69
124
  }).withTypeProvider();
@@ -133,7 +188,7 @@ export async function buildApp() {
133
188
  app.addHook("onClose", async () => {
134
189
  await contentDb.adapter.disconnect();
135
190
  });
136
- const mediaService = new MediaService(prisma, mediaStorageConfigFromEnv(),
191
+ const mediaService = new MediaService(prisma, resolveMediaStorage(),
137
192
  // Routed through resolveClientDir() rather than reading
138
193
  // VELORA_PRISMA_CLIENT_DIR directly, so there's one channel deciding
139
194
  // "which generated client dir" instead of two (db/prisma.ts's own
@@ -143,7 +198,7 @@ export async function buildApp() {
143
198
  // branch untouched, so resolvePrismaDialect still falls through to the
144
199
  // DATABASE_URL-scheme branch for it exactly as before.
145
200
  resolvePrismaDialect(resolveClientDir(), process.env.DATABASE_URL));
146
- await mediaService.ensureBucket();
201
+ await mediaService.ensureReady();
147
202
  // The registry's dialect gate follows the content database's resolved
148
203
  // dialect — contentDb.dialect is the resolved postgresql|mysql|sqlite
149
204
  // union (Session 122), so 'mock' is excluded by construction and no
@@ -195,6 +250,10 @@ export async function buildApp() {
195
250
  // 404-with-cause there, not a bare unmatched-route 404), while leaving
196
251
  // GET / on its pre-S184 headless-bridge behaviour.
197
252
  await app.register(adminStaticRoutes);
253
+ // The stable media route (S186c §3) — full app only, same as
254
+ // adminStaticRoutes above; buildSetupOnlyApp() (setup-app.ts) has no
255
+ // MediaService/Prisma to serve from and never registers this.
256
+ await app.register(mediaPublicRoutes, { mediaService });
198
257
  await app.register(pluginAssetsRoutes);
199
258
  await app.register(authRoutes);
200
259
  await app.register(usersRoutes);
@@ -1,5 +1,6 @@
1
1
  import type { FastifyReply, FastifyRequest } from "fastify";
2
2
  import type { ApiKeyScope } from "@velora-cms/api-schemas";
3
+ export declare const KEY_PREFIX = "vk_";
3
4
  export declare function generateApiKey(): string;
4
5
  export declare function hashApiKey(key: string): string;
5
6
  export declare function isApiKeyHashValid(hash: string): Promise<boolean>;
@@ -3,7 +3,11 @@ import { prisma } from "../db/prisma.js";
3
3
  // Public Content API keys (Month 9, Session 101). A deliberately separate
4
4
  // code path from the admin JWT/cookie session (api-design.md: never
5
5
  // conflate headless consumers with logged-in admin sessions).
6
- const KEY_PREFIX = "vk_";
6
+ // Exported so any other caller that must recognize a "this even looks like
7
+ // one of ours" key (e.g. media-public.ts's hasReadApiKey, L2 fix wave)
8
+ // checks against the exact same literal rather than a second, potentially
9
+ // drifting copy of it.
10
+ export const KEY_PREFIX = "vk_";
7
11
  // High-entropy random secret, so sha256 (fast) is the right hash — same
8
12
  // reasoning as hashRefreshToken in tokens.ts, NOT bcrypt like passwords.
9
13
  export function generateApiKey() {
@@ -16,6 +16,10 @@ export declare const ADMIN_RATE_LIMIT: {
16
16
  max: () => number;
17
17
  timeWindow: () => string;
18
18
  };
19
+ export declare const MEDIA_RATE_LIMIT: {
20
+ max: () => number;
21
+ timeWindow: () => string;
22
+ };
19
23
  export declare function ipOnlyKeyGenerator(request: FastifyRequest): Promise<string>;
20
24
  export declare function ipOnlyRateLimitConfig(): {
21
25
  max: number;
@@ -65,6 +65,19 @@ export const ADMIN_RATE_LIMIT = {
65
65
  max: () => parsePositiveInt(process.env.VELORA_RATE_LIMIT_ADMIN, 120),
66
66
  timeWindow: () => parseWindow(process.env.VELORA_RATE_LIMIT_ADMIN_WINDOW, "1 minute"),
67
67
  };
68
+ // The stable media route (S186c §3), GET /media/:id/:filename —
69
+ // registered in media-public.ts, plugin-level, IP-only (same shape as
70
+ // ADMIN_RATE_LIMIT/DOCS_RATE_LIMIT above): a public bandwidth endpoint
71
+ // that both anonymous public-image requests and headless consumers hit
72
+ // directly (not behind an API key or JWT for public items), so it cannot
73
+ // bucket on the three-lane rateLimitConfig's jwt:/apiKey: lanes — IP is
74
+ // the only key every caller has. Generous ceiling: this serves actual
75
+ // bytes (images, downloads) embedded in ordinary pages, so a real page
76
+ // load can fire many requests against it in a burst.
77
+ export const MEDIA_RATE_LIMIT = {
78
+ max: () => parsePositiveInt(process.env.VELORA_RATE_LIMIT_MEDIA, 300),
79
+ timeWindow: () => parseWindow(process.env.VELORA_RATE_LIMIT_MEDIA_WINDOW, "1 minute"),
80
+ };
68
81
  // The shared rateLimitKey puts a VERIFIED JWT into the jwt: lane, which is
69
82
  // Number.MAX_SAFE_INTEGER — effectively unlimited. Login must never inherit
70
83
  // that, or anyone holding one valid session could brute-force passwords
@@ -0,0 +1,2 @@
1
+ #!/usr/bin/env node
2
+ export {};
@@ -0,0 +1,39 @@
1
+ #!/usr/bin/env node
2
+ // The `velora-sync-admin` command (S186b): re-copies the installed admin
3
+ // bundle into the scaffold's public/velora-admin (or VELORA_ADMIN_DIR),
4
+ // rewriting its version stamp — the drift-control half of the visible
5
+ // scaffold, run after `npm update @velora-cms/server`. Runs with cwd set to
6
+ // the USER's project, never this package, which is exactly what
7
+ // syncAdminBundle resolves targetDir against.
8
+ import { resolve } from "node:path";
9
+ import { syncAdminBundle } from "./admin/sync-admin-bundle.js";
10
+ import { loadEnvFile } from "./config/load-env.js";
11
+ // Review finding I2: spec §3 puts VELORA_ADMIN_DIR in the scaffold's
12
+ // `.env`, but this bin used to read process.env directly and never loaded
13
+ // it — so the override only ever worked if it happened to already be in
14
+ // the shell's real environment. Same loader index.ts/lib.ts use, called
15
+ // with defaults (process.env, process.cwd()) since this bin, like them,
16
+ // runs with cwd set to the scaffold, not this package.
17
+ loadEnvFile();
18
+ // Review finding C1: --force bypasses syncAdminBundle's dangerous-target
19
+ // guard, for the rare case where a caller genuinely wants to replace a
20
+ // directory that doesn't look like a prior admin bundle.
21
+ const force = process.argv.slice(2).includes("--force");
22
+ const targetDir = process.env.VELORA_ADMIN_DIR || "public/velora-admin";
23
+ // Resolved up front so every line this bin prints — success or failure —
24
+ // names the actual absolute path being acted on, not the raw (possibly
25
+ // relative) override string.
26
+ const resolvedTarget = resolve(targetDir);
27
+ try {
28
+ const { version, copied } = await syncAdminBundle(targetDir, { force });
29
+ console.log(`Synced admin UI ${version} into ${resolvedTarget} (${copied} files).`);
30
+ }
31
+ catch (err) {
32
+ // Review finding M1: every failure — including syncAdminBundle's own
33
+ // missing-source and dangerous-target messages — is wrapped with a
34
+ // consistent "what were we trying to do" prefix naming the resolved
35
+ // target, rather than printing the bare underlying message.
36
+ const message = err instanceof Error ? err.message : String(err);
37
+ console.error(`Could not sync the admin UI into ${resolvedTarget}: ${message}`);
38
+ process.exit(1);
39
+ }
@@ -0,0 +1,3 @@
1
+ import type { FastifyRequest } from "fastify";
2
+ export declare function configuredPublicUrl(): string | null;
3
+ export declare function resolvePublicBaseUrl(request: FastifyRequest): string;
@@ -0,0 +1,45 @@
1
+ // S186c Task 3 fix wave, L1: extracted out of published-item.ts's
2
+ // resolvePublicBaseUrl (which still re-exports it for its existing call
3
+ // sites) so this base-resolution logic lives in `config/` beside every
4
+ // other env-derived base URL, and mirrors config/preview.ts's
5
+ // previewBaseUrl idiom exactly: read fresh at call time (not frozen at
6
+ // module-import time, so a test's env override always takes effect),
7
+ // empty/whitespace-only treated as unset, trailing slashes stripped.
8
+ // Configured public base URL override — production behind a reverse
9
+ // proxy/CDN, where the request's own Host/proto may not be the
10
+ // public-facing one. Unset (or blank) means "derive from the request"
11
+ // (see resolvePublicBaseUrl below).
12
+ export function configuredPublicUrl() {
13
+ const raw = process.env.VELORA_PUBLIC_URL;
14
+ if (!raw) {
15
+ return null;
16
+ }
17
+ const trimmed = raw.trim();
18
+ if (!trimmed) {
19
+ return null;
20
+ }
21
+ return trimmed.replace(/\/+$/, "");
22
+ }
23
+ // S186c Task 3, mandate 1: the PUBLIC surface (REST /api/v1/media* and
24
+ // GraphQL) is consumed cross-origin by design — a headless frontend's own
25
+ // server fetches `downloadUrl` directly, so a path-relative URL there
26
+ // resolves against the wrong origin.
27
+ //
28
+ // Base resolution: VELORA_PUBLIC_URL when the operator has set one;
29
+ // otherwise derived from THIS request's protocol + `request.host` — NOT
30
+ // `request.hostname`, which strips the port in Fastify 5 (H2 fix: a
31
+ // non-default-port deployment, e.g. the blog starter's default
32
+ // http://localhost:3000, was getting handed back
33
+ // http://localhost/media/... with the port silently dropped).
34
+ // `request.host`/`request.protocol` both honor trustProxyFromEnv() the
35
+ // same way every other host-derived value in this app does (they read
36
+ // X-Forwarded-Host/-Proto once trustProxy is configured). Never cached —
37
+ // re-derived per request, since two requests can legitimately arrive with
38
+ // different hosts (multiple domains pointed at one instance).
39
+ export function resolvePublicBaseUrl(request) {
40
+ const configured = configuredPublicUrl();
41
+ if (configured) {
42
+ return configured;
43
+ }
44
+ return `${request.protocol}://${request.host}`;
45
+ }
@@ -1,3 +1,43 @@
1
+ // Shared probe for every additive step below. NEVER probe by running a
2
+ // statement that's expected to fail on a pre-column database and catching
3
+ // the error — `applyMigrations` (packages/db-adapter) wraps each step's
4
+ // up() in a single BEGIN/COMMIT. On postgresql, one failed statement
5
+ // (`SELECT <missing column>`) leaves that transaction in error state
6
+ // 25P02 ("current transaction is aborted, commands ignored until end of
7
+ // transaction block"); every statement issued afterwards on the SAME
8
+ // transaction — including the ALTER meant to fix things — fails too, and
9
+ // the whole step throws. A pre-column postgres database can then never
10
+ // get the column added: the boot gate refuses the site forever. MySQL and
11
+ // SQLite don't poison the transaction this way, but postgres is Tier 1
12
+ // and this idiom is banned everywhere for consistency — no step body may
13
+ // contain a try/catch around a statement expected to fail.
14
+ //
15
+ // Instead, ask the schema catalog directly — a query that ALWAYS
16
+ // succeeds, column present or not:
17
+ // - mysql: information_schema.columns, scoped to the current database.
18
+ // - sqlite: the pragma_table_info() table-valued function.
19
+ // - postgresql: not used by this helper — see the comment on each
20
+ // postgres branch below, `ADD COLUMN IF NOT EXISTS` makes the probe
21
+ // unnecessary there and this helper is never called with "postgresql".
22
+ async function columnExists(tx, dialect, table, column) {
23
+ if (dialect === "postgresql") {
24
+ // ADD COLUMN IF NOT EXISTS makes probing unnecessary on postgres —
25
+ // no step should ever call this helper with "postgresql".
26
+ throw new Error("columnExists: postgresql steps use ADD COLUMN IF NOT EXISTS instead of probing");
27
+ }
28
+ if (dialect === "sqlite") {
29
+ const row = await tx.queryOne({
30
+ sql: "SELECT COUNT(*) AS n FROM pragma_table_info(?) WHERE name = ?",
31
+ params: [table, column],
32
+ });
33
+ return Number(row?.n ?? 0) > 0;
34
+ }
35
+ const row = await tx.queryOne({
36
+ sql: "SELECT COUNT(*) AS n FROM information_schema.columns WHERE table_schema = DATABASE() AND table_name = ? AND column_name = ?",
37
+ params: [table, column],
38
+ });
39
+ return Number(row?.n ?? 0) > 0;
40
+ }
1
41
  // The Prisma-owned schema's upgrade ledger. 0001 is a pure baseline: it
2
42
  // marks "the 0.10.0-release db-push shape" and carries no SQL. Every schema
3
43
  // change that ships AFTER that release becomes its own numbered step here —
@@ -26,27 +66,66 @@ const coreBaseline = {
26
66
  // demo box after S182 shipped) already has the column, and this step must
27
67
  // run harmlessly against it too. Rather than branch on "has 0001 already
28
68
  // run without this column" (which the ledger can't tell apart from "db
29
- // push already included it"), probe directly try a SELECT of the column
30
- // and only ALTER if that probe fails. The probe is dialect-free (the same
31
- // SELECT works identically against all three), so only the ALTER itself
32
- // needs the per-dialect branch below.
69
+ // push already included it"), check the schema catalog first via the
70
+ // shared columnExists() helper and only ALTER if it's missing see that
71
+ // helper's comment for why this can never be a try/catch-of-a-failing-
72
+ // probe (it poisons the whole step's transaction on postgres). Postgres
73
+ // skips the check entirely: `ADD COLUMN IF NOT EXISTS` is natively
74
+ // idempotent and transaction-safe, so there's nothing to probe for.
33
75
  function apiKeyScopeStep(dialect) {
34
76
  return {
35
77
  id: "0002_api_key_scope",
36
78
  name: "api_keys.scope column (S182)",
37
79
  up: async (tx) => {
38
- try {
39
- await tx.query({ sql: "SELECT scope FROM api_keys LIMIT 1" });
80
+ if (dialect === "postgresql") {
81
+ await tx.execute({
82
+ sql: "ALTER TABLE api_keys ADD COLUMN IF NOT EXISTS scope TEXT NOT NULL DEFAULT 'read'",
83
+ });
84
+ return;
85
+ }
86
+ if (await columnExists(tx, dialect, "api_keys", "scope")) {
40
87
  return; // column already present — nothing to do
41
88
  }
42
- catch {
43
- // column missing pre-S182 database, fall through and add it
89
+ const alter = dialect === "mysql"
90
+ ? "ALTER TABLE api_keys ADD COLUMN scope VARCHAR(191) NOT NULL DEFAULT 'read'"
91
+ : "ALTER TABLE api_keys ADD COLUMN scope TEXT NOT NULL DEFAULT 'read'";
92
+ await tx.execute({ sql: alter });
93
+ },
94
+ // No-op, same as the baseline: additive steps never need to undo
95
+ // anything (house pattern — this ledger only ever moves forward).
96
+ down: async () => { },
97
+ };
98
+ }
99
+ // media_files.visibility (S186c §2): `TEXT NOT NULL DEFAULT 'public'` on
100
+ // postgresql/sqlite, `VARCHAR(191) NOT NULL DEFAULT 'public'` on mysql —
101
+ // matching schema.prisma's `visibility String @default("public")`, which
102
+ // Prisma maps to VARCHAR(191) on mysql by its own default (same reasoning
103
+ // as 0002_api_key_scope above: no `@db.VarChar` override in either
104
+ // schema.prisma or .prisma-variant-mysql.schema.prisma).
105
+ //
106
+ // Same columnExists()-then-ALTER idiom as 0002 above (see its comment,
107
+ // and columnExists' own comment, for why a try/catch-of-a-failing-probe
108
+ // is banned): a post-S186c database (fresh db-push, or any deployment
109
+ // that boots after this ships) already has the column, and up() must run
110
+ // harmlessly against it too. Postgres again skips the check — ADD COLUMN
111
+ // IF NOT EXISTS is already idempotent and transaction-safe.
112
+ function mediaVisibilityStep(dialect) {
113
+ return {
114
+ id: "0003_media_visibility",
115
+ name: "media_files.visibility column (S186c)",
116
+ up: async (tx) => {
117
+ if (dialect === "postgresql") {
118
+ await tx.execute({
119
+ sql: "ALTER TABLE media_files ADD COLUMN IF NOT EXISTS visibility TEXT NOT NULL DEFAULT 'public'",
120
+ });
121
+ return;
122
+ }
123
+ if (await columnExists(tx, dialect, "media_files", "visibility")) {
124
+ return; // column already present — nothing to do
44
125
  }
45
- const alter = dialect === "postgresql"
46
- ? "ALTER TABLE api_keys ADD COLUMN IF NOT EXISTS scope TEXT NOT NULL DEFAULT 'read'"
47
- : dialect === "mysql"
48
- ? "ALTER TABLE api_keys ADD COLUMN scope VARCHAR(191) NOT NULL DEFAULT 'read'"
49
- : "ALTER TABLE api_keys ADD COLUMN scope TEXT NOT NULL DEFAULT 'read'";
126
+ const alter = dialect === "mysql"
127
+ ? "ALTER TABLE media_files ADD COLUMN visibility VARCHAR(191) NOT NULL DEFAULT 'public'"
128
+ : "ALTER TABLE media_files ADD COLUMN visibility TEXT NOT NULL DEFAULT 'public'";
50
129
  await tx.execute({ sql: alter });
51
130
  },
52
131
  // No-op, same as the baseline: additive steps never need to undo
@@ -54,13 +133,13 @@ function apiKeyScopeStep(dialect) {
54
133
  down: async () => { },
55
134
  };
56
135
  }
57
- // A factory, not a plain array: 0002's up() needs to know which dialect
58
- // it's running against (TransactionContext carries no dialect field, only
136
+ // A factory, not a plain array: 0002/0003's up() need to know which dialect
137
+ // they're running against (TransactionContext carries no dialect field, only
59
138
  // DatabaseAdapter does), so the registry is built per-dialect at the call
60
139
  // site instead of threading dialect through the shared Migration type.
61
140
  // CORE_MIGRATION_IDS below stays dialect-independent — ids never vary by
62
141
  // dialect — so it's fine to read off of any one dialect's build.
63
142
  export function buildCoreMigrations(dialect) {
64
- return [coreBaseline, apiKeyScopeStep(dialect)];
143
+ return [coreBaseline, apiKeyScopeStep(dialect), mediaVisibilityStep(dialect)];
65
144
  }
66
145
  export const CORE_MIGRATION_IDS = buildCoreMigrations("sqlite").map((m) => m.id);
@@ -1 +1 @@
1
- {"version":"1.5.2","languages":{"en":{"hash":"en_1e94abd852","wasm":"en","page_count":11}},"include_characters":["_","‿","⁀","⁔","︳","︴","﹍","﹎","﹏","_"]}
1
+ {"version":"1.5.2","languages":{"en":{"hash":"en_57d2f8922f","wasm":"en","page_count":11}},"include_characters":["_","‿","⁀","⁔","︳","︴","﹍","﹎","﹏","_"]}