@rsc-kit/core 0.29.2 → 0.29.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.
- package/dist/files.d.ts +20 -0
- package/dist/files.js +53 -0
- package/dist/files.js.map +1 -1
- package/dist/js/useSearchParams.d.ts +10 -0
- package/dist/js/useSearchParams.js +54 -17
- package/dist/js/useSearchParams.js.map +1 -1
- package/dist/request.d.ts +7 -0
- package/dist/request.js +17 -0
- package/dist/request.js.map +1 -1
- package/dist/vite.js +101 -18
- package/dist/vite.js.map +1 -1
- package/package.json +1 -1
package/dist/files.d.ts
CHANGED
|
@@ -92,6 +92,26 @@ export declare function writeTo(dir: string): ((name: string, contents: string)
|
|
|
92
92
|
* filesystem operation by nature — a deploy that uploads them to a bucket
|
|
93
93
|
* has its own way to do that, and passes its own callback instead.
|
|
94
94
|
*/
|
|
95
|
+
/**
|
|
96
|
+
* The whole client output into an exported site: every file a server would
|
|
97
|
+
* have answered as a file - the bundle, public/, icons, the web manifest,
|
|
98
|
+
* the service worker. Precompressed copies (.br, .gz, .zst) come too; a host
|
|
99
|
+
* that does not serve them ignores them.
|
|
100
|
+
*/
|
|
101
|
+
export declare function copyPublic(from: string, to: string): () => Promise<void>;
|
|
102
|
+
/**
|
|
103
|
+
* Stored route.ts answers written out as the files they are: the body at the
|
|
104
|
+
* url, `robots.txt` at robots.txt. Only answers a static host can give as
|
|
105
|
+
* they were - a 200 the same for everyone, at a url with an extension, since
|
|
106
|
+
* a file is typed by its extension and the stored content type would be lost.
|
|
107
|
+
*/
|
|
108
|
+
export declare function exportStoredAnswers(staticDir: string, to: string): Promise<{
|
|
109
|
+
written: string[];
|
|
110
|
+
skipped: {
|
|
111
|
+
url: string;
|
|
112
|
+
why: string;
|
|
113
|
+
}[];
|
|
114
|
+
}>;
|
|
95
115
|
export declare function copyAssets(from: string, to: string, url?: string): () => Promise<void>;
|
|
96
116
|
/**
|
|
97
117
|
* Put the stored pages among a Worker's static assets, and have the Worker
|
package/dist/files.js
CHANGED
|
@@ -346,6 +346,59 @@ export function writeTo(dir) {
|
|
|
346
346
|
* filesystem operation by nature — a deploy that uploads them to a bucket
|
|
347
347
|
* has its own way to do that, and passes its own callback instead.
|
|
348
348
|
*/
|
|
349
|
+
/**
|
|
350
|
+
* The whole client output into an exported site: every file a server would
|
|
351
|
+
* have answered as a file - the bundle, public/, icons, the web manifest,
|
|
352
|
+
* the service worker. Precompressed copies (.br, .gz, .zst) come too; a host
|
|
353
|
+
* that does not serve them ignores them.
|
|
354
|
+
*/
|
|
355
|
+
export function copyPublic(from, to) {
|
|
356
|
+
return async () => {
|
|
357
|
+
await mkdir(to, { recursive: true });
|
|
358
|
+
await cp(from, to, { recursive: true });
|
|
359
|
+
};
|
|
360
|
+
}
|
|
361
|
+
/**
|
|
362
|
+
* Stored route.ts answers written out as the files they are: the body at the
|
|
363
|
+
* url, `robots.txt` at robots.txt. Only answers a static host can give as
|
|
364
|
+
* they were - a 200 the same for everyone, at a url with an extension, since
|
|
365
|
+
* a file is typed by its extension and the stored content type would be lost.
|
|
366
|
+
*/
|
|
367
|
+
export async function exportStoredAnswers(staticDir, to) {
|
|
368
|
+
const written = [];
|
|
369
|
+
const skipped = [];
|
|
370
|
+
let entries;
|
|
371
|
+
try {
|
|
372
|
+
entries = (await readdir(staticDir, { recursive: true }));
|
|
373
|
+
}
|
|
374
|
+
catch {
|
|
375
|
+
return { written, skipped };
|
|
376
|
+
}
|
|
377
|
+
for (const entry of entries.sort()) {
|
|
378
|
+
if (!entry.endsWith('.api.json'))
|
|
379
|
+
continue;
|
|
380
|
+
const path = entry.slice(0, -'.api.json'.length).split(/[\\/]/).join('/');
|
|
381
|
+
const url = '/' + (path === 'index' ? '' : path);
|
|
382
|
+
const answer = JSON.parse(await readFile(join(staticDir, entry), 'utf-8'));
|
|
383
|
+
if (answer.status !== 200) {
|
|
384
|
+
skipped.push({ url, why: `answers ${answer.status}` });
|
|
385
|
+
continue;
|
|
386
|
+
}
|
|
387
|
+
if (answer.varies) {
|
|
388
|
+
skipped.push({ url, why: 'varies by request' });
|
|
389
|
+
continue;
|
|
390
|
+
}
|
|
391
|
+
if (!/\.[a-z0-9]+$/i.test(path)) {
|
|
392
|
+
skipped.push({ url, why: 'no extension to give a static host its content type' });
|
|
393
|
+
continue;
|
|
394
|
+
}
|
|
395
|
+
const target = join(to, path);
|
|
396
|
+
await mkdir(dirname(target), { recursive: true });
|
|
397
|
+
await writeFile(target, answer.body);
|
|
398
|
+
written.push(url);
|
|
399
|
+
}
|
|
400
|
+
return { written, skipped };
|
|
401
|
+
}
|
|
349
402
|
export function copyAssets(from, to, url = '/assets/') {
|
|
350
403
|
return async () => {
|
|
351
404
|
const at = url.replace(/^\/+|\/+$/g, '');
|
package/dist/files.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"files.js","sourceRoot":"","sources":["../src/files.ts"],"names":[],"mappings":"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","sourcesContent":["// Reading built output off a disk.\n//\n// Kept apart from the host on purpose: it is the only part of serving an RSC\n// app that assumes a filesystem, and plenty of places to run one do not have\n// one. Nothing in `@rsc-kit/core/host` imports this module, so a bundle for a\n// host without a filesystem carries no reference to `node:fs` at all.\n//\n// Assets are not here any more — Nitro publishes and serves those. What is\n// left is the prerendered output: written by the build, read by the server it\n// generates, and copied by a static export.\n\nimport { cp, mkdir, readdir, readFile, writeFile } from 'node:fs/promises'\nimport { dirname, join } from 'node:path'\n\n/**\n * Read what the prerenderer wrote, from a directory.\n *\n * Missing is an answer, not an error: a partial prerender is a valid state,\n * and anything not found here is rendered on demand instead.\n */\nexport function prerenderedFrom(dir: string) {\n /**\n * What is on disk, listed once.\n *\n * A miss used to be a thrown ENOENT, and misses are the common case: the\n * host asks for `{url}.html`, then `{url}.ppr.html`, then the route's\n * pattern — so every request to a page served by a pattern shell threw and\n * caught two exceptions before finding anything. Measured at 3,000 req/s\n * against 28,000 for the same page read from memory.\n *\n * Contents are cached for the life of the process. A build's output does\n * not change under a running server - a deploy restarts it, and a server\n * that outlived a rebuild would be serving a stale engine against new\n * pages anyway - so the first read is the only one. Under load the same\n * page used to be opened, read and closed thousands of times a second,\n * which a profile showed as the one cost on a stored page that was ours\n * rather than React's. Capped by bytes, so a site with more pages than\n * memory holds the hot ones and re-reads the rest.\n */\n let present: Promise<Set<string>> | null = null\n\n const CONTENT_CAP_BYTES = 64 * 1024 * 1024\n const contents = new Map<string, string>()\n let held = 0\n\n const remember = (name: string, text: string): void => {\n const size = text.length * 2\n\n if (size > CONTENT_CAP_BYTES / 4) return\n\n while (held + size > CONTENT_CAP_BYTES && contents.size > 0) {\n const oldest = contents.keys().next().value as string\n held -= contents.get(oldest)!.length * 2\n contents.delete(oldest)\n }\n\n contents.set(name, text)\n held += size\n }\n\n const listing = async (): Promise<Set<string>> => {\n present ??= readdir(dir, { recursive: true })\n .then((names) => new Set(names.map((n) => String(n).replace(/\\\\/g, '/'))))\n // An absent directory is an empty one: a partial prerender is a valid\n // state, and everything falls through to being rendered.\n .catch(() => new Set<string>())\n\n return await present\n }\n\n return async (name: string): Promise<string | null> => {\n if (name.includes('..')) return null\n\n if (!(await listing()).has(name)) return null\n\n const cached = contents.get(name)\n\n if (cached !== undefined) return cached\n\n try {\n const text = await readFile(join(dir, name), 'utf-8')\n\n remember(name, text)\n\n return text\n } catch {\n return null\n }\n }\n}\n\n/**\n * The same reader, for a directory whose absolute path is not known until the\n * server runs.\n *\n * Nitro bundles the generated entry to a different depth depending on the\n * preset — `.output/server/index.mjs` for one, `.output/server/_ssr/rsc.mjs`\n * for another — so neither a fixed relative path nor a path baked in at build\n * time survives: the first is wrong for half the presets, and the second stops\n * being true the moment `.output/` is copied to the machine that serves it.\n *\n * So the caller passes its own `import.meta.url` and the directory is found by\n * walking up from it. A few levels, bounded, and resolved once.\n *\n * prerendered: prerenderedBeside(import.meta.url, 'rsc-static')\n *\n * Not finding it is a valid state and not an error: nothing was frozen, or\n * this host has no filesystem to have frozen it on. Every page renders live,\n * which is what happens today everywhere.\n */\n/**\n * Where a compiled binary puts the frozen pages.\n *\n * `bun build --compile` embeds what is imported statically and nothing a\n * computed import names, so the walk below finds no directory and no\n * module inside a binary. The build writes `compile.mjs` beside the\n * server: it imports the inline module by name - which embeds it - and\n * hands the pages over here before importing the server. Shared as a\n * global under a registered symbol, because the wrapper and this module\n * are bundled apart.\n */\nexport const EMBEDDED_PAGES = Symbol.for('rsc-kit.embedded-pages')\n\nfunction embeddedPages(): Record<string, string> | null {\n const pages = (globalThis as Record<symbol, unknown>)[EMBEDDED_PAGES]\n\n return pages && typeof pages === 'object' ? (pages as Record<string, string>) : null\n}\n\nexport function prerenderedBeside(moduleUrl: string, dirName: string, levels = 4) {\n let reader: Promise<(name: string) => Promise<string | null>> | null = null\n\n const resolveDir = async (): Promise<(name: string) => Promise<string | null>> => {\n const embedded = embeddedPages()\n\n if (embedded) return async (name) => embedded[name] ?? null\n\n let dir: string | null = null\n\n try {\n const { fileURLToPath } = await import('node:url')\n\n dir = dirname(fileURLToPath(moduleUrl))\n } catch {\n // No filesystem, or no file: url to speak of. The inline module below\n // is the only place the pages can be.\n }\n\n if (dir !== null) {\n for (let i = 0; i <= levels; i++) {\n const candidate = join(dir, ...Array(i).fill('..'), dirName)\n\n try {\n await readdir(candidate)\n\n return prerenderedFrom(candidate)\n } catch {\n // Not at this level. Keep walking.\n }\n }\n }\n\n // A Worker: the pages were uploaded as static assets, under a prefix\n // the Worker answers first, and are read back through the binding.\n const assets = await workersAssets()\n\n if (assets) return assetsReader(assets, `/${ASSETS_PREFIX(dirName)}`)\n\n const inline = await inlinePrerendered(moduleUrl, `${dirName}-inline.mjs`, levels)\n\n return inline ? async (name) => inline[name] ?? null : async () => null\n }\n\n return async (name: string): Promise<string | null> => {\n reader ??= resolveDir()\n\n return await (await reader)(name)\n }\n}\n\n/**\n * Where the stored pages live among a Worker's static assets.\n *\n * Under a prefix, beside the app's own public files, because that is the\n * one store a Worker has that costs nothing in script size: an inline module\n * counts against the bundle's limit, and a port's 571 stored category pages\n * came to 69 MB of module against a limit of 10. The prefix is one the\n * Worker answers first - `run_worker_first` in wrangler.json, written by\n * the build - so a browser asking for `/_rsc-static/x.ppr.html` reaches the\n * app, which has no such route, rather than the asset; a stored page of a\n * guarded route is served only by the host that runs the guard.\n */\nexport const ASSETS_PREFIX = (dirName: string): string => `_${dirName}`\n\n/** The Workers assets binding, where this runs on Workers and it is bound. */\nasync function workersAssets(): Promise<AssetsBinding | null> {\n if (typeof navigator === 'undefined' || navigator.userAgent !== 'Cloudflare-Workers') return null\n\n try {\n // Computed, so neither the bundler nor tsc looks for a module only the\n // Workers runtime has.\n const specifier = 'cloudflare:workers'\n const { env } = (await import(/* @vite-ignore */ specifier)) as { env: { ASSETS?: AssetsBinding } }\n\n return env.ASSETS && typeof env.ASSETS.fetch === 'function' ? env.ASSETS : null\n } catch {\n return null\n }\n}\n\ninterface AssetsBinding {\n fetch(input: Request | string): Promise<Response>\n}\n\n/**\n * Read stored pages through the assets binding, each name once per isolate.\n *\n * The host asks for `{url}.html`, then `{url}.ppr.html`, then the pattern's,\n * on every request: three asks per page, most of them misses. The binding\n * is a fetch, not a memory read, so the answers - misses included - are kept\n * for the life of the isolate, the way the disk reader keeps its listing.\n */\nconst KNOWN_LIMIT = 4096\n\nexport function assetsReader(assets: AssetsBinding, prefix: string): (name: string) => Promise<string | null> {\n const known = new Map<string, Promise<string | null>>()\n\n return (name) => {\n let pending = known.get(name)\n\n if (!pending) {\n // Bounded. Misses are kept too, and every made-up path is three of\n // them: kept for the life of the isolate, a crawler of random urls grew\n // this without end. Dropping the oldest costs one fetch, later.\n if (known.size >= KNOWN_LIMIT) known.delete(known.keys().next().value!)\n\n const path = `${prefix}/${name.split('/').map(encodeURIComponent).join('/')}`\n\n pending = assets\n .fetch(new Request(`https://assets.invalid${path}`))\n .then((response) => (response.ok ? response.text() : null))\n .catch(() => null)\n\n known.set(name, pending)\n }\n\n return pending\n }\n}\n\n/**\n * The frozen pages as one module, for a runtime with no filesystem.\n *\n * A Worker cannot readdir. Its modules are what wrangler uploaded, and a\n * sibling .mjs beside the bundle is one of them - so the build writes every\n * stored file into `rsc-static-inline.mjs` as strings, and this walks up from\n * the caller the way the disk reader does, importing rather than reading.\n * The specifier is computed, and marked for the bundler to leave alone: at\n * bundle time the file does not exist yet, because it is written by the\n * prerender that runs the bundle.\n *\n * Two forms of the specifier, because runtimes disagree. workerd resolves a\n * relative string against the importing module's name and refuses a url;\n * Node and Bun want the url, since a relative string would resolve against\n * this file rather than the caller's.\n */\nasync function inlinePrerendered(\n moduleUrl: string,\n fileName: string,\n levels: number,\n): Promise<Record<string, string> | null> {\n for (let i = 0; i <= levels; i++) {\n const relative = './' + '../'.repeat(i) + fileName\n\n for (const specifier of [relative, safeUrl(relative, moduleUrl)]) {\n if (!specifier) continue\n\n try {\n const loaded = (await import(/* @vite-ignore */ specifier)) as { default?: Record<string, string> }\n\n if (loaded.default && typeof loaded.default === 'object') return loaded.default\n } catch {\n // Not there, or not at this level.\n }\n }\n }\n\n return null\n}\n\nfunction safeUrl(relative: string, base: string): string | null {\n try {\n return new URL(relative, base).href\n } catch {\n return null\n }\n}\n\n/**\n * The entry a binary is compiled from, written beside the server.\n *\n * Two static imports, in this order: the inline module first - evaluating\n * it hands the pages over - and the server second. A module's imports are\n * evaluated in order, before its own body, so the pages are in place before\n * the server's first line runs. Bun embeds both.\n *\n * Static rather than `await import()`: a top-level await is what made Bun\n * skip `--bytecode` for this entry, silently, byte for byte - and a port\n * whose other Nitro app compiled with it asked why this one could not.\n * `bun build --compile --bytecode .output/server/compile.mjs` works now.\n */\nexport function compileEntrySource(dirName: string): string {\n return (\n '// The entry to compile into one binary:\\n' +\n '// bun build --compile .output/server/compile.mjs --outfile dist/app\\n' +\n '//\\n' +\n '//\\n' +\n '// A binary carries what is imported by name. The server reads its frozen pages\\n' +\n '// through a computed import, which a compile cannot see - imported here, they\\n' +\n '// travel inside the binary and are handed to the server before it starts.\\n' +\n '// Two static imports in this order, and no top-level await: imports evaluate\\n' +\n '// in order, and an await here is what stopped --bytecode from applying.\\n' +\n `import \"./${inlineModuleName(dirName)}\";\\n` +\n 'import \"./index.mjs\";\\n'\n )\n}\n\n/** The name the build writes the inline module under, beside the stored pages' directory. */\nexport function inlineModuleName(dirName: string): string {\n return `${dirName}-inline.mjs`\n}\n\n/**\n * Every stored file under `dir`, as the source of the inline module.\n * Strings only: a frozen page, its flight payload, its meta, an api answer.\n */\nexport async function inlineModuleSource(dir: string): Promise<string> {\n const { readdir: list, readFile: read } = await import('node:fs/promises')\n const entries: Record<string, string> = {}\n\n const walk = async (sub: string): Promise<void> => {\n for (const entry of await list(join(dir, sub), { withFileTypes: true })) {\n const rel = sub ? `${sub}/${entry.name}` : entry.name\n\n if (entry.isDirectory()) await walk(rel)\n else entries[rel] = await read(join(dir, rel), 'utf-8')\n }\n }\n\n await walk('')\n\n // Exported for the Worker, which imports it when the directory is not\n // there, and handed over as a global for the binary, whose compile entry\n // imports it first for exactly this side effect. The same data either way.\n return (\n '// @generated by the RSC build: the stored pages, for a runtime with no filesystem.\\n' +\n 'const pages = ' +\n JSON.stringify(entries) +\n ';\\n' +\n 'globalThis[Symbol.for(\"rsc-kit.embedded-pages\")] = pages;\\n' +\n 'export default pages;\\n'\n )\n}\n\nfunction contentTypeOf(pathname: string): string {\n if (pathname.endsWith('.js')) return 'text/javascript; charset=utf-8'\n if (pathname.endsWith('.css')) return 'text/css; charset=utf-8'\n if (pathname.endsWith('.map')) return 'application/json; charset=utf-8'\n if (pathname.endsWith('.svg')) return 'image/svg+xml'\n if (pathname.endsWith('.woff2')) return 'font/woff2'\n\n return 'application/octet-stream'\n}\n\n/**\n * Write build output into a directory.\n *\n * The sink `prerender` and `exportSite` take. Names are relative and may\n * contain directories — `docs/index.html` — so each one's parent is created\n * as it goes.\n */\nexport function writeTo(dir: string): ((name: string, contents: string) => Promise<void>) & { dir: string } {\n const write = async (name: string, contents: string): Promise<void> => {\n const path = join(dir, name)\n\n await mkdir(dirname(path), { recursive: true })\n await writeFile(path, contents)\n }\n\n // Where it wrote, for a caller that has to read it back. The embeddable\n // module has to list these files, and being told the directory a second time\n // is a second place for it to be wrong.\n return Object.assign(write, { dir })\n}\n\n/**\n * Copy the built browser bundle into an exported site.\n *\n * Separate from the export itself because copying a tree of files is a\n * filesystem operation by nature — a deploy that uploads them to a bucket\n * has its own way to do that, and passes its own callback instead.\n */\nexport function copyAssets(from: string, to: string, url = '/assets/') {\n return async (): Promise<void> => {\n const at = url.replace(/^\\/+|\\/+$/g, '')\n\n if (at === '') return\n\n const target = join(to, at)\n\n await mkdir(dirname(target), { recursive: true })\n await cp(from, target, { recursive: true })\n }\n}\n\n/**\n * Put the stored pages among a Worker's static assets, and have the Worker\n * answer their prefix first.\n *\n * Run after Nitro has written its public-asset list and wrangler.json, so\n * the copies are in neither: not served as assets ahead of the Worker, and\n * not needing a wrangler key Nitro would override. `run_worker_first` is\n * added to the written config for the one prefix. The server-side directory\n * is removed once copied, so nothing in it is uploaded twice. Returns how\n * many files were moved; none when nothing was stored.\n */\nexport async function storedPagesToAssets(staticDir: string, publicDir: string, wranglerPath: string): Promise<number> {\n const { cp, readFile: read, writeFile: write, stat, readdir: list } = await import('node:fs/promises')\n const prefix = ASSETS_PREFIX(staticDir.split(/[\\\\/]/).pop() || 'rsc-static')\n\n try {\n await stat(staticDir)\n } catch {\n return 0\n }\n\n let copied = 0\n const count = async (dir: string): Promise<void> => {\n for (const entry of await list(dir, { withFileTypes: true })) {\n if (entry.isDirectory()) await count(join(dir, entry.name))\n else copied++\n }\n }\n\n await count(staticDir)\n await cp(staticDir, join(publicDir, prefix), { recursive: true })\n\n // Moved, not copied: wrangler's default rules upload every .html and\n // .txt under the server directory as a text module, and 573 stored\n // shells left beside the bundle were 55 MB of modules against a 10 MB\n // limit - a deploy that happened to fit, once.\n const { rm } = await import('node:fs/promises')\n\n await rm(staticDir, { recursive: true, force: true })\n\n try {\n const config = JSON.parse(await read(wranglerPath, 'utf-8')) as {\n assets?: { run_worker_first?: boolean | string[] } & Record<string, unknown>\n }\n\n if (config.assets && config.assets.run_worker_first !== true) {\n const first = Array.isArray(config.assets.run_worker_first) ? config.assets.run_worker_first : []\n const pattern = `/${prefix}/*`\n\n if (!first.includes(pattern)) config.assets.run_worker_first = [...first, pattern]\n\n await write(wranglerPath, JSON.stringify(config, null, 2))\n }\n } catch {\n // No wrangler.json to amend: a deploy config the app writes itself, which\n // then carries the prefix in its own run_worker_first.\n }\n\n return copied\n}\n"]}
|
|
1
|
+
{"version":3,"file":"files.js","sourceRoot":"","sources":["../src/files.ts"],"names":[],"mappings":"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","sourcesContent":["// Reading built output off a disk.\n//\n// Kept apart from the host on purpose: it is the only part of serving an RSC\n// app that assumes a filesystem, and plenty of places to run one do not have\n// one. Nothing in `@rsc-kit/core/host` imports this module, so a bundle for a\n// host without a filesystem carries no reference to `node:fs` at all.\n//\n// Assets are not here any more — Nitro publishes and serves those. What is\n// left is the prerendered output: written by the build, read by the server it\n// generates, and copied by a static export.\n\nimport { cp, mkdir, readdir, readFile, writeFile } from 'node:fs/promises'\nimport { dirname, join } from 'node:path'\n\n/**\n * Read what the prerenderer wrote, from a directory.\n *\n * Missing is an answer, not an error: a partial prerender is a valid state,\n * and anything not found here is rendered on demand instead.\n */\nexport function prerenderedFrom(dir: string) {\n /**\n * What is on disk, listed once.\n *\n * A miss used to be a thrown ENOENT, and misses are the common case: the\n * host asks for `{url}.html`, then `{url}.ppr.html`, then the route's\n * pattern — so every request to a page served by a pattern shell threw and\n * caught two exceptions before finding anything. Measured at 3,000 req/s\n * against 28,000 for the same page read from memory.\n *\n * Contents are cached for the life of the process. A build's output does\n * not change under a running server - a deploy restarts it, and a server\n * that outlived a rebuild would be serving a stale engine against new\n * pages anyway - so the first read is the only one. Under load the same\n * page used to be opened, read and closed thousands of times a second,\n * which a profile showed as the one cost on a stored page that was ours\n * rather than React's. Capped by bytes, so a site with more pages than\n * memory holds the hot ones and re-reads the rest.\n */\n let present: Promise<Set<string>> | null = null\n\n const CONTENT_CAP_BYTES = 64 * 1024 * 1024\n const contents = new Map<string, string>()\n let held = 0\n\n const remember = (name: string, text: string): void => {\n const size = text.length * 2\n\n if (size > CONTENT_CAP_BYTES / 4) return\n\n while (held + size > CONTENT_CAP_BYTES && contents.size > 0) {\n const oldest = contents.keys().next().value as string\n held -= contents.get(oldest)!.length * 2\n contents.delete(oldest)\n }\n\n contents.set(name, text)\n held += size\n }\n\n const listing = async (): Promise<Set<string>> => {\n present ??= readdir(dir, { recursive: true })\n .then((names) => new Set(names.map((n) => String(n).replace(/\\\\/g, '/'))))\n // An absent directory is an empty one: a partial prerender is a valid\n // state, and everything falls through to being rendered.\n .catch(() => new Set<string>())\n\n return await present\n }\n\n return async (name: string): Promise<string | null> => {\n if (name.includes('..')) return null\n\n if (!(await listing()).has(name)) return null\n\n const cached = contents.get(name)\n\n if (cached !== undefined) return cached\n\n try {\n const text = await readFile(join(dir, name), 'utf-8')\n\n remember(name, text)\n\n return text\n } catch {\n return null\n }\n }\n}\n\n/**\n * The same reader, for a directory whose absolute path is not known until the\n * server runs.\n *\n * Nitro bundles the generated entry to a different depth depending on the\n * preset — `.output/server/index.mjs` for one, `.output/server/_ssr/rsc.mjs`\n * for another — so neither a fixed relative path nor a path baked in at build\n * time survives: the first is wrong for half the presets, and the second stops\n * being true the moment `.output/` is copied to the machine that serves it.\n *\n * So the caller passes its own `import.meta.url` and the directory is found by\n * walking up from it. A few levels, bounded, and resolved once.\n *\n * prerendered: prerenderedBeside(import.meta.url, 'rsc-static')\n *\n * Not finding it is a valid state and not an error: nothing was frozen, or\n * this host has no filesystem to have frozen it on. Every page renders live,\n * which is what happens today everywhere.\n */\n/**\n * Where a compiled binary puts the frozen pages.\n *\n * `bun build --compile` embeds what is imported statically and nothing a\n * computed import names, so the walk below finds no directory and no\n * module inside a binary. The build writes `compile.mjs` beside the\n * server: it imports the inline module by name - which embeds it - and\n * hands the pages over here before importing the server. Shared as a\n * global under a registered symbol, because the wrapper and this module\n * are bundled apart.\n */\nexport const EMBEDDED_PAGES = Symbol.for('rsc-kit.embedded-pages')\n\nfunction embeddedPages(): Record<string, string> | null {\n const pages = (globalThis as Record<symbol, unknown>)[EMBEDDED_PAGES]\n\n return pages && typeof pages === 'object' ? (pages as Record<string, string>) : null\n}\n\nexport function prerenderedBeside(moduleUrl: string, dirName: string, levels = 4) {\n let reader: Promise<(name: string) => Promise<string | null>> | null = null\n\n const resolveDir = async (): Promise<(name: string) => Promise<string | null>> => {\n const embedded = embeddedPages()\n\n if (embedded) return async (name) => embedded[name] ?? null\n\n let dir: string | null = null\n\n try {\n const { fileURLToPath } = await import('node:url')\n\n dir = dirname(fileURLToPath(moduleUrl))\n } catch {\n // No filesystem, or no file: url to speak of. The inline module below\n // is the only place the pages can be.\n }\n\n if (dir !== null) {\n for (let i = 0; i <= levels; i++) {\n const candidate = join(dir, ...Array(i).fill('..'), dirName)\n\n try {\n await readdir(candidate)\n\n return prerenderedFrom(candidate)\n } catch {\n // Not at this level. Keep walking.\n }\n }\n }\n\n // A Worker: the pages were uploaded as static assets, under a prefix\n // the Worker answers first, and are read back through the binding.\n const assets = await workersAssets()\n\n if (assets) return assetsReader(assets, `/${ASSETS_PREFIX(dirName)}`)\n\n const inline = await inlinePrerendered(moduleUrl, `${dirName}-inline.mjs`, levels)\n\n return inline ? async (name) => inline[name] ?? null : async () => null\n }\n\n return async (name: string): Promise<string | null> => {\n reader ??= resolveDir()\n\n return await (await reader)(name)\n }\n}\n\n/**\n * Where the stored pages live among a Worker's static assets.\n *\n * Under a prefix, beside the app's own public files, because that is the\n * one store a Worker has that costs nothing in script size: an inline module\n * counts against the bundle's limit, and a port's 571 stored category pages\n * came to 69 MB of module against a limit of 10. The prefix is one the\n * Worker answers first - `run_worker_first` in wrangler.json, written by\n * the build - so a browser asking for `/_rsc-static/x.ppr.html` reaches the\n * app, which has no such route, rather than the asset; a stored page of a\n * guarded route is served only by the host that runs the guard.\n */\nexport const ASSETS_PREFIX = (dirName: string): string => `_${dirName}`\n\n/** The Workers assets binding, where this runs on Workers and it is bound. */\nasync function workersAssets(): Promise<AssetsBinding | null> {\n if (typeof navigator === 'undefined' || navigator.userAgent !== 'Cloudflare-Workers') return null\n\n try {\n // Computed, so neither the bundler nor tsc looks for a module only the\n // Workers runtime has.\n const specifier = 'cloudflare:workers'\n const { env } = (await import(/* @vite-ignore */ specifier)) as { env: { ASSETS?: AssetsBinding } }\n\n return env.ASSETS && typeof env.ASSETS.fetch === 'function' ? env.ASSETS : null\n } catch {\n return null\n }\n}\n\ninterface AssetsBinding {\n fetch(input: Request | string): Promise<Response>\n}\n\n/**\n * Read stored pages through the assets binding, each name once per isolate.\n *\n * The host asks for `{url}.html`, then `{url}.ppr.html`, then the pattern's,\n * on every request: three asks per page, most of them misses. The binding\n * is a fetch, not a memory read, so the answers - misses included - are kept\n * for the life of the isolate, the way the disk reader keeps its listing.\n */\nconst KNOWN_LIMIT = 4096\n\nexport function assetsReader(assets: AssetsBinding, prefix: string): (name: string) => Promise<string | null> {\n const known = new Map<string, Promise<string | null>>()\n\n return (name) => {\n let pending = known.get(name)\n\n if (!pending) {\n // Bounded. Misses are kept too, and every made-up path is three of\n // them: kept for the life of the isolate, a crawler of random urls grew\n // this without end. Dropping the oldest costs one fetch, later.\n if (known.size >= KNOWN_LIMIT) known.delete(known.keys().next().value!)\n\n const path = `${prefix}/${name.split('/').map(encodeURIComponent).join('/')}`\n\n pending = assets\n .fetch(new Request(`https://assets.invalid${path}`))\n .then((response) => (response.ok ? response.text() : null))\n .catch(() => null)\n\n known.set(name, pending)\n }\n\n return pending\n }\n}\n\n/**\n * The frozen pages as one module, for a runtime with no filesystem.\n *\n * A Worker cannot readdir. Its modules are what wrangler uploaded, and a\n * sibling .mjs beside the bundle is one of them - so the build writes every\n * stored file into `rsc-static-inline.mjs` as strings, and this walks up from\n * the caller the way the disk reader does, importing rather than reading.\n * The specifier is computed, and marked for the bundler to leave alone: at\n * bundle time the file does not exist yet, because it is written by the\n * prerender that runs the bundle.\n *\n * Two forms of the specifier, because runtimes disagree. workerd resolves a\n * relative string against the importing module's name and refuses a url;\n * Node and Bun want the url, since a relative string would resolve against\n * this file rather than the caller's.\n */\nasync function inlinePrerendered(\n moduleUrl: string,\n fileName: string,\n levels: number,\n): Promise<Record<string, string> | null> {\n for (let i = 0; i <= levels; i++) {\n const relative = './' + '../'.repeat(i) + fileName\n\n for (const specifier of [relative, safeUrl(relative, moduleUrl)]) {\n if (!specifier) continue\n\n try {\n const loaded = (await import(/* @vite-ignore */ specifier)) as { default?: Record<string, string> }\n\n if (loaded.default && typeof loaded.default === 'object') return loaded.default\n } catch {\n // Not there, or not at this level.\n }\n }\n }\n\n return null\n}\n\nfunction safeUrl(relative: string, base: string): string | null {\n try {\n return new URL(relative, base).href\n } catch {\n return null\n }\n}\n\n/**\n * The entry a binary is compiled from, written beside the server.\n *\n * Two static imports, in this order: the inline module first - evaluating\n * it hands the pages over - and the server second. A module's imports are\n * evaluated in order, before its own body, so the pages are in place before\n * the server's first line runs. Bun embeds both.\n *\n * Static rather than `await import()`: a top-level await is what made Bun\n * skip `--bytecode` for this entry, silently, byte for byte - and a port\n * whose other Nitro app compiled with it asked why this one could not.\n * `bun build --compile --bytecode .output/server/compile.mjs` works now.\n */\nexport function compileEntrySource(dirName: string): string {\n return (\n '// The entry to compile into one binary:\\n' +\n '// bun build --compile .output/server/compile.mjs --outfile dist/app\\n' +\n '//\\n' +\n '//\\n' +\n '// A binary carries what is imported by name. The server reads its frozen pages\\n' +\n '// through a computed import, which a compile cannot see - imported here, they\\n' +\n '// travel inside the binary and are handed to the server before it starts.\\n' +\n '// Two static imports in this order, and no top-level await: imports evaluate\\n' +\n '// in order, and an await here is what stopped --bytecode from applying.\\n' +\n `import \"./${inlineModuleName(dirName)}\";\\n` +\n 'import \"./index.mjs\";\\n'\n )\n}\n\n/** The name the build writes the inline module under, beside the stored pages' directory. */\nexport function inlineModuleName(dirName: string): string {\n return `${dirName}-inline.mjs`\n}\n\n/**\n * Every stored file under `dir`, as the source of the inline module.\n * Strings only: a frozen page, its flight payload, its meta, an api answer.\n */\nexport async function inlineModuleSource(dir: string): Promise<string> {\n const { readdir: list, readFile: read } = await import('node:fs/promises')\n const entries: Record<string, string> = {}\n\n const walk = async (sub: string): Promise<void> => {\n for (const entry of await list(join(dir, sub), { withFileTypes: true })) {\n const rel = sub ? `${sub}/${entry.name}` : entry.name\n\n if (entry.isDirectory()) await walk(rel)\n else entries[rel] = await read(join(dir, rel), 'utf-8')\n }\n }\n\n await walk('')\n\n // Exported for the Worker, which imports it when the directory is not\n // there, and handed over as a global for the binary, whose compile entry\n // imports it first for exactly this side effect. The same data either way.\n return (\n '// @generated by the RSC build: the stored pages, for a runtime with no filesystem.\\n' +\n 'const pages = ' +\n JSON.stringify(entries) +\n ';\\n' +\n 'globalThis[Symbol.for(\"rsc-kit.embedded-pages\")] = pages;\\n' +\n 'export default pages;\\n'\n )\n}\n\nfunction contentTypeOf(pathname: string): string {\n if (pathname.endsWith('.js')) return 'text/javascript; charset=utf-8'\n if (pathname.endsWith('.css')) return 'text/css; charset=utf-8'\n if (pathname.endsWith('.map')) return 'application/json; charset=utf-8'\n if (pathname.endsWith('.svg')) return 'image/svg+xml'\n if (pathname.endsWith('.woff2')) return 'font/woff2'\n\n return 'application/octet-stream'\n}\n\n/**\n * Write build output into a directory.\n *\n * The sink `prerender` and `exportSite` take. Names are relative and may\n * contain directories — `docs/index.html` — so each one's parent is created\n * as it goes.\n */\nexport function writeTo(dir: string): ((name: string, contents: string) => Promise<void>) & { dir: string } {\n const write = async (name: string, contents: string): Promise<void> => {\n const path = join(dir, name)\n\n await mkdir(dirname(path), { recursive: true })\n await writeFile(path, contents)\n }\n\n // Where it wrote, for a caller that has to read it back. The embeddable\n // module has to list these files, and being told the directory a second time\n // is a second place for it to be wrong.\n return Object.assign(write, { dir })\n}\n\n/**\n * Copy the built browser bundle into an exported site.\n *\n * Separate from the export itself because copying a tree of files is a\n * filesystem operation by nature — a deploy that uploads them to a bucket\n * has its own way to do that, and passes its own callback instead.\n */\n/**\n * The whole client output into an exported site: every file a server would\n * have answered as a file - the bundle, public/, icons, the web manifest,\n * the service worker. Precompressed copies (.br, .gz, .zst) come too; a host\n * that does not serve them ignores them.\n */\nexport function copyPublic(from: string, to: string) {\n return async (): Promise<void> => {\n await mkdir(to, { recursive: true })\n await cp(from, to, { recursive: true })\n }\n}\n\n/** A stored route.ts answer, as prerender writes it. */\ninterface StoredAnswer {\n status: number\n headers: [string, string][]\n body: string\n varies: boolean\n}\n\n/**\n * Stored route.ts answers written out as the files they are: the body at the\n * url, `robots.txt` at robots.txt. Only answers a static host can give as\n * they were - a 200 the same for everyone, at a url with an extension, since\n * a file is typed by its extension and the stored content type would be lost.\n */\nexport async function exportStoredAnswers(\n staticDir: string,\n to: string,\n): Promise<{ written: string[]; skipped: { url: string; why: string }[] }> {\n const written: string[] = []\n const skipped: { url: string; why: string }[] = []\n let entries: string[]\n\n try {\n entries = (await readdir(staticDir, { recursive: true })) as string[]\n } catch {\n return { written, skipped }\n }\n\n for (const entry of entries.sort()) {\n if (!entry.endsWith('.api.json')) continue\n\n const path = entry.slice(0, -'.api.json'.length).split(/[\\\\/]/).join('/')\n const url = '/' + (path === 'index' ? '' : path)\n const answer = JSON.parse(await readFile(join(staticDir, entry), 'utf-8')) as StoredAnswer\n\n if (answer.status !== 200) {\n skipped.push({ url, why: `answers ${answer.status}` })\n continue\n }\n\n if (answer.varies) {\n skipped.push({ url, why: 'varies by request' })\n continue\n }\n\n if (!/\\.[a-z0-9]+$/i.test(path)) {\n skipped.push({ url, why: 'no extension to give a static host its content type' })\n continue\n }\n\n const target = join(to, path)\n\n await mkdir(dirname(target), { recursive: true })\n await writeFile(target, answer.body)\n written.push(url)\n }\n\n return { written, skipped }\n}\n\nexport function copyAssets(from: string, to: string, url = '/assets/') {\n return async (): Promise<void> => {\n const at = url.replace(/^\\/+|\\/+$/g, '')\n\n if (at === '') return\n\n const target = join(to, at)\n\n await mkdir(dirname(target), { recursive: true })\n await cp(from, target, { recursive: true })\n }\n}\n\n/**\n * Put the stored pages among a Worker's static assets, and have the Worker\n * answer their prefix first.\n *\n * Run after Nitro has written its public-asset list and wrangler.json, so\n * the copies are in neither: not served as assets ahead of the Worker, and\n * not needing a wrangler key Nitro would override. `run_worker_first` is\n * added to the written config for the one prefix. The server-side directory\n * is removed once copied, so nothing in it is uploaded twice. Returns how\n * many files were moved; none when nothing was stored.\n */\nexport async function storedPagesToAssets(staticDir: string, publicDir: string, wranglerPath: string): Promise<number> {\n const { cp, readFile: read, writeFile: write, stat, readdir: list } = await import('node:fs/promises')\n const prefix = ASSETS_PREFIX(staticDir.split(/[\\\\/]/).pop() || 'rsc-static')\n\n try {\n await stat(staticDir)\n } catch {\n return 0\n }\n\n let copied = 0\n const count = async (dir: string): Promise<void> => {\n for (const entry of await list(dir, { withFileTypes: true })) {\n if (entry.isDirectory()) await count(join(dir, entry.name))\n else copied++\n }\n }\n\n await count(staticDir)\n await cp(staticDir, join(publicDir, prefix), { recursive: true })\n\n // Moved, not copied: wrangler's default rules upload every .html and\n // .txt under the server directory as a text module, and 573 stored\n // shells left beside the bundle were 55 MB of modules against a 10 MB\n // limit - a deploy that happened to fit, once.\n const { rm } = await import('node:fs/promises')\n\n await rm(staticDir, { recursive: true, force: true })\n\n try {\n const config = JSON.parse(await read(wranglerPath, 'utf-8')) as {\n assets?: { run_worker_first?: boolean | string[] } & Record<string, unknown>\n }\n\n if (config.assets && config.assets.run_worker_first !== true) {\n const first = Array.isArray(config.assets.run_worker_first) ? config.assets.run_worker_first : []\n const pattern = `/${prefix}/*`\n\n if (!first.includes(pattern)) config.assets.run_worker_first = [...first, pattern]\n\n await write(wranglerPath, JSON.stringify(config, null, 2))\n }\n } catch {\n // No wrangler.json to amend: a deploy config the app writes itself, which\n // then carries the prefix in its own run_worker_first.\n }\n\n return copied\n}\n"]}
|
|
@@ -1,3 +1,13 @@
|
|
|
1
|
+
import type { Context } from "react";
|
|
2
|
+
/**
|
|
3
|
+
* The query of the request the server is rendering for, or null when the
|
|
4
|
+
* render may be stored. Set by the server's render around the whole tree;
|
|
5
|
+
* absent in the browser.
|
|
6
|
+
*
|
|
7
|
+
* Kept on a global symbol so the server's entry and the copy of this module
|
|
8
|
+
* the client components were bundled with agree on one context.
|
|
9
|
+
*/
|
|
10
|
+
export declare function searchSnapshotContext(): Context<string | null | undefined>;
|
|
1
11
|
/**
|
|
2
12
|
* The digest a stored page carries where the query was read under the
|
|
3
13
|
* boundary that caught it. The client recognises it on hydration and does
|
|
@@ -7,23 +7,35 @@
|
|
|
7
7
|
* same route is asked for with `?q=shoes` and `?q=hats`, and a page stored
|
|
8
8
|
* holding one of them would serve it to everyone.
|
|
9
9
|
*
|
|
10
|
-
* So
|
|
11
|
-
*
|
|
12
|
-
*
|
|
13
|
-
*
|
|
14
|
-
*
|
|
15
|
-
*
|
|
10
|
+
* So the server answers only when it is rendering for a request: a page
|
|
11
|
+
* rendered per visitor - or the hole of a stored shell, filled per request -
|
|
12
|
+
* has that visitor's query, and a component reading it renders on the server
|
|
13
|
+
* like any other, with no flash. Where the HTML may be stored - the build -
|
|
14
|
+
* there is no query to give, and this throws rather than inventing one.
|
|
15
|
+
* React treats that as recoverable at the nearest Suspense boundary: the
|
|
16
|
+
* fallback is what gets stored, and the client renders the real thing on
|
|
17
|
+
* hydration. Without a boundary the error reaches the root, nothing paints,
|
|
18
|
+
* and the build refuses the route and says why.
|
|
16
19
|
*
|
|
17
|
-
*
|
|
18
|
-
*
|
|
19
|
-
*
|
|
20
|
-
|
|
20
|
+
* Returning an empty URLSearchParams at build instead would be worse than
|
|
21
|
+
* either: the page would be stored showing results for no query at all, and
|
|
22
|
+
* nothing would say so.
|
|
23
|
+
*/
|
|
24
|
+
import { createContext, useContext, useSyncExternalStore } from "react";
|
|
25
|
+
/**
|
|
26
|
+
* The query of the request the server is rendering for, or null when the
|
|
27
|
+
* render may be stored. Set by the server's render around the whole tree;
|
|
28
|
+
* absent in the browser.
|
|
21
29
|
*
|
|
22
|
-
*
|
|
23
|
-
*
|
|
24
|
-
* say so.
|
|
30
|
+
* Kept on a global symbol so the server's entry and the copy of this module
|
|
31
|
+
* the client components were bundled with agree on one context.
|
|
25
32
|
*/
|
|
26
|
-
|
|
33
|
+
export function searchSnapshotContext() {
|
|
34
|
+
const key = Symbol.for("rsc-kit.search-snapshot");
|
|
35
|
+
const store = globalThis;
|
|
36
|
+
// undefined: no server render set it - the browser, hydrating.
|
|
37
|
+
return (store[key] ??= createContext(undefined));
|
|
38
|
+
}
|
|
27
39
|
const listeners = new Set();
|
|
28
40
|
/**
|
|
29
41
|
* Cached by the string it was parsed from.
|
|
@@ -67,14 +79,39 @@ function getSnapshot() {
|
|
|
67
79
|
* not report the fallback as an error, because it is the designed path.
|
|
68
80
|
*/
|
|
69
81
|
export const SEARCH_PARAMS_FALLBACK = "rsc-kit:search-params-fallback";
|
|
70
|
-
|
|
71
|
-
|
|
82
|
+
/** One URLSearchParams per query the server renders for: the snapshot must keep its identity. */
|
|
83
|
+
const serverParams = new Map();
|
|
84
|
+
function paramsFor(search) {
|
|
85
|
+
let params = serverParams.get(search);
|
|
86
|
+
if (!params) {
|
|
87
|
+
if (serverParams.size > 500)
|
|
88
|
+
serverParams.clear();
|
|
89
|
+
params = new URLSearchParams(search);
|
|
90
|
+
serverParams.set(search, params);
|
|
91
|
+
}
|
|
92
|
+
return params;
|
|
93
|
+
}
|
|
94
|
+
function serverSnapshot(search) {
|
|
95
|
+
// The server rendering for a request: that request's query.
|
|
96
|
+
if (typeof search === "string")
|
|
97
|
+
return paramsFor(search);
|
|
98
|
+
// Hydrating in the browser, where no server render set one: the server
|
|
99
|
+
// rendered for the url in the bar, so that is what it saw. A part the
|
|
100
|
+
// server refused was never hydrated - the client renders it fresh.
|
|
101
|
+
if (search === undefined && typeof window !== "undefined")
|
|
102
|
+
return getSnapshot();
|
|
103
|
+
// A render whose HTML may be stored - or a server render nobody told.
|
|
104
|
+
return refuse();
|
|
105
|
+
}
|
|
106
|
+
function refuse() {
|
|
107
|
+
const error = new Error("useSearchParams() was read while rendering a page that may be stored, where there is no query string to give: " +
|
|
72
108
|
"a stored page would serve one visitor's query to everyone. Wrap the component in <Suspense> — or add a " +
|
|
73
109
|
"loading.tsx beside the page — so the fallback is stored and the real value arrives in the browser.");
|
|
74
110
|
error.digest = SEARCH_PARAMS_FALLBACK;
|
|
75
111
|
throw error;
|
|
76
112
|
}
|
|
77
113
|
export function useSearchParams() {
|
|
78
|
-
|
|
114
|
+
const search = useContext(searchSnapshotContext());
|
|
115
|
+
return useSyncExternalStore(subscribe, getSnapshot, () => serverSnapshot(search));
|
|
79
116
|
}
|
|
80
117
|
//# sourceMappingURL=useSearchParams.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useSearchParams.js","sourceRoot":"","sources":["../../src/js/useSearchParams.ts"],"names":[],"mappings":"AAAA,YAAY,CAAC;AAEb
|
|
1
|
+
{"version":3,"file":"useSearchParams.js","sourceRoot":"","sources":["../../src/js/useSearchParams.ts"],"names":[],"mappings":"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","sourcesContent":["\"use client\";\n\n/**\n * The query string, live across navigations.\n *\n * Deliberately unlike usePathname, which answers with the url being rendered.\n * A pathname is fixed for a given stored page; a query string is not — the\n * same route is asked for with `?q=shoes` and `?q=hats`, and a page stored\n * holding one of them would serve it to everyone.\n *\n * So the server answers only when it is rendering for a request: a page\n * rendered per visitor - or the hole of a stored shell, filled per request -\n * has that visitor's query, and a component reading it renders on the server\n * like any other, with no flash. Where the HTML may be stored - the build -\n * there is no query to give, and this throws rather than inventing one.\n * React treats that as recoverable at the nearest Suspense boundary: the\n * fallback is what gets stored, and the client renders the real thing on\n * hydration. Without a boundary the error reaches the root, nothing paints,\n * and the build refuses the route and says why.\n *\n * Returning an empty URLSearchParams at build instead would be worse than\n * either: the page would be stored showing results for no query at all, and\n * nothing would say so.\n */\n\nimport { createContext, useContext, useSyncExternalStore } from \"react\";\nimport type { Context } from \"react\";\n\n/**\n * The query of the request the server is rendering for, or null when the\n * render may be stored. Set by the server's render around the whole tree;\n * absent in the browser.\n *\n * Kept on a global symbol so the server's entry and the copy of this module\n * the client components were bundled with agree on one context.\n */\nexport function searchSnapshotContext(): Context<string | null | undefined> {\n const key = Symbol.for(\"rsc-kit.search-snapshot\");\n const store = globalThis as Record<symbol, Context<string | null | undefined> | undefined>;\n\n // undefined: no server render set it - the browser, hydrating.\n return (store[key] ??= createContext<string | null | undefined>(undefined));\n}\n\nconst listeners = new Set<() => void>();\n\n/**\n * Cached by the string it was parsed from.\n *\n * useSyncExternalStore compares snapshots by identity, so handing back a fresh\n * URLSearchParams on every read reads as \"changed every time\" and loops until\n * React gives up.\n */\nlet cached = { search: \"\", params: new URLSearchParams() };\n\nfunction currentSearch(): string {\n return typeof window === \"undefined\" ? \"\" : window.location.search;\n}\n\nfunction notify(): void {\n listeners.forEach((fn) => fn());\n}\n\nlet listening = false;\n\nfunction subscribe(callback: () => void): () => void {\n // On the first subscriber rather than at module load. A listener attached\n // when the module is evaluated is attached to whatever `window` exists at\n // that moment — which in a test that installs a DOM after its imports is\n // none, and the hook silently never updates. Attaching here is the shape\n // useSyncExternalStore expects and is correct wherever the module loads.\n if (!listening && typeof window !== \"undefined\") {\n window.addEventListener(\"rsc-navigate\", notify);\n window.addEventListener(\"popstate\", notify);\n listening = true;\n }\n\n listeners.add(callback);\n\n return () => listeners.delete(callback);\n}\n\nfunction getSnapshot(): URLSearchParams {\n const search = currentSearch();\n\n if (search !== cached.search) {\n cached = { search, params: new URLSearchParams(search) };\n }\n\n return cached.params;\n}\n\n/**\n * The digest a stored page carries where the query was read under the\n * boundary that caught it. The client recognises it on hydration and does\n * not report the fallback as an error, because it is the designed path.\n */\nexport const SEARCH_PARAMS_FALLBACK = \"rsc-kit:search-params-fallback\";\n\n/** One URLSearchParams per query the server renders for: the snapshot must keep its identity. */\nconst serverParams = new Map<string, URLSearchParams>();\n\nfunction paramsFor(search: string): URLSearchParams {\n let params = serverParams.get(search);\n\n if (!params) {\n if (serverParams.size > 500) serverParams.clear();\n params = new URLSearchParams(search);\n serverParams.set(search, params);\n }\n\n return params;\n}\n\nfunction serverSnapshot(search: string | null | undefined): URLSearchParams {\n // The server rendering for a request: that request's query.\n if (typeof search === \"string\") return paramsFor(search);\n\n // Hydrating in the browser, where no server render set one: the server\n // rendered for the url in the bar, so that is what it saw. A part the\n // server refused was never hydrated - the client renders it fresh.\n if (search === undefined && typeof window !== \"undefined\") return getSnapshot();\n\n // A render whose HTML may be stored - or a server render nobody told.\n return refuse();\n}\n\nfunction refuse(): URLSearchParams {\n const error = new Error(\n \"useSearchParams() was read while rendering a page that may be stored, where there is no query string to give: \" +\n \"a stored page would serve one visitor's query to everyone. Wrap the component in <Suspense> — or add a \" +\n \"loading.tsx beside the page — so the fallback is stored and the real value arrives in the browser.\",\n ) as Error & { digest?: string };\n\n error.digest = SEARCH_PARAMS_FALLBACK;\n\n throw error;\n}\n\nexport function useSearchParams(): URLSearchParams {\n const search = useContext(searchSnapshotContext());\n\n return useSyncExternalStore(subscribe, getSnapshot, () => serverSnapshot(search));\n}\n"]}
|
package/dist/request.d.ts
CHANGED
|
@@ -124,6 +124,13 @@ export declare function request(): Promise<Request | null>;
|
|
|
124
124
|
* The same name and behaviour as Next's `connection()`.
|
|
125
125
|
*/
|
|
126
126
|
export declare function connection(): Promise<void>;
|
|
127
|
+
/**
|
|
128
|
+
* The query of the request being rendered - `?q=shoes`, or "" - and null when
|
|
129
|
+
* there is no request: a build, whose render may be stored. For the server's
|
|
130
|
+
* HTML render, which hands it to useSearchParams. Not a read of the request:
|
|
131
|
+
* the render it serves is per request already.
|
|
132
|
+
*/
|
|
133
|
+
export declare function requestSearch(): string | null;
|
|
127
134
|
/** The url this request was made to, whichever way the host supplied it. */
|
|
128
135
|
export declare function url(): Promise<string | null>;
|
|
129
136
|
/**
|
package/dist/request.js
CHANGED
|
@@ -434,6 +434,23 @@ export async function connection() {
|
|
|
434
434
|
if (!store.request)
|
|
435
435
|
return never("connection()");
|
|
436
436
|
}
|
|
437
|
+
/**
|
|
438
|
+
* The query of the request being rendered - `?q=shoes`, or "" - and null when
|
|
439
|
+
* there is no request: a build, whose render may be stored. For the server's
|
|
440
|
+
* HTML render, which hands it to useSearchParams. Not a read of the request:
|
|
441
|
+
* the render it serves is per request already.
|
|
442
|
+
*/
|
|
443
|
+
export function requestSearch() {
|
|
444
|
+
const store = scope()?.getStore();
|
|
445
|
+
if (!store?.request || !store.url)
|
|
446
|
+
return null;
|
|
447
|
+
try {
|
|
448
|
+
return new URL(store.url, "http://rsc.invalid").search;
|
|
449
|
+
}
|
|
450
|
+
catch {
|
|
451
|
+
return null;
|
|
452
|
+
}
|
|
453
|
+
}
|
|
437
454
|
/** The url this request was made to, whichever way the host supplied it. */
|
|
438
455
|
export async function url() {
|
|
439
456
|
const store = slot();
|