gemi 0.45.0 → 0.46.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 (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-3ervqphj.js} +2 -2
  5. package/dist/{chunk-tvp3xgfq.js.map → chunk-3ervqphj.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-396qq8ge.js → chunk-qmsngk2y.js} +1 -1
  13. package/dist/{chunk-ppn0j67g.js → chunk-r64ba1pf.js} +1 -1
  14. package/dist/{chunk-63gmzy5r.js → chunk-zp9ybbp6.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 +173 -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-396qq8ge.js.map → chunk-qmsngk2y.js.map} +0 -0
  52. /package/dist/{chunk-ppn0j67g.js.map → chunk-r64ba1pf.js.map} +0 -0
  53. /package/dist/{chunk-63gmzy5r.js.map → chunk-zp9ybbp6.js.map} +0 -0
@@ -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-3ervqphj.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,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{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-3ervqphj.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 +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,28 @@ function useQuery(url, ...args) {
264
321
  error: null,
265
322
  version: 0
266
323
  };
267
- return resource.getVariant(variantKey);
324
+ return resource.peek(variantKey) ?? {
325
+ loading: true,
326
+ data: null,
327
+ error: null,
328
+ version: 0
329
+ };
268
330
  });
269
331
  const retry = useCallback((vk) => {
270
332
  if (!retryingMap.current.get(vk)) {
271
333
  if (configRef.current.debug) console.log("retrying", vk);
272
334
  retryingMap.current.set(vk, true);
273
335
  retryIntervalRef.current = setTimeout(() => {
274
- resource.getVariant(vk);
336
+ resource.getVariant(vk, configRef.current.staleTime);
275
337
  retryingMap.current.set(vk, false);
276
338
  }, configRef.current.retryIntervalOnError);
277
339
  }
278
340
  }, [resource]);
279
341
  useEffect(() => {
280
342
  if (paramsKey !== paramsRef.current) {
281
- setResource(getResource(normalPath));
282
- if (fetchedRef.current) setState(resource.getVariant(variantKey));
343
+ const nextResource = getResource(normalPath, fallbackData);
344
+ setResource(nextResource);
345
+ if (fetchedRef.current) setState(nextResource.getVariant(variantKey, configRef.current.staleTime));
283
346
  paramsRef.current = paramsKey;
284
347
  }
285
348
  }, [
@@ -287,11 +350,11 @@ function useQuery(url, ...args) {
287
350
  normalPath,
288
351
  variantKey,
289
352
  getResource,
290
- resource
353
+ fallbackData
291
354
  ]);
292
355
  const handleReload = useCallback(() => {
293
356
  if (configRef.current.debug) console.log("Reloading query for", variantKey);
294
- const data = resource.getVariant(variantKey).data;
357
+ const data = resource.getVariant(variantKey, configRef.current.staleTime).data;
295
358
  resource.mutate(variantKey, () => data);
296
359
  }, [variantKey, resource]);
297
360
  useEffect(() => {
@@ -337,7 +400,7 @@ function useQuery(url, ...args) {
337
400
  resource
338
401
  ]);
339
402
  useEffect(() => {
340
- if (fetchedRef.current) handleStateUpdate(resource.getVariant(variantKey));
403
+ if (fetchedRef.current) handleStateUpdate(resource.getVariant(variantKey, configRef.current.staleTime));
341
404
  const unsub = resource.store.subscribe((store) => {
342
405
  const variant = store.get(variantKey);
343
406
  if (variant) handleStateUpdate(variant);
@@ -2610,6 +2673,7 @@ var WebSocketContextProvider = (props) => {
2610
2673
  //#endregion
2611
2674
  //#region client/Head.tsx
2612
2675
  function updateMeta(meta) {
2676
+ if (!meta) return;
2613
2677
  const { title, description } = meta;
2614
2678
  if (title) document.title = title;
2615
2679
  if (description) {
@@ -2745,6 +2809,66 @@ function useTheme() {
2745
2809
  return context;
2746
2810
  }
2747
2811
  //#endregion
2812
+ //#region utils/partialRender.ts
2813
+ /**
2814
+ * Route the client is currently rendering, sent on `.json` navigations so the
2815
+ * server can skip the handlers of the segments that route already has mounted.
2816
+ * Value is a locale-less pathname plus search, e.g. `/app/A/chat?tab=2`.
2817
+ */
2818
+ var PARTIAL_RENDER_HEADER = "x-gemi-from";
2819
+ /**
2820
+ * The `x-gemi-from` value for the route the client starts on.
2821
+ *
2822
+ * On the first render the router's `pathname` is still the route *pattern* the
2823
+ * server matched — it only becomes a resolved path once the history listener
2824
+ * has run — so this has to apply the params. Sending `/app/:orgId/chat` names
2825
+ * no route the server can resolve, and the first navigation after every full
2826
+ * page load would skip nothing.
2827
+ */
2828
+ function initialRenderedRoute(route) {
2829
+ return `${applyParams$1(route.pathname ?? "/", route.params ?? {}) || "/"}${route.search ?? ""}`;
2830
+ }
2831
+ //#endregion
2832
+ //#region client/helpers/mergeCarriedSegments.ts
2833
+ /**
2834
+ * A partially rendered response only carries the segments the server actually
2835
+ * ran. Everything is keyed by the *new* pathname, so a carried layout would
2836
+ * render with empty props unless the data it already had is copied across.
2837
+ *
2838
+ * Data the server sent always wins: a carried view is only filled in where the
2839
+ * response has nothing for it.
2840
+ */
2841
+ function mergeCarriedSegments(previous, next, carriedViews) {
2842
+ if (carriedViews.length === 0) return {
2843
+ data: next.data,
2844
+ breadcrumbs: next.breadcrumbs
2845
+ };
2846
+ const previousData = previous.data ?? {};
2847
+ const previousViewData = previousData[previous.pathname] ?? previousData[Object.keys(previousData)[0]] ?? {};
2848
+ const previousBreadcrumbs = previous.breadcrumbs ?? {};
2849
+ const carriedViewData = {};
2850
+ const carriedBreadcrumbs = {};
2851
+ for (const viewPath of carriedViews) {
2852
+ if (viewPath in previousViewData) carriedViewData[viewPath] = previousViewData[viewPath];
2853
+ const previousKey = `${viewPath}:${previous.routePath}`;
2854
+ if (previousKey in previousBreadcrumbs) carriedBreadcrumbs[`${viewPath}:${next.routePath}`] = previousBreadcrumbs[previousKey];
2855
+ }
2856
+ const [nextKey = next.pathname] = Object.keys(next.data ?? {});
2857
+ return {
2858
+ data: {
2859
+ ...next.data,
2860
+ [nextKey]: {
2861
+ ...carriedViewData,
2862
+ ...next.data?.[nextKey]
2863
+ }
2864
+ },
2865
+ breadcrumbs: {
2866
+ ...carriedBreadcrumbs,
2867
+ ...next.breadcrumbs
2868
+ }
2869
+ };
2870
+ }
2871
+ //#endregion
2748
2872
  //#region client/ClientRouter.tsx
2749
2873
  function restoreScroll(action = null, _pathname = "no path") {
2750
2874
  if (action === null) return;
@@ -2811,6 +2935,7 @@ var Routes = (props) => {
2811
2935
  const [isPending, startTransition] = useTransition();
2812
2936
  const [isFetching, setIsFetching] = useState(false);
2813
2937
  const { routerSubject, fetchRouteCSS } = useContext(ClientRouterContext);
2938
+ const { hydrate } = useContext(QueryManagerContext);
2814
2939
  const [transitionPath, setTransitionPath] = useState([null, routerSubject?.getValue().pathname]);
2815
2940
  const { breadcrumbs, pageData, i18n, prefetchedData, appId: currentAppId } = useContext(ServerDataContext);
2816
2941
  const [routeState, setRouteState] = useState({
@@ -2830,6 +2955,10 @@ var Routes = (props) => {
2830
2955
  appId: currentAppId
2831
2956
  });
2832
2957
  const { replace } = useNavigate();
2958
+ useEffect(() => {
2959
+ hydrate(prefetchedData);
2960
+ }, [hydrate, prefetchedData]);
2961
+ const renderedRouteRef = useRef(initialRenderedRoute(routeState));
2833
2962
  useEffect(() => {
2834
2963
  return routerSubject?.subscribe(async (routerState) => {
2835
2964
  const { pathname, search, state, views } = routerState;
@@ -2853,6 +2982,7 @@ var Routes = (props) => {
2853
2982
  }
2854
2983
  const localeSegment = routerState.locale ? `/${routerState.locale}` : "";
2855
2984
  const url = `${`${localeSegment}${localeSegment.length > 0 && pathname === "/" ? "" : pathname}`}.json${search}`;
2985
+ const from = renderedRouteRef.current;
2856
2986
  setIsFetching(true);
2857
2987
  let res = {
2858
2988
  ok: false,
@@ -2860,7 +2990,7 @@ var Routes = (props) => {
2860
2990
  };
2861
2991
  try {
2862
2992
  res = (await Promise.all([
2863
- fetch(url),
2993
+ fetch(url, { headers: { [PARTIAL_RENDER_HEADER]: from } }),
2864
2994
  fetchRouteCSS(pathname),
2865
2995
  ...views.map((component) => {
2866
2996
  if (!window?.loaders) return Promise.resolve();
@@ -2871,7 +3001,15 @@ var Routes = (props) => {
2871
3001
  console.error(e);
2872
3002
  }
2873
3003
  if (res.ok) {
2874
- const { data, i18n, prefetchedData, breadcrumbs, meta, directive = {}, is404 = false, appId } = await res.json();
3004
+ let payload = await res.json();
3005
+ const claimed = payload.partial ?? null;
3006
+ if (claimed && claimed.from !== renderedRouteRef.current) try {
3007
+ const full = await fetch(url);
3008
+ if (full.ok) payload = await full.json();
3009
+ } catch (e) {
3010
+ console.error(e);
3011
+ }
3012
+ const { data, i18n, prefetchedData, breadcrumbs, meta, directive = {}, is404 = false, appId } = payload;
2875
3013
  updateMeta(meta);
2876
3014
  if (directive?.kind === "Redirect") {
2877
3015
  if (directive?.path) replace(directive.path, { params: {} });
@@ -2884,15 +3022,22 @@ var Routes = (props) => {
2884
3022
  views: ["404"]
2885
3023
  }));
2886
3024
  });
3025
+ const carriedViews = payload.partial?.carriedViews ?? [];
3026
+ renderedRouteRef.current = `${pathname}${search}`;
3027
+ hydrate(prefetchedData);
2887
3028
  startTransition(() => {
2888
- setRouteState({
3029
+ setRouteState((state) => ({
2889
3030
  ...routerState,
2890
3031
  appId,
2891
- data,
2892
3032
  i18n,
2893
3033
  prefetchedData,
2894
- breadcrumbs
2895
- });
3034
+ ...mergeCarriedSegments(state, {
3035
+ pathname,
3036
+ routePath: routerState.routePath,
3037
+ data,
3038
+ breadcrumbs
3039
+ }, carriedViews)
3040
+ }));
2896
3041
  });
2897
3042
  }
2898
3043
  setIsFetching(false);
@@ -2900,7 +3045,8 @@ var Routes = (props) => {
2900
3045
  }, [
2901
3046
  routerSubject,
2902
3047
  fetchRouteCSS,
2903
- replace
3048
+ replace,
3049
+ hydrate
2904
3050
  ]);
2905
3051
  return /* @__PURE__ */ jsx(RouteTransitionProvider, {
2906
3052
  isPending,