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
@@ -1,11 +1,14 @@
1
+ // @ts-ignore
2
+ import { compile } from "@mdx-js/mdx";
3
+ import debug from "debug";
1
4
  import fsp from "node:fs/promises";
2
- import { hasDirective } from "./hasDirective.mjs";
3
5
  import path from "node:path";
4
- import debug from "debug";
5
- import { getViteEsbuild } from "./getViteEsbuild.mjs";
6
+ import { INTERMEDIATES_OUTPUT_DIR } from "../lib/constants.mjs";
6
7
  import { normalizeModulePath } from "../lib/normalizeModulePath.mjs";
7
8
  import { externalModules } from "./constants.mjs";
8
- import { createViteAwareResolver, } from "./createViteAwareResolver.mjs";
9
+ import { createViteAwareResolver } from "./createViteAwareResolver.mjs";
10
+ import { getViteEsbuild } from "./getViteEsbuild.mjs";
11
+ import { hasDirective } from "./hasDirective.mjs";
9
12
  const log = debug("rwsdk:vite:run-directives-scan");
10
13
  // Copied from Vite's source code.
11
14
  // https://github.com/vitejs/vite/blob/main/packages/vite/src/shared/utils.ts
@@ -14,13 +17,47 @@ const isObject = (value) => Object.prototype.toString.call(value) === "[object O
14
17
  // https://github.com/vitejs/vite/blob/main/packages/vite/src/node/utils.ts
15
18
  const externalRE = /^(https?:)?\/\//;
16
19
  const isExternalUrl = (url) => externalRE.test(url);
17
- export const runDirectivesScan = async ({ rootConfig, environments, clientFiles, serverFiles, }) => {
18
- console.log("\n🔍 Scanning for 'use client' and 'use server' directives...");
20
+ export async function resolveModuleWithEnvironment({ path, importer, importerEnv, clientResolver, workerResolver, }) {
21
+ const resolver = importerEnv === "client" ? clientResolver : workerResolver;
22
+ return new Promise((resolvePromise) => {
23
+ resolver({}, importer || "", path, {}, (err, result) => {
24
+ if (!err && result) {
25
+ resolvePromise({ id: result });
26
+ }
27
+ else {
28
+ if (err) {
29
+ const errorMessage = err.message || String(err);
30
+ if (errorMessage.includes("Package path . is not exported")) {
31
+ log("Package exports error for %s, marking as external", path);
32
+ }
33
+ else {
34
+ log("Resolution failed for %s: %s", path, errorMessage);
35
+ }
36
+ }
37
+ resolvePromise(null);
38
+ }
39
+ });
40
+ });
41
+ }
42
+ export function classifyModule({ contents, inheritedEnv, }) {
43
+ let moduleEnv = inheritedEnv;
44
+ const isClient = hasDirective(contents, "use client");
45
+ const isServer = hasDirective(contents, "use server");
46
+ if (isClient) {
47
+ moduleEnv = "client";
48
+ }
49
+ else if (isServer) {
50
+ moduleEnv = "worker";
51
+ }
52
+ return { moduleEnv, isClient, isServer };
53
+ }
54
+ export const runDirectivesScan = async ({ rootConfig, environments, clientFiles, serverFiles, entries: initialEntries, }) => {
55
+ deferredLog("\n… (rwsdk) Scanning for 'use client' and 'use server' directives...");
19
56
  // Set environment variable to indicate scanning is in progress
20
57
  process.env.RWSDK_DIRECTIVE_SCAN_ACTIVE = "true";
21
58
  try {
22
59
  const esbuild = await getViteEsbuild(rootConfig.root);
23
- const input = environments.worker.config.build.rollupOptions?.input;
60
+ const input = initialEntries ?? environments.worker.config.build.rollupOptions?.input;
24
61
  let entries;
25
62
  if (Array.isArray(input)) {
26
63
  entries = input;
@@ -38,7 +75,9 @@ export const runDirectivesScan = async ({ rootConfig, environments, clientFiles,
38
75
  log("No entries found for directives scan in worker environment, skipping.");
39
76
  return;
40
77
  }
41
- const absoluteEntries = entries.map((entry) => path.resolve(rootConfig.root, entry));
78
+ // Filter out virtual modules since they can't be scanned by esbuild
79
+ const realEntries = entries.filter((entry) => !entry.includes("virtual:"));
80
+ const absoluteEntries = realEntries.map((entry) => path.resolve(rootConfig.root, entry));
42
81
  log("Starting directives scan for worker environment with entries:", absoluteEntries);
43
82
  const workerResolver = createViteAwareResolver(rootConfig, environments.worker);
44
83
  const clientResolver = createViteAwareResolver(rootConfig, environments.client);
@@ -57,7 +96,7 @@ export const runDirectivesScan = async ({ rootConfig, environments, clientFiles,
57
96
  setup(build) {
58
97
  // Match Vite's behavior by externalizing assets and special queries.
59
98
  // This prevents esbuild from trying to bundle them, which would fail.
60
- const scriptFilter = /\.(c|m)?[jt]sx?$/;
99
+ const scriptFilter = /\.(c|m)?[jt]sx?$|\.mdx$/;
61
100
  const specialQueryFilter = /[?&](?:url|raw|worker|sharedworker|inline)\b/;
62
101
  // This regex is used to identify if a path has any file extension.
63
102
  const hasExtensionRegex = /\.[^/]+$/;
@@ -87,17 +126,12 @@ export const runDirectivesScan = async ({ rootConfig, environments, clientFiles,
87
126
  /\.(m|c)?[jt]sx?$/.test(args.importer)) {
88
127
  try {
89
128
  const importerContents = await readFileWithCache(args.importer);
90
- if (hasDirective(importerContents, "use client")) {
91
- importerEnv = "client";
92
- log("Pre-detected importer 'use client' in:", args.importer);
93
- }
94
- else if (hasDirective(importerContents, "use server")) {
95
- importerEnv = "worker";
96
- log("Pre-detected importer 'use server' in:", args.importer);
97
- }
98
- else {
99
- importerEnv = "worker"; // Default for entry points
100
- }
129
+ const classification = classifyModule({
130
+ contents: importerContents,
131
+ inheritedEnv: "worker", // Default for entry points
132
+ });
133
+ importerEnv = classification.moduleEnv;
134
+ log("Pre-detected importer environment in:", args.importer, "as", importerEnv);
101
135
  moduleEnvironments.set(args.importer, importerEnv);
102
136
  }
103
137
  catch (e) {
@@ -109,25 +143,12 @@ export const runDirectivesScan = async ({ rootConfig, environments, clientFiles,
109
143
  importerEnv = "worker"; // Default for entry points or non-script files
110
144
  }
111
145
  log("Importer:", args.importer, "environment:", importerEnv);
112
- const resolver = importerEnv === "client" ? clientResolver : workerResolver;
113
- const resolved = await new Promise((resolve) => {
114
- resolver({}, args.importer || rootConfig.root, args.path, {}, (err, result) => {
115
- if (!err && result) {
116
- resolve({ id: result });
117
- }
118
- else {
119
- if (err) {
120
- const errorMessage = err.message || String(err);
121
- if (errorMessage.includes("Package path . is not exported")) {
122
- log("Package exports error for %s, marking as external", args.path);
123
- }
124
- else {
125
- log("Resolution failed for %s: %s", args.path, errorMessage);
126
- }
127
- }
128
- resolve(null);
129
- }
130
- });
146
+ const resolved = await resolveModuleWithEnvironment({
147
+ path: args.path,
148
+ importer: args.importer,
149
+ importerEnv,
150
+ clientResolver,
151
+ workerResolver,
131
152
  });
132
153
  log("Resolution result:", resolved);
133
154
  const resolvedPath = resolved?.id;
@@ -143,7 +164,7 @@ export const runDirectivesScan = async ({ rootConfig, environments, clientFiles,
143
164
  log("Marking as external:", args.path, "resolved to:", resolvedPath);
144
165
  return { external: true };
145
166
  });
146
- build.onLoad({ filter: /\.(m|c)?[jt]sx?$/ }, async (args) => {
167
+ build.onLoad({ filter: /\.(m|c)?[jt]sx?$|\.mdx$/ }, async (args) => {
147
168
  log("onLoad called for:", args.path);
148
169
  if (!args.path.startsWith("/") ||
149
170
  args.path.includes("virtual:") ||
@@ -156,33 +177,52 @@ export const runDirectivesScan = async ({ rootConfig, environments, clientFiles,
156
177
  return null;
157
178
  }
158
179
  try {
159
- const contents = await readFileWithCache(args.path);
180
+ const originalContents = await readFileWithCache(args.path);
160
181
  const inheritedEnv = args.pluginData?.inheritedEnv || "worker";
161
- let currentEnv = inheritedEnv;
162
- const isClient = hasDirective(contents, "use client");
163
- const isServer = hasDirective(contents, "use server");
164
- // A file's own directive takes precedence over the inherited environment.
165
- if (isClient) {
166
- currentEnv = "client";
167
- }
168
- else if (isServer) {
169
- // `else if` handles cases where a file might have both directives.
170
- // "use client" takes precedence.
171
- currentEnv = "worker";
172
- }
182
+ const { moduleEnv, isClient, isServer } = classifyModule({
183
+ contents: originalContents,
184
+ inheritedEnv,
185
+ });
173
186
  // Store the definitive environment for this module, so it can be used when it becomes an importer.
174
- moduleEnvironments.set(args.path, currentEnv);
175
- log("Set environment for", args.path, "to", currentEnv);
187
+ const realPath = await fsp.realpath(args.path);
188
+ moduleEnvironments.set(realPath, moduleEnv);
189
+ log("Set environment for", realPath, "to", moduleEnv);
176
190
  // Finally, populate the output sets if the file has a directive.
177
191
  if (isClient) {
178
- log("Discovered 'use client' in:", args.path);
179
- clientFiles.add(normalizeModulePath(args.path, rootConfig.root));
192
+ log("Discovered 'use client' in:", realPath);
193
+ clientFiles.add(normalizeModulePath(realPath, rootConfig.root));
180
194
  }
181
195
  if (isServer) {
182
- log("Discovered 'use server' in:", args.path);
183
- serverFiles.add(normalizeModulePath(args.path, rootConfig.root));
196
+ log("Discovered 'use server' in:", realPath);
197
+ serverFiles.add(normalizeModulePath(realPath, rootConfig.root));
184
198
  }
185
- return { contents, loader: "default" };
199
+ let code;
200
+ let loader;
201
+ if (args.path.endsWith(".mdx")) {
202
+ const result = await compile(originalContents, {
203
+ jsx: true,
204
+ jsxImportSource: "react",
205
+ });
206
+ code = String(result.value);
207
+ loader = "tsx";
208
+ }
209
+ else if (/\.(m|c)?tsx$/.test(args.path)) {
210
+ code = originalContents;
211
+ loader = "tsx";
212
+ }
213
+ else if (/\.(m|c)?ts$/.test(args.path)) {
214
+ code = originalContents;
215
+ loader = "ts";
216
+ }
217
+ else if (/\.(m|c)?jsx$/.test(args.path)) {
218
+ code = originalContents;
219
+ loader = "jsx";
220
+ }
221
+ else {
222
+ code = originalContents;
223
+ loader = "js";
224
+ }
225
+ return { contents: code, loader };
186
226
  }
187
227
  catch (e) {
188
228
  log("Could not read file during scan, skipping:", args.path, e);
@@ -195,6 +235,7 @@ export const runDirectivesScan = async ({ rootConfig, environments, clientFiles,
195
235
  entryPoints: absoluteEntries,
196
236
  bundle: true,
197
237
  write: false,
238
+ outdir: path.join(INTERMEDIATES_OUTPUT_DIR, "directive-scan"),
198
239
  platform: "node",
199
240
  format: "esm",
200
241
  logLevel: "silent",
@@ -207,6 +248,13 @@ export const runDirectivesScan = async ({ rootConfig, environments, clientFiles,
207
248
  finally {
208
249
  // Always clear the scanning flag when done
209
250
  delete process.env.RWSDK_DIRECTIVE_SCAN_ACTIVE;
210
- console.log(" Scan complete.");
251
+ deferredLog(" (rwsdk) Done scanning for 'use client' and 'use server' directives.");
252
+ process.env.VERBOSE &&
253
+ log("Client/server files after scanning: client=%O, server=%O", Array.from(clientFiles), Array.from(serverFiles));
211
254
  }
212
255
  };
256
+ const deferredLog = (message) => {
257
+ setTimeout(() => {
258
+ console.log(message);
259
+ }, 500);
260
+ };
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,73 @@
1
+ import { describe, expect, it, vi } from "vitest";
2
+ import { classifyModule, resolveModuleWithEnvironment, } from "./runDirectivesScan.mjs";
3
+ describe("runDirectivesScan helpers", () => {
4
+ describe("resolveModuleWithEnvironment", () => {
5
+ it("should use the client resolver when importerEnv is 'client'", async () => {
6
+ const clientResolver = vi.fn((_a, _b, _c, _d, cb) => cb(null, "/resolved/client"));
7
+ const workerResolver = vi.fn();
8
+ const result = await resolveModuleWithEnvironment({
9
+ path: "test-path",
10
+ importerEnv: "client",
11
+ clientResolver,
12
+ workerResolver,
13
+ });
14
+ expect(clientResolver).toHaveBeenCalled();
15
+ expect(workerResolver).not.toHaveBeenCalled();
16
+ expect(result).toEqual({ id: "/resolved/client" });
17
+ });
18
+ it("should use the worker resolver when importerEnv is 'worker'", async () => {
19
+ const clientResolver = vi.fn();
20
+ const workerResolver = vi.fn((_a, _b, _c, _d, cb) => cb(null, "/resolved/worker"));
21
+ const result = await resolveModuleWithEnvironment({
22
+ path: "test-path",
23
+ importerEnv: "worker",
24
+ clientResolver,
25
+ workerResolver,
26
+ });
27
+ expect(workerResolver).toHaveBeenCalled();
28
+ expect(clientResolver).not.toHaveBeenCalled();
29
+ expect(result).toEqual({ id: "/resolved/worker" });
30
+ });
31
+ it("should return null on resolution error", async () => {
32
+ const clientResolver = vi.fn((_a, _b, _c, _d, cb) => cb(new Error("Resolution failed")));
33
+ const workerResolver = vi.fn();
34
+ const result = await resolveModuleWithEnvironment({
35
+ path: "test-path",
36
+ importerEnv: "client",
37
+ clientResolver,
38
+ workerResolver,
39
+ });
40
+ expect(result).toBeNull();
41
+ });
42
+ });
43
+ describe("classifyModule", () => {
44
+ it("should return 'client' if 'use client' directive is present", () => {
45
+ const contents = `'use client';\nconsole.log('hello');`;
46
+ const result = classifyModule({ contents, inheritedEnv: "worker" });
47
+ expect(result.moduleEnv).toBe("client");
48
+ expect(result.isClient).toBe(true);
49
+ expect(result.isServer).toBe(false);
50
+ });
51
+ it("should return 'worker' if 'use server' directive is present", () => {
52
+ const contents = `"use server";\nexport default () => {};`;
53
+ const result = classifyModule({ contents, inheritedEnv: "client" });
54
+ expect(result.moduleEnv).toBe("worker");
55
+ expect(result.isClient).toBe(false);
56
+ expect(result.isServer).toBe(true);
57
+ });
58
+ it("should prioritize 'use client' over 'use server'", () => {
59
+ const contents = `'use client';\n'use server';\nconsole.log('hello');`;
60
+ const result = classifyModule({ contents, inheritedEnv: "worker" });
61
+ expect(result.moduleEnv).toBe("client");
62
+ expect(result.isClient).toBe(true);
63
+ expect(result.isServer).toBe(false);
64
+ });
65
+ it("should return the inherited environment if no directive is present", () => {
66
+ const contents = `console.log('no directive');`;
67
+ const result = classifyModule({ contents, inheritedEnv: "worker" });
68
+ expect(result.moduleEnv).toBe("worker");
69
+ expect(result.isClient).toBe(false);
70
+ expect(result.isServer).toBe(false);
71
+ });
72
+ });
73
+ });
@@ -1,7 +1,7 @@
1
1
  import debug from "debug";
2
- import { findSsrImportCallSites } from "./findSsrSpecifiers.mjs";
3
- import { INTERMEDIATE_SSR_BRIDGE_PATH } from "../lib/constants.mjs";
4
2
  import MagicString from "magic-string";
3
+ import { INTERMEDIATE_SSR_BRIDGE_PATH } from "../lib/constants.mjs";
4
+ import { findSsrImportCallSites } from "./findSsrSpecifiers.mjs";
5
5
  const log = debug("rwsdk:vite:ssr-bridge-plugin");
6
6
  export const VIRTUAL_SSR_PREFIX = "virtual:rwsdk:ssr:";
7
7
  export const ssrBridgePlugin = ({ clientFiles, serverFiles, }) => {
@@ -34,7 +34,8 @@ export const ssrBridgePlugin = ({ clientFiles, serverFiles, }) => {
34
34
  build.onResolve({ filter: /.*$/ }, (args) => {
35
35
  process.env.VERBOSE &&
36
36
  log("Esbuild onResolve called for path=%s, args=%O", args.path, args);
37
- if (args.path === "rwsdk/__ssr_bridge") {
37
+ if (args.path === "rwsdk/__ssr_bridge" ||
38
+ args.path.startsWith(VIRTUAL_SSR_PREFIX)) {
38
39
  log("Marking as external: %s", args.path);
39
40
  return {
40
41
  path: args.path,
@@ -77,6 +78,12 @@ export const ssrBridgePlugin = ({ clientFiles, serverFiles, }) => {
77
78
  }
78
79
  else {
79
80
  // In build mode, the behavior depends on the build pass
81
+ if (id.startsWith(VIRTUAL_SSR_PREFIX)) {
82
+ if (this.environment.name === "worker") {
83
+ log("Virtual SSR module case (build-worker pass): resolving to external");
84
+ return { id, external: true };
85
+ }
86
+ }
80
87
  if (id === "rwsdk/__ssr_bridge" && this.environment.name === "worker") {
81
88
  if (process.env.RWSDK_BUILD_PASS === "worker") {
82
89
  // First pass: resolve to a temporary, external path
@@ -1,11 +1,12 @@
1
- import MagicString from "magic-string";
2
1
  import debug from "debug";
3
- import { hasDirective } from "./hasDirective.mjs";
2
+ import MagicString from "magic-string";
4
3
  import { findExports } from "./findSpecifiers.mjs";
4
+ import { hasDirective } from "./hasDirective.mjs";
5
5
  const logVite = debug("rwsdk:vite:transform-client-components:vite");
6
6
  const logEsbuild = debug("rwsdk:vite:transform-client-components:esbuild");
7
7
  export async function transformClientComponents(code, normalizedId, ctx) {
8
- if (!hasDirective(code, "use client")) {
8
+ if (!ctx.clientFiles?.has(normalizedId) &&
9
+ !hasDirective(code, "use client")) {
9
10
  return;
10
11
  }
11
12
  const log = ctx.isEsbuild ? logEsbuild : logVite;
@@ -76,13 +77,14 @@ export async function transformClientComponents(code, normalizedId, ctx) {
76
77
  // 4. Non-SSR files: replace all implementation with registerClientReference logic
77
78
  // Generate completely new code for worker/client environments
78
79
  const s = new MagicString("");
79
- // Add import declaration
80
+ s.append('import { ssrLoadModule } from "rwsdk/__ssr_bridge";\n');
80
81
  s.append('import { registerClientReference } from "rwsdk/worker";\n');
82
+ s.append(`const SSRModule = await ssrLoadModule("${normalizedId}");\n`);
81
83
  // Compute unique computed local names first
82
84
  const computedLocalNames = new Map(processedExports.map((info) => [getComputedLocalName(info), info]));
83
85
  // Add registerClientReference assignments for unique names
84
86
  for (const [computedLocalName, correspondingInfo] of computedLocalNames) {
85
- s.append(`const ${computedLocalName} = registerClientReference("${normalizedId}", "${correspondingInfo.exported}");\n`);
87
+ s.append(`const ${computedLocalName} = registerClientReference(SSRModule, "${normalizedId}", "${correspondingInfo.exported}");\n`);
86
88
  }
87
89
  // Add grouped export statement for named exports (preserving order and alias)
88
90
  if (processedExports.length > 0) {
@@ -94,7 +96,7 @@ export async function transformClientComponents(code, normalizedId, ctx) {
94
96
  // Add default export if present
95
97
  if (defaultExportInfo) {
96
98
  log(":isEsbuild=%s: Registering client reference for default export: %s", !!ctx.isEsbuild, defaultExportInfo.exported);
97
- s.append(`export default registerClientReference("${normalizedId}", "${defaultExportInfo.exported}");\n`);
99
+ s.append(`export default registerClientReference(SSRModule, "${normalizedId}", "${defaultExportInfo.exported}");\n`);
98
100
  }
99
101
  const sourceMap = s.generateMap({
100
102
  source: normalizedId,