rwsdk 0.1.5 → 0.1.6-test.20250702135708
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 +7 -3
- package/dist/vite/createDirectiveLookupPlugin.mjs +2 -1
- 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
package/dist/runtime/client.js
CHANGED
|
@@ -59,7 +59,12 @@ export const initClient = async ({ transport = fetchTransport, hydrateRootOption
|
|
|
59
59
|
transportContext.setRscPayload = (v) => startTransition(() => setStreamData(v));
|
|
60
60
|
return _jsx(_Fragment, { children: React.use(streamData).node });
|
|
61
61
|
}
|
|
62
|
-
hydrateRoot(rootEl, _jsx(Content, {}),
|
|
62
|
+
hydrateRoot(rootEl, _jsx(Content, {}), {
|
|
63
|
+
onUncaughtError: (error, { componentStack }) => {
|
|
64
|
+
console.error("Uncaught error: %O\n\nComponent stack:%s", error, componentStack);
|
|
65
|
+
},
|
|
66
|
+
...hydrateRootOptions,
|
|
67
|
+
});
|
|
63
68
|
if (import.meta.hot) {
|
|
64
69
|
import.meta.hot.on("rsc:update", (e) => {
|
|
65
70
|
console.log("[rwsdk] hot update", e.file);
|
|
@@ -1,3 +1,32 @@
|
|
|
1
|
+
export function validateClickEvent(event, target) {
|
|
2
|
+
// should this only work for left click?
|
|
3
|
+
if (event.button !== 0) {
|
|
4
|
+
return false;
|
|
5
|
+
}
|
|
6
|
+
if (event.ctrlKey || event.metaKey || event.shiftKey || event.altKey) {
|
|
7
|
+
return false;
|
|
8
|
+
}
|
|
9
|
+
const link = target.closest("a");
|
|
10
|
+
if (!link) {
|
|
11
|
+
return false;
|
|
12
|
+
}
|
|
13
|
+
const href = link.getAttribute("href");
|
|
14
|
+
if (!href) {
|
|
15
|
+
return false;
|
|
16
|
+
}
|
|
17
|
+
// Skip if target="_blank" or similar
|
|
18
|
+
if (link.target && link.target !== "_self") {
|
|
19
|
+
return false;
|
|
20
|
+
}
|
|
21
|
+
if (href.startsWith("http")) {
|
|
22
|
+
return false;
|
|
23
|
+
}
|
|
24
|
+
// Skip if download attribute
|
|
25
|
+
if (link.hasAttribute("download")) {
|
|
26
|
+
return false;
|
|
27
|
+
}
|
|
28
|
+
return true;
|
|
29
|
+
}
|
|
1
30
|
export function initClientNavigation(opts = {
|
|
2
31
|
onNavigate: async function onNavigate() {
|
|
3
32
|
// @ts-expect-error
|
|
@@ -6,33 +35,14 @@ export function initClientNavigation(opts = {
|
|
|
6
35
|
}) {
|
|
7
36
|
// Intercept all anchor tag clicks
|
|
8
37
|
document.addEventListener("click", async function handleClickEvent(event) {
|
|
9
|
-
//
|
|
10
|
-
if (event.
|
|
11
|
-
return;
|
|
12
|
-
}
|
|
13
|
-
if (event.ctrlKey || event.metaKey || event.shiftKey || event.altKey) {
|
|
14
|
-
return;
|
|
15
|
-
}
|
|
16
|
-
const target = event.target;
|
|
17
|
-
const link = target.closest("a");
|
|
18
|
-
if (!link) {
|
|
19
|
-
return;
|
|
20
|
-
}
|
|
21
|
-
const href = link.getAttribute("href");
|
|
22
|
-
if (!href) {
|
|
23
|
-
return;
|
|
24
|
-
}
|
|
25
|
-
// Skip if target="_blank" or similar
|
|
26
|
-
if (link.target && link.target !== "_self") {
|
|
27
|
-
return;
|
|
28
|
-
}
|
|
29
|
-
// Skip if download attribute
|
|
30
|
-
if (link.hasAttribute("download")) {
|
|
38
|
+
// Prevent default navigation
|
|
39
|
+
if (!validateClickEvent(event, event.target)) {
|
|
31
40
|
return;
|
|
32
41
|
}
|
|
33
|
-
// Prevent default navigation
|
|
34
42
|
event.preventDefault();
|
|
35
|
-
|
|
43
|
+
const el = event.target;
|
|
44
|
+
const a = el.closest("a");
|
|
45
|
+
const href = a?.getAttribute("href");
|
|
36
46
|
window.history.pushState({ path: href }, "", window.location.origin + href);
|
|
37
47
|
await opts.onNavigate();
|
|
38
48
|
}, true);
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import { describe, it, expect } from "vitest";
|
|
2
|
+
import { validateClickEvent } from "./clientNavigation";
|
|
3
|
+
describe("clientNavigation", () => {
|
|
4
|
+
let mockEvent = {
|
|
5
|
+
button: 0, // right click
|
|
6
|
+
metaKey: false,
|
|
7
|
+
altKey: false,
|
|
8
|
+
shiftKey: false,
|
|
9
|
+
ctrlKey: false,
|
|
10
|
+
};
|
|
11
|
+
let mockTarget = {
|
|
12
|
+
closest: () => {
|
|
13
|
+
return {
|
|
14
|
+
getAttribute: () => "/test",
|
|
15
|
+
hasAttribute: () => false,
|
|
16
|
+
};
|
|
17
|
+
},
|
|
18
|
+
};
|
|
19
|
+
it("should return true", () => {
|
|
20
|
+
expect(validateClickEvent(mockEvent, mockTarget)).toBe(true);
|
|
21
|
+
});
|
|
22
|
+
it("should return false if the event is not a left click", () => {
|
|
23
|
+
expect(validateClickEvent({ ...mockEvent, button: 1 }, mockTarget)).toBe(false);
|
|
24
|
+
});
|
|
25
|
+
it("none of the modifier keys are pressed", () => {
|
|
26
|
+
expect(validateClickEvent({ ...mockEvent, metaKey: true }, mockTarget)).toBe(false);
|
|
27
|
+
});
|
|
28
|
+
it("the target is not an anchor tag", () => {
|
|
29
|
+
expect(validateClickEvent(mockEvent, {
|
|
30
|
+
closest: () => undefined,
|
|
31
|
+
})).toBe(false);
|
|
32
|
+
});
|
|
33
|
+
it("should have an href attribute", () => {
|
|
34
|
+
expect(validateClickEvent(mockEvent, {
|
|
35
|
+
closest: () => ({ getAttribute: () => undefined }),
|
|
36
|
+
})).toBe(false);
|
|
37
|
+
});
|
|
38
|
+
it("should not have a target attribute", () => {
|
|
39
|
+
expect(validateClickEvent(mockEvent, {
|
|
40
|
+
closest: () => ({
|
|
41
|
+
target: "_blank",
|
|
42
|
+
getAttribute: () => "/test",
|
|
43
|
+
hasAttribute: () => false,
|
|
44
|
+
}),
|
|
45
|
+
})).toBe(false);
|
|
46
|
+
});
|
|
47
|
+
it("should be a relative link", () => {
|
|
48
|
+
expect(validateClickEvent(mockEvent, {
|
|
49
|
+
closest: () => ({
|
|
50
|
+
getAttribute: () => "/test",
|
|
51
|
+
hasAttribute: () => false,
|
|
52
|
+
}),
|
|
53
|
+
})).toBe(true);
|
|
54
|
+
});
|
|
55
|
+
});
|
|
@@ -82,12 +82,18 @@ export const realtimeTransport = ({ key = DEFAULT_KEY }) => (transportContext) =
|
|
|
82
82
|
try {
|
|
83
83
|
const socket = ensureWs();
|
|
84
84
|
const { encodeReply } = await import("react-server-dom-webpack/client.browser");
|
|
85
|
+
// Note(peterp, 2025-07-02): We need to send the "current URL" per message,
|
|
86
|
+
// in case the user has enabled client side navigation.
|
|
87
|
+
const clientUrl = new URL(window.location.href);
|
|
88
|
+
clientUrl.protocol = "";
|
|
89
|
+
clientUrl.host = "";
|
|
85
90
|
const encodedArgs = args != null ? await encodeReply(args) : null;
|
|
86
91
|
const requestId = crypto.randomUUID();
|
|
87
92
|
const messageData = JSON.stringify({
|
|
88
93
|
id,
|
|
89
94
|
args: encodedArgs,
|
|
90
95
|
requestId,
|
|
96
|
+
clientUrl,
|
|
91
97
|
});
|
|
92
98
|
const encoder = new TextEncoder();
|
|
93
99
|
const messageBytes = encoder.encode(messageData);
|
|
@@ -56,9 +56,9 @@ export class RealtimeDurableObject extends DurableObject {
|
|
|
56
56
|
if (messageType === MESSAGE_TYPE.ACTION_REQUEST) {
|
|
57
57
|
const decoder = new TextDecoder();
|
|
58
58
|
const jsonData = decoder.decode(message.slice(1));
|
|
59
|
-
const { id, args, requestId } = JSON.parse(jsonData);
|
|
59
|
+
const { id, args, requestId, clientUrl } = JSON.parse(jsonData);
|
|
60
60
|
try {
|
|
61
|
-
await this.handleAction(ws, id, args, clientInfo, requestId);
|
|
61
|
+
await this.handleAction(ws, id, args, clientInfo, requestId, clientUrl);
|
|
62
62
|
}
|
|
63
63
|
catch (error) {
|
|
64
64
|
const encoder = new TextEncoder();
|
|
@@ -100,10 +100,12 @@ export class RealtimeDurableObject extends DurableObject {
|
|
|
100
100
|
reader.releaseLock();
|
|
101
101
|
}
|
|
102
102
|
}
|
|
103
|
-
async handleAction(ws, id, args, clientInfo, requestId) {
|
|
104
|
-
const url = new URL(
|
|
105
|
-
url.searchParams.set("__rsc", "
|
|
106
|
-
|
|
103
|
+
async handleAction(ws, id, args, clientInfo, requestId, clientUrl) {
|
|
104
|
+
const url = new URL(clientUrl);
|
|
105
|
+
url.searchParams.set("__rsc", "");
|
|
106
|
+
if (id != null) {
|
|
107
|
+
url.searchParams.set("__rsc_action_id", id);
|
|
108
|
+
}
|
|
107
109
|
const response = await fetch(url.toString(), {
|
|
108
110
|
method: "POST",
|
|
109
111
|
body: args,
|
|
@@ -1,11 +1,9 @@
|
|
|
1
1
|
import { route } from "../../entries/router";
|
|
2
2
|
import { validateUpgradeRequest } from "./validateUpgradeRequest";
|
|
3
3
|
import { DEFAULT_REALTIME_KEY } from "./constants";
|
|
4
|
-
import { requestInfo } from "../../requestInfo/worker";
|
|
5
4
|
import { env } from "cloudflare:workers";
|
|
6
5
|
export { renderRealtimeClients } from "./renderRealtimeClients";
|
|
7
|
-
export const realtimeRoute = (getDurableObjectNamespace) => route("/__realtime", async function () {
|
|
8
|
-
const { request } = requestInfo;
|
|
6
|
+
export const realtimeRoute = (getDurableObjectNamespace) => route("/__realtime", async function ({ request }) {
|
|
9
7
|
const validation = validateUpgradeRequest(request);
|
|
10
8
|
if (!validation.valid) {
|
|
11
9
|
return validation.response;
|
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
import { type DocumentProps } from "../lib/router";
|
|
2
2
|
import { type RequestInfo } from "../requestInfo/types";
|
|
3
|
-
export declare const renderRscThenableToHtmlStream: ({ thenable, Document, requestInfo, shouldSSR, }: {
|
|
3
|
+
export declare const renderRscThenableToHtmlStream: ({ thenable, Document, requestInfo, shouldSSR, onError, }: {
|
|
4
4
|
thenable: any;
|
|
5
5
|
Document: React.FC<DocumentProps>;
|
|
6
6
|
requestInfo: RequestInfo;
|
|
7
7
|
shouldSSR: boolean;
|
|
8
|
+
onError: (error: unknown) => void;
|
|
8
9
|
}) => Promise<import("react-dom/server").ReactDOMServerReadableStream>;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
2
|
import { use } from "react";
|
|
3
3
|
import { renderToReadableStream } from "react-dom/server.edge";
|
|
4
|
-
export const renderRscThenableToHtmlStream = async ({ thenable, Document, requestInfo, shouldSSR, }) => {
|
|
4
|
+
export const renderRscThenableToHtmlStream = async ({ thenable, Document, requestInfo, shouldSSR, onError, }) => {
|
|
5
5
|
const Component = () => {
|
|
6
6
|
const node = use(thenable).node;
|
|
7
7
|
// todo(justinvdm, 18 Jun 2025): We can build on this later to allow users
|
|
@@ -21,5 +21,26 @@ export const renderRscThenableToHtmlStream = async ({ thenable, Document, reques
|
|
|
21
21
|
};
|
|
22
22
|
return await renderToReadableStream(_jsx(Component, {}), {
|
|
23
23
|
nonce: requestInfo.rw.nonce,
|
|
24
|
+
onError(error, { componentStack }) {
|
|
25
|
+
try {
|
|
26
|
+
const message = error
|
|
27
|
+
? (error.stack ?? error.message ?? error)
|
|
28
|
+
: error;
|
|
29
|
+
const wrappedMessage = `Error rendering RSC to HTML stream: ${message}\n\nComponent stack:\n${componentStack}`;
|
|
30
|
+
if (error instanceof Error) {
|
|
31
|
+
const wrappedError = new Error(wrappedMessage);
|
|
32
|
+
wrappedError.stack = error.stack;
|
|
33
|
+
error = wrappedError;
|
|
34
|
+
}
|
|
35
|
+
else {
|
|
36
|
+
error = new Error(wrappedMessage);
|
|
37
|
+
error.stack = componentStack;
|
|
38
|
+
}
|
|
39
|
+
onError(error);
|
|
40
|
+
}
|
|
41
|
+
catch {
|
|
42
|
+
onError(error);
|
|
43
|
+
}
|
|
44
|
+
},
|
|
24
45
|
});
|
|
25
46
|
};
|
|
@@ -4,7 +4,7 @@ import { transformRscToHtmlStream } from "./transformRscToHtmlStream";
|
|
|
4
4
|
import { requestInfo } from "../requestInfo/worker";
|
|
5
5
|
import { injectRSCPayload } from "rsc-html-stream/server";
|
|
6
6
|
export const IdentityDocument = ({ children }) => (_jsx(_Fragment, { children: children }));
|
|
7
|
-
export const renderToStream = async (element, { Document = IdentityDocument, injectRSCPayload: shouldInjectRSCPayload = false, onError, } = {}) => {
|
|
7
|
+
export const renderToStream = async (element, { Document = IdentityDocument, injectRSCPayload: shouldInjectRSCPayload = false, onError = () => { }, } = {}) => {
|
|
8
8
|
let rscStream = renderToRscStream({
|
|
9
9
|
node: element,
|
|
10
10
|
actionResult: null,
|
|
@@ -21,6 +21,7 @@ export const renderToStream = async (element, { Document = IdentityDocument, inj
|
|
|
21
21
|
stream: rscStream,
|
|
22
22
|
Document,
|
|
23
23
|
requestInfo,
|
|
24
|
+
onError,
|
|
24
25
|
});
|
|
25
26
|
return htmlStream;
|
|
26
27
|
};
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import { DocumentProps } from "../lib/router";
|
|
2
2
|
import { RequestInfo } from "../requestInfo/types";
|
|
3
|
-
export declare const transformRscToHtmlStream: ({ stream, Document, requestInfo, }: {
|
|
3
|
+
export declare const transformRscToHtmlStream: ({ stream, Document, requestInfo, onError, }: {
|
|
4
4
|
stream: ReadableStream;
|
|
5
5
|
Document: React.FC<DocumentProps>;
|
|
6
6
|
requestInfo: RequestInfo;
|
|
7
|
+
onError: (error: unknown) => void;
|
|
7
8
|
}) => Promise<import("react-dom/server.js").ReactDOMServerReadableStream>;
|
|
@@ -2,7 +2,7 @@ import { createModuleMap } from "./createModuleMap.js";
|
|
|
2
2
|
import ReactServerDom from "react-server-dom-webpack/client.edge";
|
|
3
3
|
import { renderRscThenableToHtmlStream } from "rwsdk/__ssr_bridge";
|
|
4
4
|
const { createFromReadableStream } = ReactServerDom;
|
|
5
|
-
export const transformRscToHtmlStream = ({ stream, Document, requestInfo, }) => {
|
|
5
|
+
export const transformRscToHtmlStream = ({ stream, Document, requestInfo, onError, }) => {
|
|
6
6
|
const thenable = createFromReadableStream(stream, {
|
|
7
7
|
serverConsumerManifest: {
|
|
8
8
|
moduleMap: createModuleMap(),
|
|
@@ -14,5 +14,6 @@ export const transformRscToHtmlStream = ({ stream, Document, requestInfo, }) =>
|
|
|
14
14
|
Document,
|
|
15
15
|
requestInfo,
|
|
16
16
|
shouldSSR: requestInfo.rw.ssr,
|
|
17
|
+
onError,
|
|
17
18
|
});
|
|
18
19
|
};
|
package/dist/runtime/worker.js
CHANGED
|
@@ -1,11 +1,12 @@
|
|
|
1
|
+
import path from "node:path";
|
|
1
2
|
import { $ } from "../lib/$.mjs";
|
|
2
3
|
export const debugSync = async (opts) => {
|
|
3
|
-
const { targetDir, dev, watch, build } = opts;
|
|
4
|
+
const { targetDir, sdkDir = process.cwd(), dev, watch, build } = opts;
|
|
4
5
|
if (!targetDir) {
|
|
5
6
|
console.error("❌ Please provide a target directory as an argument.");
|
|
6
7
|
process.exit(1);
|
|
7
8
|
}
|
|
8
|
-
const syncCommand = `echo 🏗️ rebuilding... && pnpm build && rm -rf ${targetDir}/node_modules/rwsdk/dist ${targetDir}/node_modules/rwsdk/package.json && echo 📁 syncing sdk from ${
|
|
9
|
+
const syncCommand = `echo 🏗️ rebuilding... && pnpm build && rm -rf ${targetDir}/node_modules/rwsdk/dist ${targetDir}/node_modules/rwsdk/package.json && echo 📁 syncing sdk from ${sdkDir} to ${targetDir}/node_modules/rwsdk/... && cp -r package.json dist ${targetDir}/node_modules/rwsdk/ && echo ✅ done syncing`;
|
|
9
10
|
// Run initial sync
|
|
10
11
|
await $({ stdio: "inherit", shell: true }) `${syncCommand}`;
|
|
11
12
|
if (!process.env.NO_CLEAN_VITE) {
|
|
@@ -40,10 +41,13 @@ export const debugSync = async (opts) => {
|
|
|
40
41
|
};
|
|
41
42
|
if (import.meta.url === new URL(process.argv[1], import.meta.url).href) {
|
|
42
43
|
const args = process.argv.slice(2);
|
|
43
|
-
const targetDir = args[0];
|
|
44
|
+
const targetDir = args[0] ?? ".";
|
|
44
45
|
const flags = new Set(args.slice(1));
|
|
45
46
|
debugSync({
|
|
46
47
|
targetDir,
|
|
48
|
+
sdkDir: process.env.SDK_REPO
|
|
49
|
+
? path.resolve(__dirname, process.env.SDK_REPO, "sdk")
|
|
50
|
+
: path.resolve(__dirname, "..", ".."),
|
|
47
51
|
dev: flags.has("--dev"),
|
|
48
52
|
watch: flags.has("--watch"),
|
|
49
53
|
build: flags.has("--build"),
|
|
@@ -182,7 +182,8 @@ export const createDirectiveLookupPlugin = async ({ projectRootDir, files, confi
|
|
|
182
182
|
resolveId(source) {
|
|
183
183
|
verboseLog("Resolving id=%s", source);
|
|
184
184
|
if (source === config.virtualModuleName ||
|
|
185
|
-
source === `/@id/${config.virtualModuleName}`
|
|
185
|
+
source === `/@id/${config.virtualModuleName}` ||
|
|
186
|
+
source === `/@id/${config.virtualModuleName}.js`) {
|
|
186
187
|
log("Resolving %s module", config.virtualModuleName);
|
|
187
188
|
// context(justinvdm, 16 Jun 2025): Include .js extension
|
|
188
189
|
// so it goes through vite processing chain
|
package/package.json
CHANGED
|
@@ -1,8 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Creates the smoke test components in the target project directory
|
|
3
|
-
*/
|
|
4
|
-
export declare function createSmokeTestComponents(targetDir: string, skipClient?: boolean): Promise<void>;
|
|
5
|
-
/**
|
|
6
|
-
* Modifies the worker.tsx and wrangler.jsonc files to add realtime support
|
|
7
|
-
*/
|
|
8
|
-
export declare function modifyAppForRealtime(targetDir: string): Promise<void>;
|
|
@@ -1,194 +0,0 @@
|
|
|
1
|
-
import { join } from "path";
|
|
2
|
-
import * as fs from "fs/promises";
|
|
3
|
-
import { log } from "./constants.mjs";
|
|
4
|
-
import { getSmokeTestFunctionsTemplate } from "./templates/smokeTestFunctions.template";
|
|
5
|
-
import { getSmokeTestTemplate } from "./templates/SmokeTest.template";
|
|
6
|
-
import { getSmokeTestClientTemplate } from "./templates/SmokeTestClient.template";
|
|
7
|
-
import MagicString from "magic-string";
|
|
8
|
-
import { parse as parseJsonc } from "jsonc-parser";
|
|
9
|
-
/**
|
|
10
|
-
* Creates the smoke test components in the target project directory
|
|
11
|
-
*/
|
|
12
|
-
export async function createSmokeTestComponents(targetDir, skipClient = false) {
|
|
13
|
-
console.log("Creating smoke test components in project...");
|
|
14
|
-
// Create directories if they don't exist
|
|
15
|
-
const componentsDir = join(targetDir, "src", "app", "components");
|
|
16
|
-
log("Creating components directory: %s", componentsDir);
|
|
17
|
-
await fs.mkdir(componentsDir, { recursive: true });
|
|
18
|
-
// Create __smokeTestFunctions.ts
|
|
19
|
-
const smokeTestFunctionsPath = join(componentsDir, "__smokeTestFunctions.ts");
|
|
20
|
-
log("Creating __smokeTestFunctions.ts at: %s", smokeTestFunctionsPath);
|
|
21
|
-
const smokeTestFunctionsContent = getSmokeTestFunctionsTemplate();
|
|
22
|
-
// Create SmokeTest.tsx with conditional client component import
|
|
23
|
-
const smokeTestPath = join(componentsDir, "__SmokeTest.tsx");
|
|
24
|
-
log("Creating __SmokeTest.tsx at: %s", smokeTestPath);
|
|
25
|
-
const smokeTestContent = getSmokeTestTemplate(skipClient);
|
|
26
|
-
// Write the server files
|
|
27
|
-
log("Writing SmokeTestFunctions file");
|
|
28
|
-
await fs.writeFile(smokeTestFunctionsPath, smokeTestFunctionsContent);
|
|
29
|
-
log("Writing SmokeTest component file");
|
|
30
|
-
await fs.writeFile(smokeTestPath, smokeTestContent);
|
|
31
|
-
// Only create client component if not skipping client-side tests
|
|
32
|
-
if (!skipClient) {
|
|
33
|
-
// Create SmokeTestClient.tsx
|
|
34
|
-
const smokeTestClientPath = join(componentsDir, "__SmokeTestClient.tsx");
|
|
35
|
-
log("Creating __SmokeTestClient.tsx at: %s", smokeTestClientPath);
|
|
36
|
-
const smokeTestClientContent = getSmokeTestClientTemplate();
|
|
37
|
-
log("Writing SmokeTestClient component file");
|
|
38
|
-
await fs.writeFile(smokeTestClientPath, smokeTestClientContent);
|
|
39
|
-
log("Created client-side smoke test component");
|
|
40
|
-
}
|
|
41
|
-
else {
|
|
42
|
-
log("Skipping client-side smoke test component creation");
|
|
43
|
-
}
|
|
44
|
-
// Modify worker.tsx and wrangler.jsonc for realtime support
|
|
45
|
-
await modifyAppForRealtime(targetDir);
|
|
46
|
-
log("Smoke test components created successfully");
|
|
47
|
-
console.log("Created smoke test components:");
|
|
48
|
-
console.log(`- ${smokeTestFunctionsPath}`);
|
|
49
|
-
console.log(`- ${smokeTestPath}`);
|
|
50
|
-
if (!skipClient) {
|
|
51
|
-
console.log(`- ${join(componentsDir, "__SmokeTestClient.tsx")}`);
|
|
52
|
-
}
|
|
53
|
-
else {
|
|
54
|
-
console.log("- Client component skipped (--skip-client was specified)");
|
|
55
|
-
}
|
|
56
|
-
}
|
|
57
|
-
/**
|
|
58
|
-
* Modifies the worker.tsx and wrangler.jsonc files to add realtime support
|
|
59
|
-
*/
|
|
60
|
-
export async function modifyAppForRealtime(targetDir) {
|
|
61
|
-
log("Modifying worker.tsx and wrangler.jsonc for realtime support");
|
|
62
|
-
// Modify worker.tsx
|
|
63
|
-
const workerPath = join(targetDir, "src", "worker.tsx");
|
|
64
|
-
if (await fs
|
|
65
|
-
.access(workerPath)
|
|
66
|
-
.then(() => true)
|
|
67
|
-
.catch(() => false)) {
|
|
68
|
-
log("Found worker.tsx, checking for realtime code");
|
|
69
|
-
const workerContent = await fs.readFile(workerPath, "utf-8");
|
|
70
|
-
// Check if the realtime export line already exists
|
|
71
|
-
const hasRealtimeExport = workerContent.includes('export { RealtimeDurableObject } from "rwsdk/realtime/durableObject"');
|
|
72
|
-
const hasRealtimeRoute = workerContent.includes("realtimeRoute(");
|
|
73
|
-
if (!hasRealtimeExport || !hasRealtimeRoute) {
|
|
74
|
-
log("Need to modify worker.tsx for realtime support");
|
|
75
|
-
const s = new MagicString(workerContent);
|
|
76
|
-
// Add the export line if it doesn't exist
|
|
77
|
-
if (!hasRealtimeExport) {
|
|
78
|
-
const importRegex = /import.*?from.*?;\n/g;
|
|
79
|
-
let lastImportMatch;
|
|
80
|
-
let lastImportPosition = 0;
|
|
81
|
-
// Find the position after the last import statement
|
|
82
|
-
while ((lastImportMatch = importRegex.exec(workerContent)) !== null) {
|
|
83
|
-
lastImportPosition =
|
|
84
|
-
lastImportMatch.index + lastImportMatch[0].length;
|
|
85
|
-
}
|
|
86
|
-
if (lastImportPosition > 0) {
|
|
87
|
-
s.appendRight(lastImportPosition, 'export { RealtimeDurableObject } from "rwsdk/realtime/durableObject";\n');
|
|
88
|
-
log("Added RealtimeDurableObject export");
|
|
89
|
-
}
|
|
90
|
-
}
|
|
91
|
-
// Add the realtimeRoute line if it doesn't exist
|
|
92
|
-
if (!hasRealtimeRoute) {
|
|
93
|
-
const defineAppMatch = workerContent.match(/export default defineApp\(\[/);
|
|
94
|
-
if (defineAppMatch && defineAppMatch.index !== undefined) {
|
|
95
|
-
const insertPosition = defineAppMatch.index + defineAppMatch[0].length;
|
|
96
|
-
s.appendRight(insertPosition, "\n realtimeRoute(() => env.REALTIME_DURABLE_OBJECT),");
|
|
97
|
-
log("Added realtimeRoute to defineApp");
|
|
98
|
-
}
|
|
99
|
-
}
|
|
100
|
-
// Import realtimeRoute if it's not already imported
|
|
101
|
-
if (!workerContent.includes("realtimeRoute")) {
|
|
102
|
-
// Find the router import to append to it
|
|
103
|
-
const routerImportMatch = workerContent.match(/import \{(.*?)\} from "rwsdk\/router";/);
|
|
104
|
-
if (routerImportMatch) {
|
|
105
|
-
const importList = routerImportMatch[1];
|
|
106
|
-
if (!importList.includes("realtimeRoute")) {
|
|
107
|
-
s.replace(routerImportMatch[0], routerImportMatch[0].replace(/import \{(.*?)\} from "rwsdk\/router";/, (match, imports) => `import { ${imports}, realtimeRoute } from "rwsdk/router";`));
|
|
108
|
-
log("Added realtimeRoute to router imports");
|
|
109
|
-
}
|
|
110
|
-
}
|
|
111
|
-
}
|
|
112
|
-
// Write the modified file
|
|
113
|
-
await fs.writeFile(workerPath, s.toString(), "utf-8");
|
|
114
|
-
log("Successfully modified worker.tsx");
|
|
115
|
-
}
|
|
116
|
-
else {
|
|
117
|
-
log("worker.tsx already has realtime support, no changes needed");
|
|
118
|
-
}
|
|
119
|
-
}
|
|
120
|
-
else {
|
|
121
|
-
log("worker.tsx not found, skipping modification");
|
|
122
|
-
}
|
|
123
|
-
// Modify wrangler.jsonc
|
|
124
|
-
const wranglerPath = join(targetDir, "wrangler.jsonc");
|
|
125
|
-
if (await fs
|
|
126
|
-
.access(wranglerPath)
|
|
127
|
-
.then(() => true)
|
|
128
|
-
.catch(() => false)) {
|
|
129
|
-
log("Found wrangler.jsonc, checking for realtime durable objects");
|
|
130
|
-
const wranglerContent = await fs.readFile(wranglerPath, "utf-8");
|
|
131
|
-
const wranglerConfig = parseJsonc(wranglerContent);
|
|
132
|
-
let modified = false;
|
|
133
|
-
// Check if REALTIME_DURABLE_OBJECT already exists in durable_objects bindings
|
|
134
|
-
const hasDurableObjectBinding = wranglerConfig.durable_objects?.bindings?.some((binding) => binding.name === "REALTIME_DURABLE_OBJECT");
|
|
135
|
-
// Check if RealtimeDurableObject is already in migrations
|
|
136
|
-
const hasMigration = wranglerConfig.migrations?.some((migration) => migration.new_sqlite_classes?.includes("RealtimeDurableObject"));
|
|
137
|
-
if (!hasDurableObjectBinding || !hasMigration) {
|
|
138
|
-
log("Need to modify wrangler.jsonc for realtime support");
|
|
139
|
-
// Create a deep copy of the config to make modifications
|
|
140
|
-
const newConfig = JSON.parse(JSON.stringify(wranglerConfig));
|
|
141
|
-
// Add durable objects binding if needed
|
|
142
|
-
if (!hasDurableObjectBinding) {
|
|
143
|
-
if (!newConfig.durable_objects) {
|
|
144
|
-
newConfig.durable_objects = {};
|
|
145
|
-
}
|
|
146
|
-
if (!newConfig.durable_objects.bindings) {
|
|
147
|
-
newConfig.durable_objects.bindings = [];
|
|
148
|
-
}
|
|
149
|
-
newConfig.durable_objects.bindings.push({
|
|
150
|
-
name: "REALTIME_DURABLE_OBJECT",
|
|
151
|
-
class_name: "RealtimeDurableObject",
|
|
152
|
-
});
|
|
153
|
-
modified = true;
|
|
154
|
-
log("Added REALTIME_DURABLE_OBJECT to durable_objects bindings");
|
|
155
|
-
}
|
|
156
|
-
// Add migration if needed
|
|
157
|
-
if (!hasMigration) {
|
|
158
|
-
if (!newConfig.migrations) {
|
|
159
|
-
newConfig.migrations = [
|
|
160
|
-
{
|
|
161
|
-
tag: "v1",
|
|
162
|
-
new_sqlite_classes: ["RealtimeDurableObject"],
|
|
163
|
-
},
|
|
164
|
-
];
|
|
165
|
-
modified = true;
|
|
166
|
-
log("Added new migrations with RealtimeDurableObject");
|
|
167
|
-
}
|
|
168
|
-
else if (newConfig.migrations.length > 0) {
|
|
169
|
-
// Add RealtimeDurableObject to the first migration's sqlite classes
|
|
170
|
-
const firstMigration = newConfig.migrations[0];
|
|
171
|
-
if (!firstMigration.new_sqlite_classes) {
|
|
172
|
-
firstMigration.new_sqlite_classes = ["RealtimeDurableObject"];
|
|
173
|
-
}
|
|
174
|
-
else if (!firstMigration.new_sqlite_classes.includes("RealtimeDurableObject")) {
|
|
175
|
-
firstMigration.new_sqlite_classes.push("RealtimeDurableObject");
|
|
176
|
-
}
|
|
177
|
-
modified = true;
|
|
178
|
-
log("Added RealtimeDurableObject to existing migration");
|
|
179
|
-
}
|
|
180
|
-
}
|
|
181
|
-
if (modified) {
|
|
182
|
-
// Write the modified config back to the file
|
|
183
|
-
await fs.writeFile(wranglerPath, JSON.stringify(newConfig, null, 2), "utf-8");
|
|
184
|
-
log("Successfully modified wrangler.jsonc");
|
|
185
|
-
}
|
|
186
|
-
}
|
|
187
|
-
else {
|
|
188
|
-
log("wrangler.jsonc already has realtime support, no changes needed");
|
|
189
|
-
}
|
|
190
|
-
}
|
|
191
|
-
else {
|
|
192
|
-
log("wrangler.jsonc not found, skipping modification");
|
|
193
|
-
}
|
|
194
|
-
}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export declare function getSmokeTestTemplate(skipClient?: boolean): string;
|