rwsdk 0.1.6 → 0.1.7-test.20250702144028
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/runtime/client.js +6 -1
- package/dist/runtime/clientNavigation.d.ts +1 -0
- package/dist/runtime/clientNavigation.js +34 -24
- package/dist/runtime/clientNavigation.test.js +55 -0
- package/dist/runtime/lib/realtime/client.js +6 -0
- package/dist/runtime/lib/realtime/durableObject.js +8 -6
- package/dist/runtime/lib/realtime/worker.js +1 -3
- package/dist/runtime/render/renderRscThenableToHtmlStream.d.ts +2 -1
- package/dist/runtime/render/renderRscThenableToHtmlStream.js +22 -1
- package/dist/runtime/render/renderToStream.js +2 -1
- package/dist/runtime/render/transformRscToHtmlStream.d.ts +2 -1
- package/dist/runtime/render/transformRscToHtmlStream.js +2 -1
- package/dist/runtime/worker.js +1 -0
- package/dist/scripts/debug-sync.d.mts +1 -0
- package/dist/scripts/debug-sync.mjs +80 -12
- package/package.json +1 -1
- package/dist/lib/smokeTests/components.d.mts +0 -8
- package/dist/lib/smokeTests/components.mjs +0 -194
- package/dist/lib/smokeTests/templates/SmokeTestInfo.template.d.ts +0 -1
- package/dist/lib/smokeTests/templates/SmokeTestInfo.template.js +0 -82
- package/dist/runtime/components/HealthCheck.d.ts +0 -13
- package/dist/runtime/components/HealthCheck.js +0 -56
- package/dist/runtime/components/HealthCheckClient.d.ts +0 -2
- package/dist/runtime/components/HealthCheckClient.js +0 -78
- package/dist/runtime/imports/NoSSRStub.d.ts +0 -1
- package/dist/runtime/imports/NoSSRStub.js +0 -4
- package/dist/runtime/lib/db/create.d.ts +0 -3
- package/dist/runtime/lib/db/create.js +0 -36
- package/dist/runtime/lib/db/logger.d.ts +0 -2
- package/dist/runtime/lib/db/logger.js +0 -41
- package/dist/runtime/lib/db/types.d.ts +0 -0
- package/dist/runtime/lib/db/types.js +0 -1
- package/dist/runtime/render/__rwsdk_ssr_bridge.d.ts +0 -10
- package/dist/runtime/render/__rwsdk_ssr_bridge.js +0 -9
- package/dist/runtime/render/__rwsdkssr_render.d.ts +0 -9
- package/dist/runtime/render/__rwsdkssr_render.js +0 -13
- package/dist/runtime/render/injectRSCPayload.d.ts +0 -3
- package/dist/runtime/render/injectRSCPayload.js +0 -79
- package/dist/runtime/render/ssrBridge.d.ts +0 -2
- package/dist/runtime/render/ssrBridge.js +0 -2
- package/dist/runtime/render/ssrRenderToReadableStream.d.ts +0 -2
- package/dist/runtime/render/ssrRenderToReadableStream.js +0 -2
- package/dist/runtime/requestInfo/__rwsdknossr_worker.d.ts +0 -5
- package/dist/runtime/requestInfo/__rwsdknossr_worker.js +0 -33
- package/dist/scripts/build-vendor-bundles.d.mts +0 -1
- package/dist/scripts/build-vendor-bundles.mjs +0 -92
- package/dist/vite/aliasedModuleResolver.d.mts +0 -9
- package/dist/vite/aliasedModuleResolver.mjs +0 -62
- package/dist/vite/aliasedSSRResolver.d.mts +0 -5
- package/dist/vite/aliasedSSRResolver.mjs +0 -74
- package/dist/vite/copyPrismaWasmPlugin.d.mts +0 -4
- package/dist/vite/copyPrismaWasmPlugin.mjs +0 -32
- package/dist/vite/ensureConfigArrays.d.mts +0 -1
- package/dist/vite/ensureConfigArrays.mjs +0 -12
- package/dist/vite/findImportSpecifiers.d.mts +0 -30
- package/dist/vite/findImportSpecifiers.mjs +0 -228
- package/dist/vite/findImportSpecifiers.test.mjs +0 -73
- package/dist/vite/isBareImport.d.mts +0 -1
- package/dist/vite/isBareImport.mjs +0 -5
- package/dist/vite/miniflarePlugin.d.mts +0 -9
- package/dist/vite/miniflarePlugin.mjs +0 -135
- package/dist/vite/moduleResolver.d.mts +0 -10
- package/dist/vite/moduleResolver.mjs +0 -74
- package/dist/vite/resolveModuleId.d.mts +0 -6
- package/dist/vite/resolveModuleId.mjs +0 -14
- package/dist/vite/rscDirectivesPlugin.d.mts +0 -6
- package/dist/vite/rscDirectivesPlugin.mjs +0 -80
- package/dist/vite/transformServerReferences.d.mts +0 -11
- package/dist/vite/transformServerReferences.mjs +0 -74
- package/dist/vite/useClientPlugin.d.mts +0 -8
- package/dist/vite/useClientPlugin.mjs +0 -299
- package/dist/vite/useClientPlugin.test.d.mts +0 -1
- package/dist/vite/useClientPlugin.test.mjs +0 -1294
- package/dist/vite/useServerPlugin.test.d.mts +0 -1
- package/dist/vite/useServerPlugin.test.mjs +0 -99
- package/dist/vite/virtualizedSSRPlugin.d.mts +0 -56
- package/dist/vite/virtualizedSSRPlugin.mjs +0 -464
- package/dist/vite/wasmPlugin.d.mts +0 -2
- package/dist/vite/wasmPlugin.mjs +0 -14
- /package/dist/{vite/findImportSpecifiers.test.d.mts → runtime/clientNavigation.test.d.ts} +0 -0
|
@@ -1,82 +0,0 @@
|
|
|
1
|
-
export function getSmokeTestTemplate(skipClient = false) {
|
|
2
|
-
return `
|
|
3
|
-
import React from "react";
|
|
4
|
-
import { RequestInfo } from "rwsdk/worker";
|
|
5
|
-
${skipClient ? "" : 'import { SmokeTestClient } from "./__SmokeTestClient";'}
|
|
6
|
-
import { smokeTestAction } from "./__smokeTestFunctions";
|
|
7
|
-
|
|
8
|
-
export const SmokeTestInfo: React.FC = async () => {
|
|
9
|
-
const timestamp = Date.now();
|
|
10
|
-
let status = "error";
|
|
11
|
-
let verificationPassed = false;
|
|
12
|
-
let serverStoredTimestamp = 0;
|
|
13
|
-
let result: any = null;
|
|
14
|
-
|
|
15
|
-
try {
|
|
16
|
-
// Call the smoke test action to verify basic server functionality
|
|
17
|
-
result = await smokeTestAction(timestamp);
|
|
18
|
-
status = result.status || "error";
|
|
19
|
-
verificationPassed = result.timestamp === timestamp;
|
|
20
|
-
serverStoredTimestamp = result.serverStoredTimestamp;
|
|
21
|
-
} catch (error) {
|
|
22
|
-
console.error("Smoke test failed:", error);
|
|
23
|
-
status = "error";
|
|
24
|
-
result = { error: error instanceof Error ? error.message : String(error) };
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
return (
|
|
28
|
-
<div
|
|
29
|
-
id="smoke-test-container"
|
|
30
|
-
data-testid="health-status"
|
|
31
|
-
data-status={status}
|
|
32
|
-
data-timestamp={timestamp}
|
|
33
|
-
data-server-timestamp={Date.now()}
|
|
34
|
-
data-server-stored-timestamp={serverStoredTimestamp}
|
|
35
|
-
data-verified={verificationPassed ? "true" : "false"}
|
|
36
|
-
style={{
|
|
37
|
-
fontFamily: "system-ui, -apple-system, sans-serif",
|
|
38
|
-
margin: "20px",
|
|
39
|
-
padding: "15px",
|
|
40
|
-
border: "1px solid #ddd",
|
|
41
|
-
borderRadius: "4px",
|
|
42
|
-
background: "#f9f9f9",
|
|
43
|
-
}}
|
|
44
|
-
>
|
|
45
|
-
<h2
|
|
46
|
-
style={{
|
|
47
|
-
color: status === "ok" ? "#0c9" : "#f44",
|
|
48
|
-
margin: "0 0 10px 0",
|
|
49
|
-
}}
|
|
50
|
-
>
|
|
51
|
-
Smoke Test: {status}
|
|
52
|
-
</h2>
|
|
53
|
-
<div
|
|
54
|
-
id="smoke-test-result"
|
|
55
|
-
>
|
|
56
|
-
{verificationPassed
|
|
57
|
-
? "Timestamp verification passed ✅"
|
|
58
|
-
: "Timestamp verification failed ⚠️"}
|
|
59
|
-
</div>
|
|
60
|
-
<div id="server-stored-timestamp">
|
|
61
|
-
Server Stored Timestamp: {serverStoredTimestamp}
|
|
62
|
-
</div>
|
|
63
|
-
<details style={{ marginTop: "10px" }}>
|
|
64
|
-
<summary>Details</summary>
|
|
65
|
-
<pre
|
|
66
|
-
style={{
|
|
67
|
-
background: "#f5f5f5",
|
|
68
|
-
padding: "10px",
|
|
69
|
-
borderRadius: "4px",
|
|
70
|
-
fontSize: "12px",
|
|
71
|
-
overflow: "auto",
|
|
72
|
-
}}
|
|
73
|
-
>
|
|
74
|
-
{JSON.stringify({ timestamp, serverStoredTimestamp, result, verificationPassed }, null, 2)}
|
|
75
|
-
</pre>
|
|
76
|
-
</details>
|
|
77
|
-
|
|
78
|
-
${!skipClient ? "<SmokeTestClient/>" : ""}
|
|
79
|
-
</div>
|
|
80
|
-
);
|
|
81
|
-
};`;
|
|
82
|
-
}
|
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
import React from "react";
|
|
2
|
-
import { RequestInfo } from "../requestInfo/types";
|
|
3
|
-
export declare const HealthCheckInfo: React.FC;
|
|
4
|
-
/**
|
|
5
|
-
* Wrapper component that displays health check info above the original page content
|
|
6
|
-
*/
|
|
7
|
-
export declare const HealthCheckWrapper: React.FC<{
|
|
8
|
-
children: React.ReactNode;
|
|
9
|
-
}>;
|
|
10
|
-
/**
|
|
11
|
-
* Standalone health check page that conforms to the RouteComponent type
|
|
12
|
-
*/
|
|
13
|
-
export declare const HealthCheckPage: (requestInfo: RequestInfo) => React.JSX.Element;
|
|
@@ -1,56 +0,0 @@
|
|
|
1
|
-
import { jsxs as _jsxs, jsx as _jsx, Fragment as _Fragment } from "react/jsx-runtime";
|
|
2
|
-
import { HealthCheckClient } from "./HealthCheckClient";
|
|
3
|
-
export const HealthCheckInfo = async () => {
|
|
4
|
-
const timestamp = Date.now();
|
|
5
|
-
let status = "error";
|
|
6
|
-
let verificationPassed = false;
|
|
7
|
-
let result = null;
|
|
8
|
-
try {
|
|
9
|
-
result = await globalThis.__rw.callServer("__health", [timestamp]);
|
|
10
|
-
// Check the result
|
|
11
|
-
if (typeof result === "object" && result !== null) {
|
|
12
|
-
status = result.status || "error";
|
|
13
|
-
verificationPassed = result.timestamp === timestamp;
|
|
14
|
-
}
|
|
15
|
-
else if (result === "ok") {
|
|
16
|
-
status = "ok";
|
|
17
|
-
verificationPassed = true;
|
|
18
|
-
}
|
|
19
|
-
}
|
|
20
|
-
catch (error) {
|
|
21
|
-
console.error("Health check failed:", error);
|
|
22
|
-
status = "error";
|
|
23
|
-
result = { error: error instanceof Error ? error.message : String(error) };
|
|
24
|
-
}
|
|
25
|
-
return (_jsxs("div", { id: "health-check-container", style: {
|
|
26
|
-
fontFamily: "system-ui, -apple-system, sans-serif",
|
|
27
|
-
margin: "20px",
|
|
28
|
-
padding: "15px",
|
|
29
|
-
border: "1px solid #ddd",
|
|
30
|
-
borderRadius: "4px",
|
|
31
|
-
background: "#f9f9f9",
|
|
32
|
-
}, children: [_jsxs("h2", { style: {
|
|
33
|
-
color: status === "ok" ? "#0c9" : "#f44",
|
|
34
|
-
margin: "0 0 10px 0",
|
|
35
|
-
}, children: ["Health Check: ", status] }), _jsx("div", { id: "health-check-result", "data-result": status, "data-timestamp": timestamp, "data-verified": verificationPassed ? "true" : "false", children: verificationPassed
|
|
36
|
-
? "Timestamp verification passed ✅"
|
|
37
|
-
: "Timestamp verification failed ⚠️" }), _jsxs("details", { style: { marginTop: "10px" }, children: [_jsx("summary", { children: "Details" }), _jsx("pre", { style: {
|
|
38
|
-
background: "#f5f5f5",
|
|
39
|
-
padding: "10px",
|
|
40
|
-
borderRadius: "4px",
|
|
41
|
-
fontSize: "12px",
|
|
42
|
-
overflow: "auto",
|
|
43
|
-
}, children: JSON.stringify({ timestamp, result, verificationPassed }, null, 2) })] }), _jsx(HealthCheckClient, {})] }));
|
|
44
|
-
};
|
|
45
|
-
/**
|
|
46
|
-
* Wrapper component that displays health check info above the original page content
|
|
47
|
-
*/
|
|
48
|
-
export const HealthCheckWrapper = ({ children }) => {
|
|
49
|
-
return (_jsxs(_Fragment, { children: [_jsx(HealthCheckInfo, {}), children] }));
|
|
50
|
-
};
|
|
51
|
-
/**
|
|
52
|
-
* Standalone health check page that conforms to the RouteComponent type
|
|
53
|
-
*/
|
|
54
|
-
export const HealthCheckPage = (requestInfo) => {
|
|
55
|
-
return (_jsxs("div", { style: { maxWidth: "800px", margin: "0 auto", padding: "40px 20px" }, children: [_jsx("h1", { children: "RedwoodJS SDK Health Check" }), _jsx(HealthCheckInfo, {}), _jsx("p", { style: { marginTop: "20px" }, children: "This is a dedicated health check page to verify that your RedwoodJS SDK application is functioning correctly. It tests that server-side rendering, client-side hydration, and RSC (React Server Components) actions are all working properly." }), _jsx("p", { children: "Use the button below to manually trigger a new health check at any time." })] }));
|
|
56
|
-
};
|
|
@@ -1,78 +0,0 @@
|
|
|
1
|
-
"use client";
|
|
2
|
-
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
|
-
import { useState } from "react";
|
|
4
|
-
export const HealthCheckClient = () => {
|
|
5
|
-
const [loading, setLoading] = useState(false);
|
|
6
|
-
const [lastCheck, setLastCheck] = useState(null);
|
|
7
|
-
const runHealthCheck = async () => {
|
|
8
|
-
setLoading(true);
|
|
9
|
-
try {
|
|
10
|
-
// Get current timestamp to verify round-trip
|
|
11
|
-
const timestamp = Date.now();
|
|
12
|
-
const result = await globalThis.__rw.callServer("__health", [timestamp]);
|
|
13
|
-
// Process the result
|
|
14
|
-
let status = "error";
|
|
15
|
-
let verificationPassed = false;
|
|
16
|
-
if (typeof result === "object" && result !== null) {
|
|
17
|
-
const typedResult = result;
|
|
18
|
-
status = typedResult.status || "error";
|
|
19
|
-
verificationPassed = typedResult.timestamp === timestamp;
|
|
20
|
-
}
|
|
21
|
-
else if (result === "ok") {
|
|
22
|
-
status = "ok";
|
|
23
|
-
verificationPassed = true;
|
|
24
|
-
}
|
|
25
|
-
setLastCheck({
|
|
26
|
-
status,
|
|
27
|
-
verificationPassed,
|
|
28
|
-
timestamp,
|
|
29
|
-
rawResult: result,
|
|
30
|
-
});
|
|
31
|
-
}
|
|
32
|
-
catch (error) {
|
|
33
|
-
setLastCheck({
|
|
34
|
-
status: "error",
|
|
35
|
-
verificationPassed: false,
|
|
36
|
-
timestamp: Date.now(),
|
|
37
|
-
error: error instanceof Error ? error.message : String(error),
|
|
38
|
-
});
|
|
39
|
-
}
|
|
40
|
-
finally {
|
|
41
|
-
setLoading(false);
|
|
42
|
-
}
|
|
43
|
-
};
|
|
44
|
-
return (_jsxs("div", { className: "health-check-client", style: {
|
|
45
|
-
margin: "20px 0",
|
|
46
|
-
padding: "15px",
|
|
47
|
-
border: "1px solid #ddd",
|
|
48
|
-
borderRadius: "4px",
|
|
49
|
-
background: "#f9f9f9",
|
|
50
|
-
fontFamily: "system-ui, -apple-system, sans-serif",
|
|
51
|
-
}, children: [_jsx("h3", { children: "Manual Health Check" }), _jsx("button", { onClick: runHealthCheck, disabled: loading, style: {
|
|
52
|
-
padding: "8px 16px",
|
|
53
|
-
background: loading ? "#ccc" : "#0070f3",
|
|
54
|
-
color: "white",
|
|
55
|
-
border: "none",
|
|
56
|
-
borderRadius: "4px",
|
|
57
|
-
cursor: loading ? "not-allowed" : "pointer",
|
|
58
|
-
fontWeight: "bold",
|
|
59
|
-
}, children: loading ? "Checking..." : "Run Health Check" }), lastCheck && (_jsx("div", { style: { marginTop: "15px" }, children: _jsxs("div", { style: {
|
|
60
|
-
padding: "10px",
|
|
61
|
-
borderRadius: "4px",
|
|
62
|
-
background: lastCheck.status === "ok" ? "#e6f7ee" : "#ffeded",
|
|
63
|
-
border: `1px solid ${lastCheck.status === "ok" ? "#0c9" : "#f44"}`,
|
|
64
|
-
}, children: [_jsxs("h4", { style: {
|
|
65
|
-
margin: "0 0 10px 0",
|
|
66
|
-
color: lastCheck.status === "ok" ? "#0c9" : "#f44",
|
|
67
|
-
}, children: ["Status: ", lastCheck.status] }), _jsxs("p", { children: ["Timestamp verification:", " ", lastCheck.verificationPassed ? "Passed ✅" : "Failed ⚠️"] }), lastCheck.error && (_jsxs("p", { style: { color: "#f44" }, children: ["Error: ", lastCheck.error] })), _jsxs("details", { style: { marginTop: "10px" }, children: [_jsx("summary", { children: "Raw Result" }), _jsx("pre", { style: {
|
|
68
|
-
background: "#f5f5f5",
|
|
69
|
-
padding: "10px",
|
|
70
|
-
borderRadius: "4px",
|
|
71
|
-
fontSize: "12px",
|
|
72
|
-
overflow: "auto",
|
|
73
|
-
}, children: JSON.stringify({
|
|
74
|
-
timestamp: lastCheck.timestamp,
|
|
75
|
-
result: lastCheck.rawResult,
|
|
76
|
-
verificationPassed: lastCheck.verificationPassed,
|
|
77
|
-
}, null, 2) })] })] }) }))] }));
|
|
78
|
-
};
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export declare const NoSSRStub: () => import("react/jsx-runtime").JSX.Element;
|
|
@@ -1,36 +0,0 @@
|
|
|
1
|
-
import { Kysely } from "kysely";
|
|
2
|
-
import { requestInfo } from "../../requestInfo/worker.js";
|
|
3
|
-
import { DOWorkerDialect } from "./SqliteDurableObject.js";
|
|
4
|
-
export function createDurableObjectDb(durableObjectBinding, name = "main") {
|
|
5
|
-
const durableObjectId = durableObjectBinding.idFromName(name);
|
|
6
|
-
const stub = durableObjectBinding.get(durableObjectId);
|
|
7
|
-
return new Kysely({
|
|
8
|
-
dialect: new DOWorkerDialect({ stub }),
|
|
9
|
-
});
|
|
10
|
-
}
|
|
11
|
-
export function createDb(durableObjectBinding, name = "main") {
|
|
12
|
-
// Create a cache key from the binding and name
|
|
13
|
-
const cacheKey = `${durableObjectBinding}_${name}`;
|
|
14
|
-
// Return a proxy that lazily creates and caches the database instance
|
|
15
|
-
return new Proxy({}, {
|
|
16
|
-
get(target, prop, receiver) {
|
|
17
|
-
if (!requestInfo.rw.databases) {
|
|
18
|
-
requestInfo.rw.databases = new Map();
|
|
19
|
-
}
|
|
20
|
-
// Check if we have a cached instance
|
|
21
|
-
let db = requestInfo.rw.databases.get(cacheKey);
|
|
22
|
-
if (!db) {
|
|
23
|
-
// Create the database instance and cache it
|
|
24
|
-
db = createDurableObjectDb(durableObjectBinding, name);
|
|
25
|
-
requestInfo.rw.databases.set(cacheKey, db);
|
|
26
|
-
}
|
|
27
|
-
// Forward the property access to the actual database instance
|
|
28
|
-
const value = db[prop];
|
|
29
|
-
// If it's a function, bind it to the database instance
|
|
30
|
-
if (typeof value === "function") {
|
|
31
|
-
return value.bind(db);
|
|
32
|
-
}
|
|
33
|
-
return value;
|
|
34
|
-
},
|
|
35
|
-
});
|
|
36
|
-
}
|
|
@@ -1,41 +0,0 @@
|
|
|
1
|
-
// Simple debug function with DEBUG environment variable filtering
|
|
2
|
-
// Supports patterns like: DEBUG=passkey:* or DEBUG=passkey:database,passkey:functions
|
|
3
|
-
function isEnabled(namespace) {
|
|
4
|
-
const debug = process.env.DEBUG;
|
|
5
|
-
if (!debug)
|
|
6
|
-
return false;
|
|
7
|
-
// Split by comma and check each pattern
|
|
8
|
-
const patterns = debug.split(",").map((p) => p.trim());
|
|
9
|
-
for (const pattern of patterns) {
|
|
10
|
-
// Handle exclusions (patterns starting with -)
|
|
11
|
-
if (pattern.startsWith("-")) {
|
|
12
|
-
const excludePattern = pattern.slice(1);
|
|
13
|
-
if (matchesPattern(namespace, excludePattern)) {
|
|
14
|
-
return false;
|
|
15
|
-
}
|
|
16
|
-
continue;
|
|
17
|
-
}
|
|
18
|
-
// Check if namespace matches this pattern
|
|
19
|
-
if (matchesPattern(namespace, pattern)) {
|
|
20
|
-
return true;
|
|
21
|
-
}
|
|
22
|
-
}
|
|
23
|
-
return false;
|
|
24
|
-
}
|
|
25
|
-
function matchesPattern(namespace, pattern) {
|
|
26
|
-
// Convert pattern to regex (handle * wildcards)
|
|
27
|
-
const regex = pattern
|
|
28
|
-
.replace(/\*/g, ".*") // * becomes .*
|
|
29
|
-
.replace(/:/g, "\\:"); // escape colons
|
|
30
|
-
return new RegExp(`^${regex}$`).test(namespace);
|
|
31
|
-
}
|
|
32
|
-
// Factory function that creates a debugger for a given namespace
|
|
33
|
-
const debug = (namespace) => {
|
|
34
|
-
return (...args) => {
|
|
35
|
-
if (isEnabled(namespace)) {
|
|
36
|
-
console.log(`[${namespace}]`, ...args);
|
|
37
|
-
}
|
|
38
|
-
};
|
|
39
|
-
};
|
|
40
|
-
// Export the factory function as default (like the real debug package)
|
|
41
|
-
export default debug;
|
|
File without changes
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
@@ -1,10 +0,0 @@
|
|
|
1
|
-
import React from "react";
|
|
2
|
-
import ReactServerDom from "react-dom/server.edge";
|
|
3
|
-
import { DocumentProps } from "../lib/router";
|
|
4
|
-
import { RequestInfo } from "../requestInfo/types";
|
|
5
|
-
export declare const renderRscThenableToHtmlStream: ({ thenable, Document, requestInfo, nonce, }: {
|
|
6
|
-
thenable: any;
|
|
7
|
-
Document: React.FC<DocumentProps>;
|
|
8
|
-
requestInfo: RequestInfo;
|
|
9
|
-
nonce?: string;
|
|
10
|
-
}) => Promise<ReactServerDom.ReactDOMServerReadableStream>;
|
|
@@ -1,9 +0,0 @@
|
|
|
1
|
-
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
-
import React from "react";
|
|
3
|
-
import ReactServerDom from "react-dom/server.edge";
|
|
4
|
-
const { use } = React;
|
|
5
|
-
const { renderToReadableStream } = ReactServerDom;
|
|
6
|
-
export const renderRscThenableToHtmlStream = ({ thenable, Document, requestInfo, nonce, }) => {
|
|
7
|
-
const Component = () => (_jsx(Document, { ...requestInfo, children: use(thenable).node }));
|
|
8
|
-
return renderToReadableStream(_jsx(Component, {}), { nonce });
|
|
9
|
-
};
|
|
@@ -1,9 +0,0 @@
|
|
|
1
|
-
import React from "react";
|
|
2
|
-
import ReactServerDom from "react-dom/server.edge";
|
|
3
|
-
import { type DocumentProps } from "../lib/router";
|
|
4
|
-
import { type RequestInfo } from "../requestInfo/types";
|
|
5
|
-
export declare const renderRscThenableToHtmlStream: ({ thenable, Document, requestInfo, }: {
|
|
6
|
-
thenable: any;
|
|
7
|
-
Document: React.FC<DocumentProps>;
|
|
8
|
-
requestInfo: RequestInfo;
|
|
9
|
-
}) => Promise<ReactServerDom.ReactDOMServerReadableStream>;
|
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
-
import React from "react";
|
|
3
|
-
import ReactServerDom from "react-dom/server.edge";
|
|
4
|
-
const { use } = React;
|
|
5
|
-
const { renderToReadableStream } = ReactServerDom;
|
|
6
|
-
export const renderRscThenableToHtmlStream = async ({ thenable, Document, requestInfo, }) => {
|
|
7
|
-
const Component = () => {
|
|
8
|
-
return (_jsx(Document, { ...requestInfo, children: use(thenable).node }));
|
|
9
|
-
};
|
|
10
|
-
return await renderToReadableStream(_jsx(Component, {}), {
|
|
11
|
-
nonce: requestInfo.rw.nonce,
|
|
12
|
-
});
|
|
13
|
-
};
|
|
@@ -1,79 +0,0 @@
|
|
|
1
|
-
// port(justinvdm, 10 Mar 2025): This is a modified version of https://github.com/devongovett/rsc-html-stream/blob/main/server.js
|
|
2
|
-
// Modification: We needed to add a nonce attribute to the script tag for CSP
|
|
3
|
-
const encoder = new TextEncoder();
|
|
4
|
-
const trailer = "</body></html>";
|
|
5
|
-
export function injectRSCPayload(rscStream, { nonce }) {
|
|
6
|
-
let decoder = new TextDecoder();
|
|
7
|
-
let resolveFlightDataPromise;
|
|
8
|
-
let flightDataPromise = new Promise((resolve) => (resolveFlightDataPromise = resolve));
|
|
9
|
-
let startedRSC = false;
|
|
10
|
-
// Buffer all HTML chunks enqueued during the current tick of the event loop (roughly)
|
|
11
|
-
// and write them to the output stream all at once. This ensures that we don't generate
|
|
12
|
-
// invalid HTML by injecting RSC in between two partial chunks of HTML.
|
|
13
|
-
let buffered = [];
|
|
14
|
-
let timeout = null;
|
|
15
|
-
function flushBufferedChunks(controller) {
|
|
16
|
-
for (let chunk of buffered) {
|
|
17
|
-
let buf = decoder.decode(chunk);
|
|
18
|
-
if (buf.endsWith(trailer)) {
|
|
19
|
-
buf = buf.slice(0, -trailer.length);
|
|
20
|
-
}
|
|
21
|
-
controller.enqueue(encoder.encode(buf));
|
|
22
|
-
}
|
|
23
|
-
buffered.length = 0;
|
|
24
|
-
timeout = null;
|
|
25
|
-
}
|
|
26
|
-
return new TransformStream({
|
|
27
|
-
transform(chunk, controller) {
|
|
28
|
-
buffered.push(chunk);
|
|
29
|
-
if (timeout) {
|
|
30
|
-
return;
|
|
31
|
-
}
|
|
32
|
-
timeout = setTimeout(async () => {
|
|
33
|
-
flushBufferedChunks(controller);
|
|
34
|
-
if (!startedRSC) {
|
|
35
|
-
startedRSC = true;
|
|
36
|
-
writeRSCStream(rscStream, controller, { nonce })
|
|
37
|
-
.catch((err) => controller.error(err))
|
|
38
|
-
.then(resolveFlightDataPromise);
|
|
39
|
-
}
|
|
40
|
-
}, 0);
|
|
41
|
-
},
|
|
42
|
-
async flush(controller) {
|
|
43
|
-
await flightDataPromise;
|
|
44
|
-
if (timeout) {
|
|
45
|
-
clearTimeout(timeout);
|
|
46
|
-
flushBufferedChunks(controller);
|
|
47
|
-
}
|
|
48
|
-
controller.enqueue(encoder.encode("</body></html>"));
|
|
49
|
-
},
|
|
50
|
-
});
|
|
51
|
-
}
|
|
52
|
-
async function writeRSCStream(rscStream, controller, { nonce }) {
|
|
53
|
-
let decoder = new TextDecoder("utf-8", { fatal: true });
|
|
54
|
-
for await (let chunk of rscStream) {
|
|
55
|
-
// Try decoding the chunk to send as a string.
|
|
56
|
-
// If that fails (e.g. binary data that is invalid unicode), write as base64.
|
|
57
|
-
try {
|
|
58
|
-
writeChunk(JSON.stringify(decoder.decode(chunk, { stream: true })), controller, { nonce });
|
|
59
|
-
}
|
|
60
|
-
catch (err) {
|
|
61
|
-
let base64 = JSON.stringify(btoa(String.fromCodePoint(...chunk)));
|
|
62
|
-
writeChunk(`Uint8Array.from(atob(${base64}), m => m.codePointAt(0))`, controller, { nonce });
|
|
63
|
-
}
|
|
64
|
-
}
|
|
65
|
-
let remaining = decoder.decode();
|
|
66
|
-
if (remaining.length) {
|
|
67
|
-
writeChunk(JSON.stringify(remaining), controller, { nonce });
|
|
68
|
-
}
|
|
69
|
-
}
|
|
70
|
-
function writeChunk(chunk, controller, { nonce }) {
|
|
71
|
-
controller.enqueue(encoder.encode(`<script nonce="${nonce}">${escapeScript(`(self.__FLIGHT_DATA||=[]).push(${chunk})`)}</script>`));
|
|
72
|
-
}
|
|
73
|
-
// Escape closing script tags and HTML comments in JS content.
|
|
74
|
-
// https://www.w3.org/TR/html52/semantics-scripting.html#restrictions-for-contents-of-script-elements
|
|
75
|
-
// Avoid replacing </script with <\/script as it would break the following valid JS: 0</script/ (i.e. regexp literal).
|
|
76
|
-
// Instead, escape the s character.
|
|
77
|
-
function escapeScript(script) {
|
|
78
|
-
return script.replace(/<!--/g, "<\\!--").replace(/<\/(script)/gi, "</\\$1");
|
|
79
|
-
}
|
|
@@ -1,5 +0,0 @@
|
|
|
1
|
-
import { RequestInfo, DefaultAppContext } from "./types";
|
|
2
|
-
export declare const requestInfo: RequestInfo<DefaultAppContext>;
|
|
3
|
-
export declare function getRequestInfo(): RequestInfo;
|
|
4
|
-
export declare function runWithRequestInfo<Result>(context: Record<string, any>, fn: () => Result): Result;
|
|
5
|
-
export declare function runWithRequestInfoOverrides<Result>(overrides: Record<string, any>, fn: () => Result): Result;
|
|
@@ -1,33 +0,0 @@
|
|
|
1
|
-
import { AsyncLocalStorage } from "async_hooks";
|
|
2
|
-
const requestInfoStore = new AsyncLocalStorage();
|
|
3
|
-
const requestInfoBase = {};
|
|
4
|
-
const REQUEST_INFO_KEYS = ["request", "params", "ctx", "headers", "rw", "cf"];
|
|
5
|
-
REQUEST_INFO_KEYS.forEach((key) => {
|
|
6
|
-
Object.defineProperty(requestInfoBase, key, {
|
|
7
|
-
enumerable: true,
|
|
8
|
-
configurable: false,
|
|
9
|
-
get: function () {
|
|
10
|
-
const store = requestInfoStore.getStore();
|
|
11
|
-
return store ? store[key] : undefined;
|
|
12
|
-
},
|
|
13
|
-
});
|
|
14
|
-
});
|
|
15
|
-
export const requestInfo = Object.freeze(requestInfoBase);
|
|
16
|
-
export function getRequestInfo() {
|
|
17
|
-
const store = requestInfoStore.getStore();
|
|
18
|
-
if (!store) {
|
|
19
|
-
throw new Error("Request context not found");
|
|
20
|
-
}
|
|
21
|
-
return store;
|
|
22
|
-
}
|
|
23
|
-
export function runWithRequestInfo(context, fn) {
|
|
24
|
-
return requestInfoStore.run(context, fn);
|
|
25
|
-
}
|
|
26
|
-
export function runWithRequestInfoOverrides(overrides, fn) {
|
|
27
|
-
const requestInfo = requestInfoStore.getStore();
|
|
28
|
-
const newRequestInfo = {
|
|
29
|
-
...requestInfo,
|
|
30
|
-
...overrides,
|
|
31
|
-
};
|
|
32
|
-
return requestInfoStore.run(newRequestInfo, fn);
|
|
33
|
-
}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export declare const buildVendorBundles: () => Promise<void>;
|
|
@@ -1,92 +0,0 @@
|
|
|
1
|
-
import { resolve } from "node:path";
|
|
2
|
-
import { build, mergeConfig } from "vite";
|
|
3
|
-
import { $ } from "../lib/$.mjs";
|
|
4
|
-
import { VENDOR_DIST_DIR, VENDOR_SRC_DIR } from "../lib/constants.mjs";
|
|
5
|
-
import { unlink } from "fs/promises";
|
|
6
|
-
import { pathExists } from "fs-extra";
|
|
7
|
-
const createConfig = (mode) => ({
|
|
8
|
-
mode,
|
|
9
|
-
plugins: [],
|
|
10
|
-
logLevel: process.env.VERBOSE ? "info" : "error",
|
|
11
|
-
build: {
|
|
12
|
-
emptyOutDir: false,
|
|
13
|
-
sourcemap: true,
|
|
14
|
-
minify: mode === "production",
|
|
15
|
-
},
|
|
16
|
-
define: {
|
|
17
|
-
"process.env.NODE_ENV": JSON.stringify(mode),
|
|
18
|
-
},
|
|
19
|
-
});
|
|
20
|
-
const configs = {
|
|
21
|
-
// Build react internals with server conditions
|
|
22
|
-
reactServerInternals: (mode) => mergeConfig(createConfig(mode), {
|
|
23
|
-
build: {
|
|
24
|
-
outDir: VENDOR_DIST_DIR,
|
|
25
|
-
lib: {
|
|
26
|
-
entry: resolve(VENDOR_SRC_DIR, "react-server-internals.js"),
|
|
27
|
-
name: "react-server-internals",
|
|
28
|
-
formats: ["es"],
|
|
29
|
-
fileName: () => `react-server-internals.${mode}.js`,
|
|
30
|
-
},
|
|
31
|
-
},
|
|
32
|
-
resolve: {
|
|
33
|
-
conditions: ["react-server"],
|
|
34
|
-
},
|
|
35
|
-
}),
|
|
36
|
-
// Build custom React implementation (for both development and production)
|
|
37
|
-
react: (mode) => mergeConfig(createConfig(mode), {
|
|
38
|
-
build: {
|
|
39
|
-
outDir: VENDOR_DIST_DIR,
|
|
40
|
-
lib: {
|
|
41
|
-
entry: resolve(VENDOR_SRC_DIR, "react.js"),
|
|
42
|
-
name: "react",
|
|
43
|
-
formats: ["es"],
|
|
44
|
-
fileName: () => `react.${mode}.js`,
|
|
45
|
-
},
|
|
46
|
-
},
|
|
47
|
-
resolve: {
|
|
48
|
-
alias: {
|
|
49
|
-
"react-server-internals": resolve(VENDOR_DIST_DIR, `react-server-internals.${mode}.js`),
|
|
50
|
-
},
|
|
51
|
-
},
|
|
52
|
-
}),
|
|
53
|
-
};
|
|
54
|
-
export const buildVendorBundles = async () => {
|
|
55
|
-
console.log("Cleaning vendor directory...");
|
|
56
|
-
await $ `pnpm clean:vendor`;
|
|
57
|
-
// Build for both development and production modes
|
|
58
|
-
const modes = ["development", "production"];
|
|
59
|
-
// Build the temporary server internals files first
|
|
60
|
-
console.log("Building react-server-internals...");
|
|
61
|
-
for (const mode of modes) {
|
|
62
|
-
await build(configs.reactServerInternals(mode));
|
|
63
|
-
}
|
|
64
|
-
// Build React using the server internals
|
|
65
|
-
console.log("Building React custom builds...");
|
|
66
|
-
for (const mode of modes) {
|
|
67
|
-
await build(configs.react(mode));
|
|
68
|
-
}
|
|
69
|
-
// Clean up temporary server internals files
|
|
70
|
-
console.log("Cleaning up temporary server internals files...");
|
|
71
|
-
for (const mode of modes) {
|
|
72
|
-
const serverInternalsFile = resolve(VENDOR_DIST_DIR, `react-server-internals.${mode}.js`);
|
|
73
|
-
const serverInternalsMapFile = `${serverInternalsFile}.map`;
|
|
74
|
-
try {
|
|
75
|
-
// Delete the server internals JavaScript file
|
|
76
|
-
if (await pathExists(serverInternalsFile)) {
|
|
77
|
-
await unlink(serverInternalsFile);
|
|
78
|
-
}
|
|
79
|
-
// Delete the source map file if it exists
|
|
80
|
-
if (await pathExists(serverInternalsMapFile)) {
|
|
81
|
-
await unlink(serverInternalsMapFile);
|
|
82
|
-
}
|
|
83
|
-
}
|
|
84
|
-
catch (error) {
|
|
85
|
-
console.warn(`Warning: Failed to delete ${serverInternalsFile}`, error);
|
|
86
|
-
}
|
|
87
|
-
}
|
|
88
|
-
console.log("Done building vendor bundles");
|
|
89
|
-
};
|
|
90
|
-
if (import.meta.url === new URL(process.argv[1], import.meta.url).href) {
|
|
91
|
-
buildVendorBundles();
|
|
92
|
-
}
|
|
@@ -1,9 +0,0 @@
|
|
|
1
|
-
export declare function createAliasedModuleResolver({ getAliases, roots, conditionNames, name, }: {
|
|
2
|
-
getAliases?: () => Array<{
|
|
3
|
-
find: string | RegExp;
|
|
4
|
-
replacement: string;
|
|
5
|
-
}>;
|
|
6
|
-
roots: string[];
|
|
7
|
-
conditionNames?: string[];
|
|
8
|
-
name?: string;
|
|
9
|
-
}): (request: string, importer: string) => string | false;
|