gemi 0.45.0 → 0.46.1

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 (53) hide show
  1. package/dist/app/index.js +1 -1
  2. package/dist/bin/gemi.js +185 -49
  3. package/dist/bin/gemi.js.map +10 -7
  4. package/dist/{chunk-tvp3xgfq.js → chunk-2ahct6kg.js} +2 -2
  5. package/dist/{chunk-tvp3xgfq.js.map → chunk-2ahct6kg.js.map} +1 -1
  6. package/dist/{chunk-v0qh5dqv.js → chunk-5hggqap1.js} +15 -15
  7. package/dist/{chunk-v0qh5dqv.js.map → chunk-5hggqap1.js.map} +3 -3
  8. package/dist/chunk-d9k245jt.js +79 -0
  9. package/dist/{chunk-jxpwexpz.js.map → chunk-d9k245jt.js.map} +8 -5
  10. package/dist/chunk-evkv0xa7.js +4 -0
  11. package/dist/{chunk-atv6nybp.js.map → chunk-evkv0xa7.js.map} +4 -4
  12. package/dist/{chunk-63gmzy5r.js → chunk-pr2xbq0m.js} +1 -1
  13. package/dist/{chunk-ppn0j67g.js → chunk-r64ba1pf.js} +1 -1
  14. package/dist/{chunk-396qq8ge.js → chunk-z29tg1ey.js} +1 -1
  15. package/dist/client/ClientRouter.d.ts.map +1 -1
  16. package/dist/client/Head.d.ts.map +1 -1
  17. package/dist/client/QueryManagerContext.d.ts +5 -2
  18. package/dist/client/QueryManagerContext.d.ts.map +1 -1
  19. package/dist/client/QueryResource.d.ts +23 -1
  20. package/dist/client/QueryResource.d.ts.map +1 -1
  21. package/dist/client/helpers/mergeCarriedSegments.d.ts +23 -0
  22. package/dist/client/helpers/mergeCarriedSegments.d.ts.map +1 -0
  23. package/dist/client/index.js +168 -27
  24. package/dist/client/index.js.map +1 -1
  25. package/dist/client/useQuery.d.ts +2 -0
  26. package/dist/client/useQuery.d.ts.map +1 -1
  27. package/dist/facades/index.js +1 -1
  28. package/dist/http/Metadata.d.ts +6 -0
  29. package/dist/http/Metadata.d.ts.map +1 -1
  30. package/dist/http/ViewRouter.d.ts +12 -0
  31. package/dist/http/ViewRouter.d.ts.map +1 -1
  32. package/dist/http/index.js +1 -1
  33. package/dist/i18n/index.js +1 -1
  34. package/dist/kernel/index.js +1 -1
  35. package/dist/server/index.js +1 -1
  36. package/dist/services/index.js +1 -1
  37. package/dist/services/router/ViewRouterServiceContainer.d.ts.map +1 -1
  38. package/dist/services/router/ViewRouterServiceProvider.d.ts +10 -0
  39. package/dist/services/router/ViewRouterServiceProvider.d.ts.map +1 -1
  40. package/dist/services/router/createFlatViewRoutes.d.ts +16 -0
  41. package/dist/services/router/createFlatViewRoutes.d.ts.map +1 -1
  42. package/dist/services/router/matchViewRoute.d.ts +12 -0
  43. package/dist/services/router/matchViewRoute.d.ts.map +1 -0
  44. package/dist/services/router/planPartialRender.d.ts +43 -0
  45. package/dist/services/router/planPartialRender.d.ts.map +1 -0
  46. package/dist/utils/partialRender.d.ts +28 -0
  47. package/dist/utils/partialRender.d.ts.map +1 -0
  48. package/package.json +1 -1
  49. package/dist/chunk-atv6nybp.js +0 -4
  50. package/dist/chunk-jxpwexpz.js +0 -79
  51. /package/dist/{chunk-63gmzy5r.js.map → chunk-pr2xbq0m.js.map} +0 -0
  52. /package/dist/{chunk-ppn0j67g.js.map → chunk-r64ba1pf.js.map} +0 -0
  53. /package/dist/{chunk-396qq8ge.js.map → chunk-z29tg1ey.js.map} +0 -0
@@ -1,5 +1,5 @@
1
1
  // @bun
2
- import{h as g,i as R}from"./chunk-tvp3xgfq.js";import"./chunk-ppt296ye.js";import{K,M as W}from"./chunk-jxpwexpz.js";import"./chunk-atv6nybp.js";import"./chunk-p5r0t9jh.js";import"./chunk-4z53shav.js";import"./chunk-m0earq80.js";import"./chunk-f18weffa.js";import{join as j}from"path";function V(J){let x=J.toString(),Q=new Bun.CryptoHasher("sha1");return Q.update(x),Q.digest("hex")}if(!globalThis.URLPattern)globalThis.URLPattern=K;import{exists as v}from"fs/promises";var u=process.env.GEMI_PROJECT_DIR??"",T=j(process.cwd(),u),F=j(T,"app"),$=j(T,"dist");async function a(J,x){let Q=await import(`${$}/client/.vite/manifest.json`),O=await import(`${$}/server/.vite/manifest.json`);process.env.ROOT_DIR=T,process.env.APP_DIR=F,process.env.DIST_DIR=$;let A={},C={},I={},S=(b,L)=>`"${b}": () => import("${L}")`,_=[];for(let b of["404",...J.getFlatComponentTree.call(J)]){let L=O[`app/views/${b}.tsx`];if(!L?.file){console.log(`Server file not found for ${b}`),console.log(L);let U=Object.keys(O),Y=`app/views/${b}.tsx`;console.log(`${Y} not found in server manifest`),console.log(U)}let z=await import(`${process.env.DIST_DIR}/server/${L?.file}`);A[b]=z.default,C[b]=z.OpenGraph;let k=Q[`app/views/${b}.tsx`];if(k?.css&&k?.css.length>0)I[b]=k?.css;if(k)_.push(S(b,`/${k?.file}`))}let N=`{${_.join(",")}}`,w=Q["app/client.tsx"]?.css??[],M=(await Promise.all(w.map((b)=>Bun.file(`${$}/client/${b}`).text()))).join(`
2
+ import{h as g,i as R}from"./chunk-2ahct6kg.js";import"./chunk-ppt296ye.js";import{K,M as W}from"./chunk-d9k245jt.js";import"./chunk-evkv0xa7.js";import"./chunk-p5r0t9jh.js";import"./chunk-4z53shav.js";import"./chunk-m0earq80.js";import"./chunk-f18weffa.js";import{join as j}from"path";function V(J){let x=J.toString(),Q=new Bun.CryptoHasher("sha1");return Q.update(x),Q.digest("hex")}if(!globalThis.URLPattern)globalThis.URLPattern=K;import{exists as v}from"fs/promises";var u=process.env.GEMI_PROJECT_DIR??"",T=j(process.cwd(),u),F=j(T,"app"),$=j(T,"dist");async function a(J,x){let Q=await import(`${$}/client/.vite/manifest.json`),O=await import(`${$}/server/.vite/manifest.json`);process.env.ROOT_DIR=T,process.env.APP_DIR=F,process.env.DIST_DIR=$;let A={},C={},I={},S=(b,L)=>`"${b}": () => import("${L}")`,_=[];for(let b of["404",...J.getFlatComponentTree.call(J)]){let L=O[`app/views/${b}.tsx`];if(!L?.file){console.log(`Server file not found for ${b}`),console.log(L);let U=Object.keys(O),Y=`app/views/${b}.tsx`;console.log(`${Y} not found in server manifest`),console.log(U)}let z=await import(`${process.env.DIST_DIR}/server/${L?.file}`);A[b]=z.default,C[b]=z.OpenGraph;let k=Q[`app/views/${b}.tsx`];if(k?.css&&k?.css.length>0)I[b]=k?.css;if(k)_.push(S(b,`/${k?.file}`))}let N=`{${_.join(",")}}`,w=Q["app/client.tsx"]?.css??[],M=(await Promise.all(w.map((b)=>Bun.file(`${$}/client/${b}`).text()))).join(`
3
3
  `),D=new K({pathname:"/*.:filetype(png|txt|js|css|jpg|svg|jpeg|avif|webp|ico|ttf|map)"});async function E(b){let{pathname:L}=new URL(b.url),z=L.startsWith("/.well-known"),k=D.test({pathname:L})||z,U=L.startsWith("/api");if(k&&!U){let Y=new URL(b.url),B=b.url.replace(Y.origin,"").split("?")[0],Z=`${$}/client${B.replace("/assets/assets","/assets")}`,H=await v(Z);if(!H&&Y.pathname.includes(".js"))return new Response(`if(caches){caches?.delete("${Z}")}window.location.reload();export {}`,{headers:{"Content-Type":"application/javascript"}});if(!H){if(L===W||L.startsWith(`${W}/`))return new Response("Not found",{status:404});return await y(b,L)}try{let G=Bun.file(Z),X=V(G.lastModified);return new Response(G.stream(),{headers:{"Content-Type":G.type,"Cache-Control":"public, max-age=31536000, must-revalidate","Content-Length":String(G.size),ETag:X}})}catch(G){return J.onException?.(G),new Response("Not found",{status:404})}}return await y(b,L)}async function y(b,L){let z=J.fetch.bind(J);try{let k=await z(b);if(k instanceof Response)return k;else{let U=[];return U.push({content:M}),await k({getStyles:async(B)=>{if(!B)return g([]);for(let Z of B){let H=Q[`app/views/${Z}.tsx`];for(let G of H?.css??[]){let X=Bun.file(`${process.env.DIST_DIR}/client/${G}`);U.push({id:G,content:await X.text()})}}return g(U)},bootstrapModules:[`/${Q["app/client.tsx"].file}`],loaders:N,viewImportMap:A,ogMap:C,cssManifest:I})}}catch(k){if(console.error(k),L.startsWith("/api"))return new Response(JSON.stringify({error:k.message}),{status:500,headers:{"Content-Type":"application/json"}});return J.onException?.(k),new Response(k.stack,{status:500})}}let P=Bun.serve({maxRequestBodySize:10737418240,fetch:async(b,L)=>{if(!b.headers.get("x-forwarded-for")){let z=L.requestIP(b);if(z)b.headers.set("x-forwarded-for",z.address)}return await x(b,E)},idleTimeout:Number(process.env.SERVER_IDLE_TIMEOUT??10),port:process.env.PORT||5173});return R({port:P.port,rootDir:T}),P}export{a as httpProd};
4
4
 
5
5
  //# debugId=B6DC0792DD8A023A64756E2164756E21
@@ -1,4 +1,4 @@
1
1
  // @bun
2
- import{N as U,O as X,s as L}from"./chunk-jxpwexpz.js";import{Ob as Y}from"./chunk-xkrthw08.js";import{fc as S,gc as $}from"./chunk-f18weffa.js";var K=$((u,I)=>{var{defineProperty:W,getOwnPropertyDescriptor:J,getOwnPropertyNames:Q}=Object,B=Object.prototype.hasOwnProperty,E=(z,F)=>{for(var G in F)W(z,G,{get:F[G],enumerable:!0})},N=(z,F,G,T)=>{if(F&&typeof F==="object"||typeof F==="function"){for(let H of Q(F))if(!B.call(z,H)&&H!==G)W(z,H,{get:()=>F[H],enumerable:!(T=J(F,H))||T.enumerable})}return z},O=(z)=>N(W({},"__esModule",{value:!0}),z),A={};E(A,{Prisma:()=>D,PrismaClient:()=>k,default:()=>v});I.exports=O(A);var R={enginesVersion:"c2990dca591cba766e3b7ef5d9e8a84796e47ab7"},V="6.19.2",h=V,k=class{constructor(){throw Error('@prisma/client did not initialize yet. Please run "prisma generate" and try to import it again.')}};function q(z){if(typeof z==="function")return z;return(F)=>F.$extends(z)}function y(z){return z}var D={defineExtension:q,getExtensionContext:y,prismaVersion:{client:h,engine:R.enginesVersion}},v={Prisma:D}});var b=$((d,M)=>{M.exports={...K()}});class Z{kernel;onException;constructor(z){this.kernel=new z.kernel,this.kernel.boot.call(this.kernel),this.onException=z.onException??((F)=>{console.error("Unhandled exception in App:",F)})}useViewRouter(){let z=this.kernel.services[U._name];if(!z)throw Error("ViewRouterServiceContainer is not registered \u2014 was the kernel booted?");return z}getComponentTree(){return this.useViewRouter().componentTree}getFlatComponentTree(){return this.useViewRouter().flatComponentTree}getRouteManifest(){return this.useViewRouter().routeManifest}async fetch(z){let F=new URL(z.url);return this.kernel.run.call(this.kernel,async()=>{if(F.pathname.startsWith("/api"))return await X.use().handleApiRequest(z);return await U.use().handleViewRequest(z)})}websocket={message:(z,F)=>{this.kernel.run.bind(this.kernel)(()=>{L.use().run(z.data.headers,()=>{L.use().handleMessage(z,F)})})},open:(z)=>{},close:(z)=>{console.log("closed ws"),z.terminate()}};onPublish(z){this.kernel.run.bind(this.kernel)(()=>{L.use().onPublish(z)})}dispatchJob(z,F){return this.kernel.run.bind(this.kernel)(()=>{return Y.use().dispatchJob(z,F)})}destroy(){this.kernel.destroy()}clone(){return Object.assign(Object.create(Object.getPrototypeOf(this)),this)}}var j=S(b(),1),P=j.Prisma.defineExtension({name:"Gemi Policies",query:{async $allOperations({args:z,operation:F,query:G,model:T}){return await G(z)}}});export{Z as o,P as p};
2
+ import{N as U,O as X,s as L}from"./chunk-d9k245jt.js";import{Ob as Y}from"./chunk-xkrthw08.js";import{fc as S,gc as $}from"./chunk-f18weffa.js";var K=$((u,I)=>{var{defineProperty:W,getOwnPropertyDescriptor:J,getOwnPropertyNames:Q}=Object,B=Object.prototype.hasOwnProperty,E=(z,F)=>{for(var G in F)W(z,G,{get:F[G],enumerable:!0})},N=(z,F,G,T)=>{if(F&&typeof F==="object"||typeof F==="function"){for(let H of Q(F))if(!B.call(z,H)&&H!==G)W(z,H,{get:()=>F[H],enumerable:!(T=J(F,H))||T.enumerable})}return z},O=(z)=>N(W({},"__esModule",{value:!0}),z),A={};E(A,{Prisma:()=>D,PrismaClient:()=>k,default:()=>v});I.exports=O(A);var R={enginesVersion:"c2990dca591cba766e3b7ef5d9e8a84796e47ab7"},V="6.19.2",h=V,k=class{constructor(){throw Error('@prisma/client did not initialize yet. Please run "prisma generate" and try to import it again.')}};function q(z){if(typeof z==="function")return z;return(F)=>F.$extends(z)}function y(z){return z}var D={defineExtension:q,getExtensionContext:y,prismaVersion:{client:h,engine:R.enginesVersion}},v={Prisma:D}});var b=$((d,M)=>{M.exports={...K()}});class Z{kernel;onException;constructor(z){this.kernel=new z.kernel,this.kernel.boot.call(this.kernel),this.onException=z.onException??((F)=>{console.error("Unhandled exception in App:",F)})}useViewRouter(){let z=this.kernel.services[U._name];if(!z)throw Error("ViewRouterServiceContainer is not registered \u2014 was the kernel booted?");return z}getComponentTree(){return this.useViewRouter().componentTree}getFlatComponentTree(){return this.useViewRouter().flatComponentTree}getRouteManifest(){return this.useViewRouter().routeManifest}async fetch(z){let F=new URL(z.url);return this.kernel.run.call(this.kernel,async()=>{if(F.pathname.startsWith("/api"))return await X.use().handleApiRequest(z);return await U.use().handleViewRequest(z)})}websocket={message:(z,F)=>{this.kernel.run.bind(this.kernel)(()=>{L.use().run(z.data.headers,()=>{L.use().handleMessage(z,F)})})},open:(z)=>{},close:(z)=>{console.log("closed ws"),z.terminate()}};onPublish(z){this.kernel.run.bind(this.kernel)(()=>{L.use().onPublish(z)})}dispatchJob(z,F){return this.kernel.run.bind(this.kernel)(()=>{return Y.use().dispatchJob(z,F)})}destroy(){this.kernel.destroy()}clone(){return Object.assign(Object.create(Object.getPrototypeOf(this)),this)}}var j=S(b(),1),P=j.Prisma.defineExtension({name:"Gemi Policies",query:{async $allOperations({args:z,operation:F,query:G,model:T}){return await G(z)}}});export{Z as o,P as p};
3
3
 
4
4
  //# debugId=52D517464DBD54BE64756E2164756E21
@@ -1,5 +1,5 @@
1
1
  // @bun
2
- import{g as I,i as f}from"./chunk-tvp3xgfq.js";import{j as b,k as y}from"./chunk-ghes36xj.js";import"./chunk-vv72kw74.js";import"./chunk-ppt296ye.js";import"./chunk-ppn0j67g.js";import"./chunk-jxpwexpz.js";import"./chunk-atv6nybp.js";import"./chunk-p5r0t9jh.js";import"./chunk-xkrthw08.js";import"./chunk-4z53shav.js";import"./chunk-m0earq80.js";import"./chunk-f18weffa.js";import{IncomingMessage as w,ServerResponse as N}from"http";import{Socket as T}from"net";import{join as g}from"path";import{createServer as E}from"vite";function S(H){return H.replace(/\x1b\[[0-9;]*m/g,"").replace(/\[[0-9;]*m/g,"").replace(/\n\s*\n/g,`
2
+ import{g as I,i as f}from"./chunk-2ahct6kg.js";import{j as b,k as y}from"./chunk-ghes36xj.js";import"./chunk-vv72kw74.js";import"./chunk-ppt296ye.js";import"./chunk-r64ba1pf.js";import"./chunk-d9k245jt.js";import"./chunk-evkv0xa7.js";import"./chunk-p5r0t9jh.js";import"./chunk-xkrthw08.js";import"./chunk-4z53shav.js";import"./chunk-m0earq80.js";import"./chunk-f18weffa.js";import{IncomingMessage as w,ServerResponse as N}from"http";import{Socket as T}from"net";import{join as g}from"path";import{createServer as E}from"vite";function S(H){return H.replace(/\x1b\[[0-9;]*m/g,"").replace(/\[[0-9;]*m/g,"").replace(/\n\s*\n/g,`
3
3
  `).split(`
4
4
  `).map((J)=>J.trim()).filter((J)=>J.length>0).join(`
5
5
  `).trim()}function P(H){return`
@@ -1 +1 @@
1
- {"version":3,"file":"ClientRouter.d.ts","sourceRoot":"","sources":["../../client/ClientRouter.tsx"],"names":[],"mappings":"AASA,OAAO,KAAK,EAAqB,SAAS,EAAE,aAAa,EAAE,IAAI,EAAE,MAAM,OAAO,CAAC;AAyB/E,OAAO,CAAC,MAAM,CAAC;IACb,UAAU,MAAM;QACd,aAAa,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;QACnC,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,IAAI,CAAC,CAAC;KACrC;CACF;AA2PD,eAAO,MAAM,YAAY,GAAI,OAAO;IAClC,aAAa,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,UAAU,CAAC,OAAO,IAAI,CAAC,CAAC,CAAC;IACxD,UAAU,EAAE,aAAa,CAAC;QAAE,QAAQ,EAAE,SAAS,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;CACpE,4CA2CA,CAAC"}
1
+ {"version":3,"file":"ClientRouter.d.ts","sourceRoot":"","sources":["../../client/ClientRouter.tsx"],"names":[],"mappings":"AAUA,OAAO,KAAK,EAAqB,SAAS,EAAE,aAAa,EAAE,IAAI,EAAE,MAAM,OAAO,CAAC;AAkC/E,OAAO,CAAC,MAAM,CAAC;IACb,UAAU,MAAM;QACd,aAAa,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;QACnC,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,IAAI,CAAC,CAAC;KACrC;CACF;AAuSD,eAAO,MAAM,YAAY,GAAI,OAAO;IAClC,aAAa,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,UAAU,CAAC,OAAO,IAAI,CAAC,CAAC,CAAC;IACxD,UAAU,EAAE,aAAa,CAAC;QAAE,QAAQ,EAAE,SAAS,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;CACpE,4CA2CA,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"Head.d.ts","sourceRoot":"","sources":["../../client/Head.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,SAAS,EAAc,MAAM,OAAO,CAAC;AAGnD,wBAAgB,UAAU,CAAC,IAAI,EAAE,GAAG,QAgBnC;AAmED,eAAO,MAAM,IAAI,GAAI,wBAGlB;IAAE,QAAQ,CAAC,EAAE,SAAS,CAAC;IAAC,OAAO,CAAC,EAAE,MAAM,CAAA;CAAE,4CAuB5C,CAAC"}
1
+ {"version":3,"file":"Head.d.ts","sourceRoot":"","sources":["../../client/Head.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,SAAS,EAAc,MAAM,OAAO,CAAC;AAGnD,wBAAgB,UAAU,CAAC,IAAI,EAAE,GAAG,QAqBnC;AAmED,eAAO,MAAM,IAAI,GAAI,wBAGlB;IAAE,QAAQ,CAAC,EAAE,SAAS,CAAC;IAAC,OAAO,CAAC,EAAE,MAAM,CAAA;CAAE,4CAuB5C,CAAC"}
@@ -1,7 +1,10 @@
1
1
  import { type PropsWithChildren } from "react";
2
2
  import { QueryResource } from "./QueryResource";
3
- export declare const QueryManagerContext: import("react").Context<{
3
+ export type PrefetchedData = Record<string, Record<string, any>>;
4
+ export interface QueryManagerContextValue {
4
5
  getResource: (key: string, initialState?: Record<string, any>) => QueryResource;
5
- }>;
6
+ hydrate: (prefetchedData?: PrefetchedData | null) => void;
7
+ }
8
+ export declare const QueryManagerContext: import("react").Context<QueryManagerContextValue>;
6
9
  export declare const QueryManagerProvider: ({ children }: PropsWithChildren<{}>) => import("react/jsx-runtime").JSX.Element;
7
10
  //# sourceMappingURL=QueryManagerContext.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"QueryManagerContext.d.ts","sourceRoot":"","sources":["../../client/QueryManagerContext.tsx"],"names":[],"mappings":"AAAA,OAAO,EAEL,KAAK,iBAAiB,EAGvB,MAAM,OAAO,CAAC;AACf,OAAO,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAEhD,eAAO,MAAM,mBAAmB;uBACX,MAAM,iBAAgB,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC;EAG5D,CAAC;AAEH,eAAO,MAAM,oBAAoB,GAAI,cAAc,iBAAiB,CAAC,EAAE,CAAC,4CAoBvE,CAAC"}
1
+ {"version":3,"file":"QueryManagerContext.d.ts","sourceRoot":"","sources":["../../client/QueryManagerContext.tsx"],"names":[],"mappings":"AAAA,OAAO,EAEL,KAAK,iBAAiB,EAIvB,MAAM,OAAO,CAAC;AACf,OAAO,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAEhD,MAAM,MAAM,cAAc,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC,CAAC;AAEjE,MAAM,WAAW,wBAAwB;IACvC,WAAW,EAAE,CACX,GAAG,EAAE,MAAM,EACX,YAAY,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,KAC/B,aAAa,CAAC;IACnB,OAAO,EAAE,CAAC,cAAc,CAAC,EAAE,cAAc,GAAG,IAAI,KAAK,IAAI,CAAC;CAC3D;AAED,eAAO,MAAM,mBAAmB,mDAK9B,CAAC;AAEH,eAAO,MAAM,oBAAoB,GAAI,cAAc,iBAAiB,CAAC,EAAE,CAAC,4CA0CvE,CAAC"}
@@ -5,13 +5,35 @@ type State = {
5
5
  error: any;
6
6
  version: number;
7
7
  };
8
+ export declare const DEFAULT_STALE_TIME = 5000;
8
9
  export declare class QueryResource {
9
10
  store: Subject<Map<string, State>>;
10
11
  staleVariants: Set<string>;
11
12
  lastFetchRecord: Map<string, number>;
12
13
  key: string;
13
14
  constructor(key: string, initialState: Record<string, any>);
14
- getVariant(variantKey: string): State;
15
+ /**
16
+ * Adopt server-prefetched data into the cache.
17
+ *
18
+ * Called once from the constructor for the SSR payload, and again on every
19
+ * client-side navigation with the `prefetchedData` the server just produced —
20
+ * otherwise the resource cache (which is keyed by path for the lifetime of
21
+ * the app) would keep serving the first payload and revalidate it over `/api`.
22
+ */
23
+ hydrate(initialState: Record<string, any> | null | undefined): void;
24
+ /**
25
+ * The cached state for a variant, or `undefined` — a plain read that never
26
+ * fetches and never revalidates.
27
+ *
28
+ * `getVariant` is the read that keeps the cache honest, and it starts a
29
+ * request when it has to. That makes it the wrong thing to call while
30
+ * rendering: React throws away a render whose subtree suspends and retries
31
+ * it, so every discarded attempt would leak a request. Renders read with
32
+ * this; effects, which only run for a render that committed, use
33
+ * `getVariant`.
34
+ */
35
+ peek(variantKey: string): State;
36
+ getVariant(variantKey: string, staleTime?: number): State;
15
37
  mutate(variantKey: string, fn?: (data: any) => any): void;
16
38
  refetch(variantKey: string): void;
17
39
  private resolveVariant;
@@ -1 +1 @@
1
- {"version":3,"file":"QueryResource.d.ts","sourceRoot":"","sources":["../../client/QueryResource.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,kBAAkB,CAAC;AAE3C,KAAK,KAAK,GAAG;IACX,OAAO,EAAE,OAAO,CAAC;IACjB,IAAI,EAAE,GAAG,CAAC;IACV,KAAK,EAAE,GAAG,CAAC;IACX,OAAO,EAAE,MAAM,CAAC;CACjB,CAAC;AAEF,qBAAa,aAAa;IACxB,KAAK,EAAE,OAAO,CAAC,GAAG,CAAC,MAAM,EAAE,KAAK,CAAC,CAAC,CAAC;IACnC,aAAa,cAAqB;IAClC,eAAe,sBAA6B;IAC5C,GAAG,EAAE,MAAM,CAAC;gBAEA,GAAG,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC;IAkB1D,UAAU,CAAC,UAAU,EAAE,MAAM;IA8B7B,MAAM,CAAC,UAAU,EAAE,MAAM,EAAE,EAAE,GAAE,CAAC,IAAI,EAAE,GAAG,KAAK,GAAoB;IAuClE,OAAO,CAAC,UAAU,EAAE,MAAM;YAIZ,cAAc;CAgE7B"}
1
+ {"version":3,"file":"QueryResource.d.ts","sourceRoot":"","sources":["../../client/QueryResource.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,kBAAkB,CAAC;AAE3C,KAAK,KAAK,GAAG;IACX,OAAO,EAAE,OAAO,CAAC;IACjB,IAAI,EAAE,GAAG,CAAC;IACV,KAAK,EAAE,GAAG,CAAC;IACX,OAAO,EAAE,MAAM,CAAC;CACjB,CAAC;AAEF,eAAO,MAAM,kBAAkB,OAAO,CAAC;AAEvC,qBAAa,aAAa;IACxB,KAAK,EAAE,OAAO,CAAC,GAAG,CAAC,MAAM,EAAE,KAAK,CAAC,CAAC,CAAC;IACnC,aAAa,cAAqB;IAClC,eAAe,sBAA6B;IAC5C,GAAG,EAAE,MAAM,CAAC;gBAEA,GAAG,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC;IAM1D;;;;;;;OAOG;IACH,OAAO,CAAC,YAAY,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,IAAI,GAAG,SAAS;IA+B5D;;;;;;;;;;OAUG;IACH,IAAI,CAAC,UAAU,EAAE,MAAM;IAIvB,UAAU,CAAC,UAAU,EAAE,MAAM,EAAE,SAAS,GAAE,MAA2B;IA+BrE,MAAM,CAAC,UAAU,EAAE,MAAM,EAAE,EAAE,GAAE,CAAC,IAAI,EAAE,GAAG,KAAK,GAAoB;IAuClE,OAAO,CAAC,UAAU,EAAE,MAAM;YAIZ,cAAc;CAgE7B"}
@@ -0,0 +1,23 @@
1
+ import type { Breadcrumb } from "../useBreadcrumbs";
2
+ interface RouteSnapshot {
3
+ /** Concrete pathname, without the locale segment. */
4
+ pathname: string;
5
+ /** Route pattern the data was produced for — part of every breadcrumb key. */
6
+ routePath: string;
7
+ data: Record<string, any>;
8
+ breadcrumbs: Record<string, Breadcrumb>;
9
+ }
10
+ /**
11
+ * A partially rendered response only carries the segments the server actually
12
+ * ran. Everything is keyed by the *new* pathname, so a carried layout would
13
+ * render with empty props unless the data it already had is copied across.
14
+ *
15
+ * Data the server sent always wins: a carried view is only filled in where the
16
+ * response has nothing for it.
17
+ */
18
+ export declare function mergeCarriedSegments(previous: RouteSnapshot, next: RouteSnapshot, carriedViews: string[]): {
19
+ data: Record<string, any>;
20
+ breadcrumbs: Record<string, Breadcrumb>;
21
+ };
22
+ export {};
23
+ //# sourceMappingURL=mergeCarriedSegments.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mergeCarriedSegments.d.ts","sourceRoot":"","sources":["../../../client/helpers/mergeCarriedSegments.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AAEpD,UAAU,aAAa;IACrB,qDAAqD;IACrD,QAAQ,EAAE,MAAM,CAAC;IACjB,8EAA8E;IAC9E,SAAS,EAAE,MAAM,CAAC;IAClB,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;IAC1B,WAAW,EAAE,MAAM,CAAC,MAAM,EAAE,UAAU,CAAC,CAAC;CACzC;AAED;;;;;;;GAOG;AACH,wBAAgB,oBAAoB,CAClC,QAAQ,EAAE,aAAa,EACvB,IAAI,EAAE,aAAa,EACnB,YAAY,EAAE,MAAM,EAAE;;;EAwCvB"}
@@ -25,6 +25,7 @@ var Subject = class {
25
25
  };
26
26
  //#endregion
27
27
  //#region client/QueryResource.ts
28
+ var DEFAULT_STALE_TIME = 5e3;
28
29
  var QueryResource = class {
29
30
  store;
30
31
  staleVariants = /* @__PURE__ */ new Set();
@@ -32,19 +33,53 @@ var QueryResource = class {
32
33
  key;
33
34
  constructor(key, initialState) {
34
35
  this.key = key;
35
- const store = /* @__PURE__ */ new Map();
36
+ this.store = new Subject(/* @__PURE__ */ new Map());
37
+ this.hydrate(initialState);
38
+ }
39
+ /**
40
+ * Adopt server-prefetched data into the cache.
41
+ *
42
+ * Called once from the constructor for the SSR payload, and again on every
43
+ * client-side navigation with the `prefetchedData` the server just produced —
44
+ * otherwise the resource cache (which is keyed by path for the lifetime of
45
+ * the app) would keep serving the first payload and revalidate it over `/api`.
46
+ */
47
+ hydrate(initialState) {
48
+ const store = this.store.getValue();
36
49
  const now = Date.now();
37
- for (const [variantKey, data] of Object.entries(initialState ?? {})) if (data) {
50
+ let changed = false;
51
+ for (const [variantKey, data] of Object.entries(initialState ?? {})) {
52
+ if (!data) continue;
53
+ const current = store.get(variantKey);
54
+ if (current?.loading) continue;
55
+ if (current && current.data === data) continue;
38
56
  store.set(variantKey, {
39
57
  loading: false,
40
58
  data,
41
- error: null
59
+ error: null,
60
+ version: now
42
61
  });
62
+ this.staleVariants.delete(variantKey);
43
63
  this.lastFetchRecord.set(variantKey, now);
64
+ changed = true;
44
65
  }
45
- this.store = new Subject(store);
66
+ if (changed) this.store.next(store);
67
+ }
68
+ /**
69
+ * The cached state for a variant, or `undefined` — a plain read that never
70
+ * fetches and never revalidates.
71
+ *
72
+ * `getVariant` is the read that keeps the cache honest, and it starts a
73
+ * request when it has to. That makes it the wrong thing to call while
74
+ * rendering: React throws away a render whose subtree suspends and retries
75
+ * it, so every discarded attempt would leak a request. Renders read with
76
+ * this; effects, which only run for a render that committed, use
77
+ * `getVariant`.
78
+ */
79
+ peek(variantKey) {
80
+ return this.store.getValue().get(variantKey);
46
81
  }
47
- getVariant(variantKey) {
82
+ getVariant(variantKey, staleTime = DEFAULT_STALE_TIME) {
48
83
  const store = this.store.getValue();
49
84
  if (!store.has(variantKey)) this.resolveVariant(variantKey);
50
85
  else {
@@ -57,7 +92,7 @@ var QueryResource = class {
57
92
  if (variant.data) {
58
93
  const stale = this.staleVariants.has(variantKey);
59
94
  const now = Date.now();
60
- const old = now - (this.lastFetchRecord.get(variantKey) ?? now) > 5e3;
95
+ const old = now - (this.lastFetchRecord.get(variantKey) ?? now) >= staleTime;
61
96
  if (stale || old) {
62
97
  this.lastFetchRecord.set(variantKey, now);
63
98
  this.resolveVariant(variantKey, true);
@@ -141,16 +176,37 @@ var QueryResource = class {
141
176
  };
142
177
  //#endregion
143
178
  //#region client/QueryManagerContext.tsx
144
- var QueryManagerContext = createContext({ getResource: (key, initialState = {}) => {
145
- return new QueryResource(key, initialState);
146
- } });
179
+ var QueryManagerContext = createContext({
180
+ getResource: (key, initialState = {}) => {
181
+ return new QueryResource(key, initialState);
182
+ },
183
+ hydrate: () => {}
184
+ });
147
185
  var QueryManagerProvider = ({ children }) => {
148
186
  const resourcesRef = useRef(/* @__PURE__ */ new Map());
187
+ const getResource = useCallback((key, initialState) => {
188
+ let resource = resourcesRef.current.get(key);
189
+ if (!resource) {
190
+ resource = new QueryResource(key, initialState ?? {});
191
+ resourcesRef.current.set(key, resource);
192
+ }
193
+ return resource;
194
+ }, []);
195
+ const hydrate = useCallback((prefetchedData) => {
196
+ if (!prefetchedData) return;
197
+ for (const [key, initialState] of Object.entries(prefetchedData)) {
198
+ if (!initialState || typeof initialState !== "object") continue;
199
+ const resource = resourcesRef.current.get(key);
200
+ if (resource) resource.hydrate(initialState);
201
+ else resourcesRef.current.set(key, new QueryResource(key, initialState));
202
+ }
203
+ }, []);
204
+ const value = useMemo(() => ({
205
+ getResource,
206
+ hydrate
207
+ }), [getResource, hydrate]);
149
208
  return /* @__PURE__ */ jsx(QueryManagerContext.Provider, {
150
- value: { getResource: (key, initialState) => {
151
- if (!resourcesRef.current.has(key)) resourcesRef.current.set(key, new QueryResource(key, initialState ?? {}));
152
- return resourcesRef.current.get(key);
153
- } },
209
+ value,
154
210
  children
155
211
  });
156
212
  };
@@ -213,6 +269,7 @@ var defaultConfig = {
213
269
  keepPreviousData: true,
214
270
  retryIntervalOnError: 1e4,
215
271
  refreshInterval: 999999,
272
+ staleTime: DEFAULT_STALE_TIME,
216
273
  debug: false,
217
274
  lazy: false
218
275
  };
@@ -264,22 +321,23 @@ function useQuery(url, ...args) {
264
321
  error: null,
265
322
  version: 0
266
323
  };
267
- return resource.getVariant(variantKey);
324
+ return resource.peek(variantKey);
268
325
  });
269
326
  const retry = useCallback((vk) => {
270
327
  if (!retryingMap.current.get(vk)) {
271
328
  if (configRef.current.debug) console.log("retrying", vk);
272
329
  retryingMap.current.set(vk, true);
273
330
  retryIntervalRef.current = setTimeout(() => {
274
- resource.getVariant(vk);
331
+ resource.getVariant(vk, configRef.current.staleTime);
275
332
  retryingMap.current.set(vk, false);
276
333
  }, configRef.current.retryIntervalOnError);
277
334
  }
278
335
  }, [resource]);
279
336
  useEffect(() => {
280
337
  if (paramsKey !== paramsRef.current) {
281
- setResource(getResource(normalPath));
282
- if (fetchedRef.current) setState(resource.getVariant(variantKey));
338
+ const nextResource = getResource(normalPath, fallbackData);
339
+ setResource(nextResource);
340
+ if (fetchedRef.current) setState(nextResource.getVariant(variantKey, configRef.current.staleTime));
283
341
  paramsRef.current = paramsKey;
284
342
  }
285
343
  }, [
@@ -287,11 +345,11 @@ function useQuery(url, ...args) {
287
345
  normalPath,
288
346
  variantKey,
289
347
  getResource,
290
- resource
348
+ fallbackData
291
349
  ]);
292
350
  const handleReload = useCallback(() => {
293
351
  if (configRef.current.debug) console.log("Reloading query for", variantKey);
294
- const data = resource.getVariant(variantKey).data;
352
+ const data = resource.getVariant(variantKey, configRef.current.staleTime).data;
295
353
  resource.mutate(variantKey, () => data);
296
354
  }, [variantKey, resource]);
297
355
  useEffect(() => {
@@ -337,7 +395,7 @@ function useQuery(url, ...args) {
337
395
  resource
338
396
  ]);
339
397
  useEffect(() => {
340
- if (fetchedRef.current) handleStateUpdate(resource.getVariant(variantKey));
398
+ if (fetchedRef.current) handleStateUpdate(resource.getVariant(variantKey, configRef.current.staleTime));
341
399
  const unsub = resource.store.subscribe((store) => {
342
400
  const variant = store.get(variantKey);
343
401
  if (variant) handleStateUpdate(variant);
@@ -2610,6 +2668,7 @@ var WebSocketContextProvider = (props) => {
2610
2668
  //#endregion
2611
2669
  //#region client/Head.tsx
2612
2670
  function updateMeta(meta) {
2671
+ if (!meta) return;
2613
2672
  const { title, description } = meta;
2614
2673
  if (title) document.title = title;
2615
2674
  if (description) {
@@ -2745,6 +2804,66 @@ function useTheme() {
2745
2804
  return context;
2746
2805
  }
2747
2806
  //#endregion
2807
+ //#region utils/partialRender.ts
2808
+ /**
2809
+ * Route the client is currently rendering, sent on `.json` navigations so the
2810
+ * server can skip the handlers of the segments that route already has mounted.
2811
+ * Value is a locale-less pathname plus search, e.g. `/app/A/chat?tab=2`.
2812
+ */
2813
+ var PARTIAL_RENDER_HEADER = "x-gemi-from";
2814
+ /**
2815
+ * The `x-gemi-from` value for the route the client starts on.
2816
+ *
2817
+ * On the first render the router's `pathname` is still the route *pattern* the
2818
+ * server matched — it only becomes a resolved path once the history listener
2819
+ * has run — so this has to apply the params. Sending `/app/:orgId/chat` names
2820
+ * no route the server can resolve, and the first navigation after every full
2821
+ * page load would skip nothing.
2822
+ */
2823
+ function initialRenderedRoute(route) {
2824
+ return `${applyParams$1(route.pathname ?? "/", route.params ?? {}) || "/"}${route.search ?? ""}`;
2825
+ }
2826
+ //#endregion
2827
+ //#region client/helpers/mergeCarriedSegments.ts
2828
+ /**
2829
+ * A partially rendered response only carries the segments the server actually
2830
+ * ran. Everything is keyed by the *new* pathname, so a carried layout would
2831
+ * render with empty props unless the data it already had is copied across.
2832
+ *
2833
+ * Data the server sent always wins: a carried view is only filled in where the
2834
+ * response has nothing for it.
2835
+ */
2836
+ function mergeCarriedSegments(previous, next, carriedViews) {
2837
+ if (carriedViews.length === 0) return {
2838
+ data: next.data,
2839
+ breadcrumbs: next.breadcrumbs
2840
+ };
2841
+ const previousData = previous.data ?? {};
2842
+ const previousViewData = previousData[previous.pathname] ?? previousData[Object.keys(previousData)[0]] ?? {};
2843
+ const previousBreadcrumbs = previous.breadcrumbs ?? {};
2844
+ const carriedViewData = {};
2845
+ const carriedBreadcrumbs = {};
2846
+ for (const viewPath of carriedViews) {
2847
+ if (viewPath in previousViewData) carriedViewData[viewPath] = previousViewData[viewPath];
2848
+ const previousKey = `${viewPath}:${previous.routePath}`;
2849
+ if (previousKey in previousBreadcrumbs) carriedBreadcrumbs[`${viewPath}:${next.routePath}`] = previousBreadcrumbs[previousKey];
2850
+ }
2851
+ const [nextKey = next.pathname] = Object.keys(next.data ?? {});
2852
+ return {
2853
+ data: {
2854
+ ...next.data,
2855
+ [nextKey]: {
2856
+ ...carriedViewData,
2857
+ ...next.data?.[nextKey]
2858
+ }
2859
+ },
2860
+ breadcrumbs: {
2861
+ ...carriedBreadcrumbs,
2862
+ ...next.breadcrumbs
2863
+ }
2864
+ };
2865
+ }
2866
+ //#endregion
2748
2867
  //#region client/ClientRouter.tsx
2749
2868
  function restoreScroll(action = null, _pathname = "no path") {
2750
2869
  if (action === null) return;
@@ -2811,6 +2930,7 @@ var Routes = (props) => {
2811
2930
  const [isPending, startTransition] = useTransition();
2812
2931
  const [isFetching, setIsFetching] = useState(false);
2813
2932
  const { routerSubject, fetchRouteCSS } = useContext(ClientRouterContext);
2933
+ const { hydrate } = useContext(QueryManagerContext);
2814
2934
  const [transitionPath, setTransitionPath] = useState([null, routerSubject?.getValue().pathname]);
2815
2935
  const { breadcrumbs, pageData, i18n, prefetchedData, appId: currentAppId } = useContext(ServerDataContext);
2816
2936
  const [routeState, setRouteState] = useState({
@@ -2830,6 +2950,10 @@ var Routes = (props) => {
2830
2950
  appId: currentAppId
2831
2951
  });
2832
2952
  const { replace } = useNavigate();
2953
+ useEffect(() => {
2954
+ hydrate(prefetchedData);
2955
+ }, [hydrate, prefetchedData]);
2956
+ const renderedRouteRef = useRef(initialRenderedRoute(routeState));
2833
2957
  useEffect(() => {
2834
2958
  return routerSubject?.subscribe(async (routerState) => {
2835
2959
  const { pathname, search, state, views } = routerState;
@@ -2853,6 +2977,7 @@ var Routes = (props) => {
2853
2977
  }
2854
2978
  const localeSegment = routerState.locale ? `/${routerState.locale}` : "";
2855
2979
  const url = `${`${localeSegment}${localeSegment.length > 0 && pathname === "/" ? "" : pathname}`}.json${search}`;
2980
+ const from = renderedRouteRef.current;
2856
2981
  setIsFetching(true);
2857
2982
  let res = {
2858
2983
  ok: false,
@@ -2860,7 +2985,7 @@ var Routes = (props) => {
2860
2985
  };
2861
2986
  try {
2862
2987
  res = (await Promise.all([
2863
- fetch(url),
2988
+ fetch(url, { headers: { [PARTIAL_RENDER_HEADER]: from } }),
2864
2989
  fetchRouteCSS(pathname),
2865
2990
  ...views.map((component) => {
2866
2991
  if (!window?.loaders) return Promise.resolve();
@@ -2871,7 +2996,15 @@ var Routes = (props) => {
2871
2996
  console.error(e);
2872
2997
  }
2873
2998
  if (res.ok) {
2874
- const { data, i18n, prefetchedData, breadcrumbs, meta, directive = {}, is404 = false, appId } = await res.json();
2999
+ let payload = await res.json();
3000
+ const claimed = payload.partial ?? null;
3001
+ if (claimed && claimed.from !== renderedRouteRef.current) try {
3002
+ const full = await fetch(url);
3003
+ if (full.ok) payload = await full.json();
3004
+ } catch (e) {
3005
+ console.error(e);
3006
+ }
3007
+ const { data, i18n, prefetchedData, breadcrumbs, meta, directive = {}, is404 = false, appId } = payload;
2875
3008
  updateMeta(meta);
2876
3009
  if (directive?.kind === "Redirect") {
2877
3010
  if (directive?.path) replace(directive.path, { params: {} });
@@ -2884,15 +3017,22 @@ var Routes = (props) => {
2884
3017
  views: ["404"]
2885
3018
  }));
2886
3019
  });
3020
+ const carriedViews = payload.partial?.carriedViews ?? [];
3021
+ renderedRouteRef.current = `${pathname}${search}`;
3022
+ hydrate(prefetchedData);
2887
3023
  startTransition(() => {
2888
- setRouteState({
3024
+ setRouteState((state) => ({
2889
3025
  ...routerState,
2890
3026
  appId,
2891
- data,
2892
3027
  i18n,
2893
3028
  prefetchedData,
2894
- breadcrumbs
2895
- });
3029
+ ...mergeCarriedSegments(state, {
3030
+ pathname,
3031
+ routePath: routerState.routePath,
3032
+ data,
3033
+ breadcrumbs
3034
+ }, carriedViews)
3035
+ }));
2896
3036
  });
2897
3037
  }
2898
3038
  setIsFetching(false);
@@ -2900,7 +3040,8 @@ var Routes = (props) => {
2900
3040
  }, [
2901
3041
  routerSubject,
2902
3042
  fetchRouteCSS,
2903
- replace
3043
+ replace,
3044
+ hydrate
2904
3045
  ]);
2905
3046
  return /* @__PURE__ */ jsx(RouteTransitionProvider, {
2906
3047
  isPending,