react-on-rails-pro 16.7.0-rc.1 → 16.7.0-rc.3

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.
package/LICENSE.md ADDED
@@ -0,0 +1,83 @@
1
+ # Licensing
2
+
3
+ This repository contains code under two different licenses:
4
+
5
+ - **Core**: MIT License (applies to most files)
6
+ - **Pro**: React on Rails Pro License (applies to specific directories)
7
+
8
+ ## License Scope
9
+
10
+ ### MIT Licensed Code
11
+
12
+ The following directories and all their contents are licensed under the **MIT License** (see full text below):
13
+
14
+ - `react_on_rails/` (entire directory, including lib/, spec/, sig/)
15
+ - `packages/react-on-rails/` (entire package)
16
+ - All other directories in this repository not explicitly listed as Pro-licensed
17
+
18
+ ### Pro Licensed Code
19
+
20
+ The following directories and all their contents are licensed under the **React on Rails Pro License**:
21
+
22
+ - `packages/react-on-rails-pro/` (entire package)
23
+ - `packages/react-on-rails-pro-node-renderer/` (entire package)
24
+ - `react_on_rails_pro/` (entire directory)
25
+
26
+ See [REACT-ON-RAILS-PRO-LICENSE.md](./REACT-ON-RAILS-PRO-LICENSE.md) for complete Pro license terms.
27
+
28
+ **Important:** Pro-licensed code is included in this package but requires a valid React on Rails Pro subscription to use. Using Pro features without a valid license violates the React on Rails Pro License.
29
+
30
+ ---
31
+
32
+ ## MIT License
33
+
34
+ This license applies to all MIT-licensed code as defined above.
35
+
36
+ Copyright (c) 2017, 2018 Justin Gordon and ShakaCode
37
+ Copyright (c) 2015–2025 ShakaCode, LLC
38
+
39
+ Permission is hereby granted, free of charge, to any person obtaining a copy
40
+ of this software and associated documentation files (the "Software"), to deal
41
+ in the Software without restriction, including without limitation the rights
42
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
43
+ copies of the Software, and to permit persons to whom the Software is
44
+ furnished to do so, subject to the following conditions:
45
+
46
+ The above copyright notice and this permission notice shall be included in
47
+ all copies or substantial portions of the Software.
48
+
49
+ ---
50
+
51
+ ## Disclaimer
52
+
53
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
54
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
55
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
56
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
57
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
58
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
59
+ SOFTWARE.
60
+
61
+ ---
62
+
63
+ ## React on Rails Pro License
64
+
65
+ For Pro-licensed code (as defined in the "License Scope" section above), see:
66
+ [REACT-ON-RAILS-PRO-LICENSE.md](./REACT-ON-RAILS-PRO-LICENSE.md)
67
+
68
+ **Key Points:**
69
+
70
+ - Pro features require a valid React on Rails Pro subscription for production use
71
+ - Free use is permitted for educational, personal, and non-production purposes
72
+ - Modifying MIT-licensed interface files is permitted under MIT terms
73
+ - However, using those modifications to access Pro features without a valid license violates the Pro License
74
+
75
+ ### License Validation Mechanisms
76
+
77
+ **License validation mechanisms** include but are not limited to:
78
+
79
+ - Runtime checks for valid Pro subscriptions
80
+ - Authentication systems in `react_on_rails/lib/react_on_rails/utils.rb` and Pro TypeScript modules
81
+ - The `react_on_rails_pro?` method and `rorPro` field generation
82
+
83
+ While MIT-licensed code may be modified under MIT terms, using such modifications to access Pro features without a valid license violates the React on Rails Pro License.
@@ -1,6 +1,7 @@
1
1
  import * as React from 'react';
2
2
  /* eslint-disable import/prefer-default-export, no-underscore-dangle */
3
3
  const { createElement, useEffect, useRef } = React;
4
+ const sharedHydrationInitStates = new WeakMap();
4
5
  function extractDehydratedData(dehydratedRouter) {
5
6
  if (!dehydratedRouter || typeof dehydratedRouter !== 'object') {
6
7
  return undefined;
@@ -33,6 +34,77 @@ function preloadMatchedRouteChunks(router, matches) {
33
34
  console.error('react-on-rails-pro/tanstack-router: Error preloading matched route chunks:', error);
34
35
  });
35
36
  }
37
+ // Each guard repeats the matchRoutes check so TypeScript narrows correctly
38
+ // when either hydration path is used independently.
39
+ function hasLegacyHydrationStore(router) {
40
+ return typeof router.matchRoutes === 'function' && typeof router.__store?.setState === 'function';
41
+ }
42
+ function hasStoresHydrationApi(router) {
43
+ const { stores } = router;
44
+ return (typeof router.matchRoutes === 'function' &&
45
+ typeof stores?.status?.set === 'function' &&
46
+ typeof stores?.resolvedLocation?.set === 'function' &&
47
+ typeof stores?.setMatches === 'function');
48
+ }
49
+ function hasHydrationInternals(router) {
50
+ // The ordering here is load-bearing: legacy `__store` wins when both APIs
51
+ // are present, so routers exposing both during a TanStack upgrade keep
52
+ // taking the well-tested __store.setState path until the legacy API is
53
+ // removed. applyHydrationMatches mirrors this preference at the call site.
54
+ return hasLegacyHydrationStore(router) || hasStoresHydrationApi(router);
55
+ }
56
+ function throwMissingHydrationInternals() {
57
+ throw new Error('react-on-rails-pro/tanstack-router: router.matchRoutes() and router.__store.setState() or ' +
58
+ 'router.stores.setMatches() are required but not available. Ensure @tanstack/react-router ' +
59
+ '>=1.139.0 <2.0.0 is installed; older 1.x routers expose __store.setState(), while newer ' +
60
+ '1.x routers expose stores.setMatches().');
61
+ }
62
+ /**
63
+ * Apply server-rendered route matches to the router's internal hydration state.
64
+ *
65
+ * Precondition: callers must validate the router with `hasHydrationInternals(router)`
66
+ * before invoking this; the union parameter type encodes that contract so TypeScript
67
+ * enforces it at the call site.
68
+ */
69
+ function applyHydrationMatches(router, matches) {
70
+ if (hasLegacyHydrationStore(router)) {
71
+ router.__store.setState((s) => ({
72
+ ...s,
73
+ status: 'idle',
74
+ resolvedLocation: s.location,
75
+ matches,
76
+ }));
77
+ return;
78
+ }
79
+ // Legacy path didn't match, so the union narrows to TanStackRouterStoresHydrationInternals.
80
+ const applyStoresUpdate = () => {
81
+ router.stores.status.set('idle');
82
+ // The freshly-created router has not rendered or awaited work yet, so
83
+ // router.state.location matches the legacy __store updater's s.location.
84
+ // Invariant: router.update({ history }) does not mutate state.location synchronously;
85
+ // if that ever changes, this path and the legacy __store path diverge.
86
+ router.stores.resolvedLocation.set(router.state.location);
87
+ router.stores.setMatches(matches);
88
+ };
89
+ if (typeof router.batch === 'function') {
90
+ router.batch(applyStoresUpdate);
91
+ return;
92
+ }
93
+ // Without router.batch, the stores API cannot make these writes atomic like
94
+ // legacy __store.setState(); this render-phase update runs before
95
+ // RouterProvider subscribes, so hydration still starts from the final state.
96
+ // NOTE: correctness here depends on RouterProvider not subscribing to stores
97
+ // during synchronous render. Re-validate this path on TanStack Router major upgrades.
98
+ // In practice router.batch is present in the supported range (>=1.139.0), so this
99
+ // branch is a defensive belt-and-suspenders fallback rather than an expected runtime
100
+ // path — the dev warning below should not fire on a correctly pinned dependency.
101
+ if (process.env.NODE_ENV !== 'production') {
102
+ console.warn('react-on-rails-pro/tanstack-router: router.batch is unavailable; stores hydration writes ' +
103
+ 'are not atomic. Upgrade @tanstack/react-router to a version that exposes router.batch ' +
104
+ 'for safer hydration.');
105
+ }
106
+ applyStoresUpdate();
107
+ }
36
108
  /**
37
109
  * Converts a dehydrated match ID (using \0 separator) back to the standard
38
110
  * route ID format (using / separator) used by matchRoutes().
@@ -74,9 +146,7 @@ function applyDehydratedMatchData(matches, ssrMatches, onMissingSsrMatch) {
74
146
  return m;
75
147
  });
76
148
  }
77
- function TanStackHydrationApp({ options, incomingProps,
78
- // eslint-disable-next-line @typescript-eslint/no-unused-vars -- Required by TanStackHydrationAppProps interface.
79
- railsContext: _railsContext, RouterProvider, createBrowserHistory, }) {
149
+ function TanStackHydrationApp({ options, incomingProps, railsContext: _railsContext, RouterProvider, createBrowserHistory, }) {
80
150
  const dehydratedState = incomingProps.__tanstackRouterDehydratedState;
81
151
  const hasSsrPayload = dehydratedState != null;
82
152
  const hasDehydratedRouter = dehydratedState?.dehydratedRouter !== undefined && dehydratedState.dehydratedRouter !== null;
@@ -113,91 +183,122 @@ railsContext: _railsContext, RouterProvider, createBrowserHistory, }) {
113
183
  // block completes. If React discards this render (StrictMode/concurrency),
114
184
  // the discarded router instance is dropped and a fresh instance is created
115
185
  // and initialized on the next render.
186
+ //
187
+ // Cross-mount invariant: sharedHydrationInitStates dedupes per-router
188
+ // side effects (loadRouteChunk, __store.setState, options.hydrate) across
189
+ // React 18 StrictMode's double-render-with-fresh-hooks behavior — which
190
+ // resets useRef on each pass, so this `routerRef.current === null` guard
191
+ // alone fires twice when options.createRouter returns the same instance.
116
192
  const router = options.createRouter();
117
- // Set browser history for client-side navigation
118
- const browserHistory = createBrowserHistory();
119
- router.update({ history: browserHistory });
120
- // Only apply SSR hydration when a server payload exists.
121
- // Client-only renders (prerender: false) must not set router.ssr or
122
- // inject matches the Transitioner handles initial loading for those.
123
- if (hasSsrPayload) {
124
- if (process.env.NODE_ENV === 'development' && !didWarnPrivateInternalsRef.current) {
125
- didWarnPrivateInternalsRef.current = true;
126
- console.warn('react-on-rails-pro/tanstack-router: Hydration uses TanStack Router private internals ' +
127
- '(matchRoutes, __store, loadRouteChunk, looseRoutesById). Keep @tanstack/react-router ' +
128
- 'within the supported range (>=1.139.0 <2.0.0) and run integration tests when upgrading.');
129
- }
130
- // Validate internal APIs before using them.
131
- if (typeof router.matchRoutes !== 'function' || !router.__store?.setState) {
132
- throw new Error('react-on-rails-pro/tanstack-router: router.matchRoutes() and router.__store are required ' +
133
- 'but not available. Ensure @tanstack/react-router >=1.139.0 <2.0.0 is installed.');
134
- }
135
- const hydrationRouter = router;
136
- // Synchronously inject route matches to match server-rendered output.
137
- // The server fully loads routes (via router.load()) before rendering, so
138
- // all matches are resolved. We replicate this on the client so the initial
139
- // render produces the same component tree as the server HTML.
140
- //
141
- // When ssrRouter match data is available (from serverRenderTanStackAppAsync),
142
- // we apply loaderData, beforeLoadContext, status, etc. from the server payload
143
- // so routes that render from loader results can hydrate correctly.
144
- // Otherwise we override 'pending' to 'success' to prevent MatchInner from
145
- // throwing loadPromise (which would cause Suspense suspension).
146
- const rawMatches = hydrationRouter.matchRoutes(hydrationRouter.state.location);
147
- routeChunkPreloadPromiseRef.current = preloadMatchedRouteChunks(router, rawMatches);
148
- const ssrMatches = dehydratedState?.ssrRouter?.matches;
149
- const matches = ssrMatches?.length
150
- ? applyDehydratedMatchData(rawMatches, ssrMatches, warnMissingSsrMatch)
151
- : rawMatches.map((match) => {
152
- const m = match;
153
- if (m.status === 'pending') {
154
- warnMissingSsrMatch(m);
155
- return { ...m, status: 'success' };
156
- }
157
- return m;
158
- });
159
- // Render-phase store injection is required for hydration parity: this
160
- // must happen before the first RouterProvider render.
161
- hydrationRouter.__store.setState((s) => ({
162
- ...s,
163
- status: 'idle',
164
- resolvedLocation: s.location,
165
- matches,
166
- }));
167
- // Set SSR flag so the Transitioner skips its initial router.load() call,
168
- // preventing a state update during hydration that would cause a mismatch.
169
- // The shape matches TanStack Router's internal $_TSR hydration contract
170
- // (the Transitioner only checks truthiness).
171
- // Preserve user-set values from createRouter() (e.g. TanStack Start).
172
- if (!router.ssr) {
173
- router.ssr = { manifest: undefined };
174
- didSetSsrFlagRef.current = true;
193
+ const cachedInit = sharedHydrationInitStates.get(router);
194
+ if (cachedInit) {
195
+ // Same router instance was already initialized by a discarded render
196
+ // (or prior mount). Reattach the pending preload/hydrate promises to
197
+ // this mount's refs so the post-hydration effect awaits the original
198
+ // work; restore didSetSsrFlag so cleanup correctly clears router.ssr.
199
+ routeChunkPreloadPromiseRef.current = cachedInit.routeChunkPreloadPromise;
200
+ hydrationCallbackPromiseRef.current = cachedInit.hydrationCallbackPromise;
201
+ didSetSsrFlagRef.current = cachedInit.didSetSsrFlag;
202
+ }
203
+ else {
204
+ // Set browser history for client-side navigation
205
+ const browserHistory = createBrowserHistory();
206
+ // Snapshot state.location before router.update so the dev-mode assertion
207
+ // below can verify the equivalence the stores hydration path relies on
208
+ // (see applyHydrationMatches: router.stores.resolvedLocation.set
209
+ // assumes router.update does not mutate state.location synchronously).
210
+ const locationBeforeUpdate = process.env.NODE_ENV !== 'production' ? router.state.location : undefined;
211
+ router.update({ history: browserHistory });
212
+ if (process.env.NODE_ENV !== 'production' &&
213
+ hasStoresHydrationApi(router) &&
214
+ // Identity check only: an in-place mutation of the same location object
215
+ // would slip past this guard. The dev warning is best-effort.
216
+ router.state.location !== locationBeforeUpdate) {
217
+ console.warn('react-on-rails-pro/tanstack-router: router.update({ history }) mutated router.state.location ' +
218
+ 'synchronously. The stores hydration path writes router.state.location to ' +
219
+ 'router.stores.resolvedLocation, which would diverge from the legacy __store path that ' +
220
+ 'snapshots the pre-update s.location. File an issue with your @tanstack/react-router version.');
175
221
  }
176
- try {
177
- // Run user-defined hydration callback for custom dehydratedData
178
- // (for example external query/cache payloads), matching TanStack
179
- // Router's ssr-client behavior.
180
- if (typeof router.options?.hydrate === 'function') {
181
- const hydrationResult = router.options.hydrate(extractDehydratedData(dehydratedState?.dehydratedRouter));
182
- // Let async hydration failures reject so we do not continue into
183
- // router.load() with partially hydrated client state.
184
- hydrationCallbackPromiseRef.current = Promise.resolve(hydrationResult).then(() => undefined);
222
+ // Only apply SSR hydration when a server payload exists.
223
+ // Client-only renders (prerender: false) must not set router.ssr or
224
+ // inject matches the Transitioner handles initial loading for those.
225
+ if (hasSsrPayload) {
226
+ if (process.env.NODE_ENV === 'development' && !didWarnPrivateInternalsRef.current) {
227
+ didWarnPrivateInternalsRef.current = true;
228
+ console.warn('react-on-rails-pro/tanstack-router: Hydration uses TanStack Router private internals ' +
229
+ '(matchRoutes, __store/stores, loadRouteChunk, looseRoutesById). Keep @tanstack/react-router ' +
230
+ 'within the supported range (>=1.139.0 <2.0.0) and run integration tests when upgrading.');
185
231
  }
186
- // Backward-compatibility hook: if user router exposes router.hydrate(),
187
- // invoke it with the full dehydrated router payload.
188
- if (hasDehydratedRouter && typeof router.hydrate === 'function') {
189
- router.hydrate(dehydratedState.dehydratedRouter);
232
+ // Validate internal APIs before using them.
233
+ if (!hasHydrationInternals(router)) {
234
+ throwMissingHydrationInternals();
190
235
  }
191
- }
192
- catch (error) {
193
- // If render-phase hydration throws, clear only the temporary SSR flag
194
- // created by this module so retries are not blocked.
195
- if (didSetSsrFlagRef.current) {
196
- router.ssr = undefined;
197
- didSetSsrFlagRef.current = false;
236
+ // Synchronously inject route matches to match server-rendered output.
237
+ // The server fully loads routes (via router.load()) before rendering, so
238
+ // all matches are resolved. We replicate this on the client so the initial
239
+ // render produces the same component tree as the server HTML.
240
+ //
241
+ // When ssrRouter match data is available (from serverRenderTanStackAppAsync),
242
+ // we apply loaderData, beforeLoadContext, status, etc. from the server payload
243
+ // so routes that render from loader results can hydrate correctly.
244
+ // Otherwise we override 'pending' to 'success' to prevent MatchInner from
245
+ // throwing loadPromise (which would cause Suspense suspension).
246
+ const rawMatches = router.matchRoutes(router.state.location);
247
+ routeChunkPreloadPromiseRef.current = preloadMatchedRouteChunks(router, rawMatches);
248
+ const ssrMatches = dehydratedState?.ssrRouter?.matches;
249
+ const matches = ssrMatches?.length
250
+ ? applyDehydratedMatchData(rawMatches, ssrMatches, warnMissingSsrMatch)
251
+ : rawMatches.map((match) => {
252
+ const m = match;
253
+ if (m.status === 'pending') {
254
+ warnMissingSsrMatch(m);
255
+ return { ...m, status: 'success' };
256
+ }
257
+ return m;
258
+ });
259
+ // Render-phase store injection is required for hydration parity: this
260
+ // must happen before the first RouterProvider render.
261
+ applyHydrationMatches(router, matches);
262
+ // Set SSR flag so the Transitioner skips its initial router.load() call,
263
+ // preventing a state update during hydration that would cause a mismatch.
264
+ // The shape matches TanStack Router's internal $_TSR hydration contract
265
+ // (the Transitioner only checks truthiness).
266
+ // Preserve user-set values from createRouter() (e.g. TanStack Start).
267
+ if (!router.ssr) {
268
+ router.ssr = { manifest: undefined };
269
+ didSetSsrFlagRef.current = true;
270
+ }
271
+ try {
272
+ // Run user-defined hydration callback for custom dehydratedData
273
+ // (for example external query/cache payloads), matching TanStack
274
+ // Router's ssr-client behavior.
275
+ if (typeof router.options?.hydrate === 'function') {
276
+ const hydrationResult = router.options.hydrate(extractDehydratedData(dehydratedState?.dehydratedRouter));
277
+ // Let async hydration failures reject so we do not continue into
278
+ // router.load() with partially hydrated client state.
279
+ hydrationCallbackPromiseRef.current = Promise.resolve(hydrationResult).then(() => undefined);
280
+ }
281
+ // Backward-compatibility hook: if user router exposes router.hydrate(),
282
+ // invoke it with the full dehydrated router payload.
283
+ if (hasDehydratedRouter && typeof router.hydrate === 'function') {
284
+ router.hydrate(dehydratedState.dehydratedRouter);
285
+ }
286
+ }
287
+ catch (error) {
288
+ // If render-phase hydration throws, clear only the temporary SSR flag
289
+ // created by this module so retries are not blocked.
290
+ if (didSetSsrFlagRef.current) {
291
+ router.ssr = undefined;
292
+ didSetSsrFlagRef.current = false;
293
+ }
294
+ throw error;
198
295
  }
199
- throw error;
200
296
  }
297
+ sharedHydrationInitStates.set(router, {
298
+ routeChunkPreloadPromise: routeChunkPreloadPromiseRef.current,
299
+ hydrationCallbackPromise: hydrationCallbackPromiseRef.current,
300
+ didSetSsrFlag: didSetSsrFlagRef.current,
301
+ });
201
302
  }
202
303
  routerRef.current = router;
203
304
  }
@@ -267,6 +368,14 @@ railsContext: _railsContext, RouterProvider, createBrowserHistory, }) {
267
368
  if (latestEffectRunIdRef.current === effectRunId && didSetSsrFlagRef.current) {
268
369
  router.ssr = undefined;
269
370
  didSetSsrFlagRef.current = false;
371
+ // Keep sharedHydrationInitStates in sync so a later mount of the
372
+ // same cached router doesn't restore a stale didSetSsrFlag=true and
373
+ // trigger the dev sanity-check warning below on a router whose ssr
374
+ // flag was already cleared correctly.
375
+ const cached = sharedHydrationInitStates.get(router);
376
+ if (cached) {
377
+ cached.didSetSsrFlag = false;
378
+ }
270
379
  }
271
380
  });
272
381
  return () => {
@@ -278,6 +387,10 @@ railsContext: _railsContext, RouterProvider, createBrowserHistory, }) {
278
387
  if (latestEffectRunIdRef.current === effectRunId && didSetSsrFlagRef.current) {
279
388
  router.ssr = undefined;
280
389
  didSetSsrFlagRef.current = false;
390
+ const cached = sharedHydrationInitStates.get(router);
391
+ if (cached) {
392
+ cached.didSetSsrFlag = false;
393
+ }
281
394
  }
282
395
  });
283
396
  const cancellableRouter = router;
@@ -2,6 +2,14 @@ import { createElement } from 'react';
2
2
  import { normalizeSearch } from "./utils.js";
3
3
  /**
4
4
  * Builds a React element tree with RouterProvider and optional AppWrapper.
5
+ *
6
+ * No <Suspense> boundary is inserted here. The client hydration tree renders
7
+ * RouterProvider directly without a wrapping <Suspense>, so introducing one
8
+ * on the server would emit `<!--$-->`/`<!--/$-->` markers (React 19's
9
+ * `renderToString` emits these for every Suspense boundary, even
10
+ * non-suspended ones) and break hydration parity. If RouterProvider suspends
11
+ * during SSR, React's own `renderToString` throws synchronously — that is
12
+ * already a loud failure mode and does not need a custom guard.
5
13
  */
6
14
  function buildAppElement(router, RouterProvider, AppWrapper, wrapperProps) {
7
15
  let app = createElement(RouterProvider, { router });
@@ -1,4 +1,15 @@
1
1
  import type { ComponentType, ReactNode } from 'react';
2
+ /**
3
+ * Shape of a writable TanStack store atom. Used by the modern `router.stores`
4
+ * API exposed on TanStackRouter below.
5
+ *
6
+ * `set` is declared as an overload to match the upstream `@tanstack/store`
7
+ * `Atom.set` signature (which is an overload, not a union parameter); a union
8
+ * parameter would not be structurally assignable from the upstream type.
9
+ */
10
+ export type TanStackRouterWritableStore<TValue = unknown> = {
11
+ set: ((value: TValue) => void) & ((updater: (prev: TValue) => TValue) => void);
12
+ };
2
13
  /**
3
14
  * Minimal type for TanStack Router instance.
4
15
  * We use this instead of importing @tanstack/react-router directly
@@ -13,6 +24,12 @@ export interface TanStackRouter {
13
24
  __store?: {
14
25
  setState: (updater: (s: Record<string, unknown>) => Record<string, unknown>) => void;
15
26
  };
27
+ stores?: {
28
+ status: TanStackRouterWritableStore<'idle' | 'pending'>;
29
+ resolvedLocation: TanStackRouterWritableStore<TanStackRouter['state']['location']>;
30
+ setMatches: (nextMatches: unknown[]) => void;
31
+ };
32
+ batch?: (callback: () => void) => void;
16
33
  looseRoutesById?: Record<string, unknown>;
17
34
  loadRouteChunk?: (route: unknown) => Promise<unknown>;
18
35
  state: {
package/package.json CHANGED
@@ -1,20 +1,9 @@
1
1
  {
2
2
  "name": "react-on-rails-pro",
3
- "version": "16.7.0-rc.1",
3
+ "version": "16.7.0-rc.3",
4
4
  "description": "React on Rails Pro package with React Server Components support",
5
5
  "main": "lib/ReactOnRails.full.js",
6
6
  "type": "module",
7
- "scripts": {
8
- "build": "pnpm run clean && tsc",
9
- "build-watch": "pnpm run clean && tsc --watch",
10
- "clean": "rm -rf ./lib",
11
- "test": "pnpm run test:non-rsc && pnpm run test:rsc",
12
- "test:non-rsc": "jest tests --testPathIgnorePatterns=\".*(RSC|stream|registerServerComponent|serverRenderReactComponent|SuspenseHydration).*\"",
13
- "test:rsc": "node scripts/check-react-version.cjs || NODE_CONDITIONS=react-server jest tests/*.rsc.test.*",
14
- "type-check": "tsc --noEmit --noErrorTruncation",
15
- "prepare": "[ -f lib/ReactOnRails.full.js ] || (rm -rf ./lib && tsc)",
16
- "prepublishOnly": "pnpm run build"
17
- },
18
7
  "repository": {
19
8
  "type": "git",
20
9
  "url": "git+https://github.com/shakacode/react_on_rails.git",
@@ -59,7 +48,7 @@
59
48
  "./ServerComponentFetchError": "./lib/ServerComponentFetchError.js"
60
49
  },
61
50
  "dependencies": {
62
- "react-on-rails": "workspace:*"
51
+ "react-on-rails": "16.7.0-rc.3"
63
52
  },
64
53
  "peerDependencies": {
65
54
  "react": ">= 16",
@@ -85,10 +74,21 @@
85
74
  },
86
75
  "homepage": "https://reactonrails.com/docs/pro/",
87
76
  "devDependencies": {
77
+ "@tanstack/react-router": "1.163.3",
78
+ "@tanstack/store": "0.9.1",
88
79
  "@types/mock-fs": "^4.13.4",
89
80
  "mock-fs": "^5.5.0",
90
81
  "react": "^19.0.3",
91
82
  "react-dom": "^19.0.3",
92
83
  "react-on-rails-rsc": "^19.0.4"
84
+ },
85
+ "scripts": {
86
+ "build": "pnpm run clean && tsc",
87
+ "build-watch": "pnpm run clean && tsc --watch",
88
+ "clean": "rm -rf ./lib",
89
+ "test": "pnpm run test:non-rsc && pnpm run test:rsc",
90
+ "test:non-rsc": "jest tests --testPathIgnorePatterns=\".*(RSC|stream|registerServerComponent|serverRenderReactComponent|SuspenseHydration).*\"",
91
+ "test:rsc": "node scripts/check-react-version.cjs || NODE_CONDITIONS=react-server jest tests/*.rsc.test.*",
92
+ "type-check": "tsc --noEmit --noErrorTruncation"
93
93
  }
94
- }
94
+ }