rwsdk 1.0.0-beta.20 → 1.0.0-beta.22

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.
@@ -1,12 +1,14 @@
1
- import path, { resolve } from "node:path";
2
- const __dirname = new URL(".", import.meta.url).pathname;
1
+ import { fileURLToPath } from "url";
2
+ import { dirname, resolve } from "path";
3
+ const __filename = fileURLToPath(import.meta.url);
4
+ const __dirname = dirname(__filename);
3
5
  export const ROOT_DIR = resolve(__dirname, "..", "..");
4
6
  export const SRC_DIR = resolve(ROOT_DIR, "src");
5
7
  export const DIST_DIR = resolve(ROOT_DIR, "dist");
6
8
  export const VITE_DIR = resolve(ROOT_DIR, "src", "vite");
7
9
  export const INTERMEDIATES_OUTPUT_DIR = resolve(DIST_DIR, "__intermediate_builds");
8
- export const VENDOR_CLIENT_BARREL_PATH = path.resolve(INTERMEDIATES_OUTPUT_DIR, "rwsdk-vendor-client-barrel.js");
9
- export const VENDOR_SERVER_BARREL_PATH = path.resolve(INTERMEDIATES_OUTPUT_DIR, "rwsdk-vendor-server-barrel.js");
10
+ export const VENDOR_CLIENT_BARREL_PATH = resolve(INTERMEDIATES_OUTPUT_DIR, "rwsdk-vendor-client-barrel.js");
11
+ export const VENDOR_SERVER_BARREL_PATH = resolve(INTERMEDIATES_OUTPUT_DIR, "rwsdk-vendor-server-barrel.js");
10
12
  export const VENDOR_CLIENT_BARREL_EXPORT_PATH = "rwsdk/__vendor_client_barrel";
11
13
  export const VENDOR_SERVER_BARREL_EXPORT_PATH = "rwsdk/__vendor_server_barrel";
12
14
  export const RW_STATE_EXPORT_PATH = "rwsdk/__state";
@@ -1,6 +1,6 @@
1
1
  import debug from "debug";
2
2
  import { setTimeout as sleep } from "node:timers/promises";
3
- import { $ } from "../../lib/$.mjs";
3
+ import { $, $sh } from "../../lib/$.mjs";
4
4
  import { poll } from "./poll.mjs";
5
5
  const DEV_SERVER_CHECK_TIMEOUT = process.env.RWSDK_DEV_SERVER_CHECK_TIMEOUT
6
6
  ? parseInt(process.env.RWSDK_DEV_SERVER_CHECK_TIMEOUT, 10)
@@ -21,43 +21,30 @@ export async function runDevServer(packageManager = "pnpm", cwd) {
21
21
  return;
22
22
  }
23
23
  console.log("Stopping development server...");
24
- try {
25
- // Send a regular termination signal to the entire process group first
26
- process.kill(-devProcess.pid, "SIGTERM");
27
- }
28
- catch (e) {
29
- log("Could not send SIGTERM to dev server process group: %O", e);
30
- }
31
- // Wait for the process to terminate with a timeout
32
- const terminationTimeout = 5000; // 5 seconds
33
- const processExitPromise = devProcess.catch(() => {
34
- // We expect this promise to reject when the process is killed,
35
- // so we catch and ignore the error.
36
- });
37
- const timeoutPromise = new Promise((resolve) => setTimeout(() => resolve(undefined), terminationTimeout));
38
- await Promise.race([processExitPromise, timeoutPromise]);
39
- // Check if the process is still alive. We can't reliably check exitCode
40
- // on a detached process, so we try sending a signal 0, which errors
41
- // if the process doesn't exist.
42
- let isAlive = true;
43
- try {
44
- // Sending signal 0 doesn't kill the process, but checks if it exists
45
- process.kill(-devProcess.pid, 0);
46
- }
47
- catch (e) {
48
- isAlive = false;
24
+ if (process.platform === "win32") {
25
+ try {
26
+ await $sh(`taskkill /pid ${devProcess.pid} /f /t`);
27
+ }
28
+ catch (err) {
29
+ log("Failed to kill process tree with taskkill:", err);
30
+ }
49
31
  }
50
- // If not terminated within timeout, force kill the entire process group
51
- if (isAlive) {
52
- log("Dev server process did not terminate within timeout, force killing with SIGKILL");
53
- console.log("⚠️ Development server not responding after 5 seconds timeout, force killing...");
32
+ else {
33
+ // On Unix-like systems, we kill the entire process group by sending a signal
34
+ // to the negative PID. This is the equivalent of the `/t` flag for `taskkill` on Windows.
35
+ // This relies on `detached: true` being set in the execa options, which makes
36
+ // the child process the leader of a new process group.
54
37
  try {
55
38
  process.kill(-devProcess.pid, "SIGKILL");
56
39
  }
57
40
  catch (e) {
58
- log("Could not send SIGKILL to dev server process group: %O", e);
41
+ log("Failed to kill process group. This may happen if the process already exited. %O", e);
59
42
  }
60
43
  }
44
+ await devProcess.catch(() => {
45
+ // We expect this promise to reject when the process is killed,
46
+ // so we catch and ignore the error.
47
+ });
61
48
  console.log("Development server stopped");
62
49
  };
63
50
  try {
@@ -88,8 +75,9 @@ export async function runDevServer(packageManager = "pnpm", cwd) {
88
75
  // Use the provided cwd if available
89
76
  devProcess = $({
90
77
  all: true,
91
- detached: true, // Run in a new process group so we can kill the entire group
92
- cleanup: false, // Don't auto-kill on exit
78
+ detached: true, // Re-enable for reliable process cleanup
79
+ cleanup: true, // Let execa handle cleanup
80
+ forceKillAfterTimeout: 2000, // Force kill if graceful shutdown fails
93
81
  cwd: cwd || process.cwd(), // Use provided directory or current directory
94
82
  env, // Pass the updated environment variables
95
83
  stdio: "pipe", // Ensure streams are piped
@@ -9,6 +9,7 @@ import { runDevServer } from "./dev.mjs";
9
9
  import { poll, pollValue } from "./poll.mjs";
10
10
  import { deleteD1Database, deleteWorker, isRelatedToTest, runRelease, } from "./release.mjs";
11
11
  import { setupTarballEnvironment } from "./tarball.mjs";
12
+ import { fileURLToPath } from "url";
12
13
  export { DEPLOYMENT_CHECK_TIMEOUT, DEPLOYMENT_MIN_TRIES, DEPLOYMENT_TIMEOUT, DEV_SERVER_MIN_TRIES, DEV_SERVER_TIMEOUT, HYDRATION_TIMEOUT, INSTALL_DEPENDENCIES_RETRIES, PUPPETEER_TIMEOUT, SETUP_PLAYGROUND_ENV_TIMEOUT, SETUP_WAIT_TIMEOUT, TEST_MAX_RETRIES, TEST_MAX_RETRIES_PER_CODE, };
13
14
  // Environment variable flags for skipping tests
14
15
  const SKIP_DEV_SERVER_TESTS = process.env.RWSDK_SKIP_DEV === "1";
@@ -64,11 +65,11 @@ function getProjectDirectory() {
64
65
  * Derive the playground directory from import.meta.url by finding the nearest package.json
65
66
  */
66
67
  function getPlaygroundDirFromImportMeta(importMetaUrl) {
67
- const url = new URL(importMetaUrl);
68
- const testFilePath = url.pathname;
68
+ const testFilePath = fileURLToPath(importMetaUrl);
69
69
  let currentDir = dirname(testFilePath);
70
70
  // Walk up the tree from the test file's directory
71
- while (currentDir !== "/") {
71
+ // Stop when the parent directory is the same as the current directory (we've reached the root)
72
+ while (dirname(currentDir) !== currentDir) {
72
73
  // Check if a package.json exists in the current directory
73
74
  if (fs.existsSync(pathJoin(currentDir, "package.json"))) {
74
75
  return currentDir;
@@ -0,0 +1 @@
1
+ export { defineLinks } from "../lib/links.js";
@@ -0,0 +1 @@
1
+ export { defineLinks } from "../lib/links.js";
@@ -1,11 +1,15 @@
1
1
  import { Fragment as _Fragment, jsx as _jsx } from "react/jsx-runtime";
2
2
  import { injectRSCPayload } from "rsc-html-stream/server";
3
+ import { ssrWebpackRequire } from "../imports/worker.js";
3
4
  import { constructWithDefaultRequestInfo } from "../requestInfo/utils";
4
- import { getRequestInfo } from "../requestInfo/worker";
5
+ import { getRequestInfo, runWithRequestInfo } from "../requestInfo/worker";
5
6
  import { renderDocumentHtmlStream } from "./renderDocumentHtmlStream";
6
7
  import { renderToRscStream } from "./renderToRscStream";
7
8
  export const IdentityDocument = ({ children }) => (_jsx(_Fragment, { children: children }));
8
9
  export const renderToStream = async (element, { ssr: shouldSSR = true, Document = IdentityDocument, injectRSCPayload: shouldInjectRSCPayload = true, requestInfo: givenRequestInfo, onError = () => { }, } = {}) => {
10
+ if (!globalThis.__webpack_require__) {
11
+ globalThis.__webpack_require__ = ssrWebpackRequire;
12
+ }
9
13
  // Try to get the context requestInfo from the async store.
10
14
  let contextRequestInfo;
11
15
  try {
@@ -24,30 +28,36 @@ export const renderToStream = async (element, { ssr: shouldSSR = true, Document
24
28
  ...givenRequestInfo?.rw,
25
29
  },
26
30
  });
27
- let rscStream = renderToRscStream({
28
- input: {
29
- node: element,
30
- actionResult: undefined,
31
- },
32
- onError,
33
- });
34
- let injectRSCStream;
35
- if (shouldInjectRSCPayload) {
36
- const [rscPayloadStream1, rscPayloadStream2] = rscStream.tee();
37
- rscStream = rscPayloadStream1;
38
- injectRSCStream = injectRSCPayload(rscPayloadStream2, {
39
- nonce: requestInfo.rw.nonce,
31
+ // context(gching, 2025-10-29): We wrap the following with context to the requestInfo
32
+ // due to `ssrWebpackRequire` needing to reference the `requestInfo` in context.
33
+ // Therefore, we need to wrap + also pass in the requestInfo in their independent
34
+ // function calls
35
+ return runWithRequestInfo(requestInfo, async () => {
36
+ let rscStream = renderToRscStream({
37
+ input: {
38
+ node: element,
39
+ actionResult: undefined,
40
+ },
41
+ onError,
40
42
  });
41
- }
42
- let htmlStream = await renderDocumentHtmlStream({
43
- rscPayloadStream: rscStream,
44
- Document,
45
- requestInfo,
46
- shouldSSR,
47
- onError,
43
+ let injectRSCStream;
44
+ if (shouldInjectRSCPayload) {
45
+ const [rscPayloadStream1, rscPayloadStream2] = rscStream.tee();
46
+ rscStream = rscPayloadStream1;
47
+ injectRSCStream = injectRSCPayload(rscPayloadStream2, {
48
+ nonce: requestInfo.rw.nonce,
49
+ });
50
+ }
51
+ let htmlStream = await renderDocumentHtmlStream({
52
+ rscPayloadStream: rscStream,
53
+ Document,
54
+ requestInfo,
55
+ shouldSSR,
56
+ onError,
57
+ });
58
+ if (injectRSCStream) {
59
+ htmlStream = htmlStream.pipeThrough(injectRSCStream);
60
+ }
61
+ return htmlStream;
48
62
  });
49
- if (injectRSCStream) {
50
- htmlStream = htmlStream.pipeThrough(injectRSCStream);
51
- }
52
- return htmlStream;
53
63
  };
@@ -1,6 +1,7 @@
1
1
  import dbg from "debug";
2
2
  import getPort from "get-port";
3
3
  import path from "path";
4
+ import { pathToFileURL } from "url";
4
5
  import * as vite from "vite";
5
6
  import { createLogger } from "vite";
6
7
  const debug = dbg("rwsdk:worker-run");
@@ -42,7 +43,8 @@ const main = async () => {
42
43
  },
43
44
  });
44
45
  await server.listen();
45
- const url = `http://localhost:${port}/__worker-run?script=${scriptPath}`;
46
+ const fileUrl = pathToFileURL(scriptPath).href;
47
+ const url = `http://localhost:${port}/__worker-run?script=${encodeURIComponent(fileUrl)}`;
46
48
  debug("Fetching %s", url);
47
49
  const response = await fetch(url);
48
50
  debug("Response from worker: %s", response);
@@ -93,6 +93,7 @@ export const configPlugin = ({ silent, projectRootDir, workerEntryPathname, clie
93
93
  "rwsdk/constants",
94
94
  "rwsdk/debug",
95
95
  "rwsdk/realtime/client",
96
+ "rwsdk/router",
96
97
  "rwsdk/turnstile",
97
98
  ],
98
99
  entries: [],
@@ -1,5 +1,6 @@
1
1
  import { createRequire } from "node:module";
2
2
  import path from "node:path";
3
+ import { pathToFileURL } from "node:url";
3
4
  const require = createRequire(import.meta.url);
4
5
  export async function getViteEsbuild(projectRootDir) {
5
6
  const vitePath = require.resolve("vite/package.json", {
@@ -7,6 +8,6 @@ export async function getViteEsbuild(projectRootDir) {
7
8
  });
8
9
  const viteDir = path.dirname(vitePath);
9
10
  const esbuildPath = require.resolve("esbuild", { paths: [viteDir] });
10
- const esbuildModule = await import(esbuildPath);
11
+ const esbuildModule = await import(pathToFileURL(esbuildPath).href);
11
12
  return esbuildModule.default || esbuildModule;
12
13
  }
@@ -1,13 +1,23 @@
1
- import { $sh } from "../lib/$.mjs";
1
+ import path from "node:path";
2
+ import fs from "fs-extra";
3
+ import { glob } from "glob";
2
4
  export const moveStaticAssetsPlugin = ({ rootDir, }) => ({
3
5
  name: "rwsdk:move-static-assets",
4
6
  apply: "build",
5
7
  async closeBundle() {
6
8
  if (this.environment.name === "worker" &&
7
9
  process.env.RWSDK_BUILD_PASS === "linker") {
8
- await $sh({
9
- cwd: rootDir,
10
- }) `mv dist/worker/assets/*.css dist/client/assets/ || true`;
10
+ const sourceDir = path.join(rootDir, "dist", "worker", "assets");
11
+ const destDir = path.join(rootDir, "dist", "client", "assets");
12
+ const cssFiles = await glob("*.css", { cwd: sourceDir });
13
+ if (cssFiles.length > 0) {
14
+ await fs.ensureDir(destDir);
15
+ for (const file of cssFiles) {
16
+ const sourceFile = path.join(sourceDir, file);
17
+ const destFile = path.join(destDir, file);
18
+ await fs.move(sourceFile, destFile, { overwrite: true });
19
+ }
20
+ }
11
21
  }
12
22
  },
13
23
  });
@@ -210,11 +210,11 @@ export const runDirectivesScan = async ({ rootConfig, environments, clientFiles,
210
210
  });
211
211
  build.onLoad({ filter: /\.(m|c)?[jt]sx?$|\.mdx$/ }, async (args) => {
212
212
  log("onLoad called for:", args.path);
213
- if (!args.path.startsWith("/") ||
213
+ if (!path.isAbsolute(args.path) ||
214
214
  args.path.includes("virtual:") ||
215
215
  isExternalUrl(args.path)) {
216
216
  log("Skipping file due to filter:", args.path, {
217
- startsWithSlash: args.path.startsWith("/"),
217
+ isAbsolute: path.isAbsolute(args.path),
218
218
  hasVirtual: args.path.includes("virtual:"),
219
219
  isExternal: isExternalUrl(args.path),
220
220
  });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "rwsdk",
3
- "version": "1.0.0-beta.20",
3
+ "version": "1.0.0-beta.22",
4
4
  "description": "Build fast, server-driven webapps on Cloudflare with SSR, RSC, and realtime",
5
5
  "type": "module",
6
6
  "bin": {
@@ -58,7 +58,8 @@
58
58
  },
59
59
  "./router": {
60
60
  "types": "./dist/runtime/entries/router.d.ts",
61
- "default": "./dist/runtime/entries/router.js"
61
+ "workerd": "./dist/runtime/entries/router.js",
62
+ "default": "./dist/runtime/entries/routerClient.js"
62
63
  },
63
64
  "./auth": {
64
65
  "types": "./dist/runtime/entries/auth.d.ts",