@ivogt/rsc-router 0.0.0-experimental.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 (123) hide show
  1. package/README.md +19 -0
  2. package/package.json +131 -0
  3. package/src/__mocks__/version.ts +6 -0
  4. package/src/__tests__/route-definition.test.ts +63 -0
  5. package/src/browser/event-controller.ts +876 -0
  6. package/src/browser/index.ts +18 -0
  7. package/src/browser/link-interceptor.ts +121 -0
  8. package/src/browser/lru-cache.ts +69 -0
  9. package/src/browser/merge-segment-loaders.ts +126 -0
  10. package/src/browser/navigation-bridge.ts +891 -0
  11. package/src/browser/navigation-client.ts +155 -0
  12. package/src/browser/navigation-store.ts +823 -0
  13. package/src/browser/partial-update.ts +545 -0
  14. package/src/browser/react/Link.tsx +248 -0
  15. package/src/browser/react/NavigationProvider.tsx +228 -0
  16. package/src/browser/react/ScrollRestoration.tsx +94 -0
  17. package/src/browser/react/context.ts +53 -0
  18. package/src/browser/react/index.ts +52 -0
  19. package/src/browser/react/location-state-shared.ts +120 -0
  20. package/src/browser/react/location-state.ts +62 -0
  21. package/src/browser/react/use-action.ts +240 -0
  22. package/src/browser/react/use-client-cache.ts +56 -0
  23. package/src/browser/react/use-handle.ts +178 -0
  24. package/src/browser/react/use-link-status.ts +134 -0
  25. package/src/browser/react/use-navigation.ts +150 -0
  26. package/src/browser/react/use-segments.ts +188 -0
  27. package/src/browser/request-controller.ts +149 -0
  28. package/src/browser/rsc-router.tsx +310 -0
  29. package/src/browser/scroll-restoration.ts +324 -0
  30. package/src/browser/server-action-bridge.ts +747 -0
  31. package/src/browser/shallow.ts +35 -0
  32. package/src/browser/types.ts +443 -0
  33. package/src/cache/__tests__/memory-segment-store.test.ts +487 -0
  34. package/src/cache/__tests__/memory-store.test.ts +484 -0
  35. package/src/cache/cache-scope.ts +565 -0
  36. package/src/cache/cf/__tests__/cf-cache-store.test.ts +361 -0
  37. package/src/cache/cf/cf-cache-store.ts +274 -0
  38. package/src/cache/cf/index.ts +19 -0
  39. package/src/cache/index.ts +52 -0
  40. package/src/cache/memory-segment-store.ts +150 -0
  41. package/src/cache/memory-store.ts +253 -0
  42. package/src/cache/types.ts +366 -0
  43. package/src/client.rsc.tsx +88 -0
  44. package/src/client.tsx +609 -0
  45. package/src/components/DefaultDocument.tsx +20 -0
  46. package/src/default-error-boundary.tsx +88 -0
  47. package/src/deps/browser.ts +8 -0
  48. package/src/deps/html-stream-client.ts +2 -0
  49. package/src/deps/html-stream-server.ts +2 -0
  50. package/src/deps/rsc.ts +10 -0
  51. package/src/deps/ssr.ts +2 -0
  52. package/src/errors.ts +259 -0
  53. package/src/handle.ts +120 -0
  54. package/src/handles/MetaTags.tsx +178 -0
  55. package/src/handles/index.ts +6 -0
  56. package/src/handles/meta.ts +247 -0
  57. package/src/href-client.ts +128 -0
  58. package/src/href.ts +139 -0
  59. package/src/index.rsc.ts +69 -0
  60. package/src/index.ts +84 -0
  61. package/src/loader.rsc.ts +204 -0
  62. package/src/loader.ts +47 -0
  63. package/src/network-error-thrower.tsx +21 -0
  64. package/src/outlet-context.ts +15 -0
  65. package/src/root-error-boundary.tsx +277 -0
  66. package/src/route-content-wrapper.tsx +198 -0
  67. package/src/route-definition.ts +1333 -0
  68. package/src/route-map-builder.ts +140 -0
  69. package/src/route-types.ts +148 -0
  70. package/src/route-utils.ts +89 -0
  71. package/src/router/__tests__/match-context.test.ts +104 -0
  72. package/src/router/__tests__/match-pipelines.test.ts +537 -0
  73. package/src/router/__tests__/match-result.test.ts +566 -0
  74. package/src/router/__tests__/on-error.test.ts +935 -0
  75. package/src/router/__tests__/pattern-matching.test.ts +577 -0
  76. package/src/router/error-handling.ts +287 -0
  77. package/src/router/handler-context.ts +60 -0
  78. package/src/router/loader-resolution.ts +326 -0
  79. package/src/router/manifest.ts +116 -0
  80. package/src/router/match-context.ts +261 -0
  81. package/src/router/match-middleware/background-revalidation.ts +236 -0
  82. package/src/router/match-middleware/cache-lookup.ts +261 -0
  83. package/src/router/match-middleware/cache-store.ts +250 -0
  84. package/src/router/match-middleware/index.ts +81 -0
  85. package/src/router/match-middleware/intercept-resolution.ts +268 -0
  86. package/src/router/match-middleware/segment-resolution.ts +174 -0
  87. package/src/router/match-pipelines.ts +214 -0
  88. package/src/router/match-result.ts +212 -0
  89. package/src/router/metrics.ts +62 -0
  90. package/src/router/middleware.test.ts +1355 -0
  91. package/src/router/middleware.ts +748 -0
  92. package/src/router/pattern-matching.ts +271 -0
  93. package/src/router/revalidation.ts +190 -0
  94. package/src/router/router-context.ts +299 -0
  95. package/src/router/types.ts +96 -0
  96. package/src/router.ts +3484 -0
  97. package/src/rsc/__tests__/helpers.test.ts +175 -0
  98. package/src/rsc/handler.ts +942 -0
  99. package/src/rsc/helpers.ts +64 -0
  100. package/src/rsc/index.ts +56 -0
  101. package/src/rsc/nonce.ts +18 -0
  102. package/src/rsc/types.ts +225 -0
  103. package/src/segment-system.tsx +405 -0
  104. package/src/server/__tests__/request-context.test.ts +171 -0
  105. package/src/server/context.ts +340 -0
  106. package/src/server/handle-store.ts +230 -0
  107. package/src/server/loader-registry.ts +174 -0
  108. package/src/server/request-context.ts +470 -0
  109. package/src/server/root-layout.tsx +10 -0
  110. package/src/server/tsconfig.json +14 -0
  111. package/src/server.ts +126 -0
  112. package/src/ssr/__tests__/ssr-handler.test.tsx +188 -0
  113. package/src/ssr/index.tsx +215 -0
  114. package/src/types.ts +1473 -0
  115. package/src/use-loader.tsx +346 -0
  116. package/src/vite/__tests__/expose-loader-id.test.ts +117 -0
  117. package/src/vite/expose-action-id.ts +344 -0
  118. package/src/vite/expose-handle-id.ts +209 -0
  119. package/src/vite/expose-loader-id.ts +357 -0
  120. package/src/vite/expose-location-state-id.ts +177 -0
  121. package/src/vite/index.ts +608 -0
  122. package/src/vite/version.d.ts +12 -0
  123. package/src/vite/virtual-entries.ts +109 -0
package/README.md ADDED
@@ -0,0 +1,19 @@
1
+ # @ivogt/rsc-router
2
+
3
+ > **Warning:** This package is experimental and under active development. APIs may change without notice.
4
+
5
+ Type-safe RSC router with partial rendering support for Vite.
6
+
7
+ ## Installation
8
+
9
+ ```bash
10
+ npm install @ivogt/rsc-router@experimental
11
+ ```
12
+
13
+ ## Status
14
+
15
+ This package is in early experimental stages. It is not recommended for production use.
16
+
17
+ ## License
18
+
19
+ MIT
package/package.json ADDED
@@ -0,0 +1,131 @@
1
+ {
2
+ "name": "@ivogt/rsc-router",
3
+ "version": "0.0.0-experimental.1",
4
+ "type": "module",
5
+ "description": "Type-safe RSC router with partial rendering support",
6
+ "author": "Ivo Todorov",
7
+ "license": "MIT",
8
+ "repository": {
9
+ "type": "git",
10
+ "url": "git+https://github.com/ivogt/vite-rsc.git",
11
+ "directory": "packages/rsc-router"
12
+ },
13
+ "homepage": "https://github.com/ivogt/vite-rsc#readme",
14
+ "bugs": {
15
+ "url": "https://github.com/ivogt/vite-rsc/issues"
16
+ },
17
+ "publishConfig": {
18
+ "access": "public",
19
+ "tag": "experimental"
20
+ },
21
+ "keywords": [
22
+ "react",
23
+ "rsc",
24
+ "react-server-components",
25
+ "router",
26
+ "vite"
27
+ ],
28
+ "exports": {
29
+ ".": {
30
+ "react-server": "./src/index.rsc.ts",
31
+ "types": "./src/index.ts",
32
+ "default": "./src/index.ts"
33
+ },
34
+ "./server": {
35
+ "types": "./src/server.ts",
36
+ "import": "./src/server.ts"
37
+ },
38
+ "./client": {
39
+ "react-server": "./src/client.rsc.tsx",
40
+ "types": "./src/client.tsx",
41
+ "default": "./src/client.tsx"
42
+ },
43
+ "./browser": {
44
+ "types": "./src/browser/index.ts",
45
+ "default": "./src/browser/index.ts"
46
+ },
47
+ "./ssr": {
48
+ "types": "./src/ssr/index.tsx",
49
+ "default": "./src/ssr/index.tsx"
50
+ },
51
+ "./rsc": {
52
+ "react-server": "./src/rsc/index.ts",
53
+ "types": "./src/rsc/index.ts",
54
+ "default": "./src/rsc/index.ts"
55
+ },
56
+ "./vite": {
57
+ "types": "./src/vite/index.ts",
58
+ "import": "./src/vite/index.ts"
59
+ },
60
+ "./types": {
61
+ "types": "./src/vite/version.d.ts"
62
+ },
63
+ "./internal/deps/browser": {
64
+ "types": "./src/deps/browser.ts",
65
+ "default": "./src/deps/browser.ts"
66
+ },
67
+ "./internal/deps/ssr": {
68
+ "types": "./src/deps/ssr.ts",
69
+ "default": "./src/deps/ssr.ts"
70
+ },
71
+ "./internal/deps/rsc": {
72
+ "react-server": "./src/deps/rsc.ts",
73
+ "types": "./src/deps/rsc.ts",
74
+ "default": "./src/deps/rsc.ts"
75
+ },
76
+ "./internal/deps/html-stream-client": {
77
+ "types": "./src/deps/html-stream-client.ts",
78
+ "default": "./src/deps/html-stream-client.ts"
79
+ },
80
+ "./internal/deps/html-stream-server": {
81
+ "types": "./src/deps/html-stream-server.ts",
82
+ "default": "./src/deps/html-stream-server.ts"
83
+ },
84
+ "./cache": {
85
+ "react-server": "./src/cache/index.ts",
86
+ "types": "./src/cache/index.ts",
87
+ "default": "./src/cache/index.ts"
88
+ }
89
+ },
90
+ "files": [
91
+ "src",
92
+ "README.md"
93
+ ],
94
+ "peerDependencies": {
95
+ "@cloudflare/vite-plugin": "^1.21.0",
96
+ "@vitejs/plugin-rsc": "^0.5.14",
97
+ "react": "^18.0.0 || ^19.0.0",
98
+ "vite": "^7.3.0"
99
+ },
100
+ "peerDependenciesMeta": {
101
+ "@cloudflare/vite-plugin": {
102
+ "optional": true
103
+ },
104
+ "vite": {
105
+ "optional": true
106
+ }
107
+ },
108
+ "dependencies": {
109
+ "@vitejs/plugin-rsc": "^0.5.14",
110
+ "magic-string": "^0.30.17",
111
+ "rsc-html-stream": "^0.0.7"
112
+ },
113
+ "devDependencies": {
114
+ "@playwright/test": "^1.49.1",
115
+ "@types/node": "^24.10.1",
116
+ "@types/react": "^19.2.7",
117
+ "@types/react-dom": "^19.2.3",
118
+ "react": "^19.2.1",
119
+ "react-dom": "^19.2.1",
120
+ "tinyexec": "^0.3.2",
121
+ "typescript": "^5.3.0",
122
+ "vitest": "^2.1.8"
123
+ },
124
+ "scripts": {
125
+ "typecheck": "tsc --noEmit",
126
+ "test": "playwright test",
127
+ "test:ui": "playwright test --ui",
128
+ "test:unit": "vitest run",
129
+ "test:unit:watch": "vitest"
130
+ }
131
+ }
@@ -0,0 +1,6 @@
1
+ /**
2
+ * Mock for rsc-router:version virtual module.
3
+ * Used by vitest since the virtual module is only available at build time.
4
+ * Empty string disables version path in URLs for simpler test assertions.
5
+ */
6
+ export const VERSION = "";
@@ -0,0 +1,63 @@
1
+ import { describe, it, expect } from "vitest";
2
+ import { route } from "../route-definition";
3
+
4
+ describe("route()", () => {
5
+ describe("with nested RouteConfig objects", () => {
6
+ it("should flatten nested RouteConfig with trailing slash config", () => {
7
+ const routes = route({
8
+ index: "/",
9
+ trailingSlash: {
10
+ ignore: { path: "/ts-ignore", trailingSlash: "ignore" },
11
+ always: { path: "/ts-always", trailingSlash: "always" },
12
+ never: { path: "/ts-never", trailingSlash: "never" },
13
+ },
14
+ }) as any;
15
+
16
+ // Check routes are flattened correctly
17
+ expect(routes.index).toBe("/");
18
+ expect(routes["trailingSlash.ignore"]).toBe("/ts-ignore");
19
+ expect(routes["trailingSlash.always"]).toBe("/ts-always");
20
+ expect(routes["trailingSlash.never"]).toBe("/ts-never");
21
+
22
+ // Check trailing slash config is attached
23
+ expect(routes.__trailingSlash).toBeDefined();
24
+ expect(routes.__trailingSlash["trailingSlash.ignore"]).toBe("ignore");
25
+ expect(routes.__trailingSlash["trailingSlash.always"]).toBe("always");
26
+ expect(routes.__trailingSlash["trailingSlash.never"]).toBe("never");
27
+ });
28
+
29
+ it("should be enumerable for Object.entries", () => {
30
+ const routes = route({
31
+ index: "/",
32
+ trailingSlash: {
33
+ ignore: { path: "/ts-ignore", trailingSlash: "ignore" },
34
+ },
35
+ });
36
+
37
+ const entries = Object.entries(routes);
38
+ expect(entries).toContainEqual(["index", "/"]);
39
+ expect(entries).toContainEqual(["trailingSlash.ignore", "/ts-ignore"]);
40
+ });
41
+
42
+ it("should apply global default to string routes", () => {
43
+ const routes = route({
44
+ blog: "/blog",
45
+ about: "/about",
46
+ }, { trailingSlash: "never" }) as any;
47
+
48
+ expect(routes.__trailingSlash).toBeDefined();
49
+ expect(routes.__trailingSlash.blog).toBe("never");
50
+ expect(routes.__trailingSlash.about).toBe("never");
51
+ });
52
+
53
+ it("should let per-route config override global default", () => {
54
+ const routes = route({
55
+ blog: "/blog",
56
+ api: { path: "/api", trailingSlash: "ignore" },
57
+ }, { trailingSlash: "never" }) as any;
58
+
59
+ expect(routes.__trailingSlash.blog).toBe("never");
60
+ expect(routes.__trailingSlash.api).toBe("ignore");
61
+ });
62
+ });
63
+ });