rwsdk 1.0.0-alpha.2 → 1.0.0-alpha.20-test.20250929144616

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 (214) hide show
  1. package/dist/lib/constants.mjs +1 -2
  2. package/dist/lib/e2e/browser.d.mts +10 -0
  3. package/dist/lib/e2e/browser.mjs +123 -0
  4. package/dist/lib/e2e/dev.d.mts +8 -0
  5. package/dist/lib/e2e/dev.mjs +242 -0
  6. package/dist/lib/e2e/environment.d.mts +10 -0
  7. package/dist/lib/e2e/environment.mjs +210 -0
  8. package/dist/lib/e2e/index.d.mts +8 -0
  9. package/dist/lib/e2e/index.mjs +8 -0
  10. package/dist/lib/e2e/poll.d.mts +8 -0
  11. package/dist/lib/e2e/poll.mjs +31 -0
  12. package/dist/lib/e2e/release.d.mts +56 -0
  13. package/dist/lib/e2e/release.mjs +559 -0
  14. package/dist/lib/e2e/retry.d.mts +4 -0
  15. package/dist/lib/e2e/retry.mjs +16 -0
  16. package/dist/lib/e2e/setup.d.mts +2 -0
  17. package/dist/lib/e2e/setup.mjs +1 -0
  18. package/dist/lib/e2e/tarball.d.mts +14 -0
  19. package/dist/lib/e2e/tarball.mjs +99 -0
  20. package/dist/lib/e2e/testHarness.d.mts +132 -0
  21. package/dist/lib/e2e/testHarness.mjs +436 -0
  22. package/dist/lib/e2e/types.d.mts +32 -0
  23. package/dist/lib/getShortName.mjs +6 -2
  24. package/dist/lib/getShortName.test.d.mts +1 -0
  25. package/dist/lib/getShortName.test.mjs +25 -0
  26. package/dist/lib/getSrcPaths.js +2 -2
  27. package/dist/lib/hasPkgScript.d.mts +4 -1
  28. package/dist/lib/hasPkgScript.mjs +9 -6
  29. package/dist/lib/hasPkgScript.test.d.mts +1 -0
  30. package/dist/lib/hasPkgScript.test.mjs +33 -0
  31. package/dist/lib/jsonUtils.mjs +3 -0
  32. package/dist/lib/jsonUtils.test.d.mts +1 -0
  33. package/dist/lib/jsonUtils.test.mjs +90 -0
  34. package/dist/lib/normalizeModulePath.d.mts +5 -0
  35. package/dist/lib/normalizeModulePath.mjs +1 -1
  36. package/dist/lib/normalizeModulePath.test.d.mts +1 -0
  37. package/dist/lib/{normalizeModulePath.test.js → normalizeModulePath.test.mjs} +21 -2
  38. package/dist/lib/setupEnvFiles.mjs +2 -2
  39. package/dist/lib/smokeTests/artifacts.mjs +2 -2
  40. package/dist/lib/smokeTests/browser.d.mts +1 -1
  41. package/dist/lib/smokeTests/browser.mjs +8 -100
  42. package/dist/lib/smokeTests/cleanup.mjs +6 -9
  43. package/dist/lib/smokeTests/codeUpdates.mjs +5 -5
  44. package/dist/lib/smokeTests/development.mjs +3 -224
  45. package/dist/lib/smokeTests/environment.d.mts +3 -11
  46. package/dist/lib/smokeTests/environment.mjs +17 -151
  47. package/dist/lib/smokeTests/release.d.mts +2 -49
  48. package/dist/lib/smokeTests/release.mjs +4 -504
  49. package/dist/lib/smokeTests/reporting.mjs +2 -2
  50. package/dist/lib/smokeTests/runSmokeTests.mjs +4 -4
  51. package/dist/lib/smokeTests/utils.mjs +3 -3
  52. package/dist/lib/testUtils/stubEnvVars.mjs +1 -1
  53. package/dist/llms/rules/middleware.d.ts +1 -1
  54. package/dist/llms/rules/middleware.js +4 -4
  55. package/dist/runtime/client/client.d.ts +2 -2
  56. package/dist/runtime/client/client.js +2 -2
  57. package/dist/runtime/client/navigation.test.js +1 -1
  58. package/dist/runtime/client/types.d.ts +1 -1
  59. package/dist/runtime/entries/client.d.ts +2 -2
  60. package/dist/runtime/entries/client.js +2 -2
  61. package/dist/runtime/entries/router.d.ts +1 -1
  62. package/dist/runtime/entries/router.js +1 -1
  63. package/dist/runtime/entries/worker.d.ts +5 -6
  64. package/dist/runtime/entries/worker.js +5 -6
  65. package/dist/runtime/imports/worker.js +1 -1
  66. package/dist/runtime/lib/auth/session.d.ts +2 -2
  67. package/dist/runtime/lib/auth/session.js +5 -5
  68. package/dist/runtime/lib/db/DOWorkerDialect.d.ts +1 -1
  69. package/dist/runtime/lib/db/DOWorkerDialect.js +1 -1
  70. package/dist/runtime/lib/db/SqliteDurableObject.js +2 -2
  71. package/dist/runtime/lib/db/index.d.ts +2 -2
  72. package/dist/runtime/lib/db/index.js +2 -2
  73. package/dist/runtime/lib/db/migrations.d.ts +1 -1
  74. package/dist/runtime/lib/db/typeInference/builders/alterTable.d.ts +3 -3
  75. package/dist/runtime/lib/db/typeInference/builders/columnDefinition.d.ts +1 -1
  76. package/dist/runtime/lib/db/typeInference/builders/createTable.d.ts +2 -2
  77. package/dist/runtime/lib/db/typeInference/builders/createView.d.ts +1 -1
  78. package/dist/runtime/lib/db/typeInference/builders/dropTable.d.ts +1 -1
  79. package/dist/runtime/lib/db/typeInference/builders/dropView.d.ts +1 -1
  80. package/dist/runtime/lib/db/typeInference/builders/schema.d.ts +3 -3
  81. package/dist/runtime/lib/db/typeInference/database.d.ts +2 -2
  82. package/dist/runtime/lib/memoizeOnId.test.d.ts +1 -0
  83. package/dist/runtime/lib/memoizeOnId.test.js +49 -0
  84. package/dist/runtime/lib/realtime/client.js +2 -2
  85. package/dist/runtime/lib/realtime/durableObject.js +1 -1
  86. package/dist/runtime/lib/realtime/protocol.test.d.ts +1 -0
  87. package/dist/runtime/lib/realtime/protocol.test.js +107 -0
  88. package/dist/runtime/lib/realtime/shared.test.d.ts +1 -0
  89. package/dist/runtime/lib/realtime/shared.test.js +18 -0
  90. package/dist/runtime/lib/realtime/validateUpgradeRequest.test.d.ts +1 -0
  91. package/dist/runtime/lib/realtime/validateUpgradeRequest.test.js +66 -0
  92. package/dist/runtime/lib/realtime/worker.d.ts +1 -1
  93. package/dist/runtime/lib/realtime/worker.js +2 -2
  94. package/dist/runtime/lib/router.d.ts +1 -1
  95. package/dist/runtime/lib/router.js +40 -22
  96. package/dist/runtime/lib/router.test.js +591 -3
  97. package/dist/runtime/lib/rwContext.d.ts +22 -0
  98. package/dist/runtime/lib/rwContext.js +1 -0
  99. package/dist/runtime/lib/stitchDocumentAndAppStreams.d.ts +18 -0
  100. package/dist/runtime/lib/stitchDocumentAndAppStreams.js +143 -0
  101. package/dist/runtime/lib/turnstile/useTurnstile.js +1 -1
  102. package/dist/runtime/lib/turnstile/verifyTurnstileToken.d.ts +2 -1
  103. package/dist/runtime/lib/turnstile/verifyTurnstileToken.js +6 -6
  104. package/dist/runtime/lib/turnstile/verifyTurnstileToken.test.d.ts +1 -0
  105. package/dist/runtime/lib/turnstile/verifyTurnstileToken.test.js +49 -0
  106. package/dist/runtime/register/worker.d.ts +1 -1
  107. package/dist/runtime/register/worker.js +34 -22
  108. package/dist/runtime/render/assembleDocument.d.ts +6 -0
  109. package/dist/runtime/render/assembleDocument.js +22 -0
  110. package/dist/runtime/render/createThenableFromReadableStream.d.ts +1 -0
  111. package/dist/runtime/render/createThenableFromReadableStream.js +9 -0
  112. package/dist/runtime/render/normalizeActionResult.d.ts +1 -0
  113. package/dist/runtime/render/normalizeActionResult.js +43 -0
  114. package/dist/runtime/render/preloads.d.ts +3 -3
  115. package/dist/runtime/render/preloads.js +2 -3
  116. package/dist/runtime/render/{renderRscThenableToHtmlStream.d.ts → renderDocumentHtmlStream.d.ts} +3 -3
  117. package/dist/runtime/render/renderDocumentHtmlStream.js +39 -0
  118. package/dist/runtime/render/renderHtmlStream.d.ts +7 -0
  119. package/dist/runtime/render/renderHtmlStream.js +31 -0
  120. package/dist/runtime/render/renderToRscStream.d.ts +5 -3
  121. package/dist/runtime/render/renderToRscStream.js +12 -41
  122. package/dist/runtime/render/renderToStream.d.ts +3 -2
  123. package/dist/runtime/render/renderToStream.js +17 -10
  124. package/dist/runtime/render/stylesheets.d.ts +2 -2
  125. package/dist/runtime/render/stylesheets.js +2 -3
  126. package/dist/runtime/requestInfo/types.d.ts +0 -2
  127. package/dist/runtime/requestInfo/worker.d.ts +1 -1
  128. package/dist/runtime/requestInfo/worker.js +1 -9
  129. package/dist/runtime/script.js +1 -1
  130. package/dist/runtime/ssrBridge.d.ts +3 -2
  131. package/dist/runtime/ssrBridge.js +3 -2
  132. package/dist/runtime/worker.d.ts +2 -1
  133. package/dist/runtime/worker.js +13 -16
  134. package/dist/scripts/addon.d.mts +1 -0
  135. package/dist/scripts/addon.mjs +75 -0
  136. package/dist/scripts/debug-sync.mjs +106 -137
  137. package/dist/scripts/ensure-deploy-env.mjs +6 -6
  138. package/dist/scripts/migrate-new.mjs +3 -4
  139. package/dist/scripts/smoke-test.mjs +2 -2
  140. package/dist/scripts/worker-run.mjs +7 -9
  141. package/dist/vite/buildApp.d.mts +2 -1
  142. package/dist/vite/buildApp.mjs +10 -6
  143. package/dist/vite/checkIsUsingPrisma.d.mts +4 -0
  144. package/dist/vite/checkIsUsingPrisma.mjs +2 -2
  145. package/dist/vite/checkIsUsingPrisma.test.d.mts +1 -0
  146. package/dist/vite/checkIsUsingPrisma.test.mjs +30 -0
  147. package/dist/vite/configPlugin.mjs +55 -15
  148. package/dist/vite/createDirectiveLookupPlugin.d.mts +9 -0
  149. package/dist/vite/createDirectiveLookupPlugin.mjs +34 -30
  150. package/dist/vite/createDirectiveLookupPlugin.test.d.mts +1 -0
  151. package/dist/vite/createDirectiveLookupPlugin.test.mjs +40 -0
  152. package/dist/vite/createViteAwareResolver.d.mts +1 -2
  153. package/dist/vite/createViteAwareResolver.mjs +1 -1
  154. package/dist/vite/directiveModulesDevPlugin.d.mts +4 -1
  155. package/dist/vite/directiveModulesDevPlugin.mjs +9 -8
  156. package/dist/vite/directiveModulesDevPlugin.test.d.mts +1 -0
  157. package/dist/vite/directiveModulesDevPlugin.test.mjs +59 -0
  158. package/dist/vite/directivesPlugin.d.mts +1 -0
  159. package/dist/vite/directivesPlugin.mjs +4 -4
  160. package/dist/vite/directivesPlugin.test.d.mts +1 -0
  161. package/dist/vite/directivesPlugin.test.mjs +24 -0
  162. package/dist/vite/ensureAliasArray.test.d.mts +1 -0
  163. package/dist/vite/ensureAliasArray.test.mjs +71 -0
  164. package/dist/vite/findSpecifiers.mjs +3 -2
  165. package/dist/vite/findSpecifiers.test.d.mts +1 -0
  166. package/dist/vite/findSpecifiers.test.mjs +202 -0
  167. package/dist/vite/findSsrSpecifiers.mjs +1 -1
  168. package/dist/vite/findSsrSpecifiers.test.d.mts +1 -0
  169. package/dist/vite/findSsrSpecifiers.test.mjs +99 -0
  170. package/dist/vite/getViteEsbuild.mjs +1 -1
  171. package/dist/vite/hasDirective.d.mts +6 -3
  172. package/dist/vite/hasDirective.mjs +43 -27
  173. package/dist/vite/hasDirective.test.d.mts +1 -0
  174. package/dist/vite/hasDirective.test.mjs +107 -0
  175. package/dist/vite/index.d.mts +1 -1
  176. package/dist/vite/invalidateCacheIfPrismaClientChanged.mjs +2 -2
  177. package/dist/vite/isJsFile.test.d.mts +1 -0
  178. package/dist/vite/isJsFile.test.mjs +38 -0
  179. package/dist/vite/{reactConditionsResolverPlugin.d.mts → knownDepsResolverPlugin.d.mts} +3 -3
  180. package/dist/vite/{reactConditionsResolverPlugin.mjs → knownDepsResolverPlugin.mjs} +29 -24
  181. package/dist/vite/linkerPlugin.d.mts +8 -0
  182. package/dist/vite/linkerPlugin.mjs +32 -24
  183. package/dist/vite/linkerPlugin.test.d.mts +1 -0
  184. package/dist/vite/linkerPlugin.test.mjs +41 -0
  185. package/dist/vite/miniflareHMRPlugin.d.mts +5 -0
  186. package/dist/vite/miniflareHMRPlugin.mjs +7 -7
  187. package/dist/vite/miniflareHMRPlugin.test.d.mts +1 -0
  188. package/dist/vite/miniflareHMRPlugin.test.mjs +42 -0
  189. package/dist/vite/prismaPlugin.mjs +1 -1
  190. package/dist/vite/redwoodPlugin.d.mts +9 -0
  191. package/dist/vite/redwoodPlugin.mjs +44 -20
  192. package/dist/vite/redwoodPlugin.test.d.mts +1 -0
  193. package/dist/vite/redwoodPlugin.test.mjs +34 -0
  194. package/dist/vite/resolveForcedPaths.d.mts +4 -0
  195. package/dist/vite/resolveForcedPaths.mjs +9 -0
  196. package/dist/vite/runDirectivesScan.d.mts +22 -1
  197. package/dist/vite/runDirectivesScan.mjs +109 -61
  198. package/dist/vite/runDirectivesScan.test.d.mts +1 -0
  199. package/dist/vite/runDirectivesScan.test.mjs +73 -0
  200. package/dist/vite/ssrBridgePlugin.mjs +10 -3
  201. package/dist/vite/transformClientComponents.mjs +8 -6
  202. package/dist/vite/transformClientComponents.test.mjs +117 -59
  203. package/dist/vite/transformJsxScriptTagsPlugin.mjs +1 -1
  204. package/dist/vite/transformJsxScriptTagsPlugin.test.mjs +2 -2
  205. package/dist/vite/transformServerFunctions.d.mts +1 -1
  206. package/dist/vite/transformServerFunctions.mjs +5 -5
  207. package/dist/vite/transformServerFunctions.test.mjs +3 -3
  208. package/package.json +61 -47
  209. package/dist/runtime/imports/resolveSSRValue.d.ts +0 -1
  210. package/dist/runtime/imports/resolveSSRValue.js +0 -8
  211. package/dist/runtime/render/renderRscThenableToHtmlStream.js +0 -54
  212. package/dist/runtime/render/transformRscToHtmlStream.d.ts +0 -8
  213. package/dist/runtime/render/transformRscToHtmlStream.js +0 -19
  214. /package/dist/lib/{normalizeModulePath.test.d.ts → e2e/types.mjs} +0 -0
@@ -6,10 +6,11 @@ import type { ViteBuilder } from "vite";
6
6
  *
7
7
  * @see docs/architecture/productionBuildProcess.md
8
8
  */
9
- export declare function buildApp({ builder, clientEntryPoints, clientFiles, serverFiles, projectRootDir, }: {
9
+ export declare function buildApp({ builder, clientEntryPoints, clientFiles, serverFiles, projectRootDir, workerEntryPathname, }: {
10
10
  builder: ViteBuilder;
11
11
  clientEntryPoints: Set<string>;
12
12
  clientFiles: Set<string>;
13
13
  serverFiles: Set<string>;
14
14
  projectRootDir: string;
15
+ workerEntryPathname: string;
15
16
  }): Promise<void>;
@@ -1,5 +1,5 @@
1
- import { resolve } from "node:path";
2
1
  import debug from "debug";
2
+ import { resolve } from "node:path";
3
3
  import { runDirectivesScan } from "./runDirectivesScan.mjs";
4
4
  const log = debug("rwsdk:vite:build-app");
5
5
  /**
@@ -9,13 +9,14 @@ const log = debug("rwsdk:vite:build-app");
9
9
  *
10
10
  * @see docs/architecture/productionBuildProcess.md
11
11
  */
12
- export async function buildApp({ builder, clientEntryPoints, clientFiles, serverFiles, projectRootDir, }) {
12
+ export async function buildApp({ builder, clientEntryPoints, clientFiles, serverFiles, projectRootDir, workerEntryPathname, }) {
13
13
  const workerEnv = builder.environments.worker;
14
14
  await runDirectivesScan({
15
15
  rootConfig: builder.config,
16
16
  environments: builder.environments,
17
17
  clientFiles,
18
18
  serverFiles,
19
+ entries: [workerEntryPathname],
19
20
  });
20
21
  console.log("Building worker to discover used client components...");
21
22
  process.env.RWSDK_BUILD_PASS = "worker";
@@ -42,11 +43,14 @@ export async function buildApp({ builder, clientEntryPoints, clientFiles, server
42
43
  // Re-configure the worker environment for the linking pass
43
44
  const workerConfig = workerEnv.config;
44
45
  workerConfig.build.emptyOutDir = false;
46
+ // context(justinvdm, 22 Sep 2025): This is a workaround to satisfy the
47
+ // Cloudflare plugin's expectation of an entry chunk named `index`. The plugin
48
+ // now manages the worker build, so we no longer set rollup options
49
+ // directly. Instead, we re-point the original entry to the intermediate
50
+ // worker bundle from the first pass. This allows the linker pass to re-use
51
+ // the same plugin-driven configuration while bundling the final worker.
45
52
  workerConfig.build.rollupOptions.input = {
46
- worker: resolve(projectRootDir, "dist", "worker", "worker.js"),
47
- };
48
- workerConfig.build.rollupOptions.output = {
49
- entryFileNames: "worker.js",
53
+ index: resolve(projectRootDir, "dist", "worker", "index.js"),
50
54
  };
51
55
  await builder.build(workerEnv);
52
56
  console.log("Build complete!");
@@ -1,6 +1,10 @@
1
1
  export type PrismaCheckResult = {
2
2
  isUsingPrisma: boolean;
3
3
  };
4
+ export declare const isUsingPrisma: ({ projectRootDir, resolver, }: {
5
+ projectRootDir: string;
6
+ resolver?: (path: string, request: string) => string | false;
7
+ }) => boolean;
4
8
  export declare const checkPrismaStatus: ({ projectRootDir, }: {
5
9
  projectRootDir: string;
6
10
  }) => PrismaCheckResult;
@@ -1,7 +1,7 @@
1
1
  import enhancedResolve from "enhanced-resolve";
2
- const isUsingPrisma = ({ projectRootDir }) => {
2
+ export const isUsingPrisma = ({ projectRootDir, resolver = enhancedResolve.sync, }) => {
3
3
  try {
4
- const prismaClientPath = enhancedResolve.sync(projectRootDir, "@prisma/client");
4
+ const prismaClientPath = resolver(projectRootDir, "@prisma/client");
5
5
  if (!prismaClientPath) {
6
6
  return false;
7
7
  }
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,30 @@
1
+ import { describe, expect, it } from "vitest";
2
+ import { isUsingPrisma } from "./checkIsUsingPrisma.mjs";
3
+ describe("isUsingPrisma", () => {
4
+ it("should return true if prisma client is resolved", () => {
5
+ const resolver = () => "/path/to/prisma/client";
6
+ const result = isUsingPrisma({
7
+ projectRootDir: "/test/project",
8
+ resolver: resolver,
9
+ });
10
+ expect(result).toBe(true);
11
+ });
12
+ it("should return false if prisma client is not resolved", () => {
13
+ const resolver = () => false;
14
+ const result = isUsingPrisma({
15
+ projectRootDir: "/test/project",
16
+ resolver: resolver,
17
+ });
18
+ expect(result).toBe(false);
19
+ });
20
+ it("should return false if resolver throws", () => {
21
+ const resolver = () => {
22
+ throw new Error("Module not found");
23
+ };
24
+ const result = isUsingPrisma({
25
+ projectRootDir: "/test/project",
26
+ resolver: resolver,
27
+ });
28
+ expect(result).toBe(false);
29
+ });
30
+ });
@@ -1,13 +1,11 @@
1
- import path, { resolve } from "node:path";
2
1
  import enhancedResolve from "enhanced-resolve";
3
- import debug from "debug";
2
+ import path, { resolve } from "node:path";
4
3
  import { INTERMEDIATE_SSR_BRIDGE_PATH } from "../lib/constants.mjs";
5
4
  import { buildApp } from "./buildApp.mjs";
6
5
  import { externalModules } from "./constants.mjs";
7
- const log = debug("rwsdk:vite:config");
8
6
  export const configPlugin = ({ silent, projectRootDir, workerEntryPathname, clientFiles, serverFiles, clientEntryPoints, }) => ({
9
7
  name: "rwsdk:config",
10
- config: async (_) => {
8
+ config: async (_, { command }) => {
11
9
  const mode = process.env.NODE_ENV;
12
10
  const workerConfig = {
13
11
  resolve: {
@@ -33,7 +31,17 @@ export const configPlugin = ({ silent, projectRootDir, workerEntryPathname, clie
33
31
  },
34
32
  optimizeDeps: {
35
33
  noDiscovery: false,
36
- include: ["rwsdk/worker"],
34
+ include: [
35
+ "rwsdk/__ssr_bridge",
36
+ "rwsdk/auth",
37
+ "rwsdk/constants",
38
+ "rwsdk/db",
39
+ "rwsdk/debug",
40
+ "rwsdk/realtime/durableObject",
41
+ "rwsdk/realtime/worker",
42
+ "rwsdk/router",
43
+ "rwsdk/worker",
44
+ ],
37
45
  exclude: [],
38
46
  entries: [workerEntryPathname],
39
47
  esbuildOptions: {
@@ -49,14 +57,6 @@ export const configPlugin = ({ silent, projectRootDir, workerEntryPathname, clie
49
57
  emitAssets: true,
50
58
  emptyOutDir: false,
51
59
  ssr: true,
52
- rollupOptions: {
53
- output: {
54
- inlineDynamicImports: true,
55
- },
56
- input: {
57
- worker: workerEntryPathname,
58
- },
59
- },
60
60
  },
61
61
  };
62
62
  const baseConfig = {
@@ -88,7 +88,13 @@ export const configPlugin = ({ silent, projectRootDir, workerEntryPathname, clie
88
88
  },
89
89
  optimizeDeps: {
90
90
  noDiscovery: false,
91
- include: ["rwsdk/client"],
91
+ include: [
92
+ "rwsdk/client",
93
+ "rwsdk/constants",
94
+ "rwsdk/debug",
95
+ "rwsdk/realtime/client",
96
+ "rwsdk/turnstile",
97
+ ],
92
98
  entries: [],
93
99
  esbuildOptions: {
94
100
  jsx: "automatic",
@@ -115,7 +121,18 @@ export const configPlugin = ({ silent, projectRootDir, workerEntryPathname, clie
115
121
  noDiscovery: false,
116
122
  entries: [workerEntryPathname],
117
123
  exclude: externalModules,
118
- include: ["rwsdk/__ssr", "rwsdk/__ssr_bridge"],
124
+ include: [
125
+ "rwsdk/__ssr",
126
+ "rwsdk/__ssr_bridge",
127
+ "rwsdk/client",
128
+ "rwsdk/constants",
129
+ "rwsdk/debug",
130
+ "rwsdk/realtime/client",
131
+ "rwsdk/router",
132
+ "rwsdk/worker",
133
+ "rwsdk/realtime/durableObject",
134
+ "rwsdk/realtime/worker",
135
+ ],
119
136
  esbuildOptions: {
120
137
  jsx: "automatic",
121
138
  jsxImportSource: "react",
@@ -136,8 +153,30 @@ export const configPlugin = ({ silent, projectRootDir, workerEntryPathname, clie
136
153
  outDir: path.dirname(INTERMEDIATE_SSR_BRIDGE_PATH),
137
154
  rollupOptions: {
138
155
  output: {
156
+ // context(justinvdm, 15 Sep 2025): The SSR bundle is a
157
+ // pre-compiled artifact. When the linker pass bundles it into
158
+ // the intermediate worker bundle (another pre-compiled
159
+ // artifact), Rollup merges their top-level scopes. Since both
160
+ // may have identical minified identifiers (e.g., `l0`), this
161
+ // causes a redeclaration error. To solve this, we wrap the SSR
162
+ // bundle in an exporting IIFE. This creates a scope boundary,
163
+ // preventing symbol collisions while producing a valid,
164
+ // tree-shakeable ES module. The inline plugin below removes the
165
+ // original `export` statement from the bundle to prevent syntax
166
+ // errors.
139
167
  inlineDynamicImports: true,
168
+ banner: `export const { renderHtmlStream, ssrLoadModule, ssrWebpackRequire, ssrGetModuleExport, createThenableFromReadableStream } = (function() {`,
169
+ footer: `return { renderHtmlStream, ssrLoadModule, ssrWebpackRequire, ssrGetModuleExport, createThenableFromReadableStream };\n})();`,
140
170
  },
171
+ plugins: [
172
+ {
173
+ name: "rwsdk:ssr-bridge-exports",
174
+ renderChunk(code) {
175
+ // Remove the original export statement as it's now handled by the banner/footer
176
+ return code.replace(/export\s*{[^}]+};?/, "");
177
+ },
178
+ },
179
+ ],
141
180
  },
142
181
  },
143
182
  },
@@ -154,6 +193,7 @@ export const configPlugin = ({ silent, projectRootDir, workerEntryPathname, clie
154
193
  clientEntryPoints,
155
194
  clientFiles,
156
195
  serverFiles,
196
+ workerEntryPathname,
157
197
  });
158
198
  },
159
199
  },
@@ -1,4 +1,13 @@
1
1
  import { Plugin } from "vite";
2
+ export declare function generateLookupMap({ files, isDev, kind, exportName, }: {
3
+ files: Set<string>;
4
+ isDev: boolean;
5
+ kind: "client" | "server";
6
+ exportName: string;
7
+ }): {
8
+ code: string;
9
+ map: import("magic-string").SourceMap;
10
+ };
2
11
  interface DirectiveLookupConfig {
3
12
  kind: "client" | "server";
4
13
  directive: "use client" | "use server";
@@ -1,7 +1,34 @@
1
+ import debug from "debug";
1
2
  import MagicString from "magic-string";
2
3
  import path from "path";
3
- import debug from "debug";
4
4
  import { VENDOR_CLIENT_BARREL_EXPORT_PATH, VENDOR_SERVER_BARREL_EXPORT_PATH, } from "../lib/constants.mjs";
5
+ export function generateLookupMap({ files, isDev, kind, exportName, }) {
6
+ const s = new MagicString(`
7
+ export const ${exportName} = {
8
+ ${Array.from(files)
9
+ .map((file) => {
10
+ if (file.includes("node_modules") && isDev) {
11
+ const barrelPath = kind === "client"
12
+ ? VENDOR_CLIENT_BARREL_EXPORT_PATH
13
+ : VENDOR_SERVER_BARREL_EXPORT_PATH;
14
+ return `
15
+ "${file}": () => import("${barrelPath}").then(m => m.default["${file}"]),
16
+ `;
17
+ }
18
+ else {
19
+ return `
20
+ "${file}": () => import("${file}"),
21
+ `;
22
+ }
23
+ })
24
+ .join("")}
25
+ };
26
+ `);
27
+ return {
28
+ code: s.toString(),
29
+ map: s.generateMap(),
30
+ };
31
+ }
5
32
  export const createDirectiveLookupPlugin = async ({ projectRootDir, files, config, }) => {
6
33
  const debugNamespace = `rwsdk:vite:${config.pluginName}`;
7
34
  const log = debug(debugNamespace);
@@ -121,35 +148,12 @@ export const createDirectiveLookupPlugin = async ({ projectRootDir, files, confi
121
148
  log("Loading %s module with %d files", config.virtualModuleName, files.size);
122
149
  const environment = this.environment?.name || "client";
123
150
  log("Current environment: %s, isDev: %s", environment, isDev);
124
- const s = new MagicString(`
125
- export const ${config.exportName} = {
126
- ${Array.from(files)
127
- .map((file) => {
128
- if (file.includes("node_modules") && isDev) {
129
- const barrelPath = config.kind === "client"
130
- ? VENDOR_CLIENT_BARREL_EXPORT_PATH
131
- : VENDOR_SERVER_BARREL_EXPORT_PATH;
132
- return `
133
- "${file}": () => import("${barrelPath}").then(m => m.default["${file}"]),
134
- `;
135
- }
136
- else {
137
- return `
138
- "${file}": () => import("${file}"),
139
- `;
140
- }
141
- })
142
- .join("")}
143
- };
144
- `);
145
- const code = s.toString();
146
- const map = s.generateMap();
147
- log("Generated virtual module code length: %d", code.length);
148
- process.env.VERBOSE && log("Generated virtual module code: %s", code);
149
- return {
150
- code,
151
- map,
152
- };
151
+ return generateLookupMap({
152
+ files,
153
+ isDev,
154
+ kind: config.kind,
155
+ exportName: config.exportName,
156
+ });
153
157
  }
154
158
  },
155
159
  };
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,40 @@
1
+ import { describe, expect, it } from "vitest";
2
+ import { VENDOR_CLIENT_BARREL_EXPORT_PATH, VENDOR_SERVER_BARREL_EXPORT_PATH, } from "../lib/constants.mjs";
3
+ import { generateLookupMap } from "./createDirectiveLookupPlugin.mjs";
4
+ describe("generateLookupMap", () => {
5
+ const files = new Set([
6
+ "src/app.js",
7
+ "node_modules/lib-a/index.js",
8
+ "src/component.tsx",
9
+ ]);
10
+ it("should generate correct map for client in dev", () => {
11
+ const result = generateLookupMap({
12
+ files,
13
+ isDev: true,
14
+ kind: "client",
15
+ exportName: "clientLookup",
16
+ });
17
+ expect(result.code).toContain("export const clientLookup = {");
18
+ expect(result.code).toContain(`"src/app.js": () => import("src/app.js")`);
19
+ expect(result.code).toContain(`"node_modules/lib-a/index.js": () => import("${VENDOR_CLIENT_BARREL_EXPORT_PATH}").then(m => m.default["node_modules/lib-a/index.js"])`);
20
+ });
21
+ it("should generate correct map for server in dev", () => {
22
+ const result = generateLookupMap({
23
+ files,
24
+ isDev: true,
25
+ kind: "server",
26
+ exportName: "serverLookup",
27
+ });
28
+ expect(result.code).toContain("export const serverLookup = {");
29
+ expect(result.code).toContain(`"node_modules/lib-a/index.js": () => import("${VENDOR_SERVER_BARREL_EXPORT_PATH}").then(m => m.default["node_modules/lib-a/index.js"])`);
30
+ });
31
+ it("should generate correct map for prod (isDev: false)", () => {
32
+ const result = generateLookupMap({
33
+ files,
34
+ isDev: false,
35
+ kind: "client",
36
+ exportName: "clientLookup",
37
+ });
38
+ expect(result.code).toContain(`"node_modules/lib-a/index.js": () => import("node_modules/lib-a/index.js")`);
39
+ });
40
+ });
@@ -1,5 +1,4 @@
1
1
  import resolve, { ResolveOptions } from "enhanced-resolve";
2
- import { ResolvedConfig } from "vite";
3
- import { Environment } from "vite";
2
+ import { Environment, ResolvedConfig } from "vite";
4
3
  export declare const mapViteResolveToEnhancedResolveOptions: (viteConfig: ResolvedConfig, envName: string) => ResolveOptions;
5
4
  export declare const createViteAwareResolver: (viteConfig: ResolvedConfig, environment: Environment) => resolve.ResolveFunctionAsync;
@@ -1,7 +1,7 @@
1
+ import createDebug from "debug";
1
2
  import resolve from "enhanced-resolve";
2
3
  import fs from "fs";
3
4
  import path from "path";
4
- import createDebug from "debug";
5
5
  import { normalizeModulePath } from "../lib/normalizeModulePath.mjs";
6
6
  const debug = createDebug("rwsdk:vite:enhanced-resolve-plugin");
7
7
  // Enhanced-resolve plugin that wraps Vite plugin resolution
@@ -1,6 +1,9 @@
1
1
  import { Plugin } from "vite";
2
- export declare const directiveModulesDevPlugin: ({ clientFiles, serverFiles, projectRootDir, }: {
2
+ export declare const generateVendorBarrelContent: (files: Set<string>, projectRootDir: string) => string;
3
+ export declare const generateAppBarrelContent: (files: Set<string>, projectRootDir: string) => string;
4
+ export declare const directiveModulesDevPlugin: ({ clientFiles, serverFiles, projectRootDir, workerEntryPathname, }: {
3
5
  clientFiles: Set<string>;
4
6
  serverFiles: Set<string>;
5
7
  projectRootDir: string;
8
+ workerEntryPathname: string;
6
9
  }) => Plugin;
@@ -1,10 +1,10 @@
1
- import path from "path";
1
+ import { mkdirSync, mkdtempSync, writeFileSync } from "node:fs";
2
2
  import os from "os";
3
- import { writeFileSync, mkdirSync, mkdtempSync } from "node:fs";
3
+ import path from "path";
4
+ import { VENDOR_CLIENT_BARREL_EXPORT_PATH, VENDOR_CLIENT_BARREL_PATH, VENDOR_SERVER_BARREL_EXPORT_PATH, VENDOR_SERVER_BARREL_PATH, } from "../lib/constants.mjs";
4
5
  import { normalizeModulePath } from "../lib/normalizeModulePath.mjs";
5
- import { VENDOR_CLIENT_BARREL_PATH, VENDOR_SERVER_BARREL_PATH, VENDOR_CLIENT_BARREL_EXPORT_PATH, VENDOR_SERVER_BARREL_EXPORT_PATH, } from "../lib/constants.mjs";
6
6
  import { runDirectivesScan } from "./runDirectivesScan.mjs";
7
- const generateVendorBarrelContent = (files, projectRootDir) => {
7
+ export const generateVendorBarrelContent = (files, projectRootDir) => {
8
8
  const imports = [...files]
9
9
  .filter((file) => file.includes("node_modules"))
10
10
  .map((file, i) => `import * as M${i} from '${normalizeModulePath(file, projectRootDir, {
@@ -19,7 +19,7 @@ const generateVendorBarrelContent = (files, projectRootDir) => {
19
19
  "\n};";
20
20
  return `${imports}\n\n${exports}`;
21
21
  };
22
- const generateAppBarrelContent = (files, projectRootDir, barrelFilePath) => {
22
+ export const generateAppBarrelContent = (files, projectRootDir) => {
23
23
  return [...files]
24
24
  .filter((file) => !file.includes("node_modules"))
25
25
  .map((file) => {
@@ -30,7 +30,7 @@ const generateAppBarrelContent = (files, projectRootDir, barrelFilePath) => {
30
30
  })
31
31
  .join("\n");
32
32
  };
33
- export const directiveModulesDevPlugin = ({ clientFiles, serverFiles, projectRootDir, }) => {
33
+ export const directiveModulesDevPlugin = ({ clientFiles, serverFiles, projectRootDir, workerEntryPathname, }) => {
34
34
  const { promise: scanPromise, resolve: resolveScanPromise } = Promise.withResolvers();
35
35
  const tempDir = mkdtempSync(path.join(os.tmpdir(), "rwsdk-"));
36
36
  const APP_CLIENT_BARREL_PATH = path.join(tempDir, "app-client-barrel.js");
@@ -47,6 +47,7 @@ export const directiveModulesDevPlugin = ({ clientFiles, serverFiles, projectRoo
47
47
  environments: server.environments,
48
48
  clientFiles,
49
49
  serverFiles,
50
+ entries: [workerEntryPathname],
50
51
  }).then(() => {
51
52
  // context(justinvdm, 11 Sep 2025): For vendor barrels, we write the
52
53
  // files directly to disk after the scan. For app barrels, we use a
@@ -83,7 +84,7 @@ export const directiveModulesDevPlugin = ({ clientFiles, serverFiles, projectRoo
83
84
  env.optimizeDeps.include ??= [];
84
85
  const entries = (env.optimizeDeps.entries = castArray(env.optimizeDeps.entries ?? []));
85
86
  env.optimizeDeps.include.push(VENDOR_CLIENT_BARREL_EXPORT_PATH, VENDOR_SERVER_BARREL_EXPORT_PATH);
86
- if (envName === "client") {
87
+ if (envName === "client" || envName === "ssr") {
87
88
  entries.push(APP_CLIENT_BARREL_PATH);
88
89
  }
89
90
  else if (envName === "worker") {
@@ -129,7 +130,7 @@ export const directiveModulesDevPlugin = ({ clientFiles, serverFiles, projectRoo
129
130
  build.onLoad({ filter: /.*/, namespace: "rwsdk-app-barrel-ns" }, (args) => {
130
131
  const isServerBarrel = args.path.includes("app-server-barrel");
131
132
  const files = isServerBarrel ? serverFiles : clientFiles;
132
- const content = generateAppBarrelContent(files, projectRootDir, args.path);
133
+ const content = generateAppBarrelContent(files, projectRootDir);
133
134
  return {
134
135
  contents: content,
135
136
  loader: "js",
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,59 @@
1
+ import { describe, expect, it } from "vitest";
2
+ import { generateAppBarrelContent, generateVendorBarrelContent, } from "./directiveModulesDevPlugin.mjs";
3
+ describe("directiveModulesDevPlugin helpers", () => {
4
+ const projectRootDir = "/Users/test/project";
5
+ describe("generateVendorBarrelContent", () => {
6
+ it("should generate correct content for vendor files", () => {
7
+ const files = new Set([
8
+ "node_modules/lib-a/index.js",
9
+ "src/app.js",
10
+ "node_modules/lib-b/component.tsx",
11
+ ]);
12
+ const content = generateVendorBarrelContent(files, projectRootDir);
13
+ const expected = `import * as M0 from '${projectRootDir}/node_modules/lib-a/index.js';
14
+ import * as M1 from '${projectRootDir}/node_modules/lib-b/component.tsx';
15
+
16
+ export default {
17
+ '/node_modules/lib-a/index.js': M0,
18
+ '/node_modules/lib-b/component.tsx': M1,
19
+ };`;
20
+ expect(content).toEqual(expected);
21
+ });
22
+ it("should return empty content if no vendor files", () => {
23
+ const files = new Set(["src/app.js", "src/component.tsx"]);
24
+ const content = generateVendorBarrelContent(files, projectRootDir);
25
+ expect(content).toEqual("\n\nexport default {\n\n};");
26
+ });
27
+ it("should handle an empty file set", () => {
28
+ const files = new Set();
29
+ const content = generateVendorBarrelContent(files, projectRootDir);
30
+ expect(content).toEqual("\n\nexport default {\n\n};");
31
+ });
32
+ });
33
+ describe("generateAppBarrelContent", () => {
34
+ it("should generate correct content for app files", () => {
35
+ const files = new Set([
36
+ "src/app.js",
37
+ "node_modules/lib-a/index.js",
38
+ "src/component.tsx",
39
+ ]);
40
+ const content = generateAppBarrelContent(files, projectRootDir);
41
+ const expected = `import "${projectRootDir}/src/app.js";
42
+ import "${projectRootDir}/src/component.tsx";`;
43
+ expect(content).toEqual(expected);
44
+ });
45
+ it("should return empty content if no app files", () => {
46
+ const files = new Set([
47
+ "node_modules/lib-a/index.js",
48
+ "node_modules/lib-b/component.tsx",
49
+ ]);
50
+ const content = generateAppBarrelContent(files, projectRootDir);
51
+ expect(content).toEqual("");
52
+ });
53
+ it("should handle an empty file set", () => {
54
+ const files = new Set();
55
+ const content = generateAppBarrelContent(files, projectRootDir);
56
+ expect(content).toEqual("");
57
+ });
58
+ });
59
+ });
@@ -1,4 +1,5 @@
1
1
  import { Plugin } from "vite";
2
+ export declare const getLoader: (filePath: string) => "jsx" | "js" | "ts" | "tsx";
2
3
  export declare const directivesPlugin: ({ projectRootDir, clientFiles, serverFiles, }: {
3
4
  projectRootDir: string;
4
5
  clientFiles: Set<string>;
@@ -1,11 +1,11 @@
1
- import path from "node:path";
2
- import fs from "node:fs/promises";
3
1
  import debug from "debug";
2
+ import fs from "node:fs/promises";
3
+ import path from "node:path";
4
+ import { normalizeModulePath } from "../lib/normalizeModulePath.mjs";
4
5
  import { transformClientComponents } from "./transformClientComponents.mjs";
5
6
  import { transformServerFunctions } from "./transformServerFunctions.mjs";
6
- import { normalizeModulePath } from "../lib/normalizeModulePath.mjs";
7
7
  const log = debug("rwsdk:vite:rsc-directives-plugin");
8
- const getLoader = (filePath) => {
8
+ export const getLoader = (filePath) => {
9
9
  const ext = path.extname(filePath).slice(1);
10
10
  switch (ext) {
11
11
  case "mjs":
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,24 @@
1
+ import { describe, expect, it } from "vitest";
2
+ import { getLoader } from "./directivesPlugin.mjs";
3
+ describe("getLoader", () => {
4
+ const testCases = [
5
+ { path: "file.js", expected: "js" },
6
+ { path: "file.mjs", expected: "js" },
7
+ { path: "file.cjs", expected: "js" },
8
+ { path: "file.ts", expected: "ts" },
9
+ { path: "file.mts", expected: "ts" },
10
+ { path: "file.cts", expected: "ts" },
11
+ { path: "file.jsx", expected: "jsx" },
12
+ { path: "file.tsx", expected: "tsx" },
13
+ { path: "/path/to/component.ts", expected: "ts" },
14
+ { path: "../relative/path.jsx", expected: "jsx" },
15
+ { path: "file.css", expected: "js" }, // default case
16
+ { path: "file.json", expected: "js" }, // default case
17
+ { path: "file", expected: "js" }, // no extension
18
+ ];
19
+ testCases.forEach(({ path, expected }) => {
20
+ it(`should return "${expected}" for "${path}"`, () => {
21
+ expect(getLoader(path)).toBe(expected);
22
+ });
23
+ });
24
+ });
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,71 @@
1
+ import { describe, expect, it } from "vitest";
2
+ import { ensureAliasArray } from "./ensureAliasArray.mjs";
3
+ describe("ensureAliasArray", () => {
4
+ it("should create resolve and alias array if resolve is undefined", () => {
5
+ const config = {};
6
+ const result = ensureAliasArray(config);
7
+ expect(result).toEqual([]);
8
+ expect(config.resolve?.alias).toEqual([]);
9
+ expect(result).toBe(config.resolve?.alias);
10
+ });
11
+ it("should create alias array if alias is undefined", () => {
12
+ const config = { resolve: {} };
13
+ const result = ensureAliasArray(config);
14
+ expect(result).toEqual([]);
15
+ expect(config.resolve?.alias).toEqual([]);
16
+ expect(result).toBe(config.resolve?.alias);
17
+ });
18
+ it("should convert an alias object to an array", () => {
19
+ const config = {
20
+ resolve: {
21
+ alias: {
22
+ find: "/replacement",
23
+ another: "/another-replacement",
24
+ },
25
+ },
26
+ };
27
+ const result = ensureAliasArray(config);
28
+ const expected = [
29
+ { find: "find", replacement: "/replacement" },
30
+ { find: "another", replacement: "/another-replacement" },
31
+ ];
32
+ expect(result).toEqual(expected);
33
+ expect(config.resolve?.alias).toEqual(expected);
34
+ expect(result).toBe(config.resolve?.alias);
35
+ });
36
+ it("should return a clone of an existing alias array", () => {
37
+ const originalAlias = [{ find: "find", replacement: "/replacement" }];
38
+ const config = {
39
+ resolve: {
40
+ alias: originalAlias,
41
+ },
42
+ };
43
+ const result = ensureAliasArray(config);
44
+ expect(result).toEqual(originalAlias);
45
+ expect(result).not.toBe(originalAlias);
46
+ expect(config.resolve?.alias).toEqual(originalAlias);
47
+ expect(config.resolve?.alias).not.toBe(originalAlias);
48
+ });
49
+ it("should handle an empty alias object", () => {
50
+ const config = {
51
+ resolve: {
52
+ alias: {},
53
+ },
54
+ };
55
+ const result = ensureAliasArray(config);
56
+ expect(result).toEqual([]);
57
+ expect(config.resolve?.alias).toEqual([]);
58
+ });
59
+ it("should handle an empty alias array", () => {
60
+ const config = {
61
+ resolve: {
62
+ alias: [],
63
+ },
64
+ };
65
+ const originalAlias = config.resolve?.alias;
66
+ const result = ensureAliasArray(config);
67
+ expect(result).toEqual([]);
68
+ expect(config.resolve?.alias).toEqual([]);
69
+ expect(result).not.toBe(originalAlias);
70
+ });
71
+ });