waku 1.0.0-beta.3 → 1.0.0-beta.4

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 (33) hide show
  1. package/README.md +3 -3
  2. package/dist/lib/utils/prefetch-cache.d.ts +5 -10
  3. package/dist/lib/utils/prefetch-cache.js +6 -19
  4. package/dist/lib/utils/prefetch-cache.js.map +1 -1
  5. package/dist/lib/utils/rsc-stream.js +1 -1
  6. package/dist/lib/utils/rsc-stream.js.map +1 -1
  7. package/dist/minimal/client.d.ts +52 -19
  8. package/dist/minimal/client.js +135 -107
  9. package/dist/minimal/client.js.map +1 -1
  10. package/dist/router/client-utils/build-route-href.d.ts +26 -0
  11. package/dist/router/client-utils/build-route-href.js +61 -0
  12. package/dist/router/client-utils/build-route-href.js.map +1 -0
  13. package/dist/router/client-utils/match-route-params.d.ts +14 -0
  14. package/dist/router/client-utils/match-route-params.js +49 -0
  15. package/dist/router/client-utils/match-route-params.js.map +1 -0
  16. package/dist/router/client.d.ts +32 -25
  17. package/dist/router/client.js +39 -28
  18. package/dist/router/client.js.map +1 -1
  19. package/dist/router/{common.js → common-utils/route-path.js} +1 -3
  20. package/dist/router/common-utils/route-path.js.map +1 -0
  21. package/dist/router/create-pages-utils/inferred-path-types.d.ts +5 -5
  22. package/dist/router/create-pages-utils/inferred-path-types.js.map +1 -1
  23. package/dist/router/create-pages-utils/util-types.js.map +1 -0
  24. package/dist/router/create-pages.js +1 -1
  25. package/dist/router/create-pages.js.map +1 -1
  26. package/dist/router/define-router.js +1 -1
  27. package/dist/router/define-router.js.map +1 -1
  28. package/package.json +2 -2
  29. package/dist/router/common.js.map +0 -1
  30. package/dist/router/util-types.js.map +0 -1
  31. /package/dist/router/{common.d.ts → common-utils/route-path.d.ts} +0 -0
  32. /package/dist/router/{util-types.d.ts → create-pages-utils/util-types.d.ts} +0 -0
  33. /package/dist/router/{util-types.js → create-pages-utils/util-types.js} +0 -0
package/README.md CHANGED
@@ -17,7 +17,7 @@ visit [waku.gg](https://waku.gg) or `npm create waku@latest`
17
17
 
18
18
  ## Getting started
19
19
 
20
- Start a new Waku project with the `create` command for your preferred package manager. It will scaffold a new project with our default [Waku starter](https://github.com/wakujs/waku/tree/main/examples/01_template).
20
+ Start a new Waku project with the `create` command for your preferred package manager. It will scaffold a new project with our default [Waku starter](https://github.com/wakujs/waku-examples/tree/main/fs-router/basic).
21
21
 
22
22
  ```sh
23
23
  npm create waku@latest
@@ -804,11 +804,11 @@ export const Component = () => {
804
804
 
805
805
  The `router` object also contains several methods for programmatic navigation:
806
806
 
807
- - `router.push(to: string)` - navigate to the provided route
807
+ - `router.push(to)` - navigate to the provided route. `to` is a route string, or a structured `{ to, params, search, hash }` target for typed navigation to dynamic routes (see [Typed Routes](https://github.com/wakujs/waku/blob/main/docs/guides/typed-routes.mdx))
808
808
 
809
809
  - `router.prefetch(to: string)` - prefetch the provided route
810
810
 
811
- - `router.replace(to: string)` - replace the current history entry
811
+ - `router.replace(to)` - replace the current history entry (same argument as `push`)
812
812
 
813
813
  - `router.reload()` - reload the current route
814
814
 
@@ -5,16 +5,11 @@ export declare const PREFETCH_LIMIT = 100;
5
5
  export type PrefetchEntry = {
6
6
  rscPath: string;
7
7
  rscParams: unknown;
8
- getElements: (store: never) => unknown;
8
+ elements: unknown;
9
9
  expireAt: number;
10
10
  };
11
- /**
12
- * Decode and cache a prefetch. `getStore` returns the entry's currently bound
13
- * store: the prefetch's now, the navigation's after `consumePrefetchEntry`.
14
- */
15
- export declare const addPrefetchEntry: <Store, Elements>(rscPath: string, rscParams: unknown, store: Store, decode: (getStore: () => Store) => Elements) => void;
11
+ /** Decode and cache a prefetch so a later navigation can reuse the tree. */
12
+ export declare const addPrefetchEntry: <Elements>(rscPath: string, rscParams: unknown, elements: Elements) => void;
16
13
  export declare const hasPrefetchEntry: (rscPath: string, rscParams: unknown) => boolean;
17
- /**
18
- * Consume a fresh prefetch, rebinding its decoded tree to the consumer's store.
19
- */
20
- export declare const consumePrefetchEntry: <Store, Elements>(rscPath: string, rscParams: unknown, store: Store) => Elements | undefined;
14
+ /** Consume a fresh prefetch, returning its eagerly decoded tree. */
15
+ export declare const consumePrefetchEntry: <Elements>(rscPath: string, rscParams: unknown) => Elements | undefined;
@@ -1,30 +1,20 @@
1
1
  // Client-side cache of prefetched navigations: a prefetch decodes the route
2
- // eagerly so a later navigation reuses it without re-fetching. Each entry keeps
3
- // a mutable store so the decoded tree's server actions bind to the consuming
4
- // navigation's store, not the prefetch's. Bounded by a ttl and a max size.
2
+ // eagerly so a later navigation reuses the decoded tree without re-fetching.
3
+ // Bounded by a ttl and a max size.
5
4
  /** How long (ms) a prefetched entry stays usable before it is discarded. */ export const PREFETCH_TTL = 1000 * 60;
6
5
  /** Maximum number of prefetched entries kept at once. */ export const PREFETCH_LIMIT = 100;
7
6
  const getCache = ()=>globalThis.__WAKU_PREFETCHED__ ||= [];
8
7
  const findFreshIndex = (cache, rscPath, rscParams, now)=>cache.findIndex((entry)=>entry.expireAt > now && entry.rscPath === rscPath && // rscParams is intentionally compared by reference.
9
8
  entry.rscParams === rscParams);
10
- /**
11
- * Decode and cache a prefetch. `getStore` returns the entry's currently bound
12
- * store: the prefetch's now, the navigation's after `consumePrefetchEntry`.
13
- */ export const addPrefetchEntry = (rscPath, rscParams, store, decode)=>{
9
+ /** Decode and cache a prefetch so a later navigation can reuse the tree. */ export const addPrefetchEntry = (rscPath, rscParams, elements)=>{
14
10
  const cache = getCache();
15
11
  const now = Date.now();
16
- let currentStore = store;
17
- const elements = decode(()=>currentStore);
18
12
  // Mark as handled so a prefetch that is never consumed stays quiet.
19
13
  Promise.resolve(elements).catch(()=>{});
20
- const getElements = (nextStore)=>{
21
- currentStore = nextStore;
22
- return elements;
23
- };
24
14
  cache.push({
25
15
  rscPath,
26
16
  rscParams,
27
- getElements,
17
+ elements,
28
18
  expireAt: now + PREFETCH_TTL
29
19
  });
30
20
  while(cache.length > 0 && (cache.length > PREFETCH_LIMIT || cache[0].expireAt <= now)){
@@ -35,16 +25,13 @@ export const hasPrefetchEntry = (rscPath, rscParams)=>{
35
25
  const cache = getCache();
36
26
  return findFreshIndex(cache, rscPath, rscParams, Date.now()) >= 0;
37
27
  };
38
- /**
39
- * Consume a fresh prefetch, rebinding its decoded tree to the consumer's store.
40
- */ export const consumePrefetchEntry = (rscPath, rscParams, store)=>{
28
+ /** Consume a fresh prefetch, returning its eagerly decoded tree. */ export const consumePrefetchEntry = (rscPath, rscParams)=>{
41
29
  const cache = getCache();
42
30
  const index = findFreshIndex(cache, rscPath, rscParams, Date.now());
43
31
  if (index < 0) {
44
32
  return undefined;
45
33
  }
46
- const { getElements } = cache.splice(index, 1)[0];
47
- return getElements(store);
34
+ return cache.splice(index, 1)[0].elements;
48
35
  };
49
36
 
50
37
  //# sourceMappingURL=prefetch-cache.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/lib/utils/prefetch-cache.ts"],"sourcesContent":["// Client-side cache of prefetched navigations: a prefetch decodes the route\n// eagerly so a later navigation reuses it without re-fetching. Each entry keeps\n// a mutable store so the decoded tree's server actions bind to the consuming\n// navigation's store, not the prefetch's. Bounded by a ttl and a max size.\n\n/** How long (ms) a prefetched entry stays usable before it is discarded. */\nexport const PREFETCH_TTL = 1000 * 60;\n\n/** Maximum number of prefetched entries kept at once. */\nexport const PREFETCH_LIMIT = 100;\n\n// This is exported only for global-types.ts. It is not a public API.\nexport type PrefetchEntry = {\n rscPath: string;\n rscParams: unknown;\n getElements: (store: never) => unknown;\n expireAt: number;\n};\n\nconst getCache = (): PrefetchEntry[] => (globalThis.__WAKU_PREFETCHED__ ||= []);\n\nconst findFreshIndex = (\n cache: PrefetchEntry[],\n rscPath: string,\n rscParams: unknown,\n now: number,\n) =>\n cache.findIndex(\n (entry) =>\n entry.expireAt > now &&\n entry.rscPath === rscPath &&\n // rscParams is intentionally compared by reference.\n entry.rscParams === rscParams,\n );\n\n/**\n * Decode and cache a prefetch. `getStore` returns the entry's currently bound\n * store: the prefetch's now, the navigation's after `consumePrefetchEntry`.\n */\nexport const addPrefetchEntry = <Store, Elements>(\n rscPath: string,\n rscParams: unknown,\n store: Store,\n decode: (getStore: () => Store) => Elements,\n): void => {\n const cache = getCache();\n const now = Date.now();\n let currentStore = store;\n const elements = decode(() => currentStore);\n // Mark as handled so a prefetch that is never consumed stays quiet.\n Promise.resolve(elements).catch(() => {});\n const getElements = (nextStore: Store): Elements => {\n currentStore = nextStore;\n return elements;\n };\n cache.push({ rscPath, rscParams, getElements, expireAt: now + PREFETCH_TTL });\n while (\n cache.length > 0 &&\n (cache.length > PREFETCH_LIMIT || cache[0]!.expireAt <= now)\n ) {\n cache.shift();\n }\n};\n\nexport const hasPrefetchEntry = (\n rscPath: string,\n rscParams: unknown,\n): boolean => {\n const cache = getCache();\n return findFreshIndex(cache, rscPath, rscParams, Date.now()) >= 0;\n};\n\n/**\n * Consume a fresh prefetch, rebinding its decoded tree to the consumer's store.\n */\nexport const consumePrefetchEntry = <Store, Elements>(\n rscPath: string,\n rscParams: unknown,\n store: Store,\n): Elements | undefined => {\n const cache = getCache();\n const index = findFreshIndex(cache, rscPath, rscParams, Date.now());\n if (index < 0) {\n return undefined;\n }\n const { getElements } = cache.splice(index, 1)[0]!;\n return (getElements as (s: Store) => Elements)(store);\n};\n"],"names":["PREFETCH_TTL","PREFETCH_LIMIT","getCache","globalThis","__WAKU_PREFETCHED__","findFreshIndex","cache","rscPath","rscParams","now","findIndex","entry","expireAt","addPrefetchEntry","store","decode","Date","currentStore","elements","Promise","resolve","catch","getElements","nextStore","push","length","shift","hasPrefetchEntry","consumePrefetchEntry","index","undefined","splice"],"mappings":"AAAA,4EAA4E;AAC5E,gFAAgF;AAChF,6EAA6E;AAC7E,2EAA2E;AAE3E,0EAA0E,GAC1E,OAAO,MAAMA,eAAe,OAAO,GAAG;AAEtC,uDAAuD,GACvD,OAAO,MAAMC,iBAAiB,IAAI;AAUlC,MAAMC,WAAW,IAAwBC,WAAWC,mBAAmB,KAAK,EAAE;AAE9E,MAAMC,iBAAiB,CACrBC,OACAC,SACAC,WACAC,MAEAH,MAAMI,SAAS,CACb,CAACC,QACCA,MAAMC,QAAQ,GAAGH,OACjBE,MAAMJ,OAAO,KAAKA,WAClB,oDAAoD;QACpDI,MAAMH,SAAS,KAAKA;AAG1B;;;CAGC,GACD,OAAO,MAAMK,mBAAmB,CAC9BN,SACAC,WACAM,OACAC;IAEA,MAAMT,QAAQJ;IACd,MAAMO,MAAMO,KAAKP,GAAG;IACpB,IAAIQ,eAAeH;IACnB,MAAMI,WAAWH,OAAO,IAAME;IAC9B,oEAAoE;IACpEE,QAAQC,OAAO,CAACF,UAAUG,KAAK,CAAC,KAAO;IACvC,MAAMC,cAAc,CAACC;QACnBN,eAAeM;QACf,OAAOL;IACT;IACAZ,MAAMkB,IAAI,CAAC;QAAEjB;QAASC;QAAWc;QAAaV,UAAUH,MAAMT;IAAa;IAC3E,MACEM,MAAMmB,MAAM,GAAG,KACdnB,CAAAA,MAAMmB,MAAM,GAAGxB,kBAAkBK,KAAK,CAAC,EAAE,CAAEM,QAAQ,IAAIH,GAAE,EAC1D;QACAH,MAAMoB,KAAK;IACb;AACF,EAAE;AAEF,OAAO,MAAMC,mBAAmB,CAC9BpB,SACAC;IAEA,MAAMF,QAAQJ;IACd,OAAOG,eAAeC,OAAOC,SAASC,WAAWQ,KAAKP,GAAG,OAAO;AAClE,EAAE;AAEF;;CAEC,GACD,OAAO,MAAMmB,uBAAuB,CAClCrB,SACAC,WACAM;IAEA,MAAMR,QAAQJ;IACd,MAAM2B,QAAQxB,eAAeC,OAAOC,SAASC,WAAWQ,KAAKP,GAAG;IAChE,IAAIoB,QAAQ,GAAG;QACb,OAAOC;IACT;IACA,MAAM,EAAER,WAAW,EAAE,GAAGhB,MAAMyB,MAAM,CAACF,OAAO,EAAE,CAAC,EAAE;IACjD,OAAO,AAACP,YAAuCR;AACjD,EAAE"}
1
+ {"version":3,"sources":["../../../src/lib/utils/prefetch-cache.ts"],"sourcesContent":["// Client-side cache of prefetched navigations: a prefetch decodes the route\n// eagerly so a later navigation reuses the decoded tree without re-fetching.\n// Bounded by a ttl and a max size.\n\n/** How long (ms) a prefetched entry stays usable before it is discarded. */\nexport const PREFETCH_TTL = 1000 * 60;\n\n/** Maximum number of prefetched entries kept at once. */\nexport const PREFETCH_LIMIT = 100;\n\n// This is exported only for global-types.ts. It is not a public API.\nexport type PrefetchEntry = {\n rscPath: string;\n rscParams: unknown;\n elements: unknown;\n expireAt: number;\n};\n\nconst getCache = (): PrefetchEntry[] => (globalThis.__WAKU_PREFETCHED__ ||= []);\n\nconst findFreshIndex = (\n cache: PrefetchEntry[],\n rscPath: string,\n rscParams: unknown,\n now: number,\n) =>\n cache.findIndex(\n (entry) =>\n entry.expireAt > now &&\n entry.rscPath === rscPath &&\n // rscParams is intentionally compared by reference.\n entry.rscParams === rscParams,\n );\n\n/** Decode and cache a prefetch so a later navigation can reuse the tree. */\nexport const addPrefetchEntry = <Elements>(\n rscPath: string,\n rscParams: unknown,\n elements: Elements,\n): void => {\n const cache = getCache();\n const now = Date.now();\n // Mark as handled so a prefetch that is never consumed stays quiet.\n Promise.resolve(elements).catch(() => {});\n cache.push({ rscPath, rscParams, elements, expireAt: now + PREFETCH_TTL });\n while (\n cache.length > 0 &&\n (cache.length > PREFETCH_LIMIT || cache[0]!.expireAt <= now)\n ) {\n cache.shift();\n }\n};\n\nexport const hasPrefetchEntry = (\n rscPath: string,\n rscParams: unknown,\n): boolean => {\n const cache = getCache();\n return findFreshIndex(cache, rscPath, rscParams, Date.now()) >= 0;\n};\n\n/** Consume a fresh prefetch, returning its eagerly decoded tree. */\nexport const consumePrefetchEntry = <Elements>(\n rscPath: string,\n rscParams: unknown,\n): Elements | undefined => {\n const cache = getCache();\n const index = findFreshIndex(cache, rscPath, rscParams, Date.now());\n if (index < 0) {\n return undefined;\n }\n return cache.splice(index, 1)[0]!.elements as Elements;\n};\n"],"names":["PREFETCH_TTL","PREFETCH_LIMIT","getCache","globalThis","__WAKU_PREFETCHED__","findFreshIndex","cache","rscPath","rscParams","now","findIndex","entry","expireAt","addPrefetchEntry","elements","Date","Promise","resolve","catch","push","length","shift","hasPrefetchEntry","consumePrefetchEntry","index","undefined","splice"],"mappings":"AAAA,4EAA4E;AAC5E,6EAA6E;AAC7E,mCAAmC;AAEnC,0EAA0E,GAC1E,OAAO,MAAMA,eAAe,OAAO,GAAG;AAEtC,uDAAuD,GACvD,OAAO,MAAMC,iBAAiB,IAAI;AAUlC,MAAMC,WAAW,IAAwBC,WAAWC,mBAAmB,KAAK,EAAE;AAE9E,MAAMC,iBAAiB,CACrBC,OACAC,SACAC,WACAC,MAEAH,MAAMI,SAAS,CACb,CAACC,QACCA,MAAMC,QAAQ,GAAGH,OACjBE,MAAMJ,OAAO,KAAKA,WAClB,oDAAoD;QACpDI,MAAMH,SAAS,KAAKA;AAG1B,0EAA0E,GAC1E,OAAO,MAAMK,mBAAmB,CAC9BN,SACAC,WACAM;IAEA,MAAMR,QAAQJ;IACd,MAAMO,MAAMM,KAAKN,GAAG;IACpB,oEAAoE;IACpEO,QAAQC,OAAO,CAACH,UAAUI,KAAK,CAAC,KAAO;IACvCZ,MAAMa,IAAI,CAAC;QAAEZ;QAASC;QAAWM;QAAUF,UAAUH,MAAMT;IAAa;IACxE,MACEM,MAAMc,MAAM,GAAG,KACdd,CAAAA,MAAMc,MAAM,GAAGnB,kBAAkBK,KAAK,CAAC,EAAE,CAAEM,QAAQ,IAAIH,GAAE,EAC1D;QACAH,MAAMe,KAAK;IACb;AACF,EAAE;AAEF,OAAO,MAAMC,mBAAmB,CAC9Bf,SACAC;IAEA,MAAMF,QAAQJ;IACd,OAAOG,eAAeC,OAAOC,SAASC,WAAWO,KAAKN,GAAG,OAAO;AAClE,EAAE;AAEF,kEAAkE,GAClE,OAAO,MAAMc,uBAAuB,CAClChB,SACAC;IAEA,MAAMF,QAAQJ;IACd,MAAMsB,QAAQnB,eAAeC,OAAOC,SAASC,WAAWO,KAAKN,GAAG;IAChE,IAAIe,QAAQ,GAAG;QACb,OAAOC;IACT;IACA,OAAOnB,MAAMoB,MAAM,CAACF,OAAO,EAAE,CAAC,EAAE,CAAEV,QAAQ;AAC5C,EAAE"}
@@ -73,7 +73,7 @@ const collectFlightChunks = (root)=>{
73
73
  };
74
74
  export async function waitForRootPrerequisites(root) {
75
75
  while(true){
76
- const unresolvedChunks = collectFlightChunks(root).filter((chunk)=>isPendingStatus(chunk.status));
76
+ const unresolvedChunks = collectFlightChunks(root).filter((chunk)=>isPendingStatus(chunk.status) && typeof chunk.then === 'function');
77
77
  if (unresolvedChunks.length === 0) {
78
78
  return;
79
79
  }
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/lib/utils/rsc-stream.ts"],"sourcesContent":["type AnyFunction = (...args: unknown[]) => unknown;\n\ntype FlightChunk = {\n _children?: unknown;\n reason?: unknown;\n status: string;\n then?: AnyFunction;\n value?: unknown;\n};\n\ntype FlightRecordLike = {\n _children?: unknown;\n _payload?: unknown;\n handler?: { chunk?: unknown };\n props?: unknown;\n value?: unknown;\n};\n\nconst isObjectOrFunction = (value: unknown): value is object | AnyFunction =>\n value !== null && (typeof value === 'object' || typeof value === 'function');\n\nconst isFlightChunk = (value: unknown): value is FlightChunk =>\n isObjectOrFunction(value) &&\n 'status' in value &&\n typeof value.status === 'string' &&\n (!('then' in value) || typeof value.then === 'function');\n\nconst isFlightRecordLike = (value: unknown): value is FlightRecordLike =>\n isObjectOrFunction(value) &&\n (!('handler' in value) ||\n (isObjectOrFunction(value.handler) && 'chunk' in value.handler)) &&\n ('_payload' in value ||\n 'handler' in value ||\n '_children' in value ||\n 'value' in value ||\n 'props' in value);\n\nconst isPendingStatus = (value: string) =>\n value === 'pending' || value === 'blocked';\n\nconst pushInspectable = (stack: object[], value: unknown) => {\n if (isObjectOrFunction(value)) {\n stack.push(value);\n }\n};\n\nconst pushInspectableValues = (stack: object[], values: Iterable<unknown>) => {\n for (const value of values) {\n pushInspectable(stack, value);\n }\n};\n\nconst pushChunkEdges = (stack: object[], chunk: FlightChunk) => {\n if (Array.isArray(chunk._children)) {\n pushInspectableValues(stack, chunk._children);\n }\n pushInspectable(stack, chunk.value);\n pushInspectable(stack, chunk.reason);\n};\n\nconst pushRecordEdges = (stack: object[], record: FlightRecordLike) => {\n pushInspectable(stack, record._payload);\n if (record.handler) {\n pushInspectable(stack, record.handler.chunk);\n }\n if (Array.isArray(record._children)) {\n pushInspectableValues(stack, record._children);\n }\n pushInspectable(stack, record.value);\n pushInspectable(stack, record.props);\n};\n\nconst pushObjectValues = (stack: object[], value: object) => {\n pushInspectableValues(stack, Object.values(value));\n};\n\nconst collectFlightChunks = (root: unknown): FlightChunk[] => {\n const seen = new Set<object>();\n const chunks: FlightChunk[] = [];\n const stack: object[] = [];\n\n if (isObjectOrFunction(root)) {\n stack.push(root);\n }\n\n while (stack.length) {\n const value = stack.pop();\n if (!value || seen.has(value)) {\n continue;\n }\n seen.add(value);\n\n if (Array.isArray(value)) {\n pushInspectableValues(stack, value);\n continue;\n }\n if (value instanceof Map) {\n pushInspectableValues(stack, value.keys());\n pushInspectableValues(stack, value.values());\n continue;\n }\n if (value instanceof Set) {\n pushInspectableValues(stack, value.values());\n continue;\n }\n if (isFlightChunk(value)) {\n chunks.push(value);\n pushChunkEdges(stack, value);\n continue;\n }\n if (isFlightRecordLike(value)) {\n pushRecordEdges(stack, value);\n }\n pushObjectValues(stack, value);\n }\n return chunks;\n};\n\nexport async function waitForRootPrerequisites(root: unknown): Promise<void> {\n while (true) {\n const unresolvedChunks = collectFlightChunks(root).filter((chunk) =>\n isPendingStatus(chunk.status),\n );\n if (unresolvedChunks.length === 0) {\n return;\n }\n await Promise.allSettled(unresolvedChunks);\n }\n}\n"],"names":["isObjectOrFunction","value","isFlightChunk","status","then","isFlightRecordLike","handler","isPendingStatus","pushInspectable","stack","push","pushInspectableValues","values","pushChunkEdges","chunk","Array","isArray","_children","reason","pushRecordEdges","record","_payload","props","pushObjectValues","Object","collectFlightChunks","root","seen","Set","chunks","length","pop","has","add","Map","keys","waitForRootPrerequisites","unresolvedChunks","filter","Promise","allSettled"],"mappings":"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"}
1
+ {"version":3,"sources":["../../../src/lib/utils/rsc-stream.ts"],"sourcesContent":["type AnyFunction = (...args: unknown[]) => unknown;\n\ntype FlightChunk = {\n _children?: unknown;\n reason?: unknown;\n status: string;\n then?: AnyFunction;\n value?: unknown;\n};\n\ntype FlightRecordLike = {\n _children?: unknown;\n _payload?: unknown;\n handler?: { chunk?: unknown };\n props?: unknown;\n value?: unknown;\n};\n\nconst isObjectOrFunction = (value: unknown): value is object | AnyFunction =>\n value !== null && (typeof value === 'object' || typeof value === 'function');\n\nconst isFlightChunk = (value: unknown): value is FlightChunk =>\n isObjectOrFunction(value) &&\n 'status' in value &&\n typeof value.status === 'string' &&\n (!('then' in value) || typeof value.then === 'function');\n\nconst isFlightRecordLike = (value: unknown): value is FlightRecordLike =>\n isObjectOrFunction(value) &&\n (!('handler' in value) ||\n (isObjectOrFunction(value.handler) && 'chunk' in value.handler)) &&\n ('_payload' in value ||\n 'handler' in value ||\n '_children' in value ||\n 'value' in value ||\n 'props' in value);\n\nconst isPendingStatus = (value: string) =>\n value === 'pending' || value === 'blocked';\n\nconst pushInspectable = (stack: object[], value: unknown) => {\n if (isObjectOrFunction(value)) {\n stack.push(value);\n }\n};\n\nconst pushInspectableValues = (stack: object[], values: Iterable<unknown>) => {\n for (const value of values) {\n pushInspectable(stack, value);\n }\n};\n\nconst pushChunkEdges = (stack: object[], chunk: FlightChunk) => {\n if (Array.isArray(chunk._children)) {\n pushInspectableValues(stack, chunk._children);\n }\n pushInspectable(stack, chunk.value);\n pushInspectable(stack, chunk.reason);\n};\n\nconst pushRecordEdges = (stack: object[], record: FlightRecordLike) => {\n pushInspectable(stack, record._payload);\n if (record.handler) {\n pushInspectable(stack, record.handler.chunk);\n }\n if (Array.isArray(record._children)) {\n pushInspectableValues(stack, record._children);\n }\n pushInspectable(stack, record.value);\n pushInspectable(stack, record.props);\n};\n\nconst pushObjectValues = (stack: object[], value: object) => {\n pushInspectableValues(stack, Object.values(value));\n};\n\nconst collectFlightChunks = (root: unknown): FlightChunk[] => {\n const seen = new Set<object>();\n const chunks: FlightChunk[] = [];\n const stack: object[] = [];\n\n if (isObjectOrFunction(root)) {\n stack.push(root);\n }\n\n while (stack.length) {\n const value = stack.pop();\n if (!value || seen.has(value)) {\n continue;\n }\n seen.add(value);\n\n if (Array.isArray(value)) {\n pushInspectableValues(stack, value);\n continue;\n }\n if (value instanceof Map) {\n pushInspectableValues(stack, value.keys());\n pushInspectableValues(stack, value.values());\n continue;\n }\n if (value instanceof Set) {\n pushInspectableValues(stack, value.values());\n continue;\n }\n if (isFlightChunk(value)) {\n chunks.push(value);\n pushChunkEdges(stack, value);\n continue;\n }\n if (isFlightRecordLike(value)) {\n pushRecordEdges(stack, value);\n }\n pushObjectValues(stack, value);\n }\n return chunks;\n};\n\nexport async function waitForRootPrerequisites(root: unknown): Promise<void> {\n while (true) {\n const unresolvedChunks = collectFlightChunks(root).filter(\n (chunk) =>\n isPendingStatus(chunk.status) && typeof chunk.then === 'function',\n );\n if (unresolvedChunks.length === 0) {\n return;\n }\n await Promise.allSettled(unresolvedChunks);\n }\n}\n"],"names":["isObjectOrFunction","value","isFlightChunk","status","then","isFlightRecordLike","handler","isPendingStatus","pushInspectable","stack","push","pushInspectableValues","values","pushChunkEdges","chunk","Array","isArray","_children","reason","pushRecordEdges","record","_payload","props","pushObjectValues","Object","collectFlightChunks","root","seen","Set","chunks","length","pop","has","add","Map","keys","waitForRootPrerequisites","unresolvedChunks","filter","Promise","allSettled"],"mappings":"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"}
@@ -1,49 +1,82 @@
1
1
  import type { ReactNode } from 'react';
2
2
  type Elements = Record<string, unknown>;
3
- type SetElements = (updater: (prev: Promise<Elements>) => Promise<Elements>) => void;
4
3
  declare const ENTRY = "e";
5
4
  declare const SET_ELEMENTS = "s";
6
- declare const FETCH_FN = "f";
5
+ declare const FETCH_ENHANCERS = "f";
7
6
  declare const FETCH_RSC_INPUT_TRANSFORMERS = "t";
8
7
  declare const CALL_SERVER_ELEMENTS_LISTENERS = "l";
9
- declare const ON_BUILD_ID_MISMATCH = "b";
10
- type TransformFetchRscInput = (rscPath: string, rscParams: unknown, prefetchOnly: boolean) => readonly [rscPath: string, rscParams: unknown, prefetchOnly: boolean];
11
- type FetchRscInputTransformers = Set<TransformFetchRscInput>;
8
+ type SetElements = (updater: (prev: Promise<Elements>) => Promise<Elements>) => void;
9
+ type FetchEnhancer = (fetchFn: typeof fetch) => typeof fetch;
10
+ type FetchEnhancers = Set<FetchEnhancer>;
11
+ type FetchRscInputTransformer = (rscPath: string, rscParams: unknown, prefetchOnly: boolean) => readonly [rscPath: string, rscParams: unknown, prefetchOnly: boolean];
12
+ type FetchRscInputTransformers = Set<FetchRscInputTransformer>;
12
13
  type CallServerElementsListeners = Set<(elements: Elements) => void>;
13
- type Unstable_FetchRscStore = {
14
+ type FetchRscStore = {
14
15
  [ENTRY]?: [
15
16
  rscPath: string,
16
17
  rscParams: unknown,
17
18
  elementsPromise: Promise<Elements>
18
19
  ];
19
20
  [SET_ELEMENTS]?: SetElements;
20
- [FETCH_FN]?: typeof fetch;
21
+ [FETCH_ENHANCERS]?: FetchEnhancers;
21
22
  [FETCH_RSC_INPUT_TRANSFORMERS]?: FetchRscInputTransformers;
22
23
  [CALL_SERVER_ELEMENTS_LISTENERS]?: CallServerElementsListeners;
23
- [ON_BUILD_ID_MISMATCH]?: () => void;
24
24
  };
25
+ type FetchRscOptions = {
26
+ signal?: AbortSignal;
27
+ onBuildIdMismatch?: () => void;
28
+ };
29
+ type Refetch = (rscPath: string, rscParams?: unknown, options?: FetchRscOptions) => Promise<Elements>;
25
30
  /**
26
31
  * callServer callback
27
32
  * This is not a public API.
28
33
  */
29
- export declare const unstable_callServerRsc: (funcId: string, args: unknown[], unstable_enhanceFetchRscStore?: (s: Unstable_FetchRscStore) => Unstable_FetchRscStore) => Promise<unknown>;
34
+ export declare const unstable_callServerRsc: (funcId: string, args: unknown[]) => Promise<unknown>;
30
35
  type Unregister = () => void;
31
- export declare const unstable_registerCallServerElementsListener: (fetchRscStore: Unstable_FetchRscStore, listener: (elements: Elements) => void) => Unregister;
32
- export declare const unstable_registerFetchRscInputTransformer: (fetchRscStore: Unstable_FetchRscStore, transformFetchRscInput: TransformFetchRscInput) => Unregister;
33
- export declare const unstable_fetchRsc: (rscPath: string, rscParams?: unknown, unstable_enhanceFetchRscStore?: (s: Unstable_FetchRscStore) => Unstable_FetchRscStore) => Promise<Elements>;
34
- export declare const unstable_prefetchRsc: (rscPath: string, rscParams?: unknown, unstable_enhanceFetchRscStore?: (s: Unstable_FetchRscStore) => Unstable_FetchRscStore) => void;
35
- export declare const unstable_withEnhanceFetchFn: (enhanceFetchFn: (fn: typeof fetch) => typeof fetch) => (fetchRscStore: Unstable_FetchRscStore) => Unstable_FetchRscStore;
36
- export declare const unstable_withBuildIdMismatchHandler: (handler: () => void) => (fetchRscStore: Unstable_FetchRscStore) => Unstable_FetchRscStore;
37
- export declare const useFetchRscStore_UNSTABLE: () => Unstable_FetchRscStore;
38
- export declare const Root: ({ initialRscPath, initialRscParams, unstable_fetchRscStore, children, }: {
36
+ /**
37
+ * Register a listener that runs when a server action returns new elements.
38
+ * Returns a function that unregisters the listener.
39
+ */
40
+ export declare const unstable_registerCallServerElementsListener: (listener: (elements: Elements) => void) => Unregister;
41
+ /**
42
+ * Register a fetch enhancer applied to every RSC request (e.g. to add headers).
43
+ * Enhancers are composed in registration order. Returns a function that
44
+ * unregisters the enhancer.
45
+ */
46
+ export declare const unstable_registerFetchEnhancer: (enhance: FetchEnhancer) => Unregister;
47
+ /**
48
+ * Register a transformer that rewrites the RSC fetch input
49
+ * (`rscPath`, `rscParams`, `prefetchOnly`) before each request. Returns a
50
+ * function that unregisters the transformer.
51
+ */
52
+ export declare function unstable_registerFetchRscInputTransformer(transformFetchRscInput: FetchRscInputTransformer): Unregister;
53
+ /**
54
+ * @deprecated Pass only the transformer. The store argument is ignored and this
55
+ * overload will be removed in a future release.
56
+ */
57
+ export declare function unstable_registerFetchRscInputTransformer(store: FetchRscStore, transformFetchRscInput: FetchRscInputTransformer): Unregister;
58
+ /** Fetch elements for an RSC path, reusing a cached or prefetched result. */
59
+ export declare const unstable_fetchRsc: (rscPath: string, rscParams?: unknown, options?: FetchRscOptions) => Promise<Elements>;
60
+ /** Eagerly fetch and cache elements so a later fetch reuses them. */
61
+ export declare const unstable_prefetchRsc: (rscPath: string, rscParams?: unknown) => void;
62
+ /**
63
+ * Client root. Seeds the initial elements, bridges the store to React state,
64
+ * and provides the elements to `Slot` descendants.
65
+ */
66
+ export declare const Root: ({ initialRscPath, initialRscParams, children, }: {
39
67
  initialRscPath?: string;
40
68
  initialRscParams?: unknown;
41
- unstable_fetchRscStore?: Unstable_FetchRscStore | undefined;
42
69
  children: ReactNode;
43
70
  }) => import("react").JSX.Element;
44
- export declare const useRefetch: () => (rscPath: string, rscParams?: unknown, unstable_enhanceFetchRscStore?: (c: Unstable_FetchRscStore) => Unstable_FetchRscStore) => Promise<Elements>;
71
+ export declare const useRefetch: () => Refetch;
45
72
  export declare const Children: () => ReactNode;
46
73
  export declare const useElementsPromise_UNSTABLE: () => Promise<Elements>;
74
+ /**
75
+ * @deprecated The store is an internal singleton; you no longer need to pass it
76
+ * to `unstable_registerFetchRscInputTransformer`. This will be removed in a
77
+ * future release.
78
+ */
79
+ export declare const useFetchRscStore_UNSTABLE: () => FetchRscStore;
47
80
  /**
48
81
  * Slot component
49
82
  * This is used under the Root component.
@@ -57,70 +57,88 @@ const mergeElementsPromise = (a, b)=>{
57
57
  };
58
58
  const ENTRY = 'e';
59
59
  const SET_ELEMENTS = 's';
60
- const FETCH_FN = 'f';
60
+ const FETCH_ENHANCERS = 'f';
61
61
  const FETCH_RSC_INPUT_TRANSFORMERS = 't';
62
62
  const CALL_SERVER_ELEMENTS_LISTENERS = 'l';
63
- const ON_BUILD_ID_MISMATCH = 'b';
64
- const defaultFetchRscStore = {};
65
- const requestRsc = (fetchFn, rscPath, rscParams, temporaryReferences)=>{
63
+ const fetchRscStore = {};
64
+ const getFetchFn = ()=>{
65
+ let fetchFn = fetch;
66
+ const enhancers = fetchRscStore[FETCH_ENHANCERS];
67
+ if (enhancers) {
68
+ for (const enhance of enhancers){
69
+ fetchFn = enhance(fetchFn);
70
+ }
71
+ }
72
+ return fetchFn;
73
+ };
74
+ const getSetElements = ()=>{
75
+ const setElements = fetchRscStore[SET_ELEMENTS];
76
+ if (!setElements) {
77
+ throw new Error('Missing Root component');
78
+ }
79
+ return setElements;
80
+ };
81
+ const requestRsc = (fetchFn, rscPath, rscParams, temporaryReferences, signal)=>{
66
82
  const url = BASE_RSC_PATH + encodeRscPath(rscPath);
83
+ const init = {};
84
+ if (signal) {
85
+ init.signal = signal;
86
+ }
67
87
  if (rscParams === undefined) {
68
- return fetchFn(url);
88
+ return fetchFn(url, init);
69
89
  }
70
90
  if (rscParams instanceof URLSearchParams) {
71
- return fetchFn(url + '?' + rscParams);
91
+ return fetchFn(url + '?' + rscParams, init);
72
92
  }
73
93
  return encodeReply(rscParams, {
74
94
  temporaryReferences
75
95
  }).then((body)=>fetchFn(url, {
96
+ ...init,
76
97
  method: 'POST',
77
98
  body
78
99
  }));
79
100
  };
80
- // `getStore` is read lazily when a server action fires: a prefetched tree is
81
- // decoded early but must act against the consuming navigation's store.
82
- const decodeRsc = (getStore, responsePromise, temporaryReferences, debugChannel)=>createFromFetch(checkStatus(responsePromise), {
83
- callServer: (funcId, args)=>unstable_callServerRsc(funcId, args, getStore),
101
+ const decodeRsc = (responsePromise, temporaryReferences, debugChannel)=>createFromFetch(checkStatus(responsePromise), {
102
+ callServer: (funcId, args)=>unstable_callServerRsc(funcId, args),
84
103
  debugChannel,
85
104
  temporaryReferences
86
105
  });
87
- const reloadOnBuildIdMismatch = (fetchRscStore, elements)=>{
106
+ const reloadOnBuildIdMismatch = (elements, onBuildIdMismatch)=>{
88
107
  if (!import.meta.env?.WAKU_BUILD_ID) {
89
108
  return;
90
109
  }
91
110
  Promise.resolve(elements).then((data)=>{
92
111
  if (data._buildId !== import.meta.env.WAKU_BUILD_ID) {
93
- (fetchRscStore[ON_BUILD_ID_MISMATCH] ?? (()=>window.location.reload()))();
112
+ (onBuildIdMismatch ?? (()=>window.location.reload()))();
94
113
  }
95
114
  }, ()=>{});
96
115
  };
97
- const prefetchRscInternal = (fetchRscStore, rscPath, rscParams)=>{
98
- const fetchFn = fetchRscStore[FETCH_FN] || fetch;
116
+ const prefetchRscInternal = (rscPath, rscParams)=>{
99
117
  const temporaryReferences = createTemporaryReferenceSet();
100
- const responsePromise = requestRsc(fetchFn, rscPath, rscParams, temporaryReferences);
101
- addPrefetchEntry(rscPath, rscParams, fetchRscStore, (getStore)=>decodeRsc(getStore, responsePromise, temporaryReferences, undefined));
118
+ const responsePromise = requestRsc(getFetchFn(), rscPath, rscParams, temporaryReferences, undefined);
119
+ addPrefetchEntry(rscPath, rscParams, decodeRsc(responsePromise, temporaryReferences, undefined));
102
120
  };
103
- const fetchRscElements = (fetchRscStore, rscPath, rscParams)=>{
104
- const prefetched = consumePrefetchEntry(rscPath, rscParams, fetchRscStore);
121
+ const fetchRscElements = (rscPath, rscParams, options)=>{
122
+ const prefetched = consumePrefetchEntry(rscPath, rscParams);
105
123
  if (prefetched) {
106
- reloadOnBuildIdMismatch(fetchRscStore, prefetched);
124
+ reloadOnBuildIdMismatch(prefetched, options?.onBuildIdMismatch);
107
125
  return prefetched;
108
126
  }
109
127
  const initial = consumeInitialRscEntry();
110
- const baseFetchFn = fetchRscStore[FETCH_FN] || fetch;
128
+ const baseFetchFn = getFetchFn();
111
129
  const debug = import.meta.hot ? setupDebugChannel(baseFetchFn, !!initial, initial?.debugId) : undefined;
112
130
  const fetchFn = debug?.fetchFn || baseFetchFn;
113
131
  const temporaryReferences = createTemporaryReferenceSet();
114
- const responsePromise = initial ? initial.response : requestRsc(fetchFn, rscPath, rscParams, temporaryReferences);
115
- const elements = decodeRsc(()=>fetchRscStore, responsePromise, temporaryReferences, debug?.debugChannel);
116
- reloadOnBuildIdMismatch(fetchRscStore, elements);
132
+ const responsePromise = initial ? initial.response : requestRsc(fetchFn, rscPath, rscParams, temporaryReferences, options?.signal);
133
+ const elements = decodeRsc(responsePromise, temporaryReferences, debug?.debugChannel);
134
+ reloadOnBuildIdMismatch(elements, options?.onBuildIdMismatch);
117
135
  if (initial) {
118
136
  const { close } = initial;
119
137
  waitForRootPrerequisites(elements).then(close, close);
120
138
  }
121
139
  return elements;
122
140
  };
123
- const applyInputTransformers = (fetchRscStore, rscPath, rscParams, prefetchOnly)=>{
141
+ const applyInputTransformers = (rscPath, rscParams, prefetchOnly)=>{
124
142
  const fetchRscInputTransformers = fetchRscStore[FETCH_RSC_INPUT_TRANSFORMERS];
125
143
  if (fetchRscInputTransformers) {
126
144
  for (const transformFetchRscInput of fetchRscInputTransformers){
@@ -133,27 +151,26 @@ const applyInputTransformers = (fetchRscStore, rscPath, rscParams, prefetchOnly)
133
151
  prefetchOnly
134
152
  ];
135
153
  };
136
- const fetchRscInternal = (fetchRscStore, rscPath, rscParams, prefetchOnly)=>{
137
- [rscPath, rscParams, prefetchOnly] = applyInputTransformers(fetchRscStore, rscPath, rscParams, prefetchOnly);
154
+ const fetchRscInternal = (rscPath, rscParams, prefetchOnly, options)=>{
155
+ [rscPath, rscParams, prefetchOnly] = applyInputTransformers(rscPath, rscParams, prefetchOnly);
138
156
  if (prefetchOnly) {
139
157
  if (!hasPrefetchEntry(rscPath, rscParams)) {
140
- prefetchRscInternal(fetchRscStore, rscPath, rscParams);
158
+ prefetchRscInternal(rscPath, rscParams);
141
159
  }
142
160
  return undefined;
143
161
  }
144
- return fetchRscElements(fetchRscStore, rscPath, rscParams);
162
+ return fetchRscElements(rscPath, rscParams, options);
145
163
  };
146
164
  /**
147
165
  * callServer callback
148
166
  * This is not a public API.
149
- */ export const unstable_callServerRsc = async (funcId, args, unstable_enhanceFetchRscStore = (s)=>s)=>{
150
- const fetchRscStore = unstable_enhanceFetchRscStore(defaultFetchRscStore);
151
- const setElements = fetchRscStore[SET_ELEMENTS];
152
- const callServerElementsListeners = fetchRscStore[CALL_SERVER_ELEMENTS_LISTENERS];
167
+ */ export const unstable_callServerRsc = async (funcId, args)=>{
153
168
  const rscPath = encodeFuncId(funcId);
154
169
  const rscParams = args.length === 1 && args[0] instanceof URLSearchParams ? args[0] : args;
155
- const { _value: value, ...data } = await fetchRscInternal(fetchRscStore, rscPath, rscParams, false);
170
+ const { _value: value, ...data } = await fetchRscInternal(rscPath, rscParams, false, undefined);
156
171
  if (Object.keys(data).length) {
172
+ const setElements = getSetElements();
173
+ const callServerElementsListeners = fetchRscStore[CALL_SERVER_ELEMENTS_LISTENERS];
157
174
  startTransition(()=>{
158
175
  callServerElementsListeners?.forEach((listener)=>{
159
176
  listener(data);
@@ -163,42 +180,68 @@ const fetchRscInternal = (fetchRscStore, rscPath, rscParams, prefetchOnly)=>{
163
180
  }
164
181
  return value;
165
182
  };
166
- export const unstable_registerCallServerElementsListener = (fetchRscStore, listener)=>{
183
+ /**
184
+ * Register a listener that runs when a server action returns new elements.
185
+ * Returns a function that unregisters the listener.
186
+ */ export const unstable_registerCallServerElementsListener = (listener)=>{
167
187
  const callServerElementsListeners = fetchRscStore[CALL_SERVER_ELEMENTS_LISTENERS] ||= new Set();
168
188
  callServerElementsListeners.add(listener);
169
189
  return ()=>{
170
190
  callServerElementsListeners.delete(listener);
171
191
  };
172
192
  };
173
- export const unstable_registerFetchRscInputTransformer = (fetchRscStore, transformFetchRscInput)=>{
174
- const fetchRscInputTransformers = fetchRscStore[FETCH_RSC_INPUT_TRANSFORMERS] || (fetchRscStore[FETCH_RSC_INPUT_TRANSFORMERS] = new Set());
193
+ /**
194
+ * Register a fetch enhancer applied to every RSC request (e.g. to add headers).
195
+ * Enhancers are composed in registration order. Returns a function that
196
+ * unregisters the enhancer.
197
+ */ export const unstable_registerFetchEnhancer = (enhance)=>{
198
+ const fetchEnhancers = fetchRscStore[FETCH_ENHANCERS] ||= new Set();
199
+ fetchEnhancers.add(enhance);
200
+ return ()=>{
201
+ fetchEnhancers.delete(enhance);
202
+ };
203
+ };
204
+ let registerTransformerStoreArgWarned = false;
205
+ export function unstable_registerFetchRscInputTransformer(storeOrTransform, maybeTransform) {
206
+ let transformFetchRscInput;
207
+ if (typeof storeOrTransform === 'function') {
208
+ transformFetchRscInput = storeOrTransform;
209
+ } else {
210
+ transformFetchRscInput = maybeTransform;
211
+ if (!registerTransformerStoreArgWarned) {
212
+ registerTransformerStoreArgWarned = true;
213
+ console.warn('[waku] Passing a store to `unstable_registerFetchRscInputTransformer` is deprecated. Pass only the transformer.');
214
+ }
215
+ }
216
+ const fetchRscInputTransformers = fetchRscStore[FETCH_RSC_INPUT_TRANSFORMERS] ||= new Set();
175
217
  fetchRscInputTransformers.add(transformFetchRscInput);
176
218
  return ()=>{
177
219
  fetchRscInputTransformers.delete(transformFetchRscInput);
178
220
  };
221
+ }
222
+ const registerHmrRefetch = (refetch)=>{
223
+ globalThis.__WAKU_RSC_RELOAD_LISTENERS__ ||= [];
224
+ const index = globalThis.__WAKU_RSC_RELOAD_LISTENERS__.indexOf(globalThis.__WAKU_REFETCH_RSC__);
225
+ if (index !== -1) {
226
+ globalThis.__WAKU_RSC_RELOAD_LISTENERS__.splice(index, 1, refetch);
227
+ } else {
228
+ globalThis.__WAKU_RSC_RELOAD_LISTENERS__.push(refetch);
229
+ }
230
+ globalThis.__WAKU_REFETCH_RSC__ = refetch;
179
231
  };
180
- export const unstable_fetchRsc = (rscPath, rscParams, unstable_enhanceFetchRscStore = (s)=>s)=>{
181
- const fetchRscStore = unstable_enhanceFetchRscStore(defaultFetchRscStore);
232
+ /** Fetch elements for an RSC path, reusing a cached or prefetched result. */ export const unstable_fetchRsc = (rscPath, rscParams, options)=>{
182
233
  if (import.meta.hot) {
183
- const refetchRsc = ()=>{
234
+ registerHmrRefetch(()=>{
184
235
  delete fetchRscStore[ENTRY];
185
- const data = unstable_fetchRsc(rscPath, rscParams, unstable_enhanceFetchRscStore);
186
- fetchRscStore[SET_ELEMENTS](()=>data);
187
- };
188
- globalThis.__WAKU_RSC_RELOAD_LISTENERS__ ||= [];
189
- const index = globalThis.__WAKU_RSC_RELOAD_LISTENERS__.indexOf(globalThis.__WAKU_REFETCH_RSC__);
190
- if (index !== -1) {
191
- globalThis.__WAKU_RSC_RELOAD_LISTENERS__.splice(index, 1, refetchRsc);
192
- } else {
193
- globalThis.__WAKU_RSC_RELOAD_LISTENERS__.push(refetchRsc);
194
- }
195
- globalThis.__WAKU_REFETCH_RSC__ = refetchRsc;
236
+ const data = unstable_fetchRsc(rscPath, rscParams, options);
237
+ getSetElements()(()=>data);
238
+ });
196
239
  }
197
240
  const entry = fetchRscStore[ENTRY];
198
241
  if (entry && entry[0] === rscPath && entry[1] === rscParams) {
199
242
  return entry[2];
200
243
  }
201
- const data = fetchRscInternal(fetchRscStore, rscPath, rscParams, false);
244
+ const data = fetchRscInternal(rscPath, rscParams, false, options);
202
245
  fetchRscStore[ENTRY] = [
203
246
  rscPath,
204
247
  rscParams,
@@ -206,60 +249,36 @@ export const unstable_fetchRsc = (rscPath, rscParams, unstable_enhanceFetchRscSt
206
249
  ];
207
250
  return data;
208
251
  };
209
- export const unstable_prefetchRsc = (rscPath, rscParams, unstable_enhanceFetchRscStore = (s)=>s)=>{
210
- const fetchRscStore = unstable_enhanceFetchRscStore(defaultFetchRscStore);
211
- fetchRscInternal(fetchRscStore, rscPath, rscParams, true);
252
+ /** Eagerly fetch and cache elements so a later fetch reuses them. */ export const unstable_prefetchRsc = (rscPath, rscParams)=>{
253
+ fetchRscInternal(rscPath, rscParams, true, undefined);
212
254
  };
213
- export const unstable_withEnhanceFetchFn = (enhanceFetchFn)=>(fetchRscStore)=>({
214
- ...fetchRscStore,
215
- [FETCH_FN]: enhanceFetchFn(fetchRscStore[FETCH_FN] || fetch)
216
- });
217
- export const unstable_withBuildIdMismatchHandler = (handler)=>(fetchRscStore)=>({
218
- ...fetchRscStore,
219
- [ON_BUILD_ID_MISMATCH]: handler
220
- });
221
255
  const RefetchContext = /*#__PURE__*/ createContext(()=>{
222
256
  throw new Error('Missing Root component');
223
257
  });
224
258
  const ElementsContext = /*#__PURE__*/ createContext(null);
225
- const FetchRscStoreContext = /*#__PURE__*/ createContext(null);
226
- export const useFetchRscStore_UNSTABLE = ()=>{
227
- const fetchRscStore = use(FetchRscStoreContext);
228
- if (!fetchRscStore) {
229
- throw new Error('Missing Root component');
230
- }
231
- return fetchRscStore;
232
- };
233
- export const Root = ({ initialRscPath, initialRscParams, unstable_fetchRscStore = defaultFetchRscStore, children })=>{
234
- const [elements, setElements] = useState(()=>unstable_fetchRsc(initialRscPath || '', initialRscParams, ()=>unstable_fetchRscStore));
259
+ /**
260
+ * Client root. Seeds the initial elements, bridges the store to React state,
261
+ * and provides the elements to `Slot` descendants.
262
+ */ export const Root = ({ initialRscPath, initialRscParams, children })=>{
263
+ const [elements, setElements] = useState(()=>unstable_fetchRsc(initialRscPath || '', initialRscParams));
235
264
  useEffect(()=>{
236
- // eslint-disable-next-line react-hooks/immutability
237
- unstable_fetchRscStore[SET_ELEMENTS] = setElements;
238
- }, [
239
- unstable_fetchRscStore
240
- ]);
241
- const refetch = useCallback(async (rscPath, rscParams, unstable_enhanceFetchRscStore = (s)=>s)=>{
242
- // clear cache entry before fetching
243
- // eslint-disable-next-line react-hooks/immutability
244
- delete unstable_fetchRscStore[ENTRY]; // use non-enhanced store
245
- const data = unstable_fetchRsc(rscPath, rscParams, ()=>unstable_enhanceFetchRscStore(unstable_fetchRscStore));
265
+ fetchRscStore[SET_ELEMENTS] = setElements;
266
+ }, []);
267
+ const refetch = useCallback(async (rscPath, rscParams, options)=>{
268
+ delete fetchRscStore[ENTRY];
269
+ const data = unstable_fetchRsc(rscPath, rscParams, options);
246
270
  const dataWithoutErrors = Promise.resolve(data).catch(()=>({}));
247
271
  setElements((prev)=>mergeElementsPromise(prev, dataWithoutErrors));
248
272
  return data;
249
- }, [
250
- unstable_fetchRscStore
251
- ]);
252
- return /*#__PURE__*/ _jsx(FetchRscStoreContext, {
253
- value: unstable_fetchRscStore,
254
- children: /*#__PURE__*/ _jsx(RefetchContext, {
255
- value: refetch,
256
- children: /*#__PURE__*/ _jsxs(ElementsContext, {
257
- value: elements,
258
- children: [
259
- DEFAULT_HTML_HEAD,
260
- children
261
- ]
262
- })
273
+ }, []);
274
+ return /*#__PURE__*/ _jsx(RefetchContext, {
275
+ value: refetch,
276
+ children: /*#__PURE__*/ _jsxs(ElementsContext, {
277
+ value: elements,
278
+ children: [
279
+ DEFAULT_HTML_HEAD,
280
+ children
281
+ ]
263
282
  })
264
283
  });
265
284
  };
@@ -274,6 +293,18 @@ export const useElementsPromise_UNSTABLE = ()=>{
274
293
  }
275
294
  return elementsPromise;
276
295
  };
296
+ let useFetchRscStoreDeprecationWarned = false;
297
+ /**
298
+ * @deprecated The store is an internal singleton; you no longer need to pass it
299
+ * to `unstable_registerFetchRscInputTransformer`. This will be removed in a
300
+ * future release.
301
+ */ export const useFetchRscStore_UNSTABLE = ()=>{
302
+ if (!useFetchRscStoreDeprecationWarned) {
303
+ useFetchRscStoreDeprecationWarned = true;
304
+ console.warn('[waku] `useFetchRscStore_UNSTABLE` is deprecated and will be removed.');
305
+ }
306
+ return fetchRscStore;
307
+ };
277
308
  /**
278
309
  * Slot component
279
310
  * This is used under the Root component.
@@ -306,17 +337,14 @@ export const useElementsPromise_UNSTABLE = ()=>{
306
337
  /**
307
338
  * ServerRoot for SSR
308
339
  * This is not a public API.
309
- */ export const INTERNAL_ServerRoot = ({ elementsPromise, children })=>/*#__PURE__*/ _jsx(FetchRscStoreContext, {
310
- value: {},
311
- children: /*#__PURE__*/ _jsx(RefetchContext, {
312
- value: async ()=>({}),
313
- children: /*#__PURE__*/ _jsxs(ElementsContext, {
314
- value: elementsPromise,
315
- children: [
316
- DEFAULT_HTML_HEAD,
317
- children
318
- ]
319
- })
340
+ */ export const INTERNAL_ServerRoot = ({ elementsPromise, children })=>/*#__PURE__*/ _jsx(RefetchContext, {
341
+ value: async ()=>({}),
342
+ children: /*#__PURE__*/ _jsxs(ElementsContext, {
343
+ value: elementsPromise,
344
+ children: [
345
+ DEFAULT_HTML_HEAD,
346
+ children
347
+ ]
320
348
  })
321
349
  });
322
350