@junejs/server 0.1.0-dev.4 → 0.1.0-dev.7
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/adapter.d.ts +56 -0
- package/dist/adapter.js +211 -0
- package/dist/agent-discover.d.ts +5 -0
- package/dist/agent-discover.js +75 -0
- package/dist/agent-durable.d.ts +72 -0
- package/dist/agent-durable.js +141 -0
- package/dist/agent-native.d.ts +40 -0
- package/dist/agent-native.js +179 -0
- package/dist/app.d.ts +15 -0
- package/dist/app.js +252 -0
- package/dist/blob.d.ts +23 -0
- package/dist/blob.js +78 -0
- package/dist/build.d.ts +40 -0
- package/dist/build.js +582 -0
- package/dist/client-bundle.d.ts +15 -0
- package/dist/client-bundle.js +91 -0
- package/dist/config-loader.d.ts +9 -0
- package/dist/config-loader.js +25 -0
- package/dist/content.d.ts +39 -0
- package/dist/content.js +201 -0
- package/dist/css-modules-ambient.d.ts +10 -0
- package/dist/css-modules.d.ts +24 -0
- package/dist/css-modules.js +127 -0
- package/dist/css.d.ts +14 -0
- package/dist/css.js +114 -0
- package/dist/d1-BkdUg9kg.d.ts +24 -0
- package/dist/d1-migrate.d.ts +31 -0
- package/dist/d1-migrate.js +156 -0
- package/dist/d1.d.ts +2 -0
- package/dist/d1.js +32 -0
- package/dist/db.d.ts +11 -0
- package/dist/db.js +20 -0
- package/dist/deploy.d.ts +25 -0
- package/dist/deploy.js +158 -0
- package/dist/dev-reload.d.ts +5 -0
- package/dist/dev-reload.js +123 -0
- package/dist/dev.d.ts +13 -0
- package/dist/dev.js +55 -0
- package/dist/host.d.ts +25 -0
- package/dist/host.js +107 -0
- package/dist/index.d.ts +26 -0
- package/dist/index.js +26 -0
- package/dist/instrumentation.d.ts +4 -0
- package/dist/instrumentation.js +15 -0
- package/dist/island-registry.d.ts +8 -0
- package/dist/island-registry.js +117 -0
- package/dist/kv.d.ts +8 -0
- package/dist/kv.js +35 -0
- package/dist/migrate-BbWt-PuB.d.ts +32 -0
- package/dist/migrate.d.ts +2 -0
- package/dist/migrate.js +115 -0
- package/dist/mysql-driver-BsrWVqbp.d.ts +12 -0
- package/dist/mysql-driver.d.ts +2 -0
- package/dist/mysql-driver.js +52 -0
- package/dist/negotiate.d.ts +11 -0
- package/dist/negotiate.js +39 -0
- package/dist/pipeline-B2V6tKfO.d.ts +49 -0
- package/dist/pipeline.d.ts +2 -0
- package/dist/pipeline.js +235 -0
- package/dist/postgres-driver-DkkBFikA.d.ts +15 -0
- package/dist/postgres-driver.d.ts +2 -0
- package/dist/postgres-driver.js +50 -0
- package/dist/resources.d.ts +15 -0
- package/dist/resources.js +31 -0
- package/dist/router.d.ts +32 -0
- package/dist/router.js +183 -0
- package/dist/rsc-build.d.ts +17 -0
- package/dist/rsc-build.js +68 -0
- package/dist/rsc-bundle.d.ts +8 -0
- package/dist/rsc-bundle.js +39 -0
- package/dist/rsc-manifest.d.ts +8 -0
- package/dist/rsc-manifest.js +67 -0
- package/dist/rsc-runtime/flight-render-routes.d.ts +5 -0
- package/dist/rsc-runtime/flight-render-routes.js +26 -0
- package/dist/rsc-runtime/flight-render.d.ts +4 -0
- package/dist/rsc-runtime/flight-render.js +21 -0
- package/dist/rsc-runtime/flight-to-html.d.ts +4 -0
- package/dist/rsc-runtime/flight-to-html.js +32 -0
- package/dist/rsc-runtime/rsc-worker.d.ts +6 -0
- package/dist/rsc-runtime/rsc-worker.js +46 -0
- package/dist/rsc-runtime/rsdw-shims.d.ts +42 -0
- package/dist/segment.d.ts +14 -0
- package/dist/segment.js +33 -0
- package/dist/sqlite-driver.d.ts +25 -0
- package/dist/sqlite-driver.js +102 -0
- package/dist/static-files.d.ts +6 -0
- package/dist/static-files.js +56 -0
- package/dist/tsconfig-jsx.d.ts +15 -0
- package/dist/tsconfig-jsx.js +35 -0
- package/dist/turso-driver-C1wEigMZ.d.ts +22 -0
- package/dist/turso-driver.d.ts +2 -0
- package/dist/turso-driver.js +68 -0
- package/dist/worker.d.ts +55 -0
- package/dist/worker.js +211 -0
- package/package.json +115 -23
- package/src/adapter.ts +20 -7
- package/src/agent-discover.ts +5 -2
- package/src/agent-durable.ts +108 -4
- package/src/app.ts +74 -2
- package/src/build.ts +52 -3
- package/src/client-bundle.ts +3 -1
- package/src/index.ts +4 -0
- package/src/rsc-bundle.ts +3 -2
- package/src/static-files.ts +84 -0
- package/src/worker.ts +46 -29
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import { walk } from "./island-registry.js";
|
|
2
|
+
import { RSC_CLIENT_MANIFEST_FILE, generateRscManifests } from "./rsc-manifest.js";
|
|
3
|
+
import { bundleServerGraph, bundleSsrGraph } from "./rsc-bundle.js";
|
|
4
|
+
import { existsSync } from "node:fs";
|
|
5
|
+
import { mkdir, writeFile } from "node:fs/promises";
|
|
6
|
+
import { dirname, join, relative } from "node:path";
|
|
7
|
+
//#region src/rsc-build.ts
|
|
8
|
+
const RSC_ROUTES_FILE = "_rsc-routes.gen.tsx";
|
|
9
|
+
const RSC_PAGE_RE = /(?:^|\/)page\.rsc\.(tsx|jsx)$/;
|
|
10
|
+
function findRscRoutes(appDir) {
|
|
11
|
+
if (!existsSync(appDir)) return [];
|
|
12
|
+
return walk(appDir).filter((f) => RSC_PAGE_RE.test(f)).map((file) => {
|
|
13
|
+
const dir = dirname(relative(appDir, file));
|
|
14
|
+
return {
|
|
15
|
+
path: "/" + (dir === "." ? [] : dir.split("/").filter((s) => !/^\(.*\)$/.test(s))).join("/"),
|
|
16
|
+
file
|
|
17
|
+
};
|
|
18
|
+
}).map((r) => ({
|
|
19
|
+
...r,
|
|
20
|
+
path: r.path === "/" ? "/" : r.path.replace(/\/$/, "")
|
|
21
|
+
})).sort((a, b) => a.path.localeCompare(b.path));
|
|
22
|
+
}
|
|
23
|
+
function runtimeEntry(name) {
|
|
24
|
+
return join(dirname(new URL(import.meta.url).pathname), "rsc-runtime", name);
|
|
25
|
+
}
|
|
26
|
+
async function buildRsc(appRoot, outDir, docConfig) {
|
|
27
|
+
const appDir = join(appRoot, "app");
|
|
28
|
+
const routes = findRscRoutes(appDir);
|
|
29
|
+
if (routes.length === 0) return null;
|
|
30
|
+
generateRscManifests(appDir);
|
|
31
|
+
let routesGen = "// AUTO-GENERATED by June — do not edit. RSC route map.\n";
|
|
32
|
+
routesGen += "import type React from \"react\";\n";
|
|
33
|
+
routes.forEach((r, i) => {
|
|
34
|
+
const rel = "./" + relative(appDir, r.file).replace(/\.(tsx|jsx)$/, "");
|
|
35
|
+
routesGen += `import V${i} from ${JSON.stringify(rel)};\n`;
|
|
36
|
+
});
|
|
37
|
+
routesGen += "export { CLIENT_MANIFEST as clientManifest } from \"./_rsc-server.gen\";\n";
|
|
38
|
+
routesGen += "export const ROUTES: Record<string, React.ComponentType> = {\n";
|
|
39
|
+
routes.forEach((r, i) => routesGen += ` ${JSON.stringify(r.path)}: V${i},\n`);
|
|
40
|
+
routesGen += "};\n";
|
|
41
|
+
await writeFile(join(appDir, RSC_ROUTES_FILE), routesGen);
|
|
42
|
+
const configFile = join(appDir, "_rsc-config.gen.ts");
|
|
43
|
+
await writeFile(configFile, `// AUTO-GENERATED by June — do not edit. RSC document config.
|
|
44
|
+
export const DOC_CONFIG = ${JSON.stringify(docConfig)} as const;\n`);
|
|
45
|
+
const dest = join(outDir, "rsc");
|
|
46
|
+
await mkdir(dest, { recursive: true });
|
|
47
|
+
const serverCode = await bundleServerGraph(runtimeEntry("flight-render-routes.tsx"), appRoot, { "june:rsc-routes": join(appDir, RSC_ROUTES_FILE) }, appDir);
|
|
48
|
+
await writeFile(join(dest, "server.js"), serverCode);
|
|
49
|
+
const workerCode = await bundleSsrGraph(runtimeEntry("rsc-worker.tsx"), appRoot, {
|
|
50
|
+
"june:rsc-client": join(appDir, RSC_CLIENT_MANIFEST_FILE),
|
|
51
|
+
"june:rsc-config": configFile
|
|
52
|
+
});
|
|
53
|
+
await writeFile(join(dest, "worker.js"), workerCode);
|
|
54
|
+
return {
|
|
55
|
+
worker: "rsc/worker.js",
|
|
56
|
+
server: "rsc/server.js",
|
|
57
|
+
paths: routes.map((r) => r.path)
|
|
58
|
+
};
|
|
59
|
+
}
|
|
60
|
+
function createRscDispatch(ssrFetch, rscFetch, rscPaths) {
|
|
61
|
+
const owned = new Set(rscPaths);
|
|
62
|
+
return (request) => {
|
|
63
|
+
const path = new URL(request.url).pathname;
|
|
64
|
+
return owned.has(path) ? rscFetch(request) : ssrFetch(request);
|
|
65
|
+
};
|
|
66
|
+
}
|
|
67
|
+
//#endregion
|
|
68
|
+
export { buildRsc, createRscDispatch, findRscRoutes };
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
//#region src/rsc-bundle.d.ts
|
|
2
|
+
type RscGraph = "server" | "ssr";
|
|
3
|
+
type RscAliases = Record<string, string>;
|
|
4
|
+
declare function bundleServerGraph(entryFile: string, cwd: string, aliases?: RscAliases, appDir?: string): Promise<string>;
|
|
5
|
+
declare function bundleSsrGraph(entryFile: string, cwd: string, aliases?: RscAliases): Promise<string>;
|
|
6
|
+
declare function referencesNodeBuiltins(code: string): boolean;
|
|
7
|
+
//#endregion
|
|
8
|
+
export { RscAliases, RscGraph, bundleServerGraph, bundleSsrGraph, referencesNodeBuiltins };
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import { rscClientReferencesPlugin } from "./rsc-manifest.js";
|
|
2
|
+
//#region src/rsc-bundle.ts
|
|
3
|
+
const EDGE_CONDITIONS = [
|
|
4
|
+
"source",
|
|
5
|
+
"workerd",
|
|
6
|
+
"edge-light",
|
|
7
|
+
"import",
|
|
8
|
+
"default"
|
|
9
|
+
];
|
|
10
|
+
async function bundleGraph(entryFile, cwd, graph, aliases = {}, plugins = []) {
|
|
11
|
+
const { rolldown } = await import("rolldown");
|
|
12
|
+
const conditionNames = graph === "server" ? ["react-server", ...EDGE_CONDITIONS] : EDGE_CONDITIONS;
|
|
13
|
+
const bundle = await rolldown({
|
|
14
|
+
input: entryFile,
|
|
15
|
+
cwd,
|
|
16
|
+
platform: "neutral",
|
|
17
|
+
plugins,
|
|
18
|
+
transform: { define: { "process.env.NODE_ENV": JSON.stringify("production") } },
|
|
19
|
+
resolve: {
|
|
20
|
+
conditionNames,
|
|
21
|
+
...Object.keys(aliases).length ? { alias: aliases } : {}
|
|
22
|
+
}
|
|
23
|
+
});
|
|
24
|
+
const { output } = await bundle.generate({ format: "esm" });
|
|
25
|
+
await bundle.close();
|
|
26
|
+
const entry = output.find((o) => o.type === "chunk" && o.isEntry);
|
|
27
|
+
return entry && entry.type === "chunk" ? entry.code : "";
|
|
28
|
+
}
|
|
29
|
+
function bundleServerGraph(entryFile, cwd, aliases, appDir) {
|
|
30
|
+
return bundleGraph(entryFile, cwd, "server", aliases, appDir ? [rscClientReferencesPlugin(appDir)] : []);
|
|
31
|
+
}
|
|
32
|
+
function bundleSsrGraph(entryFile, cwd, aliases) {
|
|
33
|
+
return bundleGraph(entryFile, cwd, "ssr", aliases);
|
|
34
|
+
}
|
|
35
|
+
function referencesNodeBuiltins(code) {
|
|
36
|
+
return /from\s*["']node:|require\(\s*["']node:/.test(code);
|
|
37
|
+
}
|
|
38
|
+
//#endregion
|
|
39
|
+
export { bundleServerGraph, bundleSsrGraph, referencesNodeBuiltins };
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { Plugin } from "rolldown";
|
|
2
|
+
//#region src/rsc-manifest.d.ts
|
|
3
|
+
declare const RSC_SERVER_MANIFEST_FILE = "_rsc-server.gen.ts";
|
|
4
|
+
declare const RSC_CLIENT_MANIFEST_FILE = "_rsc-client.gen.ts";
|
|
5
|
+
declare function rscClientReferencesPlugin(appDir: string): Plugin;
|
|
6
|
+
declare function generateRscManifests(appDir: string): number;
|
|
7
|
+
//#endregion
|
|
8
|
+
export { RSC_CLIENT_MANIFEST_FILE, RSC_SERVER_MANIFEST_FILE, generateRscManifests, rscClientReferencesPlugin };
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import { exportNames, firstStatementIsDirective, walk } from "./island-registry.js";
|
|
2
|
+
import { readFileSync, writeFileSync } from "node:fs";
|
|
3
|
+
import { join, relative } from "node:path";
|
|
4
|
+
//#region src/rsc-manifest.ts
|
|
5
|
+
const RSC_SERVER_MANIFEST_FILE = "_rsc-server.gen.ts";
|
|
6
|
+
const RSC_CLIENT_MANIFEST_FILE = "_rsc-client.gen.ts";
|
|
7
|
+
function refId(appDir, absPath, name) {
|
|
8
|
+
return `${relative(appDir, absPath).replace(/\.(tsx|ts|jsx)$/, "")}#${name}`;
|
|
9
|
+
}
|
|
10
|
+
function clientModules(appDir) {
|
|
11
|
+
return walk(appDir).filter((f) => /\.(tsx|ts|jsx)$/.test(f) && !f.endsWith("_rsc-server.gen.ts") && !f.endsWith("_rsc-client.gen.ts")).map((abs) => ({
|
|
12
|
+
abs,
|
|
13
|
+
src: readFileSync(abs, "utf8")
|
|
14
|
+
})).filter(({ src }) => firstStatementIsDirective(src, "use client")).map(({ abs, src }) => ({
|
|
15
|
+
abs,
|
|
16
|
+
rel: "./" + relative(appDir, abs).replace(/\.(tsx|ts|jsx)$/, ""),
|
|
17
|
+
names: exportNames(src).filter((n) => n !== "default")
|
|
18
|
+
})).filter((m) => m.names.length > 0).sort((a, b) => a.rel.localeCompare(b.rel));
|
|
19
|
+
}
|
|
20
|
+
function rscClientReferencesPlugin(appDir) {
|
|
21
|
+
return {
|
|
22
|
+
name: "june:rsc-client-references",
|
|
23
|
+
transform(code, id) {
|
|
24
|
+
if (!id.startsWith(appDir)) return null;
|
|
25
|
+
if (!firstStatementIsDirective(code, "use client")) return null;
|
|
26
|
+
const names = exportNames(code).filter((n) => n !== "default");
|
|
27
|
+
let out = `import { registerClientReference } from "react-server-dom-webpack/server";\n`;
|
|
28
|
+
for (const name of names) {
|
|
29
|
+
const rid = refId(appDir, id, name);
|
|
30
|
+
out += `export const ${name} = registerClientReference({}, ${JSON.stringify(rid)}, ${JSON.stringify(name)});\n`;
|
|
31
|
+
}
|
|
32
|
+
return {
|
|
33
|
+
code: out,
|
|
34
|
+
map: null
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
};
|
|
38
|
+
}
|
|
39
|
+
function generateRscManifests(appDir) {
|
|
40
|
+
const mods = clientModules(appDir);
|
|
41
|
+
let server = "// AUTO-GENERATED by June — do not edit. RSC render manifest.\n";
|
|
42
|
+
server += "export const CLIENT_MANIFEST: Record<string, { id: string; chunks: string[]; name: string }> = {\n";
|
|
43
|
+
for (const m of mods) for (const name of m.names) {
|
|
44
|
+
const rid = `${m.rel.slice(2)}#${name}`;
|
|
45
|
+
server += ` ${JSON.stringify(rid)}: { id: ${JSON.stringify(rid)}, chunks: [], name: ${JSON.stringify(name)} },\n`;
|
|
46
|
+
}
|
|
47
|
+
server += "};\n";
|
|
48
|
+
writeFileSync(join(appDir, RSC_SERVER_MANIFEST_FILE), server);
|
|
49
|
+
let client = "// AUTO-GENERATED by June — do not edit. RSC consumer manifest.\n";
|
|
50
|
+
mods.forEach((m, i) => client += `import * as m${i} from ${JSON.stringify(m.rel)};\n`);
|
|
51
|
+
client += "\nconst CLIENT_MODULES: Record<string, unknown> = {\n";
|
|
52
|
+
mods.forEach((m, i) => {
|
|
53
|
+
for (const name of m.names) client += ` ${JSON.stringify(`${m.rel.slice(2)}#${name}`)}: m${i},\n`;
|
|
54
|
+
});
|
|
55
|
+
client += "};\n";
|
|
56
|
+
client += "export const MODULE_MAP: Record<string, Record<string, { id: string; chunks: string[]; name: string }>> = {\n";
|
|
57
|
+
for (const m of mods) for (const name of m.names) {
|
|
58
|
+
const rid = `${m.rel.slice(2)}#${name}`;
|
|
59
|
+
client += ` ${JSON.stringify(rid)}: { ${JSON.stringify(name)}: { id: ${JSON.stringify(rid)}, chunks: [], name: ${JSON.stringify(name)} } },\n`;
|
|
60
|
+
}
|
|
61
|
+
client += "};\n\n";
|
|
62
|
+
client += "const g = globalThis as Record<string, unknown>;\ng.__webpack_require__ = (id: string) => CLIENT_MODULES[id];\ng.__webpack_chunk_load__ = () => Promise.resolve();\nexport { CLIENT_MODULES };\n";
|
|
63
|
+
writeFileSync(join(appDir, RSC_CLIENT_MANIFEST_FILE), client);
|
|
64
|
+
return mods.length;
|
|
65
|
+
}
|
|
66
|
+
//#endregion
|
|
67
|
+
export { RSC_CLIENT_MANIFEST_FILE, RSC_SERVER_MANIFEST_FILE, generateRscManifests, rscClientReferencesPlugin };
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { renderToReadableStream } from "react-server-dom-webpack/server";
|
|
2
|
+
import { ROUTES, clientManifest } from "june:rsc-routes";
|
|
3
|
+
import { jsx } from "@junejs/core/jsx-runtime";
|
|
4
|
+
//#region src/rsc-runtime/flight-render-routes.tsx
|
|
5
|
+
async function streamToString(stream) {
|
|
6
|
+
const reader = stream.getReader();
|
|
7
|
+
const dec = new TextDecoder();
|
|
8
|
+
let out = "";
|
|
9
|
+
for (;;) {
|
|
10
|
+
const { done, value } = await reader.read();
|
|
11
|
+
if (done) break;
|
|
12
|
+
out += dec.decode(value, { stream: true });
|
|
13
|
+
}
|
|
14
|
+
out += dec.decode();
|
|
15
|
+
return out;
|
|
16
|
+
}
|
|
17
|
+
async function renderFlight(path) {
|
|
18
|
+
const View = ROUTES[path];
|
|
19
|
+
if (!View) return null;
|
|
20
|
+
return streamToString(renderToReadableStream(/* @__PURE__ */ jsx(View, {}), clientManifest ?? {}));
|
|
21
|
+
}
|
|
22
|
+
function rscPaths() {
|
|
23
|
+
return Object.keys(ROUTES);
|
|
24
|
+
}
|
|
25
|
+
//#endregion
|
|
26
|
+
export { renderFlight, rscPaths };
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { renderToReadableStream } from "react-server-dom-webpack/server";
|
|
2
|
+
import { jsx } from "@junejs/core/jsx-runtime";
|
|
3
|
+
import { App, clientManifest } from "june:app";
|
|
4
|
+
//#region src/rsc-runtime/flight-render.tsx
|
|
5
|
+
async function streamToString(stream) {
|
|
6
|
+
const reader = stream.getReader();
|
|
7
|
+
const dec = new TextDecoder();
|
|
8
|
+
let out = "";
|
|
9
|
+
for (;;) {
|
|
10
|
+
const { done, value } = await reader.read();
|
|
11
|
+
if (done) break;
|
|
12
|
+
out += dec.decode(value, { stream: true });
|
|
13
|
+
}
|
|
14
|
+
out += dec.decode();
|
|
15
|
+
return out;
|
|
16
|
+
}
|
|
17
|
+
async function renderFlight() {
|
|
18
|
+
return streamToString(renderToReadableStream(/* @__PURE__ */ jsx(App, {}), clientManifest ?? {}));
|
|
19
|
+
}
|
|
20
|
+
//#endregion
|
|
21
|
+
export { renderFlight };
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { use } from "react";
|
|
2
|
+
import { jsx } from "@junejs/core/jsx-runtime";
|
|
3
|
+
import { createFromReadableStream } from "react-server-dom-webpack/client";
|
|
4
|
+
import { renderToReadableStream } from "react-dom/server.edge";
|
|
5
|
+
//#region src/rsc-runtime/flight-to-html.tsx
|
|
6
|
+
function Root({ tree }) {
|
|
7
|
+
return use(tree);
|
|
8
|
+
}
|
|
9
|
+
async function streamToString(stream) {
|
|
10
|
+
const reader = stream.getReader();
|
|
11
|
+
const dec = new TextDecoder();
|
|
12
|
+
let out = "";
|
|
13
|
+
for (;;) {
|
|
14
|
+
const { done, value } = await reader.read();
|
|
15
|
+
if (done) break;
|
|
16
|
+
out += dec.decode(value, { stream: true });
|
|
17
|
+
}
|
|
18
|
+
out += dec.decode();
|
|
19
|
+
return out;
|
|
20
|
+
}
|
|
21
|
+
async function flightToHtml(flight, moduleMap = {}) {
|
|
22
|
+
const flightStream = new Response(flight).body;
|
|
23
|
+
const html = await renderToReadableStream(/* @__PURE__ */ jsx(Root, { tree: createFromReadableStream(flightStream, { serverConsumerManifest: {
|
|
24
|
+
moduleMap,
|
|
25
|
+
serverModuleMap: null,
|
|
26
|
+
moduleLoading: null
|
|
27
|
+
} }) }));
|
|
28
|
+
if (typeof html.allReady?.then === "function") await html.allReady;
|
|
29
|
+
return streamToString(html);
|
|
30
|
+
}
|
|
31
|
+
//#endregion
|
|
32
|
+
export { flightToHtml };
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import { use } from "react";
|
|
2
|
+
import { Document } from "@junejs/core/document";
|
|
3
|
+
import { jsx } from "@junejs/core/jsx-runtime";
|
|
4
|
+
import { createFromReadableStream } from "react-server-dom-webpack/client";
|
|
5
|
+
import { renderToReadableStream } from "react-dom/server.edge";
|
|
6
|
+
import { MODULE_MAP } from "june:rsc-client";
|
|
7
|
+
import { DOC_CONFIG } from "june:rsc-config";
|
|
8
|
+
//#region src/rsc-runtime/rsc-worker.tsx
|
|
9
|
+
function Root({ tree }) {
|
|
10
|
+
return use(tree);
|
|
11
|
+
}
|
|
12
|
+
async function streamToString(stream) {
|
|
13
|
+
const reader = stream.getReader();
|
|
14
|
+
const dec = new TextDecoder();
|
|
15
|
+
let out = "";
|
|
16
|
+
for (;;) {
|
|
17
|
+
const { done, value } = await reader.read();
|
|
18
|
+
if (done) break;
|
|
19
|
+
out += dec.decode(value, { stream: true });
|
|
20
|
+
}
|
|
21
|
+
out += dec.decode();
|
|
22
|
+
return out;
|
|
23
|
+
}
|
|
24
|
+
async function renderDocument(path) {
|
|
25
|
+
const flight = await (await import(new URL("./server.js", import.meta.url).href)).renderFlight(path);
|
|
26
|
+
if (flight === null) return null;
|
|
27
|
+
const flightStream = new Response(flight).body;
|
|
28
|
+
const html = await renderToReadableStream(/* @__PURE__ */ jsx(Document, {
|
|
29
|
+
config: DOC_CONFIG,
|
|
30
|
+
children: /* @__PURE__ */ jsx(Root, { tree: createFromReadableStream(flightStream, { serverConsumerManifest: {
|
|
31
|
+
moduleMap: MODULE_MAP,
|
|
32
|
+
serverModuleMap: null,
|
|
33
|
+
moduleLoading: null
|
|
34
|
+
} }) })
|
|
35
|
+
}));
|
|
36
|
+
if (typeof html.allReady?.then === "function") await html.allReady;
|
|
37
|
+
return "<!DOCTYPE html>" + await streamToString(html);
|
|
38
|
+
}
|
|
39
|
+
var rsc_worker_default = { async fetch(request) {
|
|
40
|
+
const path = new URL(request.url).pathname;
|
|
41
|
+
const body = await renderDocument(path);
|
|
42
|
+
if (body === null) return new Response("Not Found", { status: 404 });
|
|
43
|
+
return new Response(body, { headers: { "content-type": "text/html; charset=utf-8" } });
|
|
44
|
+
} };
|
|
45
|
+
//#endregion
|
|
46
|
+
export { rsc_worker_default as default };
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
//#region src/rsc-runtime/rsdw-shims.d.ts
|
|
2
|
+
// Ambient declarations for react-server-dom-webpack (it ships no .d.ts) and the
|
|
3
|
+
// "june:app" virtual the RSC runtime entries import (aliased at bundle time).
|
|
4
|
+
// Minimal — only the surface the runtime entries use.
|
|
5
|
+
declare module "react-server-dom-webpack/server" {
|
|
6
|
+
export function renderToReadableStream(model: unknown, webpackMap?: unknown, options?: unknown): ReadableStream<Uint8Array>;
|
|
7
|
+
export function registerClientReference(proxy: object, id: string, exportName: string): unknown;
|
|
8
|
+
// "use server" — register a server function so it serializes as a server
|
|
9
|
+
// reference and can be invoked from a decoded client request.
|
|
10
|
+
export function registerServerReference<F>(fn: F, id: string, exportName: string): F;
|
|
11
|
+
export function decodeReply(body: string | FormData, serverManifest?: unknown, options?: unknown): Promise<unknown[]>;
|
|
12
|
+
}
|
|
13
|
+
declare module "react-server-dom-webpack/client" {
|
|
14
|
+
export function createFromReadableStream(stream: ReadableStream<Uint8Array>, options?: unknown): Promise<React.ReactNode> & React.ReactNode;
|
|
15
|
+
// "use server" client half — encode args for a server-function POST.
|
|
16
|
+
export function encodeReply(value: unknown): Promise<string | FormData>;
|
|
17
|
+
}
|
|
18
|
+
// The app under render, injected by the build (resolve.alias "june:app" → app).
|
|
19
|
+
declare module "june:app" {
|
|
20
|
+
import type React from "react";
|
|
21
|
+
export const App: React.ComponentType;
|
|
22
|
+
export const clientManifest: Record<string, unknown> | undefined;
|
|
23
|
+
}
|
|
24
|
+
// The generated per-route map (resolve.alias "june:rsc-routes" → _rsc-routes.gen.tsx).
|
|
25
|
+
declare module "june:rsc-routes" {
|
|
26
|
+
import type React from "react";
|
|
27
|
+
export const ROUTES: Record<string, React.ComponentType>;
|
|
28
|
+
export const clientManifest: Record<string, unknown> | undefined;
|
|
29
|
+
}
|
|
30
|
+
// The generated consumer manifest (resolve.alias "june:rsc-client" → app/_rsc-client.gen.ts).
|
|
31
|
+
declare module "june:rsc-client" {
|
|
32
|
+
export const MODULE_MAP: Record<string, Record<string, {
|
|
33
|
+
id: string;
|
|
34
|
+
chunks: string[];
|
|
35
|
+
name: string;
|
|
36
|
+
}>>;
|
|
37
|
+
}
|
|
38
|
+
// The frozen document config (resolve.alias "june:rsc-config" → generated).
|
|
39
|
+
declare module "june:rsc-config" {
|
|
40
|
+
import type { DocumentConfig } from "@junejs/core/document";
|
|
41
|
+
export const DOC_CONFIG: DocumentConfig;
|
|
42
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
//#region src/segment.d.ts
|
|
2
|
+
declare const boundaryWarning: (file: string) => string;
|
|
3
|
+
declare function boundaryKey(file: string): string;
|
|
4
|
+
declare function resolveBoundary<C>(items: Array<{
|
|
5
|
+
file: string;
|
|
6
|
+
entry: C | null;
|
|
7
|
+
boundary: boolean;
|
|
8
|
+
}>): {
|
|
9
|
+
chain: C[];
|
|
10
|
+
boundaryIndex: number | null;
|
|
11
|
+
key: string | null;
|
|
12
|
+
};
|
|
13
|
+
//#endregion
|
|
14
|
+
export { boundaryKey, boundaryWarning, resolveBoundary };
|
package/dist/segment.js
ADDED
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { createHash } from "node:crypto";
|
|
2
|
+
//#region src/segment.ts
|
|
3
|
+
const boundaryWarning = (file) => `[june] multiple segmentBoundary layouts in one chain (${file}); using the deepest.`;
|
|
4
|
+
const keyCache = /* @__PURE__ */ new Map();
|
|
5
|
+
function boundaryKey(file) {
|
|
6
|
+
let key = keyCache.get(file);
|
|
7
|
+
if (key === void 0) {
|
|
8
|
+
key = createHash("sha256").update(file).digest("hex").slice(0, 16);
|
|
9
|
+
keyCache.set(file, key);
|
|
10
|
+
}
|
|
11
|
+
return key;
|
|
12
|
+
}
|
|
13
|
+
function resolveBoundary(items) {
|
|
14
|
+
const chain = [];
|
|
15
|
+
let boundaryIndex = null;
|
|
16
|
+
let boundaryFile = null;
|
|
17
|
+
for (const it of items) {
|
|
18
|
+
if (it.entry == null) continue;
|
|
19
|
+
if (it.boundary) {
|
|
20
|
+
if (boundaryIndex !== null) console.warn(boundaryWarning(it.file));
|
|
21
|
+
boundaryIndex = chain.length;
|
|
22
|
+
boundaryFile = it.file;
|
|
23
|
+
}
|
|
24
|
+
chain.push(it.entry);
|
|
25
|
+
}
|
|
26
|
+
return {
|
|
27
|
+
chain,
|
|
28
|
+
boundaryIndex,
|
|
29
|
+
key: boundaryFile === null ? null : boundaryKey(boundaryFile)
|
|
30
|
+
};
|
|
31
|
+
}
|
|
32
|
+
//#endregion
|
|
33
|
+
export { boundaryKey, boundaryWarning, resolveBoundary };
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { JuneDb } from "@junejs/core/resources";
|
|
2
|
+
//#region src/sqlite-driver.d.ts
|
|
3
|
+
type SyncStatement = {
|
|
4
|
+
all(...params: unknown[]): unknown[];
|
|
5
|
+
get(...params: unknown[]): unknown;
|
|
6
|
+
run(...params: unknown[]): {
|
|
7
|
+
changes: number | bigint;
|
|
8
|
+
lastInsertRowid?: number | bigint;
|
|
9
|
+
};
|
|
10
|
+
};
|
|
11
|
+
type SyncSqlite = {
|
|
12
|
+
query(sql: string): SyncStatement;
|
|
13
|
+
exec(sql: string): void;
|
|
14
|
+
close(): void;
|
|
15
|
+
};
|
|
16
|
+
declare const NODE_SQLITE_MIN_LTS = "22.13.0";
|
|
17
|
+
declare const NODE_SQLITE_MIN_ODD = "23.4.0";
|
|
18
|
+
declare function nodeSqliteHelp(nodeVersion: string): string;
|
|
19
|
+
declare function isNodeSqliteExperimentalWarning(type: unknown, message: string): boolean;
|
|
20
|
+
type EmitWarning = (warning: string | Error, ...rest: unknown[]) => void;
|
|
21
|
+
declare function makeWarningFilter(original: EmitWarning): EmitWarning;
|
|
22
|
+
declare function openLocalSqliteSync(path: string): Promise<SyncSqlite>;
|
|
23
|
+
declare function openLocalSqlite(path: string): Promise<JuneDb>;
|
|
24
|
+
//#endregion
|
|
25
|
+
export { NODE_SQLITE_MIN_LTS, NODE_SQLITE_MIN_ODD, SyncSqlite, SyncStatement, isNodeSqliteExperimentalWarning, makeWarningFilter, nodeSqliteHelp, openLocalSqlite, openLocalSqliteSync };
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
//#region src/sqlite-driver.ts
|
|
2
|
+
const NODE_SQLITE_MIN_LTS = "22.13.0";
|
|
3
|
+
const NODE_SQLITE_MIN_ODD = "23.4.0";
|
|
4
|
+
function asyncSqlite(db) {
|
|
5
|
+
const stmts = /* @__PURE__ */ new Map();
|
|
6
|
+
const prep = (sql) => {
|
|
7
|
+
let s = stmts.get(sql);
|
|
8
|
+
if (!s) {
|
|
9
|
+
s = db.query(sql);
|
|
10
|
+
stmts.set(sql, s);
|
|
11
|
+
}
|
|
12
|
+
return s;
|
|
13
|
+
};
|
|
14
|
+
const self = {
|
|
15
|
+
dialect: "sqlite",
|
|
16
|
+
async query(sql, params = []) {
|
|
17
|
+
return prep(sql).all(...params);
|
|
18
|
+
},
|
|
19
|
+
async get(sql, params = []) {
|
|
20
|
+
return prep(sql).get(...params) ?? void 0;
|
|
21
|
+
},
|
|
22
|
+
async run(sql, params = []) {
|
|
23
|
+
const r = prep(sql).run(...params);
|
|
24
|
+
return {
|
|
25
|
+
changes: Number(r.changes),
|
|
26
|
+
lastInsertRowid: r.lastInsertRowid ?? 0
|
|
27
|
+
};
|
|
28
|
+
},
|
|
29
|
+
async exec(sql) {
|
|
30
|
+
db.exec(sql);
|
|
31
|
+
},
|
|
32
|
+
async transaction(fn) {
|
|
33
|
+
db.exec("BEGIN");
|
|
34
|
+
try {
|
|
35
|
+
const out = await fn(self);
|
|
36
|
+
db.exec("COMMIT");
|
|
37
|
+
return out;
|
|
38
|
+
} catch (e) {
|
|
39
|
+
db.exec("ROLLBACK");
|
|
40
|
+
throw e;
|
|
41
|
+
}
|
|
42
|
+
},
|
|
43
|
+
async close() {
|
|
44
|
+
stmts.clear();
|
|
45
|
+
db.close();
|
|
46
|
+
}
|
|
47
|
+
};
|
|
48
|
+
return self;
|
|
49
|
+
}
|
|
50
|
+
function nodeSqliteHelp(nodeVersion) {
|
|
51
|
+
return [
|
|
52
|
+
`June's local database needs Node's built-in sqlite (node:sqlite), which this`,
|
|
53
|
+
`runtime can't load. You're on Node v${nodeVersion}.`,
|
|
54
|
+
``,
|
|
55
|
+
`node:sqlite is available without a flag in Node >= ${NODE_SQLITE_MIN_LTS} (LTS) or`,
|
|
56
|
+
`>= ${NODE_SQLITE_MIN_ODD}. Node 22.5–22.12 / 23.0–23.3 have it behind`,
|
|
57
|
+
`--experimental-sqlite, and older Node doesn't ship it at all.`,
|
|
58
|
+
``,
|
|
59
|
+
`Fix it one of two ways:`,
|
|
60
|
+
` • Upgrade Node to ${NODE_SQLITE_MIN_LTS}+ (recommended), or`,
|
|
61
|
+
` • Run June with Bun — bun:sqlite is built in, no flag, no version floor.`
|
|
62
|
+
].join("\n");
|
|
63
|
+
}
|
|
64
|
+
function isNodeSqliteExperimentalWarning(type, message) {
|
|
65
|
+
return type === "ExperimentalWarning" && /sqlite/i.test(message);
|
|
66
|
+
}
|
|
67
|
+
function makeWarningFilter(original) {
|
|
68
|
+
return (warning, ...rest) => {
|
|
69
|
+
const message = typeof warning === "string" ? warning : warning?.message ?? "";
|
|
70
|
+
const first = rest[0];
|
|
71
|
+
if (isNodeSqliteExperimentalWarning(typeof first === "string" ? first : first?.type, message)) return;
|
|
72
|
+
original(warning, ...rest);
|
|
73
|
+
};
|
|
74
|
+
}
|
|
75
|
+
async function openLocalSqliteSync(path) {
|
|
76
|
+
if (typeof Bun !== "undefined") {
|
|
77
|
+
const { Database } = await import("bun:sqlite");
|
|
78
|
+
return new Database(path, { create: true });
|
|
79
|
+
}
|
|
80
|
+
const specifier = "node:sqlite";
|
|
81
|
+
let mod;
|
|
82
|
+
const originalEmitWarning = process.emitWarning;
|
|
83
|
+
process.emitWarning = makeWarningFilter(originalEmitWarning.bind(process));
|
|
84
|
+
try {
|
|
85
|
+
mod = await import(specifier);
|
|
86
|
+
} catch (cause) {
|
|
87
|
+
throw new Error(nodeSqliteHelp(process.versions.node), { cause });
|
|
88
|
+
} finally {
|
|
89
|
+
process.emitWarning = originalEmitWarning;
|
|
90
|
+
}
|
|
91
|
+
const db = new mod.DatabaseSync(path);
|
|
92
|
+
return {
|
|
93
|
+
query: (sql) => db.prepare(sql),
|
|
94
|
+
exec: (sql) => db.exec(sql),
|
|
95
|
+
close: () => db.close()
|
|
96
|
+
};
|
|
97
|
+
}
|
|
98
|
+
async function openLocalSqlite(path) {
|
|
99
|
+
return asyncSqlite(await openLocalSqliteSync(path));
|
|
100
|
+
}
|
|
101
|
+
//#endregion
|
|
102
|
+
export { NODE_SQLITE_MIN_LTS, NODE_SQLITE_MIN_ODD, isNodeSqliteExperimentalWarning, makeWarningFilter, nodeSqliteHelp, openLocalSqlite, openLocalSqliteSync };
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
//#region src/static-files.d.ts
|
|
2
|
+
declare const RESERVED_PREFIX = "_june";
|
|
3
|
+
declare function contentTypeFor(pathname: string): string;
|
|
4
|
+
declare function safeRelativePath(pathname: string): string | null;
|
|
5
|
+
//#endregion
|
|
6
|
+
export { RESERVED_PREFIX, contentTypeFor, safeRelativePath };
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
//#region src/static-files.ts
|
|
2
|
+
const RESERVED_PREFIX = "_june";
|
|
3
|
+
const CONTENT_TYPES = {
|
|
4
|
+
html: "text/html; charset=utf-8",
|
|
5
|
+
css: "text/css; charset=utf-8",
|
|
6
|
+
js: "text/javascript; charset=utf-8",
|
|
7
|
+
mjs: "text/javascript; charset=utf-8",
|
|
8
|
+
json: "application/json; charset=utf-8",
|
|
9
|
+
map: "application/json; charset=utf-8",
|
|
10
|
+
xml: "application/xml; charset=utf-8",
|
|
11
|
+
txt: "text/plain; charset=utf-8",
|
|
12
|
+
md: "text/markdown; charset=utf-8",
|
|
13
|
+
csv: "text/csv; charset=utf-8",
|
|
14
|
+
webmanifest: "application/manifest+json",
|
|
15
|
+
svg: "image/svg+xml",
|
|
16
|
+
png: "image/png",
|
|
17
|
+
jpg: "image/jpeg",
|
|
18
|
+
jpeg: "image/jpeg",
|
|
19
|
+
gif: "image/gif",
|
|
20
|
+
webp: "image/webp",
|
|
21
|
+
avif: "image/avif",
|
|
22
|
+
ico: "image/x-icon",
|
|
23
|
+
bmp: "image/bmp",
|
|
24
|
+
woff2: "font/woff2",
|
|
25
|
+
woff: "font/woff",
|
|
26
|
+
ttf: "font/ttf",
|
|
27
|
+
otf: "font/otf",
|
|
28
|
+
mp4: "video/mp4",
|
|
29
|
+
webm: "video/webm",
|
|
30
|
+
mp3: "audio/mpeg",
|
|
31
|
+
ogg: "audio/ogg",
|
|
32
|
+
wav: "audio/wav",
|
|
33
|
+
wasm: "application/wasm",
|
|
34
|
+
pdf: "application/pdf",
|
|
35
|
+
zip: "application/zip"
|
|
36
|
+
};
|
|
37
|
+
function contentTypeFor(pathname) {
|
|
38
|
+
const dot = pathname.lastIndexOf(".");
|
|
39
|
+
if (dot === -1) return "application/octet-stream";
|
|
40
|
+
return CONTENT_TYPES[pathname.slice(dot + 1).toLowerCase()] ?? "application/octet-stream";
|
|
41
|
+
}
|
|
42
|
+
function safeRelativePath(pathname) {
|
|
43
|
+
let decoded;
|
|
44
|
+
try {
|
|
45
|
+
decoded = decodeURIComponent(pathname);
|
|
46
|
+
} catch {
|
|
47
|
+
return null;
|
|
48
|
+
}
|
|
49
|
+
if (decoded.includes("\0") || decoded.includes("\\")) return null;
|
|
50
|
+
const segments = decoded.split("/").filter((s) => s !== "" && s !== ".");
|
|
51
|
+
if (segments.length === 0) return null;
|
|
52
|
+
if (segments.some((s) => s === "..")) return null;
|
|
53
|
+
return segments.join("/");
|
|
54
|
+
}
|
|
55
|
+
//#endregion
|
|
56
|
+
export { RESERVED_PREFIX, contentTypeFor, safeRelativePath };
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
//#region src/tsconfig-jsx.d.ts
|
|
2
|
+
/** Read the app's tsconfig.json and return compilerOptions.jsxImportSource.
|
|
3
|
+
* Follows one level of `extends` so apps that inherit from a base tsconfig
|
|
4
|
+
* (e.g. "@kurajs/docs/tsconfig.kura.json") are handled correctly.
|
|
5
|
+
* Returns undefined when absent or unreadable. */
|
|
6
|
+
declare function appJsxImportSource(appRoot: string): Promise<string | undefined>;
|
|
7
|
+
/** The transform.jsx both bundles use: June's island JSX runtime, with the explicit importSource
|
|
8
|
+
* skipped when the app's tsconfig already declares it — rolldown then reads it from tsconfig
|
|
9
|
+
* silently instead of warning about the (same-value) override. */
|
|
10
|
+
declare function jsxTransform(appRoot: string): Promise<{
|
|
11
|
+
runtime: "automatic";
|
|
12
|
+
importSource?: string;
|
|
13
|
+
}>;
|
|
14
|
+
//#endregion
|
|
15
|
+
export { appJsxImportSource, jsxTransform };
|