@rangojs/router 0.32.0 → 0.33.1

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 (181) hide show
  1. package/README.md +3 -2
  2. package/dist/bin/browser-7KIJ5HSV.js +15 -0
  3. package/dist/bin/chunk-3B7CKBRO.js +463 -0
  4. package/dist/bin/chunk-524VACCG.js +71 -0
  5. package/dist/bin/chunk-LD7UBHT4.js +196 -0
  6. package/dist/bin/chunk-TO6CRWLN.js +1429 -0
  7. package/dist/bin/chunk-TTXC2U3G.js +2477 -0
  8. package/dist/bin/client-urls-projection-DQLWPDAT.js +28 -0
  9. package/dist/bin/forward-user-plugins-URBZKJP4.js +62 -0
  10. package/dist/bin/rango.js +42 -10173
  11. package/dist/bin/runtime-EPUDEHO4.js +596 -0
  12. package/dist/bin/runtime-discovery-3HH6BP3K.js +352 -0
  13. package/dist/bin/state-ACD2MGKJ.js +16 -0
  14. package/dist/bin/temp-rsc-server-JALTIWLT.js +3190 -0
  15. package/dist/types/bin/rango.d.ts +1 -0
  16. package/dist/types/browser/action-fence.d.ts +20 -0
  17. package/dist/types/browser/cookie-name.d.ts +51 -10
  18. package/dist/types/browser/invalidate-client-cache.d.ts +8 -6
  19. package/dist/types/browser/navigation-bridge.d.ts +36 -1
  20. package/dist/types/browser/navigation-client.d.ts +19 -0
  21. package/dist/types/browser/navigation-store-handle.d.ts +37 -4
  22. package/dist/types/browser/navigation-store.d.ts +2 -2
  23. package/dist/types/browser/navigation-transaction.d.ts +0 -1
  24. package/dist/types/browser/partial-update.d.ts +13 -0
  25. package/dist/types/browser/prefetch/cache.d.ts +96 -8
  26. package/dist/types/browser/prefetch/fetch.d.ts +26 -2
  27. package/dist/types/browser/prefetch/queue.d.ts +3 -2
  28. package/dist/types/browser/rango-state.d.ts +34 -5
  29. package/dist/types/browser/react/Link.d.ts +15 -6
  30. package/dist/types/browser/types.d.ts +25 -0
  31. package/dist/types/build/generate-route-types.d.ts +1 -1
  32. package/dist/types/build/route-types/include-resolution.d.ts +9 -1
  33. package/dist/types/build/route-types/router-processing.d.ts +3 -1
  34. package/dist/types/cache/cache-key-utils.d.ts +12 -8
  35. package/dist/types/cache/cache-scope.d.ts +4 -2
  36. package/dist/types/cache/cf/cf-cache-types.d.ts +9 -5
  37. package/dist/types/cache/document-cache-policy.d.ts +9 -1
  38. package/dist/types/cache/memory-segment-store.d.ts +3 -2
  39. package/dist/types/cache/segment-codec.d.ts +2 -2
  40. package/dist/types/cache/shell-snapshot.d.ts +1 -1
  41. package/dist/types/cache/types.d.ts +12 -7
  42. package/dist/types/cache/vercel/vercel-cache-store.d.ts +2 -1
  43. package/dist/types/client-urls/types.d.ts +7 -5
  44. package/dist/types/prefetch-markers.d.ts +9 -0
  45. package/dist/types/prefetch-source-scope.d.ts +66 -0
  46. package/dist/types/route-definition/helpers-types.d.ts +8 -5
  47. package/dist/types/router/intercept-resolution.d.ts +25 -11
  48. package/dist/types/router/match-context.d.ts +1 -0
  49. package/dist/types/router/match-handlers.d.ts +1 -1
  50. package/dist/types/router/prefetch-cache-ttl.d.ts +11 -3
  51. package/dist/types/router/router-context.d.ts +1 -1
  52. package/dist/types/router/router-options.d.ts +6 -3
  53. package/dist/types/router/segment-resolution/loader-cache.d.ts +8 -0
  54. package/dist/types/router/segment-resolution/prefetch-deferral.d.ts +23 -7
  55. package/dist/types/router/segment-resolution/revalidation.d.ts +19 -0
  56. package/dist/types/router/source-reads.d.ts +53 -0
  57. package/dist/types/router/types.d.ts +1 -1
  58. package/dist/types/rsc/helpers.d.ts +5 -2
  59. package/dist/types/rsc/prefetch-render-error.d.ts +7 -2
  60. package/dist/types/rsc/request-stages.d.ts +2 -0
  61. package/dist/types/rsc/shell-serve.d.ts +6 -1
  62. package/dist/types/server/context.d.ts +23 -6
  63. package/dist/types/server/cookie-store.d.ts +15 -1
  64. package/dist/types/server/document-location-state.d.ts +5 -2
  65. package/dist/types/server/handle-store.d.ts +2 -0
  66. package/dist/types/server/request-context.d.ts +43 -7
  67. package/dist/types/testing/e2e/server.d.ts +16 -1
  68. package/dist/types/testing/render-route.d.ts +66 -2
  69. package/dist/types/testing/serve-shell-request.d.ts +6 -3
  70. package/dist/types/types/handler-context.d.ts +7 -5
  71. package/dist/types/types/loader-types.d.ts +7 -4
  72. package/dist/types/types/segments.d.ts +15 -4
  73. package/dist/types/urls/path-helper-types.d.ts +7 -5
  74. package/dist/types/vite/temp-rsc-server.d.ts +2 -2
  75. package/dist/vite/index.js +449 -189
  76. package/package.json +2 -2
  77. package/skills/app-structure/SKILL.md +81 -0
  78. package/skills/app-structure/e-commerce.md +10 -9
  79. package/skills/app-structure/large-app.md +18 -2
  80. package/skills/caching/SKILL.md +10 -5
  81. package/skills/client-urls/SKILL.md +29 -11
  82. package/skills/comparison/references/framework-comparison.md +13 -8
  83. package/skills/document-cache/SKILL.md +8 -0
  84. package/skills/hooks/navigation.md +8 -8
  85. package/skills/hooks/outlets.md +4 -0
  86. package/skills/hooks/state.md +24 -8
  87. package/skills/intercept/SKILL.md +33 -12
  88. package/skills/layout/SKILL.md +60 -0
  89. package/skills/links/SKILL.md +101 -4
  90. package/skills/loader/SKILL.md +49 -22
  91. package/skills/migrate-nextjs/SKILL.md +8 -2
  92. package/skills/migrate-react-router/data-and-actions.md +5 -0
  93. package/skills/ppr/SKILL.md +26 -5
  94. package/skills/prerender/SKILL.md +4 -1
  95. package/skills/route/SKILL.md +6 -6
  96. package/skills/router-setup/SKILL.md +2 -1
  97. package/skills/server-actions/SKILL.md +41 -8
  98. package/skills/testing/client-components.md +29 -13
  99. package/skills/testing/serve-shell-request.md +7 -7
  100. package/skills/testing/server-actions.md +8 -0
  101. package/skills/ux-architecture/SKILL.md +70 -19
  102. package/src/bin/rango.ts +39 -13
  103. package/src/browser/action-fence.ts +72 -0
  104. package/src/browser/cookie-name.ts +82 -14
  105. package/src/browser/invalidate-client-cache.ts +9 -7
  106. package/src/browser/navigation-bridge.ts +164 -32
  107. package/src/browser/navigation-client.ts +95 -20
  108. package/src/browser/navigation-store-handle.ts +67 -5
  109. package/src/browser/navigation-store.ts +86 -17
  110. package/src/browser/navigation-transaction.ts +0 -6
  111. package/src/browser/partial-update.ts +31 -12
  112. package/src/browser/prefetch/cache.ts +188 -11
  113. package/src/browser/prefetch/fetch.ts +211 -51
  114. package/src/browser/prefetch/queue.ts +3 -2
  115. package/src/browser/rango-state.ts +50 -8
  116. package/src/browser/react/Link.tsx +20 -9
  117. package/src/browser/react/use-navigation.ts +1 -1
  118. package/src/browser/rsc-router.tsx +8 -1
  119. package/src/browser/server-action-bridge.ts +16 -11
  120. package/src/browser/types.ts +25 -0
  121. package/src/build/generate-route-types.ts +1 -0
  122. package/src/build/route-types/include-resolution.ts +40 -3
  123. package/src/build/route-types/router-processing.ts +170 -25
  124. package/src/build/route-types/scan-filter.ts +1 -0
  125. package/src/cache/cache-key-utils.ts +12 -8
  126. package/src/cache/cache-runtime.ts +5 -1
  127. package/src/cache/cache-scope.ts +28 -7
  128. package/src/cache/cf/cf-cache-types.ts +9 -5
  129. package/src/cache/document-cache-policy.ts +27 -0
  130. package/src/cache/document-cache.ts +5 -0
  131. package/src/cache/memory-segment-store.ts +3 -2
  132. package/src/cache/segment-codec.ts +2 -2
  133. package/src/cache/shell-snapshot.ts +1 -1
  134. package/src/cache/types.ts +12 -7
  135. package/src/cache/vercel/vercel-cache-store.ts +2 -1
  136. package/src/client-urls/types.ts +7 -5
  137. package/src/prefetch-markers.ts +10 -0
  138. package/src/prefetch-source-scope.ts +137 -0
  139. package/src/route-definition/helpers-types.ts +8 -5
  140. package/src/router/intercept-resolution.ts +94 -50
  141. package/src/router/loader-resolution.ts +8 -6
  142. package/src/router/match-api.ts +33 -29
  143. package/src/router/match-context.ts +5 -0
  144. package/src/router/match-handlers.ts +2 -1
  145. package/src/router/match-middleware/cache-lookup.ts +21 -13
  146. package/src/router/match-result.ts +39 -87
  147. package/src/router/navigation-snapshot.ts +18 -3
  148. package/src/router/prefetch-cache-ttl.ts +15 -3
  149. package/src/router/revalidation.ts +53 -23
  150. package/src/router/router-context.ts +2 -1
  151. package/src/router/router-options.ts +6 -3
  152. package/src/router/segment-resolution/loader-cache.ts +21 -3
  153. package/src/router/segment-resolution/prefetch-deferral.ts +38 -31
  154. package/src/router/segment-resolution/revalidation.ts +40 -12
  155. package/src/router/source-reads.ts +122 -0
  156. package/src/router/types.ts +2 -1
  157. package/src/router.ts +11 -12
  158. package/src/rsc/helpers.ts +8 -3
  159. package/src/rsc/prefetch-render-error.ts +7 -2
  160. package/src/rsc/progressive-enhancement.ts +3 -2
  161. package/src/rsc/request-stages.ts +59 -0
  162. package/src/rsc/rsc-rendering.ts +49 -33
  163. package/src/rsc/server-action.ts +2 -1
  164. package/src/rsc/shell-capture.ts +4 -5
  165. package/src/rsc/shell-serve.ts +12 -1
  166. package/src/segment-system.tsx +1 -1
  167. package/src/server/context.ts +37 -6
  168. package/src/server/cookie-store.ts +22 -1
  169. package/src/server/document-location-state.ts +23 -2
  170. package/src/server/handle-store.ts +2 -0
  171. package/src/server/request-context.ts +113 -28
  172. package/src/testing/dispatch.ts +3 -0
  173. package/src/testing/e2e/fixture.ts +4 -12
  174. package/src/testing/e2e/server.ts +91 -4
  175. package/src/testing/render-route.tsx +269 -4
  176. package/src/testing/serve-shell-request.ts +6 -3
  177. package/src/types/handler-context.ts +7 -5
  178. package/src/types/loader-types.ts +7 -4
  179. package/src/types/segments.ts +15 -4
  180. package/src/urls/path-helper-types.ts +7 -5
  181. package/src/vite/temp-rsc-server.ts +2 -2
@@ -0,0 +1,3190 @@
1
+ import {
2
+ VIRTUAL_LOADER_MANIFEST_ID
3
+ } from "./chunk-524VACCG.js";
4
+ import {
5
+ CLIENT_IMPORT_RE,
6
+ CLIENT_URLS_REVALIDATE_QUERY,
7
+ HOISTED_REVALIDATE_KEY,
8
+ NS,
9
+ TYPE_KEYS,
10
+ TransitionWhenError,
11
+ analyzeScopes,
12
+ collectFreeReferences,
13
+ collectImports,
14
+ componentUseSignature,
15
+ computeProductionHash,
16
+ createCounter,
17
+ createRangoDebugger,
18
+ directivePrologueEnd,
19
+ emitImports,
20
+ findHelperCalls,
21
+ findLexicalCapture,
22
+ hasUseClientDirective,
23
+ hashClientRefs,
24
+ hoistedRevalidateId,
25
+ isFunctionLiteral,
26
+ parseLang,
27
+ propertyKeyIs,
28
+ recordClientUrlsModule,
29
+ unwrapExpression
30
+ } from "./chunk-TTXC2U3G.js";
31
+ import "./chunk-3B7CKBRO.js";
32
+ import {
33
+ codeMatchIndices,
34
+ isSkippedSourceScanDir
35
+ } from "./chunk-LD7UBHT4.js";
36
+
37
+ // src/vite/temp-rsc-server.ts
38
+ import { createServer as createViteServer } from "vite";
39
+ import { register } from "node:module";
40
+
41
+ // src/vite/plugins/version-plugin.ts
42
+ import { parseAst } from "vite";
43
+
44
+ // src/router-versions.ts
45
+ var DEFAULT_ROUTER_VERSIONS_KEY = "*";
46
+
47
+ // package.json
48
+ var package_default = {
49
+ name: "@rangojs/router",
50
+ version: "0.33.1",
51
+ description: "Django-inspired RSC router with composable URL patterns",
52
+ keywords: [
53
+ "react",
54
+ "react-server-components",
55
+ "router",
56
+ "rsc",
57
+ "vite"
58
+ ],
59
+ homepage: "https://github.com/rangojs/rango#readme",
60
+ bugs: {
61
+ url: "https://github.com/rangojs/rango/issues"
62
+ },
63
+ license: "MIT",
64
+ author: "Ivo Todorov",
65
+ repository: {
66
+ type: "git",
67
+ url: "git+https://github.com/rangojs/rango.git",
68
+ directory: "packages/rangojs-router"
69
+ },
70
+ bin: {
71
+ rango: "./dist/bin/rango.js"
72
+ },
73
+ files: [
74
+ "src",
75
+ "!src/**/__tests__",
76
+ "!src/**/__mocks__",
77
+ "!src/**/*.test.ts",
78
+ "!src/**/*.test.tsx",
79
+ "dist",
80
+ "skills",
81
+ "AGENTS.md",
82
+ "README.md",
83
+ "LICENSE"
84
+ ],
85
+ type: "module",
86
+ exports: {
87
+ ".": {
88
+ types: "./dist/types/index.rsc.d.ts",
89
+ "react-server": "./src/index.rsc.ts",
90
+ default: "./src/index.ts"
91
+ },
92
+ "./server": {
93
+ types: "./dist/types/server.d.ts",
94
+ import: "./src/server.ts"
95
+ },
96
+ "./client": {
97
+ types: "./dist/types/client.d.ts",
98
+ "react-server": "./src/client.rsc.tsx",
99
+ default: "./src/client.tsx"
100
+ },
101
+ "./browser": {
102
+ types: "./dist/types/browser/index.d.ts",
103
+ default: "./src/browser/index.ts"
104
+ },
105
+ "./ssr": {
106
+ types: "./dist/types/ssr/index.d.ts",
107
+ default: "./src/ssr/index.tsx"
108
+ },
109
+ "./rsc": {
110
+ types: "./dist/types/rsc/index.d.ts",
111
+ "react-server": "./src/rsc/index.ts",
112
+ default: "./src/rsc/index.ts"
113
+ },
114
+ "./vite": {
115
+ types: "./dist/types/vite/index.d.ts",
116
+ import: "./dist/vite/index.js"
117
+ },
118
+ "./types": {
119
+ types: "./src/vite/plugins/version.d.ts"
120
+ },
121
+ "./__internal": {
122
+ types: "./dist/types/__internal.d.ts",
123
+ default: "./src/__internal.ts"
124
+ },
125
+ "./internal/deps/browser": {
126
+ types: "./dist/types/deps/browser.d.ts",
127
+ default: "./src/deps/browser.ts"
128
+ },
129
+ "./internal/deps/ssr": {
130
+ types: "./dist/types/deps/ssr.d.ts",
131
+ default: "./src/deps/ssr.ts"
132
+ },
133
+ "./internal/deps/rsc": {
134
+ types: "./dist/types/deps/rsc.d.ts",
135
+ "react-server": "./src/deps/rsc.ts",
136
+ default: "./src/deps/rsc.ts"
137
+ },
138
+ "./internal/deps/rsc-client": {
139
+ types: "./dist/types/deps/rsc-client.d.ts",
140
+ "react-server": "./src/deps/rsc-client.ts",
141
+ default: "./src/deps/rsc-client.ts"
142
+ },
143
+ "./internal/deps/html-stream-client": {
144
+ types: "./dist/types/deps/html-stream-client.d.ts",
145
+ default: "./src/deps/html-stream-client.ts"
146
+ },
147
+ "./internal/deps/html-stream-server": {
148
+ types: "./dist/types/deps/html-stream-server.d.ts",
149
+ default: "./src/deps/html-stream-server.ts"
150
+ },
151
+ "./internal/rsc-handler": {
152
+ types: "./dist/types/rsc/handler.d.ts",
153
+ "react-server": "./src/rsc/handler.ts",
154
+ default: "./src/rsc/handler.ts"
155
+ },
156
+ "./internal/browser/dev-discovery": {
157
+ types: "./dist/types/browser/dev-discovery.d.ts",
158
+ default: "./src/browser/dev-discovery.ts"
159
+ },
160
+ "./cache": {
161
+ types: "./dist/types/cache/index.d.ts",
162
+ "react-server": "./src/cache/index.ts",
163
+ default: "./src/cache/index.ts"
164
+ },
165
+ "./cache-runtime": {
166
+ types: "./dist/types/cache/cache-runtime.d.ts",
167
+ "react-server": "./src/cache/cache-runtime.ts",
168
+ default: "./src/cache/cache-runtime.ts"
169
+ },
170
+ "./cloudflare": {
171
+ types: "./dist/types/cloudflare/index.d.ts",
172
+ "react-server": "./src/cloudflare/index.ts",
173
+ default: "./src/cloudflare/index.ts"
174
+ },
175
+ "./prerender": {
176
+ types: "./dist/types/prerender/index.d.ts",
177
+ "react-server": "./src/prerender/index.ts",
178
+ default: "./src/prerender/index.ts"
179
+ },
180
+ "./prerender/cloudflare": {
181
+ types: "./dist/types/prerender/cloudflare.d.ts",
182
+ "react-server": "./src/prerender/cloudflare.ts",
183
+ default: "./src/prerender/cloudflare.ts"
184
+ },
185
+ "./vercel": {
186
+ types: "./dist/types/vercel/index.d.ts",
187
+ "react-server": "./src/vercel/index.ts",
188
+ default: "./src/vercel/index.ts"
189
+ },
190
+ "./theme": {
191
+ types: "./dist/types/theme/index.d.ts",
192
+ default: "./src/theme/index.ts"
193
+ },
194
+ "./build": {
195
+ types: "./dist/types/build/index.d.ts",
196
+ import: "./src/build/index.ts"
197
+ },
198
+ "./build/shell-capture": {
199
+ types: "./dist/types/prerender/build-shell-capture.d.ts",
200
+ "react-server": "./src/prerender/build-shell-capture.ts",
201
+ import: "./src/prerender/build-shell-capture.ts"
202
+ },
203
+ "./host": {
204
+ types: "./dist/types/host/index.d.ts",
205
+ "react-server": "./src/host/index.ts",
206
+ default: "./src/host/index.ts"
207
+ },
208
+ "./host/testing": {
209
+ types: "./dist/types/host/testing.d.ts",
210
+ default: "./src/host/testing.ts"
211
+ },
212
+ "./testing": {
213
+ types: "./dist/types/testing/index.d.ts",
214
+ default: "./src/testing/index.ts"
215
+ },
216
+ "./testing/vitest": {
217
+ types: "./dist/types/testing/vitest.d.ts",
218
+ default: "./dist/testing/vitest.js"
219
+ },
220
+ "./testing/dom": {
221
+ types: "./dist/types/testing/dom.entry.d.ts",
222
+ default: "./src/testing/dom.entry.ts"
223
+ },
224
+ "./testing/e2e": {
225
+ types: "./dist/types/testing/e2e/index.d.ts",
226
+ default: "./src/testing/e2e/index.ts"
227
+ },
228
+ "./testing/flight": {
229
+ types: "./dist/types/testing/flight.entry.d.ts",
230
+ "react-server": "./src/testing/flight.entry.ts",
231
+ default: "./src/testing/flight.entry.ts"
232
+ },
233
+ "./testing/flight-matchers": {
234
+ types: "./dist/types/testing/flight-matchers.d.ts",
235
+ default: "./src/testing/flight-matchers.ts"
236
+ }
237
+ },
238
+ publishConfig: {
239
+ access: "public",
240
+ tag: "latest"
241
+ },
242
+ scripts: {
243
+ build: "pnpm run build:types && pnpm exec esbuild src/vite/index.ts --bundle --format=esm --outfile=dist/vite/index.js --platform=node --packages=external && mkdir -p dist/vite/plugins && cp src/vite/plugins/cloudflare-protocol-loader-hook.mjs dist/vite/plugins/cloudflare-protocol-loader-hook.mjs && pnpm exec esbuild src/testing/vitest.ts --bundle --format=esm --outfile=dist/testing/vitest.js --platform=node --packages=external && rm -rf dist/bin && pnpm exec esbuild src/bin/rango.ts --bundle --format=esm --splitting --outdir=dist/bin --platform=node --packages=external && chmod +x dist/bin/rango.js && mkdir -p dist/bin/plugins && cp src/vite/plugins/cloudflare-protocol-loader-hook.mjs dist/bin/plugins/cloudflare-protocol-loader-hook.mjs",
244
+ "build:types": "rm -rf dist/types && pnpm exec tsc -p tsconfig.types.json",
245
+ prepublishOnly: "pnpm build",
246
+ typecheck: "tsc --noEmit && tsc -p tsconfig.strict-check.json --noEmit && tsc -p tsconfig.augment-check.json --noEmit",
247
+ test: "playwright test",
248
+ "test:preload": "playwright test --config=playwright.preload.config.ts",
249
+ "test:ui": "playwright test --ui",
250
+ "test:hmr-local": "playwright test --project=dev-warmup --project=hmr-basename --project=hmr-prerender --no-deps --workers=1 && RANGO_E2E_ROUTE_HMR_ONLY=1 playwright test --project=hmr-routes --no-deps --workers=1",
251
+ "test:hmr-routes-local": "RANGO_E2E_ROUTE_HMR_ONLY=1 playwright test --project=hmr-routes --no-deps --workers=1",
252
+ "test:unit": "pnpm run build:types && vitest run",
253
+ "test:unit:watch": "vitest",
254
+ "test:unit:rsc": "vitest run --config vitest.rsc.config.ts"
255
+ },
256
+ dependencies: {
257
+ "@types/debug": "^4.1.12",
258
+ "@vitejs/plugin-rsc": "^0.5.38",
259
+ debug: "^4.4.1",
260
+ "magic-string": "^0.30.17",
261
+ picomatch: "^4.0.4",
262
+ "rsc-html-stream": "^0.0.7",
263
+ srvx: "^0.11.15",
264
+ tinyexec: "^0.3.2",
265
+ typescript: "^5.3.0 || ^6.0.0"
266
+ },
267
+ devDependencies: {
268
+ "@opentelemetry/api": "^1.9.0",
269
+ "@opentelemetry/context-async-hooks": "^2.9.0",
270
+ "@opentelemetry/sdk-trace-base": "^2.9.0",
271
+ "@playwright/test": "^1.62.0",
272
+ "@shared/e2e": "workspace:*",
273
+ "@testing-library/dom": "^10.4.1",
274
+ "@testing-library/react": "^16.3.2",
275
+ "@types/node": "^24.10.1",
276
+ "@types/react": "catalog:",
277
+ "@types/react-dom": "catalog:",
278
+ esbuild: "^0.28.1",
279
+ "happy-dom": "^20.10.1",
280
+ jiti: "^2.7.0",
281
+ react: "catalog:",
282
+ "react-dom": "catalog:",
283
+ vitest: "^4.1.11"
284
+ },
285
+ peerDependencies: {
286
+ "@cloudflare/vite-plugin": "^1.42.1",
287
+ "@opentelemetry/api": "^1.9.0",
288
+ "@playwright/test": "^1.49.1",
289
+ "@testing-library/react": ">=16",
290
+ "@vercel/functions": "^3.0.0",
291
+ react: ">=19.2.8 <20",
292
+ "react-dom": ">=19.2.8 <20",
293
+ vite: "^8.0.16",
294
+ vitest: ">=3"
295
+ },
296
+ peerDependenciesMeta: {
297
+ "@cloudflare/vite-plugin": {
298
+ optional: true
299
+ },
300
+ "@opentelemetry/api": {
301
+ optional: true
302
+ },
303
+ "@playwright/test": {
304
+ optional: true
305
+ },
306
+ "@testing-library/react": {
307
+ optional: true
308
+ },
309
+ "@vercel/functions": {
310
+ optional: true
311
+ },
312
+ vite: {
313
+ optional: true
314
+ },
315
+ vitest: {
316
+ optional: true
317
+ }
318
+ },
319
+ engines: {
320
+ node: ">=24.0.0"
321
+ }
322
+ };
323
+
324
+ // src/vite/utils/banner.ts
325
+ var rangoVersion = package_default.version;
326
+
327
+ // src/vite/plugins/virtual-entries.ts
328
+ var VIRTUAL_ENTRY_BROWSER = `
329
+ import {
330
+ createFromReadableStream,
331
+ createFromFetch,
332
+ setServerCallback,
333
+ encodeReply,
334
+ createTemporaryReferenceSet,
335
+ } from "@rangojs/router/internal/deps/browser";
336
+ import { createElement, StrictMode } from "react";
337
+ import { createRoot, hydrateRoot } from "react-dom/client";
338
+ import { rscStream } from "@rangojs/router/internal/deps/html-stream-client";
339
+ import { initBrowserApp, Rango } from "@rangojs/router/browser";
340
+
341
+ async function initializeApp() {
342
+ const deps = {
343
+ createFromFetch,
344
+ createFromReadableStream,
345
+ encodeReply,
346
+ setServerCallback,
347
+ createTemporaryReferenceSet,
348
+ };
349
+
350
+ // initBrowserApp resolves the initial payload and returns the browser app
351
+ // context, including strictMode (default true) from createRouter. StrictMode
352
+ // is the default; createRouter({ strictMode: false }) ships the opt-out in the
353
+ // payload metadata. StrictMode emits no DOM, so toggling never changes markup.
354
+ const { strictMode, initialPayload } = await initBrowserApp({ rscStream, deps });
355
+ // Set only on a document a no-JS useActionState POST rendered: React needs
356
+ // the server's form state to hydrate the hook without resetting it. A state
357
+ // Flight could not carry rejects: hydrate without it, as before.
358
+ const formState = await Promise.resolve(initialPayload.formState).catch(
359
+ () => undefined
360
+ );
361
+
362
+ if (import.meta.hot) {
363
+ const { startDevDiscoveryHandshake } = await import(
364
+ "@rangojs/router/internal/browser/dev-discovery"
365
+ );
366
+ startDevDiscoveryHandshake(
367
+ initialPayload.metadata?.devDiscoveryEpoch,
368
+ import.meta.hot
369
+ );
370
+ }
371
+
372
+ const app = createElement(Rango);
373
+ const root = strictMode === false ? app : createElement(StrictMode, null, app);
374
+ // The server render failed its shell and answered a recovery document
375
+ // (ssr/shell-error-document.tsx): nothing to hydrate, so render it, and the
376
+ // router's error boundaries run as on a client navigation.
377
+ if (document.documentElement.hasAttribute("data-rango-ssr-error")) {
378
+ createRoot(document).render(root);
379
+ } else {
380
+ hydrateRoot(document, root, formState ? { formState } : undefined);
381
+ }
382
+ }
383
+
384
+ initializeApp().catch(console.error);
385
+ `.trim();
386
+ function emitProgressiveChunkSize(value) {
387
+ if (value === Number.POSITIVE_INFINITY) {
388
+ return "Number.POSITIVE_INFINITY";
389
+ }
390
+ if (!Number.isFinite(value)) {
391
+ throw new Error(
392
+ `rango({ progressiveChunkSize }) must be a finite number or Infinity, received ${String(value)}`
393
+ );
394
+ }
395
+ return JSON.stringify(value);
396
+ }
397
+ function getVirtualEntrySSR(headScripts = "preinit", progressiveChunkSize) {
398
+ if (headScripts !== "preinit" && headScripts !== "preload") {
399
+ throw new Error(
400
+ `rango({ headScripts }) must be "preinit" or "preload", received ${JSON.stringify(headScripts)}`
401
+ );
402
+ }
403
+ const preinit = headScripts === "preinit";
404
+ const depsImportNames = preinit ? "createFromReadableStream,\n setOnClientReference,\n getClientEntryUrl," : "createFromReadableStream,";
405
+ const ssrImportNames = preinit ? "\n installClientReferencePreinit," : "";
406
+ const install = preinit ? `
407
+ // Upgrade client-reference modulepreload hints to executing module scripts in
408
+ // the document head, for every render pass (live SSR, shell capture, resume).
409
+ // See src/ssr/preinit-client-references.ts for the full rationale.
410
+ installClientReferencePreinit(setOnClientReference);
411
+ ` : "";
412
+ const bootstrapDep = preinit ? "getClientEntryUrl," : `loadBootstrapScriptContent: () =>
413
+ import.meta.viteRsc.loadBootstrapScriptContent("index"),`;
414
+ const hs = JSON.stringify(headScripts);
415
+ const pcs = progressiveChunkSize !== void 0 ? `
416
+ progressiveChunkSize: ${emitProgressiveChunkSize(progressiveChunkSize)},` : "";
417
+ return `
418
+ import {
419
+ ${depsImportNames}
420
+ } from "@rangojs/router/internal/deps/ssr";
421
+ import { renderToReadableStream, resume } from "react-dom/server.edge";
422
+ import { prerender } from "react-dom/static.edge";
423
+ import { injectRSCPayload } from "@rangojs/router/internal/deps/html-stream-server";
424
+ import {
425
+ createSSRHandler,
426
+ createShellCaptureHandler,
427
+ createShellResumeHandler,${ssrImportNames}
428
+ } from "@rangojs/router/ssr";
429
+ ${install}
430
+ export const renderHTML = createSSRHandler({
431
+ createFromReadableStream,
432
+ renderToReadableStream,
433
+ injectRSCPayload,
434
+ headScripts: ${hs},${pcs}
435
+ ${bootstrapDep}
436
+ });
437
+
438
+ export const captureShellHTML = createShellCaptureHandler({
439
+ createFromReadableStream,
440
+ renderToReadableStream,
441
+ injectRSCPayload,
442
+ prerender,
443
+ resume,
444
+ headScripts: ${hs},${pcs}
445
+ ${bootstrapDep}
446
+ });
447
+
448
+ export const resumeShellHTML = createShellResumeHandler({
449
+ createFromReadableStream,
450
+ renderToReadableStream,
451
+ injectRSCPayload,
452
+ prerender,
453
+ resume,
454
+ headScripts: ${hs},${pcs}
455
+ ${bootstrapDep}
456
+ });
457
+ `.trim();
458
+ }
459
+ var VIRTUAL_IDS = {
460
+ browser: "virtual:rsc-router/entry.browser.js",
461
+ ssr: "virtual:rsc-router/entry.ssr.js",
462
+ rsc: "virtual:rsc-router/entry.rsc.js",
463
+ version: "@rangojs/router:version"
464
+ };
465
+ function getPackageVersionExport() {
466
+ return `export const PACKAGE_VERSION = ${JSON.stringify(rangoVersion)};`;
467
+ }
468
+ function getVirtualPackageVersionContent() {
469
+ return getPackageVersionExport();
470
+ }
471
+ function getVirtualVersionContent(version) {
472
+ return [
473
+ getPackageVersionExport(),
474
+ `export const VERSION = ${JSON.stringify(version)};`,
475
+ `export const ROUTER_VERSIONS = undefined;`
476
+ ].join("\n");
477
+ }
478
+ var ROUTER_VERSIONS_PLACEHOLDER = "__RANGO_ROUTER_VERSIONS__";
479
+ function getVirtualBuildVersionContent() {
480
+ return [
481
+ getPackageVersionExport(),
482
+ `export const ROUTER_VERSIONS = ${ROUTER_VERSIONS_PLACEHOLDER};`,
483
+ `export const VERSION = ROUTER_VERSIONS[${JSON.stringify(DEFAULT_ROUTER_VERSIONS_KEY)}][1];`
484
+ ].join("\n");
485
+ }
486
+
487
+ // src/vite/plugins/version-plugin.ts
488
+ function isCodeModule(id) {
489
+ return /\.(tsx?|jsx?)($|\?)/.test(id);
490
+ }
491
+ function normalizeModuleId(id) {
492
+ return id.split("?", 1)[0];
493
+ }
494
+ function getClientModuleSignature(source) {
495
+ if (!hasUseClientDirective(source)) return void 0;
496
+ let program;
497
+ try {
498
+ program = parseAst(source, { lang: "tsx" });
499
+ } catch {
500
+ return void 0;
501
+ }
502
+ const exports = /* @__PURE__ */ new Set();
503
+ let hasDefault = false;
504
+ let hasExportAll = false;
505
+ const collectBindingNames = (pattern) => {
506
+ if (!pattern) return;
507
+ if (pattern.type === "Identifier") {
508
+ exports.add(pattern.name);
509
+ } else if (pattern.type === "ObjectPattern") {
510
+ for (const prop of pattern.properties ?? []) {
511
+ if (prop?.type === "RestElement") {
512
+ collectBindingNames(prop.argument);
513
+ } else {
514
+ collectBindingNames(prop?.value);
515
+ }
516
+ }
517
+ } else if (pattern.type === "ArrayPattern") {
518
+ for (const el of pattern.elements ?? []) {
519
+ if (el?.type === "RestElement") {
520
+ collectBindingNames(el.argument);
521
+ } else {
522
+ collectBindingNames(el);
523
+ }
524
+ }
525
+ }
526
+ };
527
+ const collectDeclarationNames = (declaration) => {
528
+ if (!declaration) return;
529
+ if (declaration.type === "VariableDeclaration") {
530
+ for (const decl of declaration.declarations ?? []) {
531
+ collectBindingNames(decl?.id);
532
+ }
533
+ return;
534
+ }
535
+ collectBindingNames(declaration.id);
536
+ };
537
+ for (const node of program.body ?? []) {
538
+ if (node?.type === "ExportDefaultDeclaration") {
539
+ hasDefault = true;
540
+ continue;
541
+ }
542
+ if (node?.type === "ExportAllDeclaration") {
543
+ hasExportAll = true;
544
+ continue;
545
+ }
546
+ if (node?.type !== "ExportNamedDeclaration") continue;
547
+ collectDeclarationNames(node.declaration);
548
+ for (const specifier of node.specifiers ?? []) {
549
+ const exportedName = specifier?.exported?.name ?? specifier?.exported?.value;
550
+ if (exportedName === "default") {
551
+ hasDefault = true;
552
+ } else if (typeof exportedName === "string") {
553
+ exports.add(exportedName);
554
+ }
555
+ }
556
+ }
557
+ return {
558
+ key: JSON.stringify({
559
+ default: hasDefault,
560
+ exportAll: hasExportAll,
561
+ exports: [...exports].sort()
562
+ })
563
+ };
564
+ }
565
+ function createVersionPlugin() {
566
+ let currentVersion = Date.now().toString(16);
567
+ let isDev = false;
568
+ let server = null;
569
+ let resolvedCacheDir;
570
+ const clientModuleSignatures = /* @__PURE__ */ new Map();
571
+ let versionCounter = 0;
572
+ const bumpVersion = (reason) => {
573
+ currentVersion = Date.now().toString(16) + String(++versionCounter);
574
+ console.log(`[rango] ${reason}, version updated: ${currentVersion}`);
575
+ const rscEnv = server?.environments?.rsc;
576
+ const versionMod = rscEnv?.moduleGraph?.getModuleById(
577
+ "\0" + VIRTUAL_IDS.version
578
+ );
579
+ if (versionMod) {
580
+ rscEnv.moduleGraph.invalidateModule(versionMod);
581
+ }
582
+ };
583
+ return {
584
+ name: "@rangojs/router:version",
585
+ enforce: "pre",
586
+ configResolved(config) {
587
+ isDev = config.command === "serve";
588
+ resolvedCacheDir = config.cacheDir ? String(config.cacheDir).replace(/\\/g, "/") : void 0;
589
+ },
590
+ configureServer(devServer) {
591
+ server = devServer;
592
+ devServer.watcher.on("unlink", (filePath) => {
593
+ if (!isDev) return;
594
+ if (!clientModuleSignatures.has(filePath)) return;
595
+ clientModuleSignatures.delete(filePath);
596
+ bumpVersion("Client module removed");
597
+ });
598
+ },
599
+ resolveId(id) {
600
+ if (id === VIRTUAL_IDS.version) {
601
+ return "\0" + id;
602
+ }
603
+ return null;
604
+ },
605
+ load(id) {
606
+ if (id === "\0" + VIRTUAL_IDS.version) {
607
+ const environment = this?.environment?.name;
608
+ if (environment === "client") {
609
+ return getVirtualPackageVersionContent();
610
+ }
611
+ return isDev ? getVirtualVersionContent(currentVersion) : getVirtualBuildVersionContent();
612
+ }
613
+ return null;
614
+ },
615
+ transform(code, id) {
616
+ if (!isDev || !isCodeModule(id)) return null;
617
+ const normalizedId = normalizeModuleId(id);
618
+ if (!code.includes("use client") && !clientModuleSignatures.has(normalizedId)) {
619
+ return null;
620
+ }
621
+ const signature = getClientModuleSignature(code);
622
+ if (signature) {
623
+ clientModuleSignatures.set(normalizedId, signature);
624
+ } else {
625
+ clientModuleSignatures.delete(normalizedId);
626
+ }
627
+ return null;
628
+ },
629
+ async hotUpdate(ctx) {
630
+ if (!isDev) return;
631
+ const isRscModule = this.environment?.name === "rsc";
632
+ if (!isRscModule) return;
633
+ if (isViteDepCachePath(ctx.file, resolvedCacheDir)) return;
634
+ if (ctx.modules.length === 1 && ctx.modules[0].id === "\0" + VIRTUAL_IDS.version) {
635
+ return;
636
+ }
637
+ if (isCodeModule(ctx.file)) {
638
+ const filePath = normalizeModuleId(ctx.file);
639
+ const previousSignature = clientModuleSignatures.get(filePath);
640
+ try {
641
+ const source = await ctx.read();
642
+ const nextSignature = getClientModuleSignature(source);
643
+ if (nextSignature) {
644
+ clientModuleSignatures.set(filePath, nextSignature);
645
+ if (previousSignature && previousSignature.key === nextSignature.key) {
646
+ return;
647
+ }
648
+ } else {
649
+ clientModuleSignatures.delete(filePath);
650
+ if (!previousSignature) {
651
+ if (ctx.modules.length === 0) return;
652
+ }
653
+ }
654
+ } catch {
655
+ }
656
+ } else {
657
+ if (ctx.modules.length === 0) return;
658
+ }
659
+ bumpVersion("RSC module changed");
660
+ }
661
+ };
662
+ }
663
+ function isViteDepCachePath(filePath, cacheDir) {
664
+ if (!filePath) return false;
665
+ const normalized = filePath.replace(/\\/g, "/");
666
+ if (cacheDir) {
667
+ const normalizedCacheDir = cacheDir.replace(/\\/g, "/").replace(/\/+$/, "");
668
+ if (normalized === normalizedCacheDir || normalized.startsWith(normalizedCacheDir + "/")) {
669
+ return true;
670
+ }
671
+ }
672
+ return /\/node_modules\/\.vite[^/]*\//.test(normalized) || normalized.includes("/.vite-isolated/");
673
+ }
674
+
675
+ // src/vite/plugins/virtual-stub-plugin.ts
676
+ function createVirtualStubPlugin() {
677
+ const STUB_PREFIXES = [
678
+ "virtual:rsc-router/",
679
+ "virtual:entry-",
680
+ "virtual:vite-rsc/"
681
+ ];
682
+ return {
683
+ name: "@rangojs/router:virtual-stubs",
684
+ resolveId(id) {
685
+ if (STUB_PREFIXES.some((p) => id.startsWith(p))) {
686
+ return "\0stub:" + id;
687
+ }
688
+ return null;
689
+ },
690
+ load(id) {
691
+ if (id.startsWith("\0stub:")) {
692
+ return "export default {}";
693
+ }
694
+ return null;
695
+ }
696
+ };
697
+ }
698
+
699
+ // src/vite/plugins/cloudflare-protocol-stub.ts
700
+ var VIRTUAL_PREFIX = "virtual:rango-cloudflare-stub-";
701
+ var NULL_PREFIX = "\0" + VIRTUAL_PREFIX;
702
+ var CF_PREFIX = "cloudflare:";
703
+ var BUILD_ENV_GLOBAL_KEY = "__rango_build_env__";
704
+ var SOURCE_EXT_RE = /\.[mc]?[jt]sx?$/;
705
+ var IMPORT_NODE_TYPES = /* @__PURE__ */ new Set([
706
+ "ImportDeclaration",
707
+ "ImportExpression",
708
+ "ExportNamedDeclaration",
709
+ "ExportAllDeclaration"
710
+ ]);
711
+ var STUBS = {
712
+ "cloudflare:workers": `
713
+ export class DurableObject { constructor(_ctx, _env) {} }
714
+ export class WorkerEntrypoint { constructor(_ctx, _env) {} }
715
+ export class WorkflowEntrypoint { constructor(_ctx, _env) {} }
716
+ export class RpcTarget {}
717
+ export const env = globalThis[${JSON.stringify(BUILD_ENV_GLOBAL_KEY)}] ?? {};
718
+ export default {};
719
+ `,
720
+ "cloudflare:email": `
721
+ export class EmailMessage { constructor(_from, _to, _raw) {} }
722
+ export default {};
723
+ `,
724
+ "cloudflare:sockets": `
725
+ export function connect() { return {}; }
726
+ export default {};
727
+ `,
728
+ "cloudflare:workflows": `
729
+ export class NonRetryableError extends Error {
730
+ constructor(message, name) { super(message); this.name = name ?? "NonRetryableError"; }
731
+ }
732
+ export default {};
733
+ `
734
+ };
735
+ var FALLBACK_STUB = `export default {};
736
+ `;
737
+ function createCloudflareProtocolStubPlugin() {
738
+ return {
739
+ name: "@rangojs/router:cloudflare-protocol-stub",
740
+ transform(code, id) {
741
+ const cleanId = id.split("?")[0] ?? id;
742
+ if (!SOURCE_EXT_RE.test(cleanId)) return null;
743
+ if (!code.includes(CF_PREFIX)) return null;
744
+ let ast;
745
+ try {
746
+ ast = this.parse(code, { lang: "tsx" });
747
+ } catch {
748
+ return null;
749
+ }
750
+ const hits = [];
751
+ walk(ast, (node) => {
752
+ if (!IMPORT_NODE_TYPES.has(node.type)) return;
753
+ const source = node.source;
754
+ if (!source || source.type !== "Literal") return;
755
+ if (typeof source.value !== "string") return;
756
+ if (!source.value.startsWith(CF_PREFIX)) return;
757
+ if (typeof source.start !== "number" || typeof source.end !== "number")
758
+ return;
759
+ hits.push({
760
+ start: source.start,
761
+ end: source.end,
762
+ value: source.value
763
+ });
764
+ });
765
+ if (hits.length === 0) return null;
766
+ hits.sort((a, b) => b.start - a.start);
767
+ let out = code;
768
+ for (const hit of hits) {
769
+ const submodule = hit.value.slice(CF_PREFIX.length);
770
+ const quote = code[hit.start] === "'" ? "'" : '"';
771
+ out = out.slice(0, hit.start) + quote + VIRTUAL_PREFIX + submodule + quote + out.slice(hit.end);
772
+ }
773
+ return { code: out, map: null };
774
+ },
775
+ resolveId(id) {
776
+ if (id.startsWith(VIRTUAL_PREFIX)) {
777
+ return "\0" + id;
778
+ }
779
+ return null;
780
+ },
781
+ load(id) {
782
+ if (!id.startsWith(NULL_PREFIX)) return null;
783
+ const submodule = id.slice(NULL_PREFIX.length);
784
+ const specifier = CF_PREFIX + submodule;
785
+ return STUBS[specifier] ?? FALLBACK_STUB;
786
+ }
787
+ };
788
+ }
789
+ function walk(node, visit) {
790
+ if (!node || typeof node !== "object") return;
791
+ if (Array.isArray(node)) {
792
+ for (const child of node) walk(child, visit);
793
+ return;
794
+ }
795
+ const n = node;
796
+ if (typeof n.type !== "string") return;
797
+ visit(n);
798
+ for (const key in n) {
799
+ if (key === "loc" || key === "start" || key === "end" || key === "range") {
800
+ continue;
801
+ }
802
+ walk(n[key], visit);
803
+ }
804
+ }
805
+
806
+ // src/vite/plugins/expose-internal-ids.ts
807
+ import { parseAst as parseAst3 } from "vite";
808
+ import MagicString2 from "magic-string";
809
+ import path3 from "node:path";
810
+
811
+ // src/vite/plugins/expose-id-utils.ts
812
+ import path from "node:path";
813
+ import crypto from "node:crypto";
814
+
815
+ // src/regex-escape.ts
816
+ function escapeRegExp(input) {
817
+ return input.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
818
+ }
819
+
820
+ // src/vite/plugins/expose-id-utils.ts
821
+ function normalizePath(p) {
822
+ return p.split(path.sep).join("/");
823
+ }
824
+ function hashId(filePath, exportName) {
825
+ const input = `${filePath}#${exportName}`;
826
+ const hash = crypto.createHash("sha256").update(input).digest("hex");
827
+ return `${hash.slice(0, 8)}#${exportName}`;
828
+ }
829
+ function makeStubId(filePath, exportName, isBuild) {
830
+ return isBuild ? hashId(filePath, exportName) : `${filePath}#${exportName}`;
831
+ }
832
+ function hashInlineId(filePath, fnName, index) {
833
+ const input = `${filePath}:${fnName}:${index}`;
834
+ return crypto.createHash("sha256").update(input).digest("hex").slice(0, 8);
835
+ }
836
+ function buildExportMap(program) {
837
+ const exportMap = /* @__PURE__ */ new Map();
838
+ const pushExport = (local, exported) => {
839
+ const list = exportMap.get(local);
840
+ if (list) {
841
+ if (!list.includes(exported)) list.push(exported);
842
+ return;
843
+ }
844
+ exportMap.set(local, [exported]);
845
+ };
846
+ for (const node of program.body ?? []) {
847
+ if (node?.type !== "ExportNamedDeclaration") continue;
848
+ if (node.declaration?.type === "VariableDeclaration") {
849
+ for (const decl of node.declaration.declarations ?? []) {
850
+ if (decl?.id?.type === "Identifier") {
851
+ pushExport(decl.id.name, decl.id.name);
852
+ }
853
+ }
854
+ }
855
+ if (!node.source && Array.isArray(node.specifiers)) {
856
+ for (const spec of node.specifiers) {
857
+ if (spec?.type === "ExportSpecifier" && spec.local?.type === "Identifier" && spec.exported?.type === "Identifier") {
858
+ pushExport(spec.local.name, spec.exported.name);
859
+ }
860
+ }
861
+ }
862
+ }
863
+ return exportMap;
864
+ }
865
+ function detectImports(code) {
866
+ const importPattern = /import\s*\{([^}]*)\}\s*from\s*["']@rangojs\/router(?:\/[^"']*)?["']/g;
867
+ const result = {
868
+ loader: false,
869
+ handle: false,
870
+ locationState: false,
871
+ prerenderHandler: false,
872
+ staticHandler: false,
873
+ router: false,
874
+ any: false
875
+ };
876
+ let match;
877
+ while ((match = importPattern.exec(code)) !== null) {
878
+ const imports = match[1];
879
+ if (/\bcreateLoader\b/.test(imports)) result.loader = true;
880
+ if (/\bcreateHandle\b/.test(imports)) result.handle = true;
881
+ if (/\bcreateLocationState\b/.test(imports)) result.locationState = true;
882
+ if (/\bPrerender\b/.test(imports)) result.prerenderHandler = true;
883
+ if (/\bStatic\b/.test(imports)) result.staticHandler = true;
884
+ if (/\bcreateRouter\b/.test(imports)) result.router = true;
885
+ }
886
+ if (result.router) {
887
+ result.router = /import\s*\{[^}]*\bcreateRouter\b[^}]*\}\s*from\s*["']@rangojs\/router["']/.test(
888
+ code
889
+ );
890
+ }
891
+ result.any = result.loader || result.handle || result.locationState || result.prerenderHandler || result.staticHandler || result.router;
892
+ return result;
893
+ }
894
+ function skipStringOrComment(code, pos) {
895
+ const ch = code[pos];
896
+ if (ch === '"' || ch === "'") {
897
+ for (let j = pos + 1; j < code.length; j++) {
898
+ if (code[j] === "\\") {
899
+ j++;
900
+ continue;
901
+ }
902
+ if (code[j] === ch) return j + 1;
903
+ }
904
+ return code.length;
905
+ }
906
+ if (ch === "`") {
907
+ let j = pos + 1;
908
+ while (j < code.length) {
909
+ if (code[j] === "\\") {
910
+ j += 2;
911
+ continue;
912
+ }
913
+ if (code[j] === "`") return j + 1;
914
+ if (code[j] === "$" && j + 1 < code.length && code[j + 1] === "{") {
915
+ j += 2;
916
+ let braceDepth = 1;
917
+ while (j < code.length && braceDepth > 0) {
918
+ const inner = skipStringOrComment(code, j);
919
+ if (inner > j) {
920
+ j = inner;
921
+ continue;
922
+ }
923
+ if (code[j] === "{") braceDepth++;
924
+ else if (code[j] === "}") braceDepth--;
925
+ if (braceDepth > 0) j++;
926
+ }
927
+ if (braceDepth === 0) j++;
928
+ continue;
929
+ }
930
+ j++;
931
+ }
932
+ return j;
933
+ }
934
+ if (ch === "/" && pos + 1 < code.length) {
935
+ if (code[pos + 1] === "/") {
936
+ const eol = code.indexOf("\n", pos + 2);
937
+ return eol === -1 ? code.length : eol + 1;
938
+ }
939
+ if (code[pos + 1] === "*") {
940
+ const end = code.indexOf("*/", pos + 2);
941
+ return end === -1 ? code.length : end + 2;
942
+ }
943
+ }
944
+ return pos;
945
+ }
946
+ function findMatchingParen(code, startPos) {
947
+ let depth = 1;
948
+ let i = startPos;
949
+ while (i < code.length && depth > 0) {
950
+ const skipped = skipStringOrComment(code, i);
951
+ if (skipped > i) {
952
+ i = skipped;
953
+ continue;
954
+ }
955
+ if (code[i] === "(") depth++;
956
+ if (code[i] === ")") depth--;
957
+ i++;
958
+ }
959
+ return i;
960
+ }
961
+ function countArgs(code, startPos, endPos) {
962
+ let depth = 0;
963
+ let argCount = 0;
964
+ let hasContent = false;
965
+ let i = startPos;
966
+ while (i < endPos) {
967
+ const skipped = skipStringOrComment(code, i);
968
+ if (skipped > i) {
969
+ const ch = code[i];
970
+ const isComment = ch === "/" && i + 1 < code.length && (code[i + 1] === "/" || code[i + 1] === "*");
971
+ if (!isComment) hasContent = true;
972
+ i = skipped;
973
+ continue;
974
+ }
975
+ const char = code[i];
976
+ if (char === "(" || char === "[" || char === "{") {
977
+ depth++;
978
+ hasContent = true;
979
+ } else if (char === ")" || char === "]" || char === "}") {
980
+ depth--;
981
+ } else if (char === "," && depth === 0) {
982
+ argCount++;
983
+ } else if (!/\s/.test(char)) {
984
+ hasContent = true;
985
+ }
986
+ i++;
987
+ }
988
+ return hasContent ? argCount + 1 : 0;
989
+ }
990
+ function findStatementEnd(code, pos) {
991
+ let i = pos;
992
+ while (i < code.length && /\s/.test(code[i])) {
993
+ i++;
994
+ }
995
+ if (i < code.length && code[i] === ";") {
996
+ i++;
997
+ }
998
+ return i;
999
+ }
1000
+ function findCallParenAfterGenerics(code, afterCalleeIndex) {
1001
+ let i = afterCalleeIndex;
1002
+ while (i < code.length) {
1003
+ const skipped = skipStringOrComment(code, i);
1004
+ if (skipped > i) {
1005
+ i = skipped;
1006
+ continue;
1007
+ }
1008
+ if (/\s/.test(code[i])) {
1009
+ i++;
1010
+ continue;
1011
+ }
1012
+ break;
1013
+ }
1014
+ if (i >= code.length) return -1;
1015
+ if (code[i] === "(") return i;
1016
+ if (code[i] === "<") {
1017
+ let depth = 0;
1018
+ while (i < code.length) {
1019
+ const skipped = skipStringOrComment(code, i);
1020
+ if (skipped > i) {
1021
+ i = skipped;
1022
+ continue;
1023
+ }
1024
+ const ch = code[i];
1025
+ if (ch === "<") {
1026
+ depth++;
1027
+ } else if (ch === ">") {
1028
+ depth--;
1029
+ if (depth === 0) {
1030
+ i++;
1031
+ break;
1032
+ }
1033
+ }
1034
+ i++;
1035
+ }
1036
+ if (depth !== 0) return -1;
1037
+ while (i < code.length) {
1038
+ const skipped = skipStringOrComment(code, i);
1039
+ if (skipped > i) {
1040
+ i = skipped;
1041
+ continue;
1042
+ }
1043
+ if (/\s/.test(code[i])) {
1044
+ i++;
1045
+ continue;
1046
+ }
1047
+ break;
1048
+ }
1049
+ if (i < code.length && code[i] === "(") return i;
1050
+ return -1;
1051
+ }
1052
+ return -1;
1053
+ }
1054
+
1055
+ // src/vite/utils/ast-handler-extract.ts
1056
+ function isDirectivePrologueStatement(node) {
1057
+ return node?.type === "ExpressionStatement" && typeof node.directive === "string";
1058
+ }
1059
+ function findImportInsertionPos(code, parseAst6) {
1060
+ let program;
1061
+ try {
1062
+ program = parseAst6(code, { lang: "tsx" });
1063
+ } catch {
1064
+ return 0;
1065
+ }
1066
+ const body = program.body;
1067
+ let i = 0;
1068
+ let insertionPos = 0;
1069
+ while (i < body.length && isDirectivePrologueStatement(body[i])) {
1070
+ insertionPos = body[i].end;
1071
+ i++;
1072
+ }
1073
+ while (i < body.length && body[i]?.type === "ImportDeclaration") {
1074
+ insertionPos = body[i].end;
1075
+ i++;
1076
+ }
1077
+ return insertionPos;
1078
+ }
1079
+ function walkNode(node, parent, ancestors, enter) {
1080
+ if (!node || typeof node !== "object") return;
1081
+ if (typeof node.type !== "string") return;
1082
+ ancestors.push(node);
1083
+ enter(node, parent, ancestors);
1084
+ for (const key of Object.keys(node)) {
1085
+ if (key === "type" || key === "start" || key === "end") continue;
1086
+ const child = node[key];
1087
+ if (Array.isArray(child)) {
1088
+ for (const item of child) {
1089
+ if (item && typeof item === "object" && typeof item.type === "string") {
1090
+ walkNode(item, node, ancestors, enter);
1091
+ }
1092
+ }
1093
+ } else if (child && typeof child === "object" && typeof child.type === "string") {
1094
+ walkNode(child, node, ancestors, enter);
1095
+ }
1096
+ }
1097
+ ancestors.pop();
1098
+ }
1099
+ function findHandlerCalls(code, fnName, parseAst6) {
1100
+ let program;
1101
+ try {
1102
+ program = parseAst6(code, { lang: "tsx" });
1103
+ } catch {
1104
+ return [];
1105
+ }
1106
+ const sites = [];
1107
+ const localNames = getImportedLocalNamesFromProgram(program, fnName);
1108
+ const exportedNamesByLocal = buildExportMap(program);
1109
+ walkNode(program, null, [], (node, parent, ancestors) => {
1110
+ if (node.type !== "CallExpression" || node.callee?.type !== "Identifier" || !localNames.has(node.callee.name)) {
1111
+ return;
1112
+ }
1113
+ const callStart = node.start;
1114
+ const callEnd = node.end;
1115
+ const argCount = node.arguments?.length ?? 0;
1116
+ const calleeName = node.callee.name;
1117
+ let lineNumber = 1;
1118
+ for (let i = 0; i < callStart && i < code.length; i++) {
1119
+ if (code[i] === "\n") lineNumber++;
1120
+ }
1121
+ let exportInfo = null;
1122
+ if (parent?.type === "VariableDeclarator" && parent.init === node) {
1123
+ const grandParent = ancestors.length >= 3 ? ancestors[ancestors.length - 3] : null;
1124
+ const greatGrandParent = ancestors.length >= 4 ? ancestors[ancestors.length - 4] : null;
1125
+ if (grandParent?.type === "VariableDeclaration" && greatGrandParent?.type === "ExportNamedDeclaration") {
1126
+ const exportName = parent.id?.name;
1127
+ if (exportName) {
1128
+ exportInfo = {
1129
+ exportName,
1130
+ statementEnd: greatGrandParent.end
1131
+ };
1132
+ }
1133
+ } else if (grandParent?.type === "VariableDeclaration" && parent.id?.type === "Identifier") {
1134
+ const exportedNames = exportedNamesByLocal.get(parent.id.name);
1135
+ if (exportedNames && exportedNames.length > 0) {
1136
+ exportInfo = {
1137
+ exportName: exportedNames[0],
1138
+ statementEnd: grandParent.end
1139
+ };
1140
+ }
1141
+ }
1142
+ }
1143
+ sites.push({
1144
+ callStart,
1145
+ callEnd,
1146
+ argCount,
1147
+ lineNumber,
1148
+ calleeName,
1149
+ exportInfo
1150
+ });
1151
+ });
1152
+ return sites;
1153
+ }
1154
+ function getImportedLocalNamesFromProgram(program, importedName) {
1155
+ const localNames = /* @__PURE__ */ new Set();
1156
+ const body = program.body;
1157
+ for (const node of body) {
1158
+ if (node?.type !== "ImportDeclaration") continue;
1159
+ const source = node.source?.value;
1160
+ if (typeof source !== "string") continue;
1161
+ if (!source.startsWith("@rangojs/router")) continue;
1162
+ const specifiers = Array.isArray(node.specifiers) ? node.specifiers : [];
1163
+ for (const spec of specifiers) {
1164
+ if (spec?.type !== "ImportSpecifier") continue;
1165
+ if (spec.imported?.type !== "Identifier") continue;
1166
+ if (spec.imported.name !== importedName) continue;
1167
+ if (spec.local?.type === "Identifier") {
1168
+ localNames.add(spec.local.name);
1169
+ }
1170
+ }
1171
+ }
1172
+ return localNames;
1173
+ }
1174
+ function getImportedLocalNames(code, importedName, parseAst6) {
1175
+ try {
1176
+ const program = parseAst6(code, { lang: "tsx" });
1177
+ return getImportedLocalNamesFromProgram(program, importedName);
1178
+ } catch {
1179
+ return /* @__PURE__ */ new Set();
1180
+ }
1181
+ }
1182
+ function extractImportDeclarations(code, parseAst6) {
1183
+ let program;
1184
+ try {
1185
+ program = parseAst6(code, { lang: "tsx" });
1186
+ } catch {
1187
+ return [];
1188
+ }
1189
+ const imports = [];
1190
+ for (const node of program.body) {
1191
+ if (node.type === "ImportDeclaration") {
1192
+ imports.push(code.slice(node.start, node.end));
1193
+ }
1194
+ }
1195
+ return imports;
1196
+ }
1197
+ function isInertExpression(node) {
1198
+ if (!node) return false;
1199
+ switch (node.type) {
1200
+ case "Literal":
1201
+ return true;
1202
+ case "TemplateLiteral":
1203
+ return (node.expressions ?? []).every((e) => isInertExpression(e));
1204
+ case "ArrayExpression":
1205
+ return (node.elements ?? []).every(
1206
+ (e) => e === null || isInertExpression(e)
1207
+ );
1208
+ case "ObjectExpression":
1209
+ return (node.properties ?? []).every((p) => {
1210
+ if (p.type === "SpreadElement" || p.type === "RestElement") {
1211
+ return isInertExpression(p.argument);
1212
+ }
1213
+ return p.type === "Property" && (!p.computed || isInertExpression(p.key)) && isInertExpression(p.value);
1214
+ });
1215
+ case "UnaryExpression":
1216
+ return isInertExpression(node.argument);
1217
+ case "BinaryExpression":
1218
+ return isInertExpression(node.left) && isInertExpression(node.right);
1219
+ case "LogicalExpression":
1220
+ return isInertExpression(node.left) && isInertExpression(node.right);
1221
+ case "ConditionalExpression":
1222
+ return isInertExpression(node.test) && isInertExpression(node.consequent) && isInertExpression(node.alternate);
1223
+ case "SpreadElement":
1224
+ return isInertExpression(node.argument);
1225
+ default:
1226
+ return false;
1227
+ }
1228
+ }
1229
+ function isSafeDeclaratorInit(init) {
1230
+ if (!init) return true;
1231
+ if (init.type === "ArrowFunctionExpression" || init.type === "FunctionExpression") {
1232
+ return true;
1233
+ }
1234
+ return isInertExpression(init);
1235
+ }
1236
+ function isSafeVariableDeclaration(node, handlerNames) {
1237
+ if (node.type !== "VariableDeclaration") return false;
1238
+ return node.declarations.every(
1239
+ (d) => isSafeDeclaratorInit(d.init) && !(d.init?.type === "CallExpression" && d.init.callee?.type === "Identifier" && handlerNames.has(d.init.callee.name))
1240
+ );
1241
+ }
1242
+ function extractModuleLevelDeclarations(code, parseAst6, handlerNames) {
1243
+ let program;
1244
+ try {
1245
+ program = parseAst6(code, { lang: "tsx" });
1246
+ } catch {
1247
+ return [];
1248
+ }
1249
+ const declarations = [];
1250
+ for (const node of program.body) {
1251
+ if (node.type === "ImportDeclaration") continue;
1252
+ if (node.type === "VariableDeclaration") {
1253
+ if (isSafeVariableDeclaration(node, handlerNames)) {
1254
+ declarations.push(code.slice(node.start, node.end));
1255
+ }
1256
+ continue;
1257
+ }
1258
+ if (node.type === "FunctionDeclaration") {
1259
+ declarations.push(code.slice(node.start, node.end));
1260
+ continue;
1261
+ }
1262
+ if (node.type === "ExportNamedDeclaration" && node.declaration) {
1263
+ const decl = node.declaration;
1264
+ if (decl.type === "VariableDeclaration") {
1265
+ if (isSafeVariableDeclaration(decl, handlerNames)) {
1266
+ declarations.push(code.slice(decl.start, decl.end));
1267
+ }
1268
+ } else if (decl.type === "FunctionDeclaration") {
1269
+ declarations.push(code.slice(decl.start, decl.end));
1270
+ }
1271
+ continue;
1272
+ }
1273
+ }
1274
+ return declarations;
1275
+ }
1276
+ function transformInlineHandlers(fnName, virtualPrefix, s, code, filePath, virtualRegistry, moduleId, parseAst6) {
1277
+ const sites = findHandlerCalls(code, fnName, parseAst6);
1278
+ const inlineSites = sites.filter((site) => site.exportInfo === null);
1279
+ if (inlineSites.length === 0) return false;
1280
+ const imports = extractImportDeclarations(code, parseAst6);
1281
+ const staticNames = getImportedLocalNames(code, "Static", parseAst6);
1282
+ const prerenderNames = getImportedLocalNames(code, "Prerender", parseAst6);
1283
+ const handlerNames = /* @__PURE__ */ new Set([...staticNames, ...prerenderNames]);
1284
+ const declarations = extractModuleLevelDeclarations(
1285
+ code,
1286
+ parseAst6,
1287
+ handlerNames
1288
+ );
1289
+ const importStatements = [];
1290
+ for (const [siteIndex, site] of inlineSites.entries()) {
1291
+ const hash = hashInlineId(filePath, fnName, siteIndex);
1292
+ const exportName = `__sh_${hash}`;
1293
+ const idSuffix = `${filePath}:${fnName}:${siteIndex}`;
1294
+ const virtualId = `\0${virtualPrefix}${idSuffix}`;
1295
+ const handlerCode = code.slice(site.callStart, site.callEnd);
1296
+ virtualRegistry.set(virtualId, {
1297
+ originalModuleId: moduleId,
1298
+ imports,
1299
+ declarations,
1300
+ handlerCode,
1301
+ exportName
1302
+ });
1303
+ s.overwrite(site.callStart, site.callEnd, exportName);
1304
+ const importId = `${virtualPrefix}${idSuffix}`;
1305
+ importStatements.push(`import { ${exportName} } from "${importId}";`);
1306
+ }
1307
+ if (importStatements.length > 0) {
1308
+ const importBlock = importStatements.join("\n") + "\n";
1309
+ const insertionPos = findImportInsertionPos(code, parseAst6);
1310
+ if (insertionPos === 0) {
1311
+ s.prepend(importBlock);
1312
+ } else {
1313
+ s.appendLeft(insertionPos, "\n" + importBlock);
1314
+ }
1315
+ }
1316
+ return true;
1317
+ }
1318
+
1319
+ // src/vite/plugins/expose-ids/types.ts
1320
+ var PRERENDER_CONFIG = {
1321
+ fnName: "Prerender",
1322
+ brand: "prerenderHandler"
1323
+ };
1324
+ var STATIC_CONFIG = {
1325
+ fnName: "Static",
1326
+ brand: "staticHandler"
1327
+ };
1328
+ var STRICT_CREATE_CONFIGS = [
1329
+ { fnName: "createLoader" },
1330
+ { fnName: "createHandle" },
1331
+ { fnName: "createLocationState" }
1332
+ ];
1333
+
1334
+ // src/vite/plugins/expose-ids/export-analysis.ts
1335
+ import { parseAst as parseAst2 } from "vite";
1336
+ function isExportOnlyFile(code, bindings) {
1337
+ if (bindings.length === 0) return false;
1338
+ const knownLocals = /* @__PURE__ */ new Set();
1339
+ const knownExports = /* @__PURE__ */ new Set();
1340
+ for (const b of bindings) {
1341
+ knownLocals.add(b.localName);
1342
+ for (const e of b.exportNames) knownExports.add(e);
1343
+ }
1344
+ if (/export\s*\*/.test(code)) return false;
1345
+ const declExportPattern = /export\s+(const|let|var|function|class|default)\s+(\w+)/g;
1346
+ let match;
1347
+ while ((match = declExportPattern.exec(code)) !== null) {
1348
+ if (!knownExports.has(match[2])) return false;
1349
+ }
1350
+ const specExportPattern = /export\s*\{([^}]+)\}/g;
1351
+ while ((match = specExportPattern.exec(code)) !== null) {
1352
+ const specifiers = match[1].split(",").map((s) => s.trim()).filter(Boolean);
1353
+ for (const spec of specifiers) {
1354
+ const m = spec.match(
1355
+ /^([A-Za-z_$][\w$]*)(?:\s+as\s+([A-Za-z_$][\w$]*))?$/
1356
+ );
1357
+ if (!m) continue;
1358
+ const local = m[1];
1359
+ if (!knownLocals.has(local)) return false;
1360
+ }
1361
+ }
1362
+ return true;
1363
+ }
1364
+ function createCallPattern(fnNames) {
1365
+ return new RegExp(`\\b(?:${fnNames.map(escapeRegExp).join("|")})\\b`, "g");
1366
+ }
1367
+ function createCallStartIndices(code, fnNames) {
1368
+ return codeMatchIndices(code, createCallPattern(fnNames)).filter(
1369
+ (index) => findCallParenAfterGenerics(
1370
+ code,
1371
+ index + matchedNameLength(code, index)
1372
+ ) !== -1
1373
+ );
1374
+ }
1375
+ function matchedNameLength(code, index) {
1376
+ let i = index;
1377
+ while (i < code.length && /[A-Za-z0-9_$]/.test(code[i])) i++;
1378
+ return i - index;
1379
+ }
1380
+ function countCreateCallsForNames(code, fnNames) {
1381
+ return createCallStartIndices(code, fnNames).length;
1382
+ }
1383
+ function offsetToLineColumn(code, index) {
1384
+ let line = 1;
1385
+ let lineStart = 0;
1386
+ const end = Math.min(index, code.length);
1387
+ for (let i = 0; i < end; i++) {
1388
+ if (code[i] === "\n") {
1389
+ line++;
1390
+ lineStart = i + 1;
1391
+ }
1392
+ }
1393
+ return { line, column: index - lineStart + 1 };
1394
+ }
1395
+ function findUnsupportedCreateCallSites(code, fnNames, supportedBindings) {
1396
+ const supported = new Set(supportedBindings.map((b) => b.callExprStart));
1397
+ return createCallStartIndices(code, fnNames).filter((index) => !supported.has(index)).map((index) => offsetToLineColumn(code, index));
1398
+ }
1399
+ function getImportedFnNames(code, importedName) {
1400
+ const importPattern = /import\s*\{([^}]*)\}\s*from\s*["']@rangojs\/router(?:\/[^"']*)?["']/g;
1401
+ const localNames = /* @__PURE__ */ new Set();
1402
+ let match;
1403
+ while ((match = importPattern.exec(code)) !== null) {
1404
+ const specList = match[1].split(",").map((s) => s.trim()).filter(Boolean);
1405
+ for (const spec of specList) {
1406
+ const m = spec.match(
1407
+ /^([A-Za-z_$][\w$]*)(?:\s+as\s+([A-Za-z_$][\w$]*))?$/
1408
+ );
1409
+ if (!m) continue;
1410
+ const imported = m[1];
1411
+ const local = m[2] || imported;
1412
+ if (imported === importedName) {
1413
+ localNames.add(local);
1414
+ }
1415
+ }
1416
+ }
1417
+ const names = Array.from(localNames);
1418
+ return names.length > 0 ? names : [importedName];
1419
+ }
1420
+ function getCalledIdentifierFromCall(callExpr) {
1421
+ const callee = callExpr?.callee;
1422
+ if (callee?.type === "Identifier") return callee.name;
1423
+ if (callee?.type === "TSInstantiationExpression" && callee.expression?.type === "Identifier") {
1424
+ return callee.expression.name;
1425
+ }
1426
+ return null;
1427
+ }
1428
+ function unwrapSignatureWrappedCall(init, fnNameSet) {
1429
+ if (init?.type !== "CallExpression") return init;
1430
+ const directId = getCalledIdentifierFromCall(init);
1431
+ if (directId && fnNameSet.has(directId)) return init;
1432
+ const firstArg = init.arguments?.[0];
1433
+ if (firstArg?.type === "CallExpression") {
1434
+ const innerId = getCalledIdentifierFromCall(firstArg);
1435
+ if (innerId && fnNameSet.has(innerId)) return firstArg;
1436
+ }
1437
+ return init;
1438
+ }
1439
+ function collectCreateExportBindingsFallback(code, fnNames) {
1440
+ const alternation = fnNames.map(escapeRegExp).join("|");
1441
+ const exportConstPattern = new RegExp(
1442
+ `export\\s+const\\s+(\\w+)\\s*=\\s*(?:${alternation})\\s*(?:<[^>]*>)?\\s*\\(`,
1443
+ "g"
1444
+ );
1445
+ const localDeclPattern = new RegExp(
1446
+ `\\bconst\\s+(\\w+)\\s*=\\s*((?:${alternation})\\s*(?:<[^>]*>)?\\s*\\()`,
1447
+ "g"
1448
+ );
1449
+ const exportSpecPattern = /export\s*\{([^}]+)\}/g;
1450
+ const exportMap = /* @__PURE__ */ new Map();
1451
+ const pushExport = (local, exported) => {
1452
+ const list = exportMap.get(local);
1453
+ if (list) {
1454
+ if (!list.includes(exported)) list.push(exported);
1455
+ return;
1456
+ }
1457
+ exportMap.set(local, [exported]);
1458
+ };
1459
+ let match;
1460
+ while ((match = exportConstPattern.exec(code)) !== null) {
1461
+ pushExport(match[1], match[1]);
1462
+ }
1463
+ while ((match = exportSpecPattern.exec(code)) !== null) {
1464
+ const specifiers = match[1].split(",").map((s) => s.trim()).filter(Boolean);
1465
+ for (const specifier of specifiers) {
1466
+ const specMatch = specifier.match(
1467
+ /^([A-Za-z_$][\w$]*)(?:\s+as\s+([A-Za-z_$][\w$]*))?$/
1468
+ );
1469
+ if (!specMatch) continue;
1470
+ const local = specMatch[1];
1471
+ const exported = specMatch[2] || local;
1472
+ pushExport(local, exported);
1473
+ }
1474
+ }
1475
+ const bindings = [];
1476
+ while ((match = localDeclPattern.exec(code)) !== null) {
1477
+ const localName = match[1];
1478
+ const exportNames = exportMap.get(localName) ?? [];
1479
+ if (exportNames.length === 0) continue;
1480
+ const openParenPos = match.index + match[0].length - 1;
1481
+ const closeParenPos = findMatchingParen(code, openParenPos + 1) - 1;
1482
+ if (closeParenPos <= openParenPos) continue;
1483
+ bindings.push({
1484
+ localName,
1485
+ exportNames,
1486
+ callExprStart: match.index + match[0].length - match[2].length,
1487
+ callOpenParenPos: openParenPos,
1488
+ callCloseParenPos: closeParenPos,
1489
+ argCount: countArgs(code, openParenPos + 1, closeParenPos),
1490
+ statementEnd: findStatementEnd(code, closeParenPos + 1)
1491
+ });
1492
+ }
1493
+ return bindings;
1494
+ }
1495
+ function collectCreateExportBindings(code, fnNames, program) {
1496
+ if (!program) {
1497
+ try {
1498
+ program = parseAst2(code, { lang: "tsx" });
1499
+ } catch {
1500
+ return collectCreateExportBindingsFallback(code, fnNames);
1501
+ }
1502
+ }
1503
+ const exportMap = buildExportMap(program);
1504
+ const fnNameSet = new Set(fnNames);
1505
+ const bindings = [];
1506
+ const collectFromVarDecl = (varDecl, statementEnd) => {
1507
+ if (varDecl?.type !== "VariableDeclaration" || varDecl.kind !== "const") {
1508
+ return;
1509
+ }
1510
+ for (const decl of varDecl.declarations ?? []) {
1511
+ const callExpr = unwrapSignatureWrappedCall(decl?.init, fnNameSet);
1512
+ const calledIdentifier = getCalledIdentifierFromCall(callExpr);
1513
+ if (decl?.id?.type !== "Identifier" || callExpr?.type !== "CallExpression" || !calledIdentifier || !fnNameSet.has(calledIdentifier)) {
1514
+ continue;
1515
+ }
1516
+ const localName = decl.id.name;
1517
+ const exportNames = exportMap.get(localName) ?? [];
1518
+ if (exportNames.length === 0) continue;
1519
+ const callEnd = callExpr.end;
1520
+ const calleeEnd = callExpr.callee.end;
1521
+ let openParenPos = -1;
1522
+ for (let i = calleeEnd; i < callEnd; i++) {
1523
+ if (code[i] === "(") {
1524
+ openParenPos = i;
1525
+ break;
1526
+ }
1527
+ }
1528
+ if (openParenPos === -1) continue;
1529
+ const closeParenPos = findMatchingParen(code, openParenPos + 1) - 1;
1530
+ if (closeParenPos <= openParenPos) continue;
1531
+ bindings.push({
1532
+ localName,
1533
+ exportNames,
1534
+ callExprStart: callExpr.start,
1535
+ callOpenParenPos: openParenPos,
1536
+ callCloseParenPos: closeParenPos,
1537
+ argCount: callExpr.arguments?.length ?? 0,
1538
+ statementEnd
1539
+ });
1540
+ }
1541
+ };
1542
+ for (const node of program.body ?? []) {
1543
+ if (node?.type === "VariableDeclaration") {
1544
+ collectFromVarDecl(node, node.end);
1545
+ continue;
1546
+ }
1547
+ if (node?.type === "ExportNamedDeclaration" && node.declaration?.type === "VariableDeclaration") {
1548
+ collectFromVarDecl(node.declaration, node.end);
1549
+ }
1550
+ }
1551
+ if (bindings.length === 0) {
1552
+ return collectCreateExportBindingsFallback(code, fnNames);
1553
+ }
1554
+ return bindings;
1555
+ }
1556
+ function buildUnsupportedShapeWarning(filePath, fnName, sites = []) {
1557
+ const lines = [`[rango] Unsupported ${fnName} shape in "${filePath}".`];
1558
+ if (sites.length === 1) {
1559
+ const s = sites[0];
1560
+ lines.push(
1561
+ `The ${fnName}(...) call at ${filePath}:${s.line}:${s.column} has no stable $$id injected \u2014 it is not in a supported shape.`
1562
+ );
1563
+ } else if (sites.length > 1) {
1564
+ lines.push(
1565
+ `These ${fnName}(...) calls have no stable $$id injected \u2014 they are not in a supported shape:`
1566
+ );
1567
+ for (const s of sites) lines.push(` - ${filePath}:${s.line}:${s.column}`);
1568
+ }
1569
+ lines.push(
1570
+ `Supported shapes are:`,
1571
+ ` - export const X = ${fnName}(...)`,
1572
+ ` - const X = ${fnName}(...); export { X }`,
1573
+ ` - const X = ${fnName}(...); export { X as Y }`,
1574
+ `Potentially unsupported forms include:`,
1575
+ ` - export let/var X = ${fnName}(...)`,
1576
+ ` - inline ${fnName}(...) calls`
1577
+ );
1578
+ return lines.join("\n");
1579
+ }
1580
+
1581
+ // src/vite/plugins/expose-ids/loader-transform.ts
1582
+ import { hasDirective } from "@vitejs/plugin-rsc/transforms";
1583
+ function hasCreateLoaderImport(code) {
1584
+ return /import\s*\{[^}]*\bcreateLoader\b[^}]*\}\s*from\s*["']@rangojs\/router(?:\/server)?["']/.test(
1585
+ code
1586
+ );
1587
+ }
1588
+ function generateClientLoaderStubs(bindings, code, filePath, isBuild) {
1589
+ if (!isExportOnlyFile(code, bindings)) return null;
1590
+ const lines = [];
1591
+ for (const binding of bindings) {
1592
+ const primaryName = binding.exportNames[0];
1593
+ const loaderId = makeStubId(filePath, primaryName, isBuild);
1594
+ lines.push(
1595
+ `export const ${primaryName} = { __brand: "loader", $$id: "${loaderId}" };`
1596
+ );
1597
+ for (const alias of binding.exportNames.slice(1)) {
1598
+ lines.push(`export const ${alias} = ${primaryName};`);
1599
+ }
1600
+ }
1601
+ return { code: lines.join("\n") + "\n" };
1602
+ }
1603
+ function transformLoaders(bindings, s, filePath, isBuild) {
1604
+ let hasChanges = false;
1605
+ for (const binding of bindings) {
1606
+ const exportName = binding.exportNames[0];
1607
+ const loaderId = makeStubId(filePath, exportName, isBuild);
1608
+ const paramInjection = binding.argCount === 1 ? `, undefined, "${loaderId}"` : `, "${loaderId}"`;
1609
+ s.appendLeft(binding.callCloseParenPos, paramInjection);
1610
+ const propInjection = `
1611
+ ${binding.localName}.$$id = "${loaderId}";`;
1612
+ s.appendRight(binding.statementEnd, propInjection);
1613
+ hasChanges = true;
1614
+ }
1615
+ return hasChanges;
1616
+ }
1617
+
1618
+ // src/vite/plugins/expose-ids/handler-transform.ts
1619
+ function transformHandles(bindings, s, filePath, isBuild) {
1620
+ let hasChanges = false;
1621
+ for (const binding of bindings) {
1622
+ const exportName = binding.exportNames[0];
1623
+ const handleId = makeStubId(filePath, exportName, isBuild);
1624
+ let paramInjection;
1625
+ if (binding.argCount === 0) {
1626
+ paramInjection = `undefined, "${handleId}"`;
1627
+ } else {
1628
+ paramInjection = `, "${handleId}"`;
1629
+ }
1630
+ s.appendLeft(binding.callCloseParenPos, paramInjection);
1631
+ const propInjection = `
1632
+ ${binding.localName}.$$id = "${handleId}";`;
1633
+ s.appendRight(binding.statementEnd, propInjection);
1634
+ hasChanges = true;
1635
+ }
1636
+ return hasChanges;
1637
+ }
1638
+ function transformLocationState(bindings, s, filePath, isBuild) {
1639
+ let hasChanges = false;
1640
+ for (const binding of bindings) {
1641
+ const exportName = binding.exportNames[0];
1642
+ const stateKey = makeStubId(filePath, exportName, isBuild);
1643
+ const propInjection = `
1644
+ ${binding.localName}.__rsc_ls_key = "__rsc_ls_${stateKey}";`;
1645
+ s.appendRight(binding.statementEnd, propInjection);
1646
+ hasChanges = true;
1647
+ }
1648
+ return hasChanges;
1649
+ }
1650
+ function generateWholeFileStubs(cfg, bindings, code, filePath, isBuild) {
1651
+ if (!isExportOnlyFile(code, bindings)) return null;
1652
+ const exportNames = bindings.flatMap((b) => b.exportNames);
1653
+ const stubs = exportNames.map((name) => {
1654
+ const handlerId = makeStubId(filePath, name, isBuild);
1655
+ return `export const ${name} = { __brand: "${cfg.brand}", $$id: "${handlerId}" };`;
1656
+ });
1657
+ return { code: stubs.join("\n") + "\n", map: null };
1658
+ }
1659
+ function stubHandlerExprs(cfg, bindings, s, filePath, isBuild) {
1660
+ let hasChanges = false;
1661
+ for (const binding of bindings) {
1662
+ const exportName = binding.exportNames[0];
1663
+ const handlerId = makeStubId(filePath, exportName, isBuild);
1664
+ s.overwrite(
1665
+ binding.callExprStart,
1666
+ binding.callCloseParenPos + 1,
1667
+ `{ __brand: "${cfg.brand}", $$id: "${handlerId}" }`
1668
+ );
1669
+ hasChanges = true;
1670
+ }
1671
+ return hasChanges;
1672
+ }
1673
+ function transformHandlerIds(cfg, bindings, s, filePath, isBuild) {
1674
+ let hasChanges = false;
1675
+ for (const binding of bindings) {
1676
+ const exportName = binding.exportNames[0];
1677
+ const handlerId = makeStubId(filePath, exportName, isBuild);
1678
+ let paramInjection;
1679
+ if (binding.argCount === 0) {
1680
+ paramInjection = `undefined, "${handlerId}"`;
1681
+ } else if (binding.argCount === 1) {
1682
+ paramInjection = `, undefined, "${handlerId}"`;
1683
+ } else {
1684
+ paramInjection = `, "${handlerId}"`;
1685
+ }
1686
+ s.appendLeft(binding.callCloseParenPos, paramInjection);
1687
+ const propInjection = `
1688
+ ${binding.localName}.$$id = "${handlerId}";`;
1689
+ s.appendRight(binding.statementEnd, propInjection);
1690
+ hasChanges = true;
1691
+ }
1692
+ return hasChanges;
1693
+ }
1694
+
1695
+ // src/vite/utils/compare-strings.ts
1696
+ function compareStrings(a, b) {
1697
+ return a < b ? -1 : a > b ? 1 : 0;
1698
+ }
1699
+
1700
+ // src/vite/plugins/expose-ids/router-transform.ts
1701
+ import MagicString from "magic-string";
1702
+ import path2 from "node:path";
1703
+ import { createHash } from "node:crypto";
1704
+ var debug = createRangoDebugger(NS.transform);
1705
+ function skipLeadingTrivia(code, start, end) {
1706
+ let i = start;
1707
+ while (i < end) {
1708
+ const skipped = skipStringOrComment(code, i);
1709
+ if (skipped > i) {
1710
+ i = skipped;
1711
+ continue;
1712
+ }
1713
+ if (/\s/.test(code[i])) {
1714
+ i++;
1715
+ continue;
1716
+ }
1717
+ break;
1718
+ }
1719
+ return i;
1720
+ }
1721
+ function routerId(filePath, callIndex) {
1722
+ return createHash("sha256").update(`${filePath}#${callIndex}`).digest("hex").slice(0, 8);
1723
+ }
1724
+ function transformRouter(code, filePath, routerFnNames, absolutePath, warn) {
1725
+ const pat = createCallPattern(routerFnNames);
1726
+ let match;
1727
+ const s = new MagicString(code);
1728
+ let changed = false;
1729
+ const unsupportedSites = [];
1730
+ let callIndex = -1;
1731
+ const basename = path2.basename(filePath).replace(/\.(tsx?|jsx?)$/, "");
1732
+ const routeNamesImport = `./${basename}.named-routes.gen.js`;
1733
+ const routeNamesVar = `__rsc_rn`;
1734
+ const codeOffsets = new Set(codeMatchIndices(code, pat));
1735
+ pat.lastIndex = 0;
1736
+ while ((match = pat.exec(code)) !== null) {
1737
+ if (!codeOffsets.has(match.index)) continue;
1738
+ const callStart = match.index;
1739
+ const calleeEnd = match.index + match[0].length;
1740
+ const parenPos = findCallParenAfterGenerics(code, calleeEnd);
1741
+ if (parenPos === -1) continue;
1742
+ callIndex++;
1743
+ const closeParen = findMatchingParen(code, parenPos + 1);
1744
+ const callArgs = code.slice(parenPos + 1, closeParen);
1745
+ if (callArgs.includes(`$$routeNames: ${routeNamesVar}`)) continue;
1746
+ const sourceFilePath = absolutePath ?? filePath;
1747
+ const injected = ` $$id: "${routerId(filePath, callIndex)}", $$sourceFile: "${sourceFilePath}", $$routeNames: ${routeNamesVar},`;
1748
+ const argsContentStart = skipLeadingTrivia(code, parenPos + 1, closeParen);
1749
+ const firstArgChar = code[argsContentStart];
1750
+ if (firstArgChar === "{") {
1751
+ changed = true;
1752
+ s.appendRight(argsContentStart + 1, injected);
1753
+ } else if (argsContentStart >= closeParen - 1) {
1754
+ changed = true;
1755
+ s.appendRight(parenPos + 1, `{${injected} }`);
1756
+ } else {
1757
+ unsupportedSites.push(offsetToLineColumn(code, callStart));
1758
+ }
1759
+ }
1760
+ if (unsupportedSites.length > 0 && warn) {
1761
+ warn(
1762
+ buildUnsupportedShapeWarning(filePath, "createRouter", unsupportedSites)
1763
+ );
1764
+ }
1765
+ if (!changed) return null;
1766
+ s.prepend(
1767
+ `import { NamedRoutes as ${routeNamesVar} } from "${routeNamesImport}";
1768
+ `
1769
+ );
1770
+ return {
1771
+ code: s.toString(),
1772
+ map: s.generateMap({ hires: true })
1773
+ };
1774
+ }
1775
+ function exposeRouterId() {
1776
+ let projectRoot = "";
1777
+ let rootRelativeSourceFile = false;
1778
+ const counter = createCounter(debug, "expose-router-id");
1779
+ return {
1780
+ name: "@rangojs/router:expose-router-id",
1781
+ configResolved(config) {
1782
+ projectRoot = config.root;
1783
+ rootRelativeSourceFile = config.command === "build";
1784
+ },
1785
+ buildEnd() {
1786
+ counter?.flush();
1787
+ },
1788
+ transform(code, id) {
1789
+ if (!code.includes("createRouter")) return null;
1790
+ if (!/import\s*\{[^}]*\bcreateRouter\b[^}]*\}\s*from\s*["']@rangojs\/router(?:\/server)?["']/.test(
1791
+ code
1792
+ )) {
1793
+ return null;
1794
+ }
1795
+ if (id.includes("node_modules")) return null;
1796
+ const start = counter ? performance.now() : 0;
1797
+ try {
1798
+ const filePath = normalizePath(path2.relative(projectRoot, id));
1799
+ const routerFnNames = getImportedFnNames(code, "createRouter");
1800
+ const warn = typeof this.warn === "function" ? (message) => this.warn(message) : void 0;
1801
+ return transformRouter(
1802
+ code,
1803
+ filePath,
1804
+ routerFnNames,
1805
+ rootRelativeSourceFile ? void 0 : normalizePath(id),
1806
+ warn
1807
+ );
1808
+ } finally {
1809
+ counter?.record(id, performance.now() - start);
1810
+ }
1811
+ }
1812
+ };
1813
+ }
1814
+
1815
+ // src/vite/plugins/expose-internal-ids.ts
1816
+ var debug2 = createRangoDebugger(NS.transform);
1817
+ var VIRTUAL_LOADER_MANIFEST = VIRTUAL_LOADER_MANIFEST_ID;
1818
+ var RESOLVED_VIRTUAL_LOADER_MANIFEST = "\0" + VIRTUAL_LOADER_MANIFEST;
1819
+ var VIRTUAL_HANDLER_PREFIX = "virtual:handler-extract:";
1820
+ function exposeInternalIds(options) {
1821
+ let config;
1822
+ let isBuild = false;
1823
+ let projectRoot = "";
1824
+ const loaderRegistry = /* @__PURE__ */ new Map();
1825
+ const prerenderHandlerModules = /* @__PURE__ */ new Map();
1826
+ const staticHandlerModules = /* @__PURE__ */ new Map();
1827
+ const virtualHandlers = /* @__PURE__ */ new Map();
1828
+ const unsupportedShapeWarnings = /* @__PURE__ */ new Set();
1829
+ const counter = createCounter(debug2, "expose-internal-ids");
1830
+ function loaderManifestCode() {
1831
+ if (!isBuild) {
1832
+ return `import { setLoaderImports } from "@rangojs/router/server";
1833
+
1834
+ // Dev mode: empty map, loaders are resolved dynamically via path parsing
1835
+ setLoaderImports({});
1836
+ `;
1837
+ }
1838
+ const lazyImports = [];
1839
+ const sortedLoaders = [...loaderRegistry].sort(
1840
+ ([a], [b]) => compareStrings(a, b)
1841
+ );
1842
+ for (const [hashedId, { filePath, exportName }] of sortedLoaders) {
1843
+ lazyImports.push(
1844
+ ` "${hashedId}": () => import("/${filePath}").then(m => m.${exportName})`
1845
+ );
1846
+ }
1847
+ if (lazyImports.length === 0) {
1848
+ return `import { setLoaderImports } from "@rangojs/router/server";
1849
+
1850
+ // No fetchable loaders discovered during build
1851
+ setLoaderImports({});
1852
+ `;
1853
+ }
1854
+ return `import { setLoaderImports } from "@rangojs/router/server";
1855
+
1856
+ // Lazy import map - loaders are loaded on-demand when first requested
1857
+ setLoaderImports({
1858
+ ${lazyImports.join(",\n")}
1859
+ });
1860
+ `;
1861
+ }
1862
+ return {
1863
+ name: "@rangojs/router:expose-internal-ids",
1864
+ enforce: "post",
1865
+ buildEnd() {
1866
+ counter?.flush();
1867
+ },
1868
+ api: {
1869
+ prerenderHandlerModules,
1870
+ staticHandlerModules
1871
+ },
1872
+ configResolved(resolved2) {
1873
+ config = resolved2;
1874
+ isBuild = options?.forceBuild || config.command === "build";
1875
+ projectRoot = config.root;
1876
+ },
1877
+ // --------------- Virtual module support ---------------
1878
+ resolveId(id, importer) {
1879
+ if (id === VIRTUAL_LOADER_MANIFEST) {
1880
+ return RESOLVED_VIRTUAL_LOADER_MANIFEST;
1881
+ }
1882
+ if (id.startsWith(VIRTUAL_HANDLER_PREFIX)) {
1883
+ return "\0" + id;
1884
+ }
1885
+ if (importer?.startsWith("\0" + VIRTUAL_HANDLER_PREFIX)) {
1886
+ const entry = virtualHandlers.get(importer);
1887
+ if (entry) {
1888
+ return this.resolve(id, entry.originalModuleId, { skipSelf: true });
1889
+ }
1890
+ }
1891
+ },
1892
+ load(id) {
1893
+ if (id.startsWith("\0" + VIRTUAL_HANDLER_PREFIX)) {
1894
+ const entry = virtualHandlers.get(id);
1895
+ if (!entry) return null;
1896
+ return [
1897
+ ...entry.imports,
1898
+ ...entry.declarations,
1899
+ `export const ${entry.exportName} = ${entry.handlerCode};`
1900
+ ].join("\n") + "\n";
1901
+ }
1902
+ if (id !== RESOLVED_VIRTUAL_LOADER_MANIFEST) return;
1903
+ return { code: loaderManifestCode(), moduleSideEffects: "no-treeshake" };
1904
+ },
1905
+ // --------------- Loader pre-scan (build mode) ---------------
1906
+ async buildStart() {
1907
+ if (!isBuild) return;
1908
+ if (this.environment && this.environment.name !== "rsc") return;
1909
+ const fs = await import("node:fs/promises");
1910
+ async function scanDir(dir) {
1911
+ const results = [];
1912
+ try {
1913
+ const entries = await fs.readdir(dir, { withFileTypes: true });
1914
+ for (const entry of entries) {
1915
+ const fullPath = path3.join(dir, entry.name);
1916
+ if (entry.isDirectory()) {
1917
+ if (!isSkippedSourceScanDir(entry.name)) {
1918
+ results.push(...await scanDir(fullPath));
1919
+ }
1920
+ } else if (/\.(ts|tsx|js|jsx)$/.test(entry.name)) {
1921
+ results.push(fullPath);
1922
+ }
1923
+ }
1924
+ } catch {
1925
+ }
1926
+ return results;
1927
+ }
1928
+ try {
1929
+ const files = await scanDir(projectRoot);
1930
+ for (const filePath of files) {
1931
+ const content = await fs.readFile(filePath, "utf-8");
1932
+ if (!content.includes("createLoader")) continue;
1933
+ if (!hasCreateLoaderImport(content)) continue;
1934
+ const fnNames = getImportedFnNames(content, "createLoader");
1935
+ const relativePath = normalizePath(
1936
+ path3.relative(projectRoot, filePath)
1937
+ );
1938
+ const bindings = collectCreateExportBindings(content, fnNames);
1939
+ for (const binding of bindings) {
1940
+ const exportName = binding.exportNames[0];
1941
+ const hashedId = hashId(relativePath, exportName);
1942
+ loaderRegistry.set(hashedId, {
1943
+ filePath: relativePath,
1944
+ exportName
1945
+ });
1946
+ }
1947
+ }
1948
+ } catch (error) {
1949
+ console.warn("[exposeInternalIds] Loader pre-scan failed:", error);
1950
+ }
1951
+ },
1952
+ // --------------- Unified transform ---------------
1953
+ transform(code, id) {
1954
+ if (id.includes("/node_modules/")) return;
1955
+ const __t0 = counter ? performance.now() : 0;
1956
+ try {
1957
+ const filePath = normalizePath(path3.relative(projectRoot, id));
1958
+ const isRscEnv = this.environment?.name === "rsc";
1959
+ if (id.includes(".named-routes.gen.") && !isRscEnv && this.environment?.name === "client") {
1960
+ this.warn(
1961
+ `
1962
+ !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
1963
+ !! !!
1964
+ !! WARNING: NamedRoutes imported in a CLIENT component! !!
1965
+ !! !!
1966
+ !! File: ${filePath.padEnd(53)}!!
1967
+ !! !!
1968
+ !! NamedRoutes contains your entire route structure \u2014 every !!
1969
+ !! route name and URL pattern in your application. Shipping !!
1970
+ !! this to the browser exposes your full routing topology to !!
1971
+ !! the client, which is a security concern (internal/admin !!
1972
+ !! routes, API endpoints, hidden paths become visible). !!
1973
+ !! !!
1974
+ !! It also bloats the client bundle \u2014 this map contains all !!
1975
+ !! named routes in your application. !!
1976
+ !! !!
1977
+ !! Fix: remove the import or move it to a server component. !!
1978
+ !! !!
1979
+ !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
1980
+ `
1981
+ );
1982
+ }
1983
+ if (!code.includes("@rangojs/router")) return;
1984
+ const has = detectImports(code);
1985
+ const hasLoaderCode = has.loader && code.includes("createLoader");
1986
+ const hasHandleCode = has.handle && code.includes("createHandle");
1987
+ const hasLocationStateCode = has.locationState && code.includes("createLocationState");
1988
+ const hasPrerenderHandlerCode = has.prerenderHandler && code.includes("Prerender");
1989
+ const hasStaticHandlerCode = has.staticHandler && code.includes("Static");
1990
+ if (!hasLoaderCode && !hasHandleCode && !hasLocationStateCode && !hasPrerenderHandlerCode && !hasStaticHandlerCode) {
1991
+ return;
1992
+ }
1993
+ const _fnNamesCache = /* @__PURE__ */ new Map();
1994
+ const _bindingsCache = /* @__PURE__ */ new Map();
1995
+ let _cachedAst;
1996
+ let _astParseFailed = false;
1997
+ let _astCodeRef = code;
1998
+ const getFnNames = (canonicalName) => {
1999
+ let result = _fnNamesCache.get(canonicalName);
2000
+ if (!result) {
2001
+ result = getImportedFnNames(code, canonicalName);
2002
+ _fnNamesCache.set(canonicalName, result);
2003
+ }
2004
+ return result;
2005
+ };
2006
+ const lazyAst = () => {
2007
+ if (code !== _astCodeRef) {
2008
+ _cachedAst = void 0;
2009
+ _astParseFailed = false;
2010
+ _astCodeRef = code;
2011
+ }
2012
+ if (_cachedAst !== void 0 || _astParseFailed) return _cachedAst;
2013
+ try {
2014
+ _cachedAst = parseAst3(code, { lang: "tsx" });
2015
+ } catch {
2016
+ _astParseFailed = true;
2017
+ }
2018
+ return _cachedAst;
2019
+ };
2020
+ const getBindings = (currentCode, fnNames) => {
2021
+ const key = fnNames.join("\0");
2022
+ let result = _bindingsCache.get(key);
2023
+ if (!result) {
2024
+ result = collectCreateExportBindings(
2025
+ currentCode,
2026
+ fnNames,
2027
+ lazyAst()
2028
+ );
2029
+ _bindingsCache.set(key, result);
2030
+ }
2031
+ return result;
2032
+ };
2033
+ for (const cfg of STRICT_CREATE_CONFIGS) {
2034
+ const hasCode = cfg.fnName === "createLoader" ? hasLoaderCode : cfg.fnName === "createHandle" ? hasHandleCode : hasLocationStateCode;
2035
+ if (!hasCode) continue;
2036
+ const fnNames = getFnNames(cfg.fnName);
2037
+ const sites = findUnsupportedCreateCallSites(
2038
+ code,
2039
+ fnNames,
2040
+ getBindings(code, fnNames)
2041
+ );
2042
+ if (sites.length === 0) continue;
2043
+ const warnKey = `${id}::${cfg.fnName}`;
2044
+ if (unsupportedShapeWarnings.has(warnKey)) continue;
2045
+ unsupportedShapeWarnings.add(warnKey);
2046
+ this.warn(buildUnsupportedShapeWarning(filePath, cfg.fnName, sites));
2047
+ }
2048
+ if (hasLoaderCode && isRscEnv) {
2049
+ const fnNames = getFnNames("createLoader");
2050
+ const bindings = getBindings(code, fnNames);
2051
+ for (const binding of bindings) {
2052
+ const exportName = binding.exportNames[0];
2053
+ const hashedId = hashId(filePath, exportName);
2054
+ loaderRegistry.set(hashedId, {
2055
+ filePath,
2056
+ exportName
2057
+ });
2058
+ }
2059
+ }
2060
+ if (hasLoaderCode && !isRscEnv) {
2061
+ const fnNames = getFnNames("createLoader");
2062
+ const bindings = getBindings(code, fnNames);
2063
+ const stubResult = generateClientLoaderStubs(
2064
+ bindings,
2065
+ code,
2066
+ filePath,
2067
+ isBuild
2068
+ );
2069
+ if (stubResult) return stubResult;
2070
+ }
2071
+ if (hasPrerenderHandlerCode && !isRscEnv) {
2072
+ const fnNames = getFnNames(PRERENDER_CONFIG.fnName);
2073
+ const bindings = getBindings(code, fnNames);
2074
+ const wholeFile = generateWholeFileStubs(
2075
+ PRERENDER_CONFIG,
2076
+ bindings,
2077
+ code,
2078
+ filePath,
2079
+ isBuild
2080
+ );
2081
+ if (wholeFile) return wholeFile;
2082
+ }
2083
+ let changed = false;
2084
+ const handlerConfigs = [
2085
+ hasStaticHandlerCode && STATIC_CONFIG,
2086
+ hasPrerenderHandlerCode && PRERENDER_CONFIG
2087
+ ].filter((c) => !!c).map((cfg) => {
2088
+ const fnNames = getFnNames(cfg.fnName);
2089
+ return { cfg, fnNames };
2090
+ });
2091
+ for (const { cfg, fnNames } of handlerConfigs) {
2092
+ const totalCalls = countCreateCallsForNames(code, fnNames);
2093
+ const supportedBindings = getBindings(code, fnNames).length;
2094
+ if (totalCalls > supportedBindings) {
2095
+ const iterS = new MagicString2(code);
2096
+ const result = transformInlineHandlers(
2097
+ cfg.fnName,
2098
+ VIRTUAL_HANDLER_PREFIX,
2099
+ iterS,
2100
+ code,
2101
+ filePath,
2102
+ virtualHandlers,
2103
+ id,
2104
+ parseAst3
2105
+ );
2106
+ if (result) {
2107
+ changed = true;
2108
+ code = iterS.toString();
2109
+ _bindingsCache.clear();
2110
+ }
2111
+ }
2112
+ }
2113
+ if (hasStaticHandlerCode && !isRscEnv) {
2114
+ const fnNames = getFnNames(STATIC_CONFIG.fnName);
2115
+ const bindings = getBindings(code, fnNames);
2116
+ const wholeFile = generateWholeFileStubs(
2117
+ STATIC_CONFIG,
2118
+ bindings,
2119
+ code,
2120
+ filePath,
2121
+ isBuild
2122
+ );
2123
+ if (wholeFile) return wholeFile;
2124
+ }
2125
+ if (!isRscEnv && (hasPrerenderHandlerCode || hasStaticHandlerCode)) {
2126
+ const prerenderFnNames = hasPrerenderHandlerCode ? getFnNames(PRERENDER_CONFIG.fnName) : [];
2127
+ const staticFnNames = hasStaticHandlerCode ? getFnNames(STATIC_CONFIG.fnName) : [];
2128
+ const loaderFnNames = hasLoaderCode ? getFnNames("createLoader") : [];
2129
+ const handleFnNames = hasHandleCode ? getFnNames("createHandle") : [];
2130
+ const lsFnNames = hasLocationStateCode ? getFnNames("createLocationState") : [];
2131
+ const allBindings = [];
2132
+ for (const fnNames of [
2133
+ prerenderFnNames,
2134
+ staticFnNames,
2135
+ loaderFnNames,
2136
+ handleFnNames,
2137
+ lsFnNames
2138
+ ]) {
2139
+ if (fnNames.length > 0) {
2140
+ allBindings.push(...getBindings(code, fnNames));
2141
+ }
2142
+ }
2143
+ let canStubWholeFile = allBindings.length > 0 && isExportOnlyFile(code, allBindings);
2144
+ if (canStubWholeFile && (handleFnNames.length > 0 || lsFnNames.length > 0)) {
2145
+ const exportedLocals = new Set(allBindings.map((b) => b.localName));
2146
+ const strippedBindings = [];
2147
+ const localDeclPattern = /(?:^|;|\n)\s*(?:const|let|var|function)\s+(\w+)/g;
2148
+ let declMatch;
2149
+ while ((declMatch = localDeclPattern.exec(code)) !== null) {
2150
+ const name = declMatch[1];
2151
+ if (!exportedLocals.has(name) && !/^_c\d*$/.test(name)) {
2152
+ strippedBindings.push(name);
2153
+ }
2154
+ }
2155
+ const importPattern = /import\s*\{([^}]*)\}\s*from\s*["'](?!@rangojs\/router)[^"']*["']/g;
2156
+ let importMatch;
2157
+ while ((importMatch = importPattern.exec(code)) !== null) {
2158
+ for (const spec of importMatch[1].split(",")) {
2159
+ const m = spec.trim().match(/^[A-Za-z_$][\w$]*(?:\s+as\s+([A-Za-z_$][\w$]*))?$/);
2160
+ if (m)
2161
+ strippedBindings.push(m[1] || m[0].trim().split(/\s/)[0]);
2162
+ }
2163
+ }
2164
+ const defaultImportPattern = /import\s+([A-Za-z_$][\w$]*)\s+from\s*["'](?!@rangojs\/router)[^"']*["']/g;
2165
+ while ((importMatch = defaultImportPattern.exec(code)) !== null) {
2166
+ strippedBindings.push(importMatch[1]);
2167
+ }
2168
+ const nsImportPattern = /import\s+\*\s+as\s+([A-Za-z_$][\w$]*)\s+from\s*["'](?!@rangojs\/router)[^"']*["']/g;
2169
+ while ((importMatch = nsImportPattern.exec(code)) !== null) {
2170
+ strippedBindings.push(importMatch[1]);
2171
+ }
2172
+ if (strippedBindings.length > 0) {
2173
+ const preservedBindings = allBindings.filter((b) => {
2174
+ const fc = code.slice(b.callExprStart, b.callOpenParenPos + 1);
2175
+ return handleFnNames.some((n) => fc.includes(n)) || lsFnNames.some((n) => fc.includes(n));
2176
+ });
2177
+ const strippedRe = new RegExp(
2178
+ `\\b(?:${strippedBindings.join("|")})\\b`
2179
+ );
2180
+ canStubWholeFile = !preservedBindings.some((b) => {
2181
+ const expr = code.slice(
2182
+ b.callExprStart,
2183
+ b.callCloseParenPos + 1
2184
+ );
2185
+ return strippedRe.test(expr);
2186
+ });
2187
+ }
2188
+ }
2189
+ if (canStubWholeFile) {
2190
+ const lines = [];
2191
+ const neededImports = [];
2192
+ if (handleFnNames.length > 0) neededImports.push("createHandle");
2193
+ if (lsFnNames.length > 0) neededImports.push("createLocationState");
2194
+ if (neededImports.length > 0) {
2195
+ lines.push(
2196
+ `import { ${neededImports.join(", ")} } from "@rangojs/router";`
2197
+ );
2198
+ }
2199
+ for (const binding of allBindings) {
2200
+ const fnCall = code.slice(
2201
+ binding.callExprStart,
2202
+ binding.callOpenParenPos + 1
2203
+ );
2204
+ const isHandle = handleFnNames.some((n) => fnCall.includes(n));
2205
+ const isLocationState = lsFnNames.some((n) => fnCall.includes(n));
2206
+ const primaryName = binding.exportNames[0];
2207
+ const stubId = makeStubId(filePath, primaryName, isBuild);
2208
+ if (isHandle || isLocationState) {
2209
+ const rawArgs = code.slice(
2210
+ binding.callOpenParenPos + 1,
2211
+ binding.callCloseParenPos
2212
+ ).replace(/\b_c\d*\s*=\s*/g, "");
2213
+ const canonicalName = isHandle ? "createHandle" : "createLocationState";
2214
+ const activeFnNames = isHandle ? handleFnNames : lsFnNames;
2215
+ let rawCallee = code.slice(
2216
+ binding.callExprStart,
2217
+ binding.callOpenParenPos
2218
+ );
2219
+ for (const alias of activeFnNames) {
2220
+ if (alias !== canonicalName && rawCallee.startsWith(alias)) {
2221
+ rawCallee = canonicalName + rawCallee.slice(alias.length);
2222
+ break;
2223
+ }
2224
+ }
2225
+ if (isHandle) {
2226
+ const idParam = binding.argCount === 0 ? `undefined, "${stubId}"` : `, "${stubId}"`;
2227
+ lines.push(
2228
+ `export const ${primaryName} = ${rawCallee}(${rawArgs}${idParam});`
2229
+ );
2230
+ lines.push(`${primaryName}.$$id = "${stubId}";`);
2231
+ } else {
2232
+ lines.push(
2233
+ `export const ${primaryName} = ${rawCallee}(${rawArgs});`
2234
+ );
2235
+ lines.push(
2236
+ `${primaryName}.__rsc_ls_key = "__rsc_ls_${stubId}";`
2237
+ );
2238
+ }
2239
+ for (const name of binding.exportNames.slice(1)) {
2240
+ lines.push(`export const ${name} = ${primaryName};`);
2241
+ }
2242
+ } else {
2243
+ let brand = "loader";
2244
+ if (prerenderFnNames.some((n) => fnCall.includes(n))) {
2245
+ brand = PRERENDER_CONFIG.brand;
2246
+ } else if (staticFnNames.some((n) => fnCall.includes(n))) {
2247
+ brand = STATIC_CONFIG.brand;
2248
+ }
2249
+ lines.push(
2250
+ `export const ${primaryName} = { __brand: "${brand}", $$id: "${stubId}" };`
2251
+ );
2252
+ for (const name of binding.exportNames.slice(1)) {
2253
+ lines.push(`export const ${name} = ${primaryName};`);
2254
+ }
2255
+ }
2256
+ }
2257
+ return { code: lines.join("\n") + "\n", map: null };
2258
+ }
2259
+ }
2260
+ if (isRscEnv && isBuild) {
2261
+ const trackTypes = [
2262
+ [
2263
+ hasPrerenderHandlerCode,
2264
+ PRERENDER_CONFIG,
2265
+ prerenderHandlerModules
2266
+ ],
2267
+ [hasStaticHandlerCode, STATIC_CONFIG, staticHandlerModules]
2268
+ ];
2269
+ for (const [has2, cfg, trackMap] of trackTypes) {
2270
+ if (!has2) continue;
2271
+ const exportNames = getBindings(code, getFnNames(cfg.fnName)).map(
2272
+ (b) => b.exportNames[0]
2273
+ );
2274
+ if (exportNames.length > 0) trackMap.set(id, exportNames);
2275
+ }
2276
+ }
2277
+ const s = new MagicString2(code);
2278
+ if (hasLoaderCode) {
2279
+ const fnNames = getFnNames("createLoader");
2280
+ changed = transformLoaders(
2281
+ getBindings(code, fnNames),
2282
+ s,
2283
+ filePath,
2284
+ isBuild
2285
+ ) || changed;
2286
+ }
2287
+ if (hasHandleCode) {
2288
+ const fnNames = getFnNames("createHandle");
2289
+ changed = transformHandles(
2290
+ getBindings(code, fnNames),
2291
+ s,
2292
+ filePath,
2293
+ isBuild
2294
+ ) || changed;
2295
+ }
2296
+ if (hasLocationStateCode) {
2297
+ const fnNames = getFnNames("createLocationState");
2298
+ changed = transformLocationState(
2299
+ getBindings(code, fnNames),
2300
+ s,
2301
+ filePath,
2302
+ isBuild
2303
+ ) || changed;
2304
+ }
2305
+ const finalHandlerConfigs = [
2306
+ hasPrerenderHandlerCode && PRERENDER_CONFIG,
2307
+ hasStaticHandlerCode && STATIC_CONFIG
2308
+ ].filter((c) => !!c);
2309
+ for (const cfg of finalHandlerConfigs) {
2310
+ const bindings = getBindings(code, getFnNames(cfg.fnName));
2311
+ changed = (isRscEnv ? transformHandlerIds(cfg, bindings, s, filePath, isBuild) : stubHandlerExprs(cfg, bindings, s, filePath, isBuild)) || changed;
2312
+ }
2313
+ if (!changed) return;
2314
+ return {
2315
+ code: s.toString(),
2316
+ map: s.generateMap({ source: id, includeContent: true })
2317
+ };
2318
+ } finally {
2319
+ counter?.record(id, performance.now() - __t0);
2320
+ }
2321
+ }
2322
+ };
2323
+ }
2324
+
2325
+ // src/vite/plugins/server-reference-pattern.ts
2326
+ function registerServerReferenceRegex() {
2327
+ return /registerServerReference\(([^,]+),\s*"([^"]+)",\s*"([^"]+)"\)/g;
2328
+ }
2329
+
2330
+ // src/vite/plugins/server-ref-hashing.ts
2331
+ var debug3 = createRangoDebugger(NS.transform);
2332
+ function transformServerRefs(code, projectRoot) {
2333
+ if (!code.includes("registerServerReference")) return null;
2334
+ const hashes = /* @__PURE__ */ new Map();
2335
+ let result = code.replace(
2336
+ registerServerReferenceRegex(),
2337
+ (match, _value, refKey) => {
2338
+ const cleanKey = refKey.split("?")[0];
2339
+ const hash = computeProductionHash(projectRoot, cleanKey);
2340
+ if (hash === cleanKey) return match;
2341
+ hashes.set(refKey, hash);
2342
+ return match.replace(`"${refKey}"`, `"${hash}"`);
2343
+ }
2344
+ );
2345
+ if (hashes.size === 0) return null;
2346
+ for (const [refKey, hash] of hashes) {
2347
+ result = result.replaceAll(`"${refKey}#`, `"${hash}#`);
2348
+ }
2349
+ return result;
2350
+ }
2351
+ function hashServerRefs(projectRoot) {
2352
+ const counter = createCounter(debug3, "hash-server-refs");
2353
+ return {
2354
+ name: "@rangojs/router:hash-server-refs",
2355
+ enforce: "post",
2356
+ applyToEnvironment(env) {
2357
+ return env.name === "rsc";
2358
+ },
2359
+ buildEnd() {
2360
+ counter?.flush();
2361
+ },
2362
+ transform(code, id) {
2363
+ const start = counter ? performance.now() : 0;
2364
+ try {
2365
+ const result = transformServerRefs(code, projectRoot);
2366
+ if (result === null) return;
2367
+ return { code: result, map: null };
2368
+ } finally {
2369
+ counter?.record(id, performance.now() - start);
2370
+ }
2371
+ }
2372
+ };
2373
+ }
2374
+
2375
+ // src/vite/encryption-key.ts
2376
+ import { randomBytes } from "node:crypto";
2377
+ var AES_KEY_BYTES = /* @__PURE__ */ new Set([16, 24, 32]);
2378
+ var EXPECTED = "a base64-encoded AES key of 16, 24 or 32 bytes (openssl rand -base64 32)";
2379
+ var resolvedKey;
2380
+ function assertValidEncryptionKey(value, source) {
2381
+ if (typeof value !== "string") {
2382
+ throw new Error(
2383
+ `[rango] ${source} must be a string, received ${typeof value}. Expected ${EXPECTED}.`
2384
+ );
2385
+ }
2386
+ if (value === "") {
2387
+ throw new Error(
2388
+ `[rango] ${source} is an empty string. Unset it to generate a key per build, or set it to ${EXPECTED}.`
2389
+ );
2390
+ }
2391
+ const bytes = /^[A-Za-z0-9+/]+={0,2}$/.test(value) ? Buffer.from(value, "base64") : void 0;
2392
+ if (!bytes || bytes.toString("base64").replace(/=+$/, "") !== value.replace(/=+$/, "")) {
2393
+ throw new Error(
2394
+ `[rango] ${source} is not valid base64. Expected ${EXPECTED}.`
2395
+ );
2396
+ }
2397
+ if (!AES_KEY_BYTES.has(bytes.length)) {
2398
+ throw new Error(
2399
+ `[rango] ${source} decodes to ${bytes.length} bytes. Expected ${EXPECTED}.`
2400
+ );
2401
+ }
2402
+ }
2403
+ function configureEncryptionKey(option) {
2404
+ if (option !== void 0) {
2405
+ assertValidEncryptionKey(option, "rango({ encryptionKey })");
2406
+ resolvedKey = { key: option, stable: true };
2407
+ return;
2408
+ }
2409
+ const fromEnv = process.env.RANGO_ENCRYPTION_KEY;
2410
+ if (fromEnv !== void 0) {
2411
+ assertValidEncryptionKey(fromEnv, "RANGO_ENCRYPTION_KEY");
2412
+ resolvedKey = { key: fromEnv, stable: true };
2413
+ return;
2414
+ }
2415
+ if (resolvedKey && !resolvedKey.stable) return;
2416
+ resolvedKey = { key: randomBytes(32).toString("base64"), stable: false };
2417
+ }
2418
+ function resolved() {
2419
+ if (!resolvedKey) configureEncryptionKey(void 0);
2420
+ return resolvedKey;
2421
+ }
2422
+ function buildEncryptionKey() {
2423
+ return resolved().key;
2424
+ }
2425
+ function defineEncryptionKeyExpr() {
2426
+ return JSON.stringify(buildEncryptionKey());
2427
+ }
2428
+
2429
+ // src/vite/plugins/transition-when-hoist.ts
2430
+ import { normalizePath as normalizePath3, parseAst as parseAst4 } from "vite";
2431
+ import MagicString3 from "magic-string";
2432
+ import { builtinModules } from "node:module";
2433
+ import { hasDirective as hasDirective2 } from "@vitejs/plugin-rsc/transforms";
2434
+
2435
+ // src/vite/plugins/hoist/source.ts
2436
+ import { readFile } from "node:fs/promises";
2437
+ import { normalizePath as normalizePath2 } from "vite";
2438
+ var SOURCE_FILE_RE = /\.[cm]?[jt]sx?$/;
2439
+ async function readSource(file) {
2440
+ try {
2441
+ return await readFile(file, "utf-8");
2442
+ } catch {
2443
+ return null;
2444
+ }
2445
+ }
2446
+ async function resolveSourceTarget(ctx, source, importer, options) {
2447
+ const resolved2 = await ctx.resolve(source, importer);
2448
+ if (!resolved2 || resolved2.external) return null;
2449
+ const target = resolved2.id.split("?", 1)[0];
2450
+ if (target.startsWith("\0")) return null;
2451
+ if (options.skipNodeModules && target.includes("/node_modules/")) {
2452
+ return null;
2453
+ }
2454
+ return target;
2455
+ }
2456
+ async function recordEmitted(emitted, file, value) {
2457
+ emitted.set(file, { disk: await readSource(file), value });
2458
+ }
2459
+ async function loadEmittedOrDisk(emitted, hoistedFile, disk, rehoist) {
2460
+ const entry = emitted.get(normalizePath2(hoistedFile));
2461
+ if (entry && (disk === null || entry.disk === disk)) return entry.value;
2462
+ return disk === null ? void 0 : rehoist(disk);
2463
+ }
2464
+
2465
+ // src/vite/plugins/transition-when-hoist.ts
2466
+ var TRANSITION_WHEN_QUERY = "rango-when";
2467
+ var EXPORT_NAME = "__rango_when";
2468
+ var LOCAL_PREFIX = "__rango_when_";
2469
+ var ROUTER_SOURCES = /* @__PURE__ */ new Set(["@rangojs/router"]);
2470
+ function findWhenSites(program, scopeOf, moduleScope, imports) {
2471
+ const sites = [];
2472
+ for (const { call, scope } of findHelperCalls(
2473
+ program,
2474
+ scopeOf,
2475
+ moduleScope,
2476
+ imports,
2477
+ {
2478
+ sources: ROUTER_SOURCES,
2479
+ builder: "urls",
2480
+ helper: "transition",
2481
+ directImport: true
2482
+ }
2483
+ )) {
2484
+ if (call.arguments[0]?.type !== "ObjectExpression") continue;
2485
+ for (const prop of call.arguments[0].properties) {
2486
+ if (propertyKeyIs(prop, "when")) {
2487
+ sites.push({ prop, value: unwrapExpression(prop.value), scope });
2488
+ }
2489
+ }
2490
+ }
2491
+ return sites;
2492
+ }
2493
+ var WHEN_CAPTURE_MESSAGES = {
2494
+ lexical: {
2495
+ this: "`this` in an arrow is the enclosing server function's `this`.",
2496
+ arguments: "`arguments` in an arrow is the enclosing server function's `arguments`.",
2497
+ super: "`super` refers to the enclosing server object.",
2498
+ "new.target": "`new.target` in an arrow is the enclosing server function's."
2499
+ },
2500
+ captureHint: 'Read what you need from `to.params`/`to.state`, or export the predicate from a "use client" module.',
2501
+ loadsHint: 'Import client-safe modules statically, or export the predicate from a "use client" module.',
2502
+ importMetaWhy: "is the server module's.",
2503
+ importMetaMemberWhy: "is resolved against the server module; only `import.meta.env` is available to an inline predicate.",
2504
+ dynamicImportWhy: "loads a module at run time, which the build cannot check is client-safe."
2505
+ };
2506
+ var NODE_BUILTINS = new Set(builtinModules);
2507
+ function isServerOnlySpecifier(source) {
2508
+ return source === "server-only" || source.startsWith("node:") || source.startsWith("cloudflare:") || NODE_BUILTINS.has(source);
2509
+ }
2510
+ var ROUTER_IMPORT_RE = /["']@rangojs\/router["']/;
2511
+ var WHEN_RE = /\bwhen\b/;
2512
+ function whenError(file, code, node, detail) {
2513
+ const { line, column } = offsetToLineColumn(code, node.start);
2514
+ return new TransitionWhenError(
2515
+ `[rango] transition({ when }) at ${file}:${line}:${column}: \`when\` runs in the browser; ${detail}`
2516
+ );
2517
+ }
2518
+ async function hoistTransitionWhens(code, id, deps = {}) {
2519
+ if (!ROUTER_IMPORT_RE.test(code) || !WHEN_RE.test(code)) return null;
2520
+ const file = normalizePath3(id.split("?", 1)[0]);
2521
+ let program;
2522
+ try {
2523
+ program = parseAst4(code, { lang: parseLang(file) });
2524
+ } catch {
2525
+ return null;
2526
+ }
2527
+ if (hasDirective2(program.body, "use client")) return null;
2528
+ const { moduleScope, references, scopeOf } = analyzeScopes(program);
2529
+ const imports = collectImports(program);
2530
+ const sites = findWhenSites(program, scopeOf, moduleScope, imports);
2531
+ if (sites.length === 0) return null;
2532
+ const s = new MagicString3(code);
2533
+ const modules = [];
2534
+ const header = [];
2535
+ for (const site of sites) {
2536
+ const { prop, value } = site;
2537
+ if (prop.kind === "get" || prop.kind === "set") {
2538
+ throw whenError(
2539
+ file,
2540
+ code,
2541
+ prop,
2542
+ `\`${prop.kind} when()\` is an accessor; \`when\` must be the predicate itself: \`when: (ctx) => ...\` or \`when(ctx) { ... }\`.`
2543
+ );
2544
+ }
2545
+ if (value.type === "Identifier") {
2546
+ const decl = site.scope.lookup(value.name);
2547
+ if (decl && !(decl === moduleScope && imports.has(value.name))) {
2548
+ throw whenError(
2549
+ file,
2550
+ code,
2551
+ value,
2552
+ `\`${value.name}\` is a server-module binding. Export the predicate from a "use client" module and import it, or write it inline.`
2553
+ );
2554
+ }
2555
+ continue;
2556
+ }
2557
+ if (!isFunctionLiteral(value)) continue;
2558
+ const lexical = findLexicalCapture(
2559
+ value,
2560
+ references,
2561
+ code,
2562
+ WHEN_CAPTURE_MESSAGES
2563
+ );
2564
+ if (lexical) throw whenError(file, code, lexical.node, lexical.detail);
2565
+ const free = collectFreeReferences(value, references, moduleScope, imports);
2566
+ const binding = free.bindings[0];
2567
+ if (binding) {
2568
+ throw whenError(
2569
+ file,
2570
+ code,
2571
+ binding.node,
2572
+ `\`${binding.node.name}\` is a server-module binding. Read it from \`to.params\`/\`to.state\`, or export the predicate from a "use client" module.`
2573
+ );
2574
+ }
2575
+ const importLines = await emitImports(
2576
+ free.imports,
2577
+ imports,
2578
+ async (local2, imported) => {
2579
+ if (isServerOnlySpecifier(imported.source) || await deps.isServerOnlyImport?.(imported.source)) {
2580
+ throw whenError(
2581
+ file,
2582
+ code,
2583
+ value,
2584
+ `\`${local2}\` is imported from "${imported.source}", a server-only module. Import only client-safe modules into an inline predicate, or export it from a "use client" module.`
2585
+ );
2586
+ }
2587
+ }
2588
+ );
2589
+ const source = prop.method ? `${value.async ? "async " : ""}function${value.generator ? "*" : ""} ` + code.slice(value.start, value.end) : code.slice(value.start, value.end);
2590
+ const index = modules.length;
2591
+ modules.push(
2592
+ [
2593
+ `"use client";`,
2594
+ ...importLines,
2595
+ `export const ${EXPORT_NAME} = ${source};`,
2596
+ ""
2597
+ ].join("\n")
2598
+ );
2599
+ const local = `${LOCAL_PREFIX}${index}`;
2600
+ s.overwrite(
2601
+ prop.start,
2602
+ prop.end,
2603
+ `${code.slice(prop.key.start, prop.key.end)}: ${local}`
2604
+ );
2605
+ header.push(
2606
+ `import { ${EXPORT_NAME} as ${local} } from ${JSON.stringify(
2607
+ `${file}?${TRANSITION_WHEN_QUERY}=${index}`
2608
+ )};`
2609
+ );
2610
+ }
2611
+ if (modules.length === 0) return null;
2612
+ const insertAt = directivePrologueEnd(program);
2613
+ s.appendLeft(insertAt, `${insertAt ? "\n" : ""}${header.join("\n")}
2614
+ `);
2615
+ return {
2616
+ code: s.toString(),
2617
+ map: s.generateMap({ hires: true, source: file }),
2618
+ modules
2619
+ };
2620
+ }
2621
+ function parseHoistedWhenId(id) {
2622
+ const q = id.indexOf("?");
2623
+ if (q === -1) return null;
2624
+ const params = new URLSearchParams(id.slice(q + 1));
2625
+ const raw = params.get(TRANSITION_WHEN_QUERY);
2626
+ if (raw === null || !/^\d+$/.test(raw)) return null;
2627
+ return { file: id.slice(0, q), index: Number(raw) };
2628
+ }
2629
+ var SERVER_ONLY_IMPORT_RE = /\bimport\s+["']server-only["']/;
2630
+ function transitionWhenHoistPlugin() {
2631
+ const emitted = /* @__PURE__ */ new Map();
2632
+ return {
2633
+ name: "@rangojs/router:transition-when-hoist",
2634
+ enforce: "pre",
2635
+ async load(id) {
2636
+ const hoisted = parseHoistedWhenId(id);
2637
+ if (!hoisted) return;
2638
+ const modules = await loadEmittedOrDisk(
2639
+ emitted,
2640
+ hoisted.file,
2641
+ await readSource(hoisted.file),
2642
+ async (disk) => (await hoistTransitionWhens(disk, hoisted.file))?.modules
2643
+ );
2644
+ const module = modules?.[hoisted.index];
2645
+ if (module === void 0) {
2646
+ throw new TransitionWhenError(
2647
+ `[rango] ${hoisted.file} has no inline transition({ when }) #${hoisted.index}.`
2648
+ );
2649
+ }
2650
+ return module;
2651
+ },
2652
+ async transform(code, id) {
2653
+ if (this.environment?.name !== "rsc") return;
2654
+ if (id.includes("/node_modules/") || parseHoistedWhenId(id)) return;
2655
+ const file = normalizePath3(id.split("?", 1)[0]);
2656
+ if (!SOURCE_FILE_RE.test(file)) return;
2657
+ emitted.delete(file);
2658
+ const result = await hoistTransitionWhens(code, id, {
2659
+ isServerOnlyImport: async (source) => {
2660
+ const target = await resolveSourceTarget(this, source, id, {
2661
+ skipNodeModules: true
2662
+ });
2663
+ if (target === null) return false;
2664
+ const text = await readSource(target);
2665
+ return text !== null && SERVER_ONLY_IMPORT_RE.test(text);
2666
+ }
2667
+ });
2668
+ if (!result) return;
2669
+ await recordEmitted(emitted, file, result.modules);
2670
+ return { code: result.code, map: result.map };
2671
+ }
2672
+ };
2673
+ }
2674
+
2675
+ // src/vite/plugins/client-urls-revalidate-hoist.ts
2676
+ import { normalizePath as normalizePath4, parseAst as parseAst5 } from "vite";
2677
+ import MagicString4 from "magic-string";
2678
+ import { createHash as createHash2 } from "node:crypto";
2679
+ import { relative } from "node:path";
2680
+ import { hasDirective as hasDirective3 } from "@vitejs/plugin-rsc/transforms";
2681
+ var REGISTER = "__rango_registerClientUrlRevalidators";
2682
+ var CLIENT_SOURCES = /* @__PURE__ */ new Set(["@rangojs/router/client"]);
2683
+ var BROWSER_GLOBALS = /* @__PURE__ */ new Set([
2684
+ "window",
2685
+ "document",
2686
+ "navigator",
2687
+ "localStorage",
2688
+ "sessionStorage",
2689
+ "location",
2690
+ "history"
2691
+ ]);
2692
+ var NOT_A_FUNCTION = /* @__PURE__ */ new Set([
2693
+ "ObjectExpression",
2694
+ "ArrayExpression",
2695
+ "Literal",
2696
+ "TemplateLiteral",
2697
+ "ClassExpression"
2698
+ ]);
2699
+ var CAPTURE_MESSAGES = {
2700
+ lexical: {
2701
+ this: "`this` in an arrow is the enclosing function's `this`.",
2702
+ arguments: "`arguments` in an arrow is the enclosing function's.",
2703
+ super: "`super` refers to the enclosing object.",
2704
+ "new.target": "`new.target` in an arrow is the enclosing function's."
2705
+ },
2706
+ captureHint: "Read what you need from the predicate's argument.",
2707
+ loadsHint: "Import server-safe modules statically.",
2708
+ importMetaWhy: `is the "use client" module's.`,
2709
+ importMetaMemberWhy: 'is resolved against the "use client" module; only `import.meta.env` is available to a hoisted predicate.',
2710
+ dynamicImportWhy: "loads a module at run time, which the build cannot check is server-safe."
2711
+ };
2712
+ var CLIENT_URLS_RE = /\bclientUrls\b/;
2713
+ var REVALIDATE_RE = /\brevalidate\b/;
2714
+ var CANDIDATE_RE = /\b(?:clientUrls|revalidate)\b/;
2715
+ function mayHoist(code) {
2716
+ return CLIENT_IMPORT_RE.test(code) && REVALIDATE_RE.test(code);
2717
+ }
2718
+ function isGroupModule(code) {
2719
+ return code.includes("use client") && CLIENT_URLS_RE.test(code) && CLIENT_IMPORT_RE.test(code) && hasUseClientDirective(code);
2720
+ }
2721
+ function revalidateError(file, code, node, detail) {
2722
+ const { line, column } = offsetToLineColumn(code, node.start);
2723
+ return new Error(
2724
+ `[rango] clientUrls() revalidate() at ${file}:${line}:${column}: revalidate() runs on the server; ${detail}`
2725
+ );
2726
+ }
2727
+ var FINGERPRINT_SKIP = /* @__PURE__ */ new Set([
2728
+ "type",
2729
+ "start",
2730
+ "end",
2731
+ "loc",
2732
+ "range",
2733
+ "raw",
2734
+ "extra",
2735
+ "shorthand",
2736
+ // TS-only flags (`let x!: T`), lost with the types.
2737
+ "definite",
2738
+ ...TYPE_KEYS
2739
+ ]);
2740
+ function fingerprint(node) {
2741
+ const out = [];
2742
+ const visit = (value) => {
2743
+ if (value === null || value === void 0) return;
2744
+ if (Array.isArray(value)) {
2745
+ out.push("[");
2746
+ for (const item of value) visit(item);
2747
+ out.push("]");
2748
+ return;
2749
+ }
2750
+ if (typeof value !== "object") {
2751
+ out.push(JSON.stringify(typeof value === "bigint" ? `${value}n` : value));
2752
+ return;
2753
+ }
2754
+ let entry = value;
2755
+ if (typeof entry.type === "string") {
2756
+ entry = unwrapExpression(entry);
2757
+ if (entry.type.startsWith("TS")) {
2758
+ visit(entry.expression);
2759
+ return;
2760
+ }
2761
+ out.push(entry.type, "(");
2762
+ if (entry.type === "TemplateElement") {
2763
+ out.push(JSON.stringify(entry.value.raw));
2764
+ }
2765
+ }
2766
+ for (const key of Object.keys(entry)) {
2767
+ if (FINGERPRINT_SKIP.has(key)) continue;
2768
+ if (key === "optional" && entry.type === "Identifier") continue;
2769
+ out.push(key);
2770
+ visit(entry[key]);
2771
+ }
2772
+ if (typeof entry.type === "string") out.push(")");
2773
+ };
2774
+ visit(node);
2775
+ return out.join(" ");
2776
+ }
2777
+ function keyOf(relativeFile, predicate) {
2778
+ return createHash2("sha256").update(relativeFile).update("\0").update(fingerprint(predicate)).digest("hex").slice(0, 12);
2779
+ }
2780
+ async function hoistClientUrlsRevalidates(code, id, deps) {
2781
+ if (!mayHoist(code)) return null;
2782
+ const file = normalizePath4(id.split("?", 1)[0]);
2783
+ const program = parseProgram(code, file);
2784
+ if (!program) return null;
2785
+ const { moduleScope, references, scopeOf } = analyzeScopes(program);
2786
+ const imports = collectImports(program);
2787
+ const calls = findHelperCalls(program, scopeOf, moduleScope, imports, {
2788
+ sources: CLIENT_SOURCES,
2789
+ builder: "clientUrls",
2790
+ helper: "revalidate",
2791
+ directImport: true
2792
+ });
2793
+ if (calls.length === 0) return null;
2794
+ const relativeFile = normalizePath4(relative(deps.root, file));
2795
+ const s = new MagicString4(code);
2796
+ const used = /* @__PURE__ */ new Map();
2797
+ const entries = /* @__PURE__ */ new Map();
2798
+ for (const { call } of calls) {
2799
+ const [arg, extra] = call.arguments;
2800
+ if (!arg || extra || arg.type === "SpreadElement") {
2801
+ throw revalidateError(
2802
+ file,
2803
+ code,
2804
+ call,
2805
+ "`revalidate()` takes exactly one predicate or boolean."
2806
+ );
2807
+ }
2808
+ const value = unwrapExpression(arg);
2809
+ if (value.type === "Literal" && typeof value.value === "boolean") continue;
2810
+ if (NOT_A_FUNCTION.has(value.type)) {
2811
+ throw revalidateError(
2812
+ file,
2813
+ code,
2814
+ value,
2815
+ "`revalidate()` expects a predicate function or a boolean."
2816
+ );
2817
+ }
2818
+ if (isFunctionLiteral(value) && (value.async || value.generator)) {
2819
+ throw revalidateError(
2820
+ file,
2821
+ code,
2822
+ value,
2823
+ `a${value.async ? "n `async`" : " generator"} function returns ${value.async ? "a Promise" : "an iterator"}, which the router ignores: return a boolean, \`{ defaultShouldRevalidate }\`, or nothing.`
2824
+ );
2825
+ }
2826
+ const lexical = findLexicalCapture(
2827
+ value,
2828
+ references,
2829
+ code,
2830
+ CAPTURE_MESSAGES
2831
+ );
2832
+ if (lexical)
2833
+ throw revalidateError(file, code, lexical.node, lexical.detail);
2834
+ const free = collectFreeReferences(value, references, moduleScope, imports);
2835
+ const binding = free.bindings[0];
2836
+ if (binding) {
2837
+ const name = binding.node.name;
2838
+ throw revalidateError(
2839
+ file,
2840
+ code,
2841
+ binding.node,
2842
+ binding.scope.lookup(name) === moduleScope ? `\`${name}\` is declared in this ` + (hasDirective3(program.body, "use client") ? '"use client" module' : "module") + '. Move the predicate to its own module (without "use client") and import it, or write it inline.' : `\`${name}\` is a binding of the enclosing function. Read what you need from the predicate's argument (\`currentParams\`, \`nextUrl\`, \`context\`, \`actionResult\`, ...).`
2843
+ );
2844
+ }
2845
+ const browserGlobal = free.globals.find(
2846
+ (ref) => BROWSER_GLOBALS.has(ref.node.name)
2847
+ );
2848
+ if (browserGlobal) {
2849
+ throw revalidateError(
2850
+ file,
2851
+ code,
2852
+ browserGlobal.node,
2853
+ `\`${browserGlobal.node.name}\` is a browser global. Put the input on the request (a cookie or a search param) and read it from the predicate's argument, or refresh the loader with useRefreshLoaders.`
2854
+ );
2855
+ }
2856
+ const unchecked = [...free.imports].filter(
2857
+ ([local, valueUse]) => valueUse && !used.get(local)
2858
+ );
2859
+ const clientOnly = await Promise.all(
2860
+ unchecked.map(([local]) => isClientOnly(imports.get(local), deps))
2861
+ );
2862
+ const offender = unchecked.find((_, i) => clientOnly[i]);
2863
+ if (offender) {
2864
+ const [local] = offender;
2865
+ throw revalidateError(
2866
+ file,
2867
+ code,
2868
+ value,
2869
+ `\`${local}\` is imported from "${imports.get(local).source}", a client-only module: on the server a "use client" module's exports are client references and cannot be called. Import the predicate's inputs from a module without "use client".`
2870
+ );
2871
+ }
2872
+ for (const [local, valueUse] of free.imports) {
2873
+ used.set(local, (used.get(local) ?? false) || valueUse);
2874
+ }
2875
+ const source = code.slice(value.start, value.end);
2876
+ const key = keyOf(relativeFile, value);
2877
+ entries.set(key, source);
2878
+ s.overwrite(
2879
+ arg.start,
2880
+ arg.end,
2881
+ `{ ${HOISTED_REVALIDATE_KEY}: ${JSON.stringify(key)} }`
2882
+ );
2883
+ }
2884
+ if (entries.size === 0) return null;
2885
+ const importLines = await emitImports(used, imports, () => {
2886
+ });
2887
+ const module = [
2888
+ `import { registerClientUrlRevalidators as ${REGISTER} } from "@rangojs/router/server";`,
2889
+ ...importLines,
2890
+ `${REGISTER}({`,
2891
+ ...[...entries].map(
2892
+ ([key, source]) => ` ${JSON.stringify(key)}: ${source},`
2893
+ ),
2894
+ `});`,
2895
+ ""
2896
+ ].join("\n");
2897
+ return {
2898
+ code: s.toString(),
2899
+ map: s.generateMap({ hires: true, source: file }),
2900
+ module,
2901
+ keys: [...entries.keys()]
2902
+ };
2903
+ }
2904
+ async function isClientOnly(binding, deps) {
2905
+ return binding.source === "client-only" || Boolean(await deps.isClientModule?.(binding.source));
2906
+ }
2907
+ function parseProgram(code, file) {
2908
+ try {
2909
+ return parseAst5(code, { lang: parseLang(file) });
2910
+ } catch {
2911
+ return null;
2912
+ }
2913
+ }
2914
+ function parseHoistedRevalidateId(id) {
2915
+ const q = id.indexOf("?");
2916
+ if (q === -1) return null;
2917
+ const params = new URLSearchParams(id.slice(q + 1));
2918
+ return params.has(CLIENT_URLS_REVALIDATE_QUERY) ? id.slice(0, q) : null;
2919
+ }
2920
+ var HOISTED_ID_RE = new RegExp(
2921
+ `[?&]${CLIENT_URLS_REVALIDATE_QUERY}(?:[=&]|$)`
2922
+ );
2923
+ var SOURCE_ID_RE = /\.[cm]?[jt]sx?(?:\?|$)/;
2924
+ var NODE_MODULES_RE = /\/node_modules\//;
2925
+ var USE_ASSIGNMENT_RE = /\.use\s*=/;
2926
+ function clientUrlsRevalidateHoistPlugin(index) {
2927
+ const emitted = /* @__PURE__ */ new Map();
2928
+ const groups = /* @__PURE__ */ new Set();
2929
+ const clientModules = /* @__PURE__ */ new Map();
2930
+ const useSignatures = /* @__PURE__ */ new Map();
2931
+ let root = process.cwd();
2932
+ const isClientFile = (file) => {
2933
+ let known = clientModules.get(file);
2934
+ if (!known) {
2935
+ known = readSource(file).then(
2936
+ (text) => text !== null && text.includes("use client") && hasUseClientDirective(text)
2937
+ );
2938
+ clientModules.set(file, known);
2939
+ }
2940
+ return known;
2941
+ };
2942
+ const clientModuleCheck = (ctx, importer) => async (source) => {
2943
+ const target = await resolveSourceTarget(ctx, source, importer, {
2944
+ skipNodeModules: false
2945
+ });
2946
+ return target !== null && await isClientFile(target);
2947
+ };
2948
+ return [
2949
+ {
2950
+ name: "@rangojs/router:client-urls-revalidate-hoist",
2951
+ enforce: "pre",
2952
+ configResolved(config) {
2953
+ root = normalizePath4(config.root);
2954
+ },
2955
+ buildStart() {
2956
+ clientModules.clear();
2957
+ },
2958
+ watchChange(id) {
2959
+ const file = normalizePath4(id);
2960
+ clientModules.delete(file);
2961
+ emitted.delete(file);
2962
+ groups.delete(file);
2963
+ },
2964
+ load: {
2965
+ filter: { id: HOISTED_ID_RE },
2966
+ async handler(id) {
2967
+ const hoistedFile = parseHoistedRevalidateId(id);
2968
+ if (hoistedFile === null) return;
2969
+ const file = normalizePath4(hoistedFile);
2970
+ const registrations = await loadEmittedOrDisk(
2971
+ emitted,
2972
+ file,
2973
+ await readSource(file),
2974
+ async (source) => (await hoistClientUrlsRevalidates(source, file, {
2975
+ root,
2976
+ isClientModule: clientModuleCheck(this, file)
2977
+ }))?.module
2978
+ );
2979
+ const assigned = index.filesByGroup.get(file) ?? [];
2980
+ const code = registrations === void 0 && assigned.length === 0 ? "export {};\n" : [
2981
+ registrations ?? "",
2982
+ ...assigned.map(
2983
+ (target) => `import ${JSON.stringify(hoistedRevalidateId(target))};
2984
+ `
2985
+ )
2986
+ ].join("");
2987
+ return { code, moduleSideEffects: "no-treeshake" };
2988
+ }
2989
+ },
2990
+ transform: {
2991
+ filter: {
2992
+ id: {
2993
+ include: SOURCE_ID_RE,
2994
+ exclude: [NODE_MODULES_RE, HOISTED_ID_RE]
2995
+ },
2996
+ code: CANDIDATE_RE
2997
+ },
2998
+ async handler(code, id) {
2999
+ if (id.includes("/node_modules/") || parseHoistedRevalidateId(id)) {
3000
+ return;
3001
+ }
3002
+ const file = normalizePath4(id.split("?", 1)[0]);
3003
+ if (!SOURCE_FILE_RE.test(file)) return;
3004
+ const rsc = this.environment?.name === "rsc";
3005
+ if (rsc) {
3006
+ emitted.delete(file);
3007
+ if (isGroupModule(code)) groups.add(file);
3008
+ else groups.delete(file);
3009
+ }
3010
+ const result = await hoistClientUrlsRevalidates(code, id, {
3011
+ root,
3012
+ isClientModule: rsc ? clientModuleCheck(this, id) : void 0
3013
+ });
3014
+ if (!result) return;
3015
+ for (const key of result.keys) index.fileByKey.set(key, file);
3016
+ if (rsc) await recordEmitted(emitted, file, result.module);
3017
+ return { code: result.code, map: result.map };
3018
+ }
3019
+ }
3020
+ },
3021
+ {
3022
+ name: "@rangojs/router:client-urls-revalidate-register",
3023
+ enforce: "post",
3024
+ applyToEnvironment: (env) => env.name === "rsc",
3025
+ transform: {
3026
+ filter: { code: "registerClientReference" },
3027
+ handler(code, id) {
3028
+ if (parseHoistedRevalidateId(id)) return;
3029
+ const file = normalizePath4(id.split("?", 1)[0]);
3030
+ if (!groups.has(file)) return;
3031
+ const s = new MagicString4(code);
3032
+ s.append(`
3033
+ import ${JSON.stringify(hoistedRevalidateId(file))};
3034
+ `);
3035
+ return { code: s.toString(), map: s.generateMap({ hires: true }) };
3036
+ }
3037
+ }
3038
+ },
3039
+ {
3040
+ name: "@rangojs/router:client-urls-component-use-hmr",
3041
+ apply: "serve",
3042
+ applyToEnvironment: (env) => env.name === "client",
3043
+ transform: {
3044
+ filter: {
3045
+ id: { include: SOURCE_ID_RE, exclude: [NODE_MODULES_RE] },
3046
+ code: USE_ASSIGNMENT_RE
3047
+ },
3048
+ async handler(_code, id) {
3049
+ const file = normalizePath4(id.split("?", 1)[0]);
3050
+ const disk = await readSource(file);
3051
+ const signature = disk && componentUseSignature(disk, file);
3052
+ if (signature) useSignatures.set(file, signature);
3053
+ }
3054
+ },
3055
+ async hotUpdate({ file, modules, read }) {
3056
+ if (modules.length === 0 || !SOURCE_FILE_RE.test(file)) return;
3057
+ const next = componentUseSignature(await read(), file);
3058
+ if (next === useSignatures.get(file)) return;
3059
+ if (next === void 0) useSignatures.delete(file);
3060
+ else useSignatures.set(file, next);
3061
+ const updated = new Set(modules);
3062
+ for (const mod of modules) {
3063
+ for (const importer of mod.importers) updated.add(importer);
3064
+ }
3065
+ return [...updated];
3066
+ }
3067
+ }
3068
+ ];
3069
+ }
3070
+
3071
+ // src/vite/temp-rsc-server.ts
3072
+ var loaderHookRegistered = false;
3073
+ function ensureCloudflareProtocolLoaderRegistered() {
3074
+ if (loaderHookRegistered) return;
3075
+ loaderHookRegistered = true;
3076
+ try {
3077
+ register(
3078
+ new URL("./plugins/cloudflare-protocol-loader-hook.mjs", import.meta.url)
3079
+ );
3080
+ } catch (err) {
3081
+ console.warn(
3082
+ `[rango] Could not register Node ESM loader hook for cloudflare:* imports (${err?.message ?? err}). Falling back to Vite transform only.`
3083
+ );
3084
+ }
3085
+ }
3086
+ async function createTempRscServer(state, options = {}) {
3087
+ ensureCloudflareProtocolLoaderRegistered();
3088
+ const { default: rsc } = await import("@vitejs/plugin-rsc");
3089
+ const runnerConfig = state.userRunnerConfig;
3090
+ const resolveConfig = runnerConfig?.resolve ?? {
3091
+ alias: state.userResolveAlias
3092
+ };
3093
+ const oxcConfig = runnerConfig?.oxc ?? {
3094
+ jsx: { runtime: "automatic", importSource: "react" }
3095
+ };
3096
+ return createViteServer({
3097
+ root: state.projectRoot,
3098
+ configFile: false,
3099
+ server: {
3100
+ middlewareMode: true,
3101
+ // Build mode: no file watching. buildStart installs the per-router tries
3102
+ // into this realm and runShellPrerenderPhase reuses it after the bundles
3103
+ // are written. A watched write in between (writeRouteTypesFiles' own
3104
+ // <router>.named-routes.gen.ts, which every router file imports) can
3105
+ // make Vite full-reload the RSC runner; the shell phase then matches in
3106
+ // a fresh realm with no tries and a root path("/*") wins (#947).
3107
+ ...options.forceBuild ? { watch: null } : {}
3108
+ },
3109
+ appType: "custom",
3110
+ logLevel: "silent",
3111
+ resolve: resolveConfig,
3112
+ ...runnerConfig?.define ? { define: runnerConfig.define } : {},
3113
+ oxc: oxcConfig,
3114
+ ...options.cacheDir && { cacheDir: options.cacheDir },
3115
+ plugins: [
3116
+ rsc({
3117
+ entries: {
3118
+ client: "virtual:entry-client",
3119
+ ssr: "virtual:entry-ssr",
3120
+ rsc: state.resolvedEntryPath
3121
+ },
3122
+ // The temp server renders Static/Prerender output and encrypts inline-
3123
+ // action bound args. Give it the SAME key as the main build/dev runtime
3124
+ // (defineEncryptionKeyExpr is process-cached) so those args decrypt at
3125
+ // invocation. Unconditional, NOT build-only: under Cloudflare/workerd dev
3126
+ // the RSC env has no module runner, so prerender is rendered by THIS temp
3127
+ // server (via /__rsc_prerender), and the action decrypts in the main
3128
+ // runtime with the rango.ts key -- gating on forceBuild left dev encrypting
3129
+ // with the temp server's own random key, failing decryptActionBoundArgs.
3130
+ // (hashServerRefs stays build-only: dev keeps dev-style ids the dev runtime
3131
+ // resolves directly.)
3132
+ defineEncryptionKey: defineEncryptionKeyExpr()
3133
+ }),
3134
+ // hashClientRefs/hashServerRefs only in build mode — production bundles
3135
+ // need hashed refs. hashServerRefs is the server-side analog: it rewrites
3136
+ // registerServerReference dev-style ids to production hashes so a
3137
+ // server-created action embedded in prerendered/static Flight resolves
3138
+ // against the production manifest on a build-time-cache hit.
3139
+ ...options.forceBuild ? [hashClientRefs(state.projectRoot), hashServerRefs(state.projectRoot)] : [],
3140
+ createVersionPlugin(),
3141
+ // Before the stub plugin, so "virtual:entry-ssr" resolves to the real
3142
+ // SSR entry when the shell endpoint needs it (see the option doc).
3143
+ ...options.realSsrEntry ? [
3144
+ {
3145
+ name: "@rangojs/router:temp-real-ssr-entry",
3146
+ enforce: "pre",
3147
+ resolveId(id) {
3148
+ return id === "virtual:entry-ssr" ? "\0rango-temp-real-ssr-entry" : null;
3149
+ },
3150
+ load(id) {
3151
+ return id === "\0rango-temp-real-ssr-entry" ? getVirtualEntrySSR(
3152
+ state.opts?.headScripts,
3153
+ state.opts?.progressiveChunkSize
3154
+ ) : null;
3155
+ }
3156
+ }
3157
+ ] : [],
3158
+ createVirtualStubPlugin(),
3159
+ createCloudflareProtocolStubPlugin(),
3160
+ // Inline transition({ when }) literals become client references here
3161
+ // too, or discovery would see (and reject) the plain function.
3162
+ transitionWhenHoistPlugin(),
3163
+ // clientUrls() revalidate() predicates move to the server here too:
3164
+ // discovery serializes the SSR copy's markers and the RSC realm
3165
+ // registers the predicates the materialized stubs call. The index is
3166
+ // the main plugin's, so its group modules import the files assigned here.
3167
+ ...clientUrlsRevalidateHoistPlugin(state.clientUrlRevalidate),
3168
+ // Dev prerender must use dev-mode IDs (path-based) to match the workerd
3169
+ // runtime. forceBuild produces hashed IDs for production bundle consistency.
3170
+ exposeInternalIds(options.forceBuild ? { forceBuild: true } : void 0),
3171
+ exposeRouterId(),
3172
+ {
3173
+ name: "@rangojs/router:client-urls-source-tracking",
3174
+ enforce: "pre",
3175
+ transform(code, id) {
3176
+ recordClientUrlsModule(state, code, id);
3177
+ }
3178
+ },
3179
+ // Forwarded user resolution plugins (e.g. vite-tsconfig-paths). Stripped
3180
+ // to resolveId/load (plus transform for import rewriters, see
3181
+ // IMPORT_REWRITE_PLUGINS) and placed last so framework resolution runs first;
3182
+ // Vite re-sorts by `enforce`, so `enforce: "pre"` resolvers still lead.
3183
+ ...state.userResolvePlugins,
3184
+ ...options.plugins ?? []
3185
+ ]
3186
+ });
3187
+ }
3188
+ export {
3189
+ createTempRscServer
3190
+ };