rwsdk 1.0.0-beta.2-test.20250930092748 → 1.0.0-beta.20

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.
Files changed (68) hide show
  1. package/dist/lib/constants.d.mts +1 -0
  2. package/dist/lib/constants.mjs +1 -0
  3. package/dist/lib/e2e/constants.d.mts +14 -0
  4. package/dist/lib/e2e/constants.mjs +74 -0
  5. package/dist/lib/e2e/dev.mjs +0 -1
  6. package/dist/lib/e2e/environment.d.mts +1 -1
  7. package/dist/lib/e2e/environment.mjs +118 -18
  8. package/dist/lib/e2e/index.d.mts +1 -0
  9. package/dist/lib/e2e/index.mjs +1 -0
  10. package/dist/lib/e2e/poll.d.mts +1 -1
  11. package/dist/lib/e2e/testHarness.d.mts +36 -3
  12. package/dist/lib/e2e/testHarness.mjs +192 -116
  13. package/dist/runtime/client/client.d.ts +1 -0
  14. package/dist/runtime/client/client.js +2 -0
  15. package/dist/runtime/client/navigation.d.ts +8 -0
  16. package/dist/runtime/client/navigation.js +39 -31
  17. package/dist/runtime/entries/clientSSR.d.ts +1 -0
  18. package/dist/runtime/entries/clientSSR.js +3 -0
  19. package/dist/runtime/entries/router.d.ts +1 -0
  20. package/dist/runtime/entries/worker.d.ts +2 -0
  21. package/dist/runtime/entries/worker.js +2 -0
  22. package/dist/runtime/lib/db/createDb.d.ts +1 -2
  23. package/dist/runtime/lib/db/createDb.js +4 -0
  24. package/dist/runtime/lib/manifest.d.ts +1 -1
  25. package/dist/runtime/lib/manifest.js +7 -4
  26. package/dist/runtime/lib/realtime/client.js +8 -2
  27. package/dist/runtime/lib/router.d.ts +16 -21
  28. package/dist/runtime/lib/router.js +67 -1
  29. package/dist/runtime/lib/router.test.js +241 -0
  30. package/dist/runtime/lib/{rwContext.d.ts → types.d.ts} +1 -0
  31. package/dist/runtime/render/renderDocumentHtmlStream.d.ts +1 -1
  32. package/dist/runtime/render/renderToStream.d.ts +4 -2
  33. package/dist/runtime/render/renderToStream.js +21 -2
  34. package/dist/runtime/render/renderToString.d.ts +3 -1
  35. package/dist/runtime/requestInfo/types.d.ts +4 -1
  36. package/dist/runtime/requestInfo/utils.d.ts +9 -0
  37. package/dist/runtime/requestInfo/utils.js +44 -0
  38. package/dist/runtime/requestInfo/worker.js +3 -2
  39. package/dist/runtime/script.d.ts +1 -3
  40. package/dist/runtime/script.js +1 -10
  41. package/dist/runtime/state.d.ts +3 -0
  42. package/dist/runtime/state.js +13 -0
  43. package/dist/runtime/worker.js +25 -0
  44. package/dist/scripts/debug-sync.mjs +18 -20
  45. package/dist/scripts/worker-run.d.mts +1 -1
  46. package/dist/scripts/worker-run.mjs +50 -113
  47. package/dist/vite/buildApp.mjs +34 -2
  48. package/dist/vite/directiveModulesDevPlugin.mjs +1 -1
  49. package/dist/vite/envResolvers.d.mts +11 -0
  50. package/dist/vite/envResolvers.mjs +20 -0
  51. package/dist/vite/hmrStabilityPlugin.d.mts +2 -0
  52. package/dist/vite/hmrStabilityPlugin.mjs +68 -0
  53. package/dist/vite/knownDepsResolverPlugin.d.mts +0 -6
  54. package/dist/vite/knownDepsResolverPlugin.mjs +1 -12
  55. package/dist/vite/linkerPlugin.d.mts +2 -1
  56. package/dist/vite/linkerPlugin.mjs +11 -3
  57. package/dist/vite/linkerPlugin.test.mjs +15 -0
  58. package/dist/vite/redwoodPlugin.mjs +7 -9
  59. package/dist/vite/runDirectivesScan.mjs +57 -12
  60. package/dist/vite/ssrBridgePlugin.mjs +104 -34
  61. package/dist/vite/staleDepRetryPlugin.d.mts +2 -0
  62. package/dist/vite/staleDepRetryPlugin.mjs +69 -0
  63. package/dist/vite/statePlugin.d.mts +4 -0
  64. package/dist/vite/statePlugin.mjs +62 -0
  65. package/package.json +13 -7
  66. package/dist/vite/manifestPlugin.d.mts +0 -4
  67. package/dist/vite/manifestPlugin.mjs +0 -63
  68. /package/dist/runtime/lib/{rwContext.js → types.js} +0 -0
@@ -1,6 +1,7 @@
1
1
  // @ts-ignore
2
2
  import { compile } from "@mdx-js/mdx";
3
3
  import debug from "debug";
4
+ import { glob } from "glob";
4
5
  import fsp from "node:fs/promises";
5
6
  import path from "node:path";
6
7
  import { INTERMEDIATES_OUTPUT_DIR } from "../lib/constants.mjs";
@@ -17,6 +18,39 @@ const isObject = (value) => Object.prototype.toString.call(value) === "[object O
17
18
  // https://github.com/vitejs/vite/blob/main/packages/vite/src/node/utils.ts
18
19
  const externalRE = /^(https?:)?\/\//;
19
20
  const isExternalUrl = (url) => externalRE.test(url);
21
+ async function findDirectiveRoots({ root, readFileWithCache, directiveCheckCache, }) {
22
+ const srcDir = path.resolve(root, "src");
23
+ const files = await glob("**/*.{ts,tsx,js,jsx,mjs,mts,cjs,cts,mdx}", {
24
+ cwd: srcDir,
25
+ absolute: true,
26
+ });
27
+ const directiveFiles = new Set();
28
+ for (const file of files) {
29
+ if (directiveCheckCache.has(file)) {
30
+ if (directiveCheckCache.get(file)) {
31
+ directiveFiles.add(file);
32
+ }
33
+ continue;
34
+ }
35
+ try {
36
+ const content = await readFileWithCache(file);
37
+ const hasClient = hasDirective(content, "use client");
38
+ const hasServer = hasDirective(content, "use server");
39
+ const hasAnyDirective = hasClient || hasServer;
40
+ directiveCheckCache.set(file, hasAnyDirective);
41
+ if (hasAnyDirective) {
42
+ directiveFiles.add(file);
43
+ }
44
+ }
45
+ catch (e) {
46
+ log("Could not read file during pre-scan, skipping:", file);
47
+ // Cache the failure to avoid re-reading a problematic file
48
+ directiveCheckCache.set(file, false);
49
+ }
50
+ }
51
+ log("Pre-scan found directive files:", Array.from(directiveFiles));
52
+ return directiveFiles;
53
+ }
20
54
  export async function resolveModuleWithEnvironment({ path, importer, importerEnv, clientResolver, workerResolver, }) {
21
55
  const resolver = importerEnv === "client" ? clientResolver : workerResolver;
22
56
  return new Promise((resolvePromise) => {
@@ -56,6 +90,16 @@ export const runDirectivesScan = async ({ rootConfig, environments, clientFiles,
56
90
  // Set environment variable to indicate scanning is in progress
57
91
  process.env.RWSDK_DIRECTIVE_SCAN_ACTIVE = "true";
58
92
  try {
93
+ const fileContentCache = new Map();
94
+ const directiveCheckCache = new Map();
95
+ const readFileWithCache = async (path) => {
96
+ if (fileContentCache.has(path)) {
97
+ return fileContentCache.get(path);
98
+ }
99
+ const contents = await fsp.readFile(path, "utf-8");
100
+ fileContentCache.set(path, contents);
101
+ return contents;
102
+ };
59
103
  const esbuild = await getViteEsbuild(rootConfig.root);
60
104
  const input = initialEntries ?? environments.worker.config.build.rollupOptions?.input;
61
105
  let entries;
@@ -78,19 +122,19 @@ export const runDirectivesScan = async ({ rootConfig, environments, clientFiles,
78
122
  // Filter out virtual modules since they can't be scanned by esbuild
79
123
  const realEntries = entries.filter((entry) => !entry.includes("virtual:"));
80
124
  const absoluteEntries = realEntries.map((entry) => path.resolve(rootConfig.root, entry));
81
- log("Starting directives scan for worker environment with entries:", absoluteEntries);
125
+ const applicationDirectiveFiles = await findDirectiveRoots({
126
+ root: rootConfig.root,
127
+ readFileWithCache,
128
+ directiveCheckCache,
129
+ });
130
+ const combinedEntries = new Set([
131
+ ...absoluteEntries,
132
+ ...applicationDirectiveFiles,
133
+ ]);
134
+ log("Starting directives scan with combined entries:", Array.from(combinedEntries));
82
135
  const workerResolver = createViteAwareResolver(rootConfig, environments.worker);
83
136
  const clientResolver = createViteAwareResolver(rootConfig, environments.client);
84
137
  const moduleEnvironments = new Map();
85
- const fileContentCache = new Map();
86
- const readFileWithCache = async (path) => {
87
- if (fileContentCache.has(path)) {
88
- return fileContentCache.get(path);
89
- }
90
- const contents = await fsp.readFile(path, "utf-8");
91
- fileContentCache.set(path, contents);
92
- return contents;
93
- };
94
138
  const esbuildScanPlugin = {
95
139
  name: "rwsdk:esbuild-scan-plugin",
96
140
  setup(build) {
@@ -232,7 +276,7 @@ export const runDirectivesScan = async ({ rootConfig, environments, clientFiles,
232
276
  },
233
277
  };
234
278
  await esbuild.build({
235
- entryPoints: absoluteEntries,
279
+ entryPoints: Array.from(combinedEntries),
236
280
  bundle: true,
237
281
  write: false,
238
282
  outdir: path.join(INTERMEDIATES_OUTPUT_DIR, "directive-scan"),
@@ -254,7 +298,8 @@ export const runDirectivesScan = async ({ rootConfig, environments, clientFiles,
254
298
  }
255
299
  };
256
300
  const deferredLog = (message) => {
301
+ const doLog = process.env.RWSDK_WORKER_RUN ? log : console.log;
257
302
  setTimeout(() => {
258
- console.log(message);
303
+ doLog(message);
259
304
  }, 500);
260
305
  };
@@ -10,9 +10,32 @@ export const ssrBridgePlugin = ({ clientFiles, serverFiles, }) => {
10
10
  const ssrBridgePlugin = {
11
11
  name: "rwsdk:ssr-bridge",
12
12
  enforce: "pre",
13
- async configureServer(server) {
13
+ configureServer(server) {
14
14
  devServer = server;
15
+ const ssrHot = server.environments.ssr.hot;
16
+ const originalSsrHotSend = ssrHot.send;
17
+ // Chain the SSR's full reload behaviour to the worker
18
+ ssrHot.send = (...args) => {
19
+ if (typeof args[0] === "object" && args[0].type === "full-reload") {
20
+ for (const envName of ["worker", "ssr"]) {
21
+ const moduleGraph = server.environments[envName].moduleGraph;
22
+ moduleGraph.invalidateAll();
23
+ }
24
+ log("SSR full-reload detected, propagating to worker");
25
+ // context(justinvdm, 21 Oct 2025): By sending the full-reload event
26
+ // to the worker, we ensure that the worker's module runner cache is
27
+ // invalidated, as it would have been if this were a full-reload event
28
+ // from the worker.
29
+ server.environments.worker.hot.send.apply(server.environments.worker.hot, args);
30
+ }
31
+ return originalSsrHotSend.apply(ssrHot, args);
32
+ };
15
33
  log("Configured dev server");
34
+ const originalRun = devServer.environments.ssr.depsOptimizer?.run;
35
+ devServer.environments.ssr.depsOptimizer.run = async () => {
36
+ originalRun();
37
+ devServer.environments.worker.depsOptimizer.run();
38
+ };
16
39
  },
17
40
  config(_, { command, isPreview }) {
18
41
  isDev = !isPreview && command === "serve";
@@ -48,7 +71,7 @@ export const ssrBridgePlugin = ({ clientFiles, serverFiles, }) => {
48
71
  log("Worker environment esbuild configuration complete");
49
72
  }
50
73
  },
51
- async resolveId(id) {
74
+ async resolveId(id, importer) {
52
75
  // Skip during directive scanning to avoid performance issues
53
76
  if (process.env.RWSDK_DIRECTIVE_SCAN_ACTIVE) {
54
77
  return;
@@ -107,46 +130,93 @@ export const ssrBridgePlugin = ({ clientFiles, serverFiles, }) => {
107
130
  if (id.startsWith(VIRTUAL_SSR_PREFIX) &&
108
131
  this.environment.name === "worker") {
109
132
  const realId = id.slice(VIRTUAL_SSR_PREFIX.length);
110
- const idForFetch = realId.endsWith(".css.js")
133
+ let idForFetch = realId.endsWith(".css.js")
111
134
  ? realId.slice(0, -3)
112
135
  : realId;
113
136
  log("Virtual SSR module load: id=%s, realId=%s, idForFetch=%s", id, realId, idForFetch);
114
137
  if (isDev) {
115
- log("Dev mode: fetching SSR module for realPath=%s", idForFetch);
116
- const result = await devServer?.environments.ssr.fetchModule(idForFetch);
117
- process.env.VERBOSE &&
118
- log("Fetch module result: id=%s, result=%O", idForFetch, result);
119
- const code = "code" in result ? result.code : undefined;
120
- if (idForFetch.endsWith(".css") &&
121
- !idForFetch.endsWith(".module.css")) {
122
- process.env.VERBOSE &&
123
- log("Plain CSS file, returning empty module for %s", idForFetch);
124
- return "export default {};";
138
+ // from the SSR environment, which is crucial for things like server
139
+ // components.
140
+ try {
141
+ const ssrOptimizer = devServer.environments.ssr.depsOptimizer;
142
+ // context(justinvdm, 20 Oct 2025): This is the fix for the stale
143
+ // dependency issue. The root cause is the "unhashed-to-hashed"
144
+ // transition. Our worker code imports a clean ID
145
+ // (`rwsdk/__ssr_bridge`), but we expect to fetch the hashed,
146
+ // optimized version from the SSR environment. When a re-optimization
147
+ // happens, Vite's `fetchModule` (running in the SSR env) finds a
148
+ // "ghost node" in its module graph for the clean ID and incorrectly
149
+ // re-uses its stale, hashed `id` property.
150
+ //
151
+ // To fix this, we manually resolve the hashed path here, before
152
+ // asking the SSR env to process the module. We look into the SSR
153
+ // optimizer's metadata to find the correct, up-to-date hash and
154
+ // construct the path ourselves. This ensures the SSR env is
155
+ // always working with the correct, versioned ID, bypassing the
156
+ // faulty ghost node lookup.
157
+ if (ssrOptimizer &&
158
+ Object.prototype.hasOwnProperty.call(ssrOptimizer.metadata.optimized, realId)) {
159
+ const depInfo = ssrOptimizer.metadata.optimized[realId];
160
+ idForFetch = ssrOptimizer.getOptimizedDepId(depInfo);
161
+ log("Manually resolved %s to hashed path for fetchModule: %s", realId, idForFetch);
162
+ }
163
+ log("Virtual SSR module load: id=%s, realId=%s, idForFetch=%s", id, realId, idForFetch);
164
+ log("Dev mode: fetching SSR module for realPath=%s", idForFetch);
165
+ // We use `fetchModule` with `cached: false` as a safeguard. Since
166
+ // we're in a `load` hook, we know the worker-side cache for this
167
+ // virtual module is stale. `cached: false` ensures that we also
168
+ // bypass any potentially stale transform result in the SSR
169
+ // environment's cache, guaranteeing we get the freshest possible
170
+ // code.
171
+ const result = await devServer.environments.ssr.fetchModule(idForFetch, undefined, { cached: false });
172
+ if ("code" in result) {
173
+ log("Fetched SSR module code length: %d", result.code?.length || 0);
174
+ const code = result.code;
175
+ if (idForFetch.endsWith(".css") &&
176
+ !idForFetch.endsWith(".module.css")) {
177
+ process.env.VERBOSE &&
178
+ log("Plain CSS file, returning empty module for %s", idForFetch);
179
+ return "export default {};";
180
+ }
181
+ const s = new MagicString(code || "");
182
+ const callsites = findSsrImportCallSites(idForFetch, code || "", log);
183
+ for (const site of callsites) {
184
+ const normalized = site.specifier.startsWith("/@id/")
185
+ ? site.specifier.slice("/@id/".length)
186
+ : site.specifier;
187
+ // context(justinvdm, 11 Aug 2025):
188
+ // - We replace __vite_ssr_import__ and __vite_ssr_dynamic_import__
189
+ // with import() calls so that the module graph can be built
190
+ // correctly (vite looks for imports and import()s to build module
191
+ // graph)
192
+ // - We prepend /@id/$VIRTUAL_SSR_PREFIX to the specifier so that we
193
+ // can stay within the SSR subgraph of the worker module graph
194
+ const replacement = `import("/@id/${VIRTUAL_SSR_PREFIX}${normalized}")`;
195
+ s.overwrite(site.start, site.end, replacement);
196
+ }
197
+ const out = s.toString();
198
+ process.env.VERBOSE &&
199
+ log("Transformed SSR module code for realId=%s: %s", realId, out);
200
+ return {
201
+ code: out,
202
+ map: null, // Sourcemaps are handled by fetchModule's inlining
203
+ };
204
+ }
205
+ else {
206
+ // This case can be hit if the module is already cached. We may
207
+ // need to handle this more gracefully, but for now we'll just
208
+ // return an empty module.
209
+ log("SSR module %s was already cached. Returning empty.", idForFetch);
210
+ return "export default {}";
211
+ }
125
212
  }
126
- log("Fetched SSR module code length: %d", code?.length || 0);
127
- const s = new MagicString(code || "");
128
- const callsites = findSsrImportCallSites(idForFetch, code || "", log);
129
- for (const site of callsites) {
130
- const normalized = site.specifier.startsWith("/@id/")
131
- ? site.specifier.slice("/@id/".length)
132
- : site.specifier;
133
- // context(justinvdm, 11 Aug 2025):
134
- // - We replace __vite_ssr_import__ and __vite_ssr_dynamic_import__
135
- // with import() calls so that the module graph can be built
136
- // correctly (vite looks for imports and import()s to build module
137
- // graph)
138
- // - We prepend /@id/$VIRTUAL_SSR_PREFIX to the specifier so that we
139
- // can stay within the SSR subgraph of the worker module graph
140
- const replacement = `import("/@id/${VIRTUAL_SSR_PREFIX}${normalized}")`;
141
- s.overwrite(site.start, site.end, replacement);
213
+ catch (e) {
214
+ log("Error fetching SSR module for realPath=%s: %s", id, e);
215
+ throw e;
142
216
  }
143
- const out = s.toString();
144
- log("Transformed SSR module code length: %d", out.length);
145
- process.env.VERBOSE &&
146
- log("Transformed SSR module code for realId=%s: %s", realId, out);
147
- return out;
148
217
  }
149
218
  }
219
+ return;
150
220
  },
151
221
  };
152
222
  return ssrBridgePlugin;
@@ -0,0 +1,2 @@
1
+ import { type Plugin } from "vite";
2
+ export declare function staleDepRetryPlugin(): Plugin;
@@ -0,0 +1,69 @@
1
+ import debug from "debug";
2
+ const log = debug("rwsdk:vite:stale-dep-retry-plugin");
3
+ let stabilityPromise = null;
4
+ let stabilityResolver = null;
5
+ let debounceTimer = null;
6
+ const DEBOUNCE_MS = 500;
7
+ function startWaitingForStability() {
8
+ if (!stabilityPromise) {
9
+ log("Starting to wait for server stability...");
10
+ stabilityPromise = new Promise((resolve) => {
11
+ stabilityResolver = resolve;
12
+ });
13
+ // Start the timer. If it fires, we're stable.
14
+ debounceTimer = setTimeout(finishWaiting, DEBOUNCE_MS);
15
+ }
16
+ }
17
+ function activityDetected() {
18
+ if (stabilityPromise) {
19
+ // If we're waiting for stability, reset the timer.
20
+ log("Activity detected, resetting stability timer.");
21
+ if (debounceTimer)
22
+ clearTimeout(debounceTimer);
23
+ debounceTimer = setTimeout(finishWaiting, DEBOUNCE_MS);
24
+ }
25
+ }
26
+ function finishWaiting() {
27
+ if (stabilityResolver) {
28
+ log("Server appears stable. Resolving promise.");
29
+ stabilityResolver();
30
+ }
31
+ stabilityPromise = null;
32
+ stabilityResolver = null;
33
+ debounceTimer = null;
34
+ }
35
+ export function staleDepRetryPlugin() {
36
+ return {
37
+ name: "rws-vite-plugin:stale-dep-retry",
38
+ apply: "serve",
39
+ // Monitor server activity by tapping into the transform hook. This is a
40
+ // reliable indicator that Vite is busy processing modules.
41
+ transform() {
42
+ activityDetected();
43
+ return null;
44
+ },
45
+ configureServer(server) {
46
+ // Return a function to ensure our middleware is placed after internal middlewares
47
+ return () => {
48
+ server.middlewares.use(async function rwsdkStaleBundleErrorHandler(err, req, res, next) {
49
+ if (err &&
50
+ typeof err.message === "string" &&
51
+ err.message.includes("new version of the pre-bundle")) {
52
+ log("Caught stale pre-bundle error. Waiting for server to stabilize...");
53
+ startWaitingForStability();
54
+ await stabilityPromise;
55
+ log("Server stabilized. Sending full-reload and redirecting.");
56
+ // Signal the client to do a full page reload.
57
+ server.environments.client.hot.send({
58
+ type: "full-reload",
59
+ });
60
+ res.writeHead(307, { Location: req.originalUrl || req.url });
61
+ res.end();
62
+ return;
63
+ }
64
+ next(err);
65
+ });
66
+ };
67
+ },
68
+ };
69
+ }
@@ -0,0 +1,4 @@
1
+ import type { Plugin } from "vite";
2
+ export declare const statePlugin: ({ projectRootDir, }: {
3
+ projectRootDir: string;
4
+ }) => Plugin;
@@ -0,0 +1,62 @@
1
+ import debug from "debug";
2
+ import fs from "node:fs/promises";
3
+ import { RW_STATE_EXPORT_PATH } from "../lib/constants.mjs";
4
+ import { maybeResolveEnvImport } from "./envResolvers.mjs";
5
+ const log = debug("rwsdk:vite:state-plugin");
6
+ const VIRTUAL_STATE_PREFIX = "virtual:rwsdk:state:";
7
+ export const statePlugin = ({ projectRootDir, }) => {
8
+ let isDev = false;
9
+ const stateModulePath = maybeResolveEnvImport({
10
+ id: RW_STATE_EXPORT_PATH,
11
+ envName: "worker",
12
+ projectRootDir,
13
+ });
14
+ if (!stateModulePath) {
15
+ throw new Error(`[rwsdk] State module path not found for project root: ${projectRootDir}. This is likely a bug in RedwoodSDK. Please report this issue at https://github.com/redwoodjs/sdk/issues/new`);
16
+ }
17
+ return {
18
+ name: "rwsdk:state",
19
+ enforce: "pre",
20
+ config(_, { command, isPreview }) {
21
+ isDev = !isPreview && command === "serve";
22
+ },
23
+ configEnvironment(env, config) {
24
+ if (env === "worker") {
25
+ config.optimizeDeps ??= {};
26
+ config.optimizeDeps.esbuildOptions ??= {};
27
+ config.optimizeDeps.esbuildOptions.plugins ??= [];
28
+ config.optimizeDeps.esbuildOptions.plugins.push({
29
+ name: "rwsdk-state-external",
30
+ setup(build) {
31
+ build.onResolve({
32
+ // context(justinvdm, 13 Oct 2025): Vite dep optimizer slugifies the export path
33
+ filter: new RegExp(`^(${RW_STATE_EXPORT_PATH}|${VIRTUAL_STATE_PREFIX}.*)$`),
34
+ }, (args) => {
35
+ log("Marking as external: %s", args.path);
36
+ return {
37
+ path: args.path,
38
+ external: true,
39
+ };
40
+ });
41
+ },
42
+ });
43
+ }
44
+ },
45
+ resolveId(id) {
46
+ if (id === RW_STATE_EXPORT_PATH) {
47
+ if (isDev && this.environment.name === "worker") {
48
+ return `${VIRTUAL_STATE_PREFIX}${id}`;
49
+ }
50
+ else {
51
+ return stateModulePath;
52
+ }
53
+ }
54
+ },
55
+ async load(id) {
56
+ if (id.startsWith(VIRTUAL_STATE_PREFIX)) {
57
+ log("Loading virtual state module from %s", stateModulePath);
58
+ return await fs.readFile(stateModulePath, "utf-8");
59
+ }
60
+ },
61
+ };
62
+ };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "rwsdk",
3
- "version": "1.0.0-beta.2-test.20250930092748",
3
+ "version": "1.0.0-beta.20",
4
4
  "description": "Build fast, server-driven webapps on Cloudflare with SSR, RSC, and realtime",
5
5
  "type": "module",
6
6
  "bin": {
@@ -36,6 +36,10 @@
36
36
  "types": "./dist/runtime/entries/client.d.ts",
37
37
  "default": "./dist/runtime/entries/client.js"
38
38
  },
39
+ "./__state": {
40
+ "types": "./dist/runtime/state.d.ts",
41
+ "default": "./dist/runtime/state.js"
42
+ },
39
43
  "./__ssr": {
40
44
  "react-server": "./dist/runtime/entries/no-react-server.js",
41
45
  "types": "./dist/runtime/entries/ssr.d.ts",
@@ -145,11 +149,13 @@
145
149
  "@vitejs/plugin-react": "~5.0.0",
146
150
  "chokidar": "~4.0.0",
147
151
  "debug": "~4.4.0",
152
+ "decompress": "~4.2.1",
148
153
  "enhanced-resolve": "~5.18.1",
149
154
  "eventsource-parser": "~3.0.0",
150
155
  "execa": "~9.6.0",
151
156
  "find-up": "~8.0.0",
152
157
  "fs-extra": "~11.3.0",
158
+ "get-port": "^7.1.0",
153
159
  "glob": "~11.0.1",
154
160
  "ignore": "~7.0.4",
155
161
  "jsonc-parser": "~3.3.1",
@@ -167,13 +173,13 @@
167
173
  "unique-names-generator": "~4.7.1",
168
174
  "vibe-rules": "~0.3.0",
169
175
  "vite-tsconfig-paths": "~5.1.4",
170
- "decompress": "~4.2.1"
176
+ "@types/glob": "^8.1.0"
171
177
  },
172
178
  "peerDependencies": {
173
- "@cloudflare/vite-plugin": "^1.12.4",
174
- "react": ">=19.2.0-canary-3fb190f7-20250908 <20.0.0",
175
- "react-dom": ">=19.2.0-canary-3fb190f7-20250908 <20.0.0",
176
- "react-server-dom-webpack": ">=19.2.0-canary-3fb190f7-20250908 <20.0.0",
179
+ "@cloudflare/vite-plugin": "^1.13.10",
180
+ "react": ">=19.2.0-0 <19.3.0 || >=19.3.0-0 <20.0.0",
181
+ "react-dom": ">=19.2.0-0 <19.3.0 || >=19.3.0-0 <20.0.0",
182
+ "react-server-dom-webpack": ">=19.2.0-0 <19.3.0 || >=19.3.0-0 <20.0.0",
177
183
  "vite": "^6.2.6 || 7.x",
178
184
  "wrangler": "^4.35.0"
179
185
  },
@@ -189,7 +195,7 @@
189
195
  "semver": "~7.7.1",
190
196
  "tsx": "~4.20.0",
191
197
  "typescript": "~5.9.0",
192
- "vite": "7.1.6",
198
+ "vite": "~7.1.9",
193
199
  "vitest": "~3.2.0"
194
200
  }
195
201
  }
@@ -1,4 +0,0 @@
1
- import { type Plugin } from "vite";
2
- export declare const manifestPlugin: ({ projectRootDir, }: {
3
- projectRootDir: string;
4
- }) => Plugin;
@@ -1,63 +0,0 @@
1
- import debug from "debug";
2
- const log = debug("rwsdk:vite:manifest-plugin");
3
- const virtualModuleId = "virtual:rwsdk:manifest.js";
4
- const resolvedVirtualModuleId = "\0" + virtualModuleId;
5
- export const manifestPlugin = ({ projectRootDir, }) => {
6
- let isBuild = false;
7
- return {
8
- name: "rwsdk:vite:manifest-plugin",
9
- enforce: "pre",
10
- configResolved(config) {
11
- isBuild = config.command === "build";
12
- },
13
- resolveId(id) {
14
- // Skip during directive scanning to avoid performance issues
15
- if (process.env.RWSDK_DIRECTIVE_SCAN_ACTIVE) {
16
- return;
17
- }
18
- if (id === virtualModuleId) {
19
- return resolvedVirtualModuleId;
20
- }
21
- },
22
- async load(id) {
23
- // Skip during directive scanning to avoid performance issues
24
- if (process.env.RWSDK_DIRECTIVE_SCAN_ACTIVE) {
25
- return;
26
- }
27
- if (id === resolvedVirtualModuleId) {
28
- if (isBuild) {
29
- // context(justinvdm, 28 Aug 2025): During the build, we don't have
30
- // the manifest yet. We insert a placeholder that the linker plugin
31
- // will replace in the final phase.
32
- log("Returning manifest placeholder for build");
33
- return `export default "__RWSDK_MANIFEST_PLACEHOLDER__"`;
34
- }
35
- // In dev, we can return an empty object.
36
- log("Not a build, returning empty manifest");
37
- return `export default {}`;
38
- }
39
- },
40
- configEnvironment(name, config) {
41
- if (name !== "worker" && name !== "ssr") {
42
- return;
43
- }
44
- log("Configuring environment: name=%s", name);
45
- config.optimizeDeps ??= {};
46
- config.optimizeDeps.esbuildOptions ??= {};
47
- config.optimizeDeps.esbuildOptions.plugins ??= [];
48
- config.optimizeDeps.esbuildOptions.plugins.push({
49
- name: "rwsdk:manifest:esbuild",
50
- setup(build) {
51
- log("Setting up esbuild plugin for environment: %s", name);
52
- build.onResolve({ filter: /^virtual:rwsdk:manifest\.js$/ }, () => {
53
- log("Resolving virtual manifest module in esbuild");
54
- return {
55
- path: "virtual:rwsdk:manifest.js",
56
- external: true,
57
- };
58
- });
59
- },
60
- });
61
- },
62
- };
63
- };
File without changes