@rsc-kit/core 0.30.25 → 0.30.26

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.
@@ -0,0 +1,123 @@
1
+ /**
2
+ * Native packages inside a compiled binary.
3
+ *
4
+ * A package with a native binary - sharp, a database driver - is left external
5
+ * by the build, and Nitro traces it into .output/server/node_modules. A server
6
+ * run from that directory loads it from there. `bun build --compile` cannot:
7
+ * it bundles the package's JavaScript, and the package then looks for its
8
+ * `.node` file beside a module that is no longer on disk, so the binary starts
9
+ * and dies on the first import of it.
10
+ *
11
+ * So a binary carries those packages as files, and writes them to disk the
12
+ * first time it runs: to `<RSC_KIT_RUNTIME_DIR>/<hash>/node_modules`, the
13
+ * binary's own directory when the variable is unset. The hash is of the files,
14
+ * so two versions sharing one directory during a deploy never share a tree,
15
+ * and a second start of the same version writes nothing.
16
+ *
17
+ * Inside a binary Bun resolves no package by name, from anywhere - not from
18
+ * the bundle, and not from a file on disk that the bundle loaded. Neither a
19
+ * `Module._resolveFilename` hook nor a runtime plugin sees an ESM import there.
20
+ * So every name is resolved here, at build time, while the tree is on disk:
21
+ * each import and require of a package in the tree is rewritten to a relative
22
+ * path, and the app's own imports of one go through a shim that loads it from
23
+ * the written tree. The hook stays, for a require whose name is computed.
24
+ *
25
+ * An app with nothing traced gets none of this: its compile entry is the one
26
+ * it always had.
27
+ */
28
+ /** Where the compile tree is written, beside .output/server. */
29
+ export declare const COMPILE_TREE_DIR = "compile";
30
+ /** A platform a binary runs on, in the terms a package.json's os, cpu and libc use. */
31
+ export interface Platform {
32
+ os: string;
33
+ arch: string;
34
+ /** Only on linux. */
35
+ libc?: 'glibc' | 'musl';
36
+ }
37
+ /** The platform this process runs on. */
38
+ export declare function hostPlatform(): Platform;
39
+ /**
40
+ * The platform a compile script targets: `--target=bun-linux-x64-musl`, or
41
+ * the build machine's own when it names none. `baseline` and `modern` are CPU
42
+ * levels of the same arch, and change nothing a package declares.
43
+ */
44
+ export declare function targetPlatform(script: string | undefined, host?: Platform): Platform;
45
+ export declare function describePlatform(platform: Platform): string;
46
+ interface PackageJson {
47
+ name?: string;
48
+ version?: string;
49
+ main?: string;
50
+ exports?: unknown;
51
+ os?: string[];
52
+ cpu?: string[];
53
+ libc?: string[];
54
+ optionalDependencies?: Record<string, string>;
55
+ }
56
+ export declare function runsOn(pkg: PackageJson, platform: Platform): boolean;
57
+ export interface MissingPackage {
58
+ name: string;
59
+ version?: string;
60
+ }
61
+ export interface NativeSet {
62
+ /** Package directory (relative to the tree's node_modules) to the directory its files are read from. */
63
+ packages: Map<string, string>;
64
+ missing: MissingPackage[];
65
+ }
66
+ /**
67
+ * The packages a binary for `target` needs: what Nitro traced, with each
68
+ * package built for the build machine swapped for the one built for the
69
+ * target. Nitro traces what is installed and loads on this machine, so a Mac
70
+ * compiling for linux-x64 traced darwin binaries; the linux ones are found
71
+ * beside them in the project's node_modules, or reported as missing.
72
+ */
73
+ export declare function nativeSet(serverNodeModules: string, projectRoot: string, target: Platform, named?: readonly string[]): NativeSet;
74
+ export declare function missingMessage(missing: MissingPackage[], target: Platform, host: Platform): string;
75
+ /**
76
+ * Every package name in a module's imports and requires, rewritten to the
77
+ * relative path of the file it resolves to inside the tree. A name the tree
78
+ * does not have - a branch for another platform, an optional peer - is left
79
+ * as it is. A file the parser cannot read is left whole; its requires reach
80
+ * the hook at runtime.
81
+ */
82
+ export declare function rewriteSpecifiers(code: string, file: string, treeRoot: string, parse: (code: string) => unknown, exists?: (path: string) => boolean): string;
83
+ /**
84
+ * What the binary runs before the first import of a native package: write the
85
+ * tree if this version has not, then answer each shim's require from it.
86
+ *
87
+ * Extraction is into a temporary directory renamed into place, so a tree that
88
+ * exists is a whole one: two copies starting at once each write their own,
89
+ * one rename wins, and the other discards its copy. A running copy touches its
90
+ * tree hourly, and a start removes the trees of other versions that nothing
91
+ * has touched for a day - never its own, and never one a running copy of
92
+ * another version is still using.
93
+ */
94
+ export declare const RUNTIME_SOURCE = "'use strict'\nconst { hash, files } = require('./natives.mjs')\nconst fs = require('node:fs')\nconst path = require('node:path')\nconst Module = require('node:module')\n\nconst HOUR = 60 * 60 * 1000\nconst STALE = 24 * HOUR\n\nlet base\n\nfunction prepare() {\n const root = process.env.RSC_KIT_RUNTIME_DIR ? path.resolve(process.env.RSC_KIT_RUNTIME_DIR) : path.dirname(process.execPath)\n const dir = path.join(root, hash)\n\n if (!fs.existsSync(dir)) {\n try {\n fs.mkdirSync(root, { recursive: true })\n const tmp = fs.mkdtempSync(path.join(root, '.' + hash + '-'))\n for (const [rel, src] of files) {\n const to = path.join(tmp, 'node_modules', rel)\n fs.mkdirSync(path.dirname(to), { recursive: true })\n fs.writeFileSync(to, fs.readFileSync(src))\n }\n try {\n fs.renameSync(tmp, dir)\n console.log('[rsc-kit] native packages: wrote ' + files.length + ' files to ' + dir)\n } catch (error) {\n fs.rmSync(tmp, { recursive: true, force: true })\n if (!fs.existsSync(dir)) throw error\n }\n } catch (error) {\n error.message =\n '[rsc-kit] the binary could not write its native packages to ' + root + ': ' + error.message +\n '. Set RSC_KIT_RUNTIME_DIR to a directory it can write to.'\n throw error\n }\n }\n\n const touch = () => { try { const now = new Date(); fs.utimesSync(dir, now, now) } catch {} }\n touch()\n setInterval(touch, HOUR).unref()\n sweep(root, path.basename(dir))\n\n base = path.join(dir, 'node_modules')\n\n // A require whose name is computed - require(name) - was not rewritten at\n // build time, and the binary's resolver cannot find it on disk. Answered\n // from the tree, for files inside it only.\n const resolve = Module._resolveFilename\n Module._resolveFilename = function (request, parent, ...rest) {\n try {\n return resolve.call(this, request, parent, ...rest)\n } catch (error) {\n const from = parent && parent.filename\n if (!from || !from.startsWith(dir) || request.startsWith('.') || request.startsWith('/') || Module.isBuiltin(request)) throw error\n const found = lookup(request, path.dirname(from))\n if (!found) throw error\n return found\n }\n }\n}\n\nfunction sweep(root, current) {\n let entries\n try { entries = fs.readdirSync(root, { withFileTypes: true }) } catch { return }\n const now = Date.now()\n for (const entry of entries) {\n if (!entry.isDirectory() || entry.name === current) continue\n const isTree = /^[0-9a-f]{16}$/.test(entry.name)\n const isPartial = /^\\.[0-9a-f]{16}-/.test(entry.name)\n if (!isTree && !isPartial) continue\n try {\n const age = now - fs.statSync(path.join(root, entry.name)).mtimeMs\n if (age > (isTree ? STALE : HOUR)) fs.rmSync(path.join(root, entry.name), { recursive: true, force: true })\n } catch {}\n }\n}\n\nfunction lookup(request, fromDir) {\n const parts = request.split('/')\n const name = request.startsWith('@') ? parts.slice(0, 2).join('/') : parts[0]\n const sub = request.slice(name.length)\n for (let dir = fromDir; dir.startsWith(base) || dir === path.dirname(base); dir = path.dirname(dir)) {\n const pkgDir = path.join(dir, 'node_modules', name)\n if (fs.existsSync(path.join(pkgDir, 'package.json'))) {\n if (sub) return path.join(pkgDir, sub)\n const pkg = JSON.parse(fs.readFileSync(path.join(pkgDir, 'package.json'), 'utf8'))\n return path.join(pkgDir, pkg.main || 'index.js')\n }\n if (dir === path.dirname(base)) break\n }\n}\n\nmodule.exports = function load(entry) {\n if (!base) prepare()\n const loaded = require(path.join(base, entry))\n // A package with only an ES module: required, it is a namespace, which an\n // import of the shim would otherwise take as a CommonJS module's exports.\n if (Object.prototype.toString.call(loaded) === '[object Module]') return { __esModule: true, ...loaded }\n return loaded\n}\n";
95
+ export interface CompileTree {
96
+ hash: string;
97
+ files: number;
98
+ packages: string[];
99
+ }
100
+ /**
101
+ * Write the compile tree for a server whose build traced external packages,
102
+ * and point compile.mjs at it. Returns undefined, and touches nothing, when
103
+ * there is nothing traced.
104
+ *
105
+ * The tree is a copy of the server with each traced package replaced by a
106
+ * shim, so `bun build --compile` bundles the shim and embeds the package's
107
+ * files: the server's own chunks import packages by name, and Bun resolves a
108
+ * name from the importing file's location, so the copy is what makes those
109
+ * names land on the shims rather than on the real packages beside the server.
110
+ */
111
+ export declare function writeCompileTree(options: {
112
+ serverDir: string;
113
+ projectRoot: string;
114
+ target: Platform;
115
+ parse: (code: string) => unknown;
116
+ /** serverExternalPackages, which go to disk whether or not they have a binary. */
117
+ named?: readonly string[];
118
+ }): CompileTree | {
119
+ missing: MissingPackage[];
120
+ } | undefined;
121
+ /** The size of a directory, for the build's one line about it. */
122
+ export declare function sizeOf(dir: string): number;
123
+ export {};