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.
- package/dist/app/index.js +1 -1
- package/dist/bin/gemi.js +185 -49
- package/dist/bin/gemi.js.map +10 -7
- package/dist/{chunk-tvp3xgfq.js → chunk-3ervqphj.js} +2 -2
- package/dist/{chunk-tvp3xgfq.js.map → chunk-3ervqphj.js.map} +1 -1
- package/dist/{chunk-v0qh5dqv.js → chunk-5hggqap1.js} +15 -15
- package/dist/{chunk-v0qh5dqv.js.map → chunk-5hggqap1.js.map} +3 -3
- package/dist/chunk-d9k245jt.js +79 -0
- package/dist/{chunk-jxpwexpz.js.map → chunk-d9k245jt.js.map} +8 -5
- package/dist/chunk-evkv0xa7.js +4 -0
- package/dist/{chunk-atv6nybp.js.map → chunk-evkv0xa7.js.map} +4 -4
- package/dist/{chunk-396qq8ge.js → chunk-qmsngk2y.js} +1 -1
- package/dist/{chunk-ppn0j67g.js → chunk-r64ba1pf.js} +1 -1
- package/dist/{chunk-63gmzy5r.js → chunk-zp9ybbp6.js} +1 -1
- package/dist/client/ClientRouter.d.ts.map +1 -1
- package/dist/client/Head.d.ts.map +1 -1
- package/dist/client/QueryManagerContext.d.ts +5 -2
- package/dist/client/QueryManagerContext.d.ts.map +1 -1
- package/dist/client/QueryResource.d.ts +23 -1
- package/dist/client/QueryResource.d.ts.map +1 -1
- package/dist/client/helpers/mergeCarriedSegments.d.ts +23 -0
- package/dist/client/helpers/mergeCarriedSegments.d.ts.map +1 -0
- package/dist/client/index.js +173 -27
- package/dist/client/index.js.map +1 -1
- package/dist/client/useQuery.d.ts +2 -0
- package/dist/client/useQuery.d.ts.map +1 -1
- package/dist/facades/index.js +1 -1
- package/dist/http/Metadata.d.ts +6 -0
- package/dist/http/Metadata.d.ts.map +1 -1
- package/dist/http/ViewRouter.d.ts +12 -0
- package/dist/http/ViewRouter.d.ts.map +1 -1
- package/dist/http/index.js +1 -1
- package/dist/i18n/index.js +1 -1
- package/dist/kernel/index.js +1 -1
- package/dist/server/index.js +1 -1
- package/dist/services/index.js +1 -1
- package/dist/services/router/ViewRouterServiceContainer.d.ts.map +1 -1
- package/dist/services/router/ViewRouterServiceProvider.d.ts +10 -0
- package/dist/services/router/ViewRouterServiceProvider.d.ts.map +1 -1
- package/dist/services/router/createFlatViewRoutes.d.ts +16 -0
- package/dist/services/router/createFlatViewRoutes.d.ts.map +1 -1
- package/dist/services/router/matchViewRoute.d.ts +12 -0
- package/dist/services/router/matchViewRoute.d.ts.map +1 -0
- package/dist/services/router/planPartialRender.d.ts +43 -0
- package/dist/services/router/planPartialRender.d.ts.map +1 -0
- package/dist/utils/partialRender.d.ts +28 -0
- package/dist/utils/partialRender.d.ts.map +1 -0
- package/package.json +1 -1
- package/dist/chunk-atv6nybp.js +0 -4
- package/dist/chunk-jxpwexpz.js +0 -79
- /package/dist/{chunk-396qq8ge.js.map → chunk-qmsngk2y.js.map} +0 -0
- /package/dist/{chunk-ppn0j67g.js.map → chunk-r64ba1pf.js.map} +0 -0
- /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-
|
|
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-
|
|
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-
|
|
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":"
|
|
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,
|
|
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
|
|
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,
|
|
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
|
-
|
|
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;
|
|
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"}
|
package/dist/client/index.js
CHANGED
|
@@ -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
|
-
|
|
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
|
-
|
|
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
|
|
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)
|
|
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({
|
|
145
|
-
|
|
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
|
|
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.
|
|
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
|
-
|
|
282
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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,
|