@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.
- package/README.md +19 -0
- package/package.json +131 -0
- package/src/__mocks__/version.ts +6 -0
- package/src/__tests__/route-definition.test.ts +63 -0
- package/src/browser/event-controller.ts +876 -0
- package/src/browser/index.ts +18 -0
- package/src/browser/link-interceptor.ts +121 -0
- package/src/browser/lru-cache.ts +69 -0
- package/src/browser/merge-segment-loaders.ts +126 -0
- package/src/browser/navigation-bridge.ts +891 -0
- package/src/browser/navigation-client.ts +155 -0
- package/src/browser/navigation-store.ts +823 -0
- package/src/browser/partial-update.ts +545 -0
- package/src/browser/react/Link.tsx +248 -0
- package/src/browser/react/NavigationProvider.tsx +228 -0
- package/src/browser/react/ScrollRestoration.tsx +94 -0
- package/src/browser/react/context.ts +53 -0
- package/src/browser/react/index.ts +52 -0
- package/src/browser/react/location-state-shared.ts +120 -0
- package/src/browser/react/location-state.ts +62 -0
- package/src/browser/react/use-action.ts +240 -0
- package/src/browser/react/use-client-cache.ts +56 -0
- package/src/browser/react/use-handle.ts +178 -0
- package/src/browser/react/use-link-status.ts +134 -0
- package/src/browser/react/use-navigation.ts +150 -0
- package/src/browser/react/use-segments.ts +188 -0
- package/src/browser/request-controller.ts +149 -0
- package/src/browser/rsc-router.tsx +310 -0
- package/src/browser/scroll-restoration.ts +324 -0
- package/src/browser/server-action-bridge.ts +747 -0
- package/src/browser/shallow.ts +35 -0
- package/src/browser/types.ts +443 -0
- package/src/cache/__tests__/memory-segment-store.test.ts +487 -0
- package/src/cache/__tests__/memory-store.test.ts +484 -0
- package/src/cache/cache-scope.ts +565 -0
- package/src/cache/cf/__tests__/cf-cache-store.test.ts +361 -0
- package/src/cache/cf/cf-cache-store.ts +274 -0
- package/src/cache/cf/index.ts +19 -0
- package/src/cache/index.ts +52 -0
- package/src/cache/memory-segment-store.ts +150 -0
- package/src/cache/memory-store.ts +253 -0
- package/src/cache/types.ts +366 -0
- package/src/client.rsc.tsx +88 -0
- package/src/client.tsx +609 -0
- package/src/components/DefaultDocument.tsx +20 -0
- package/src/default-error-boundary.tsx +88 -0
- package/src/deps/browser.ts +8 -0
- package/src/deps/html-stream-client.ts +2 -0
- package/src/deps/html-stream-server.ts +2 -0
- package/src/deps/rsc.ts +10 -0
- package/src/deps/ssr.ts +2 -0
- package/src/errors.ts +259 -0
- package/src/handle.ts +120 -0
- package/src/handles/MetaTags.tsx +178 -0
- package/src/handles/index.ts +6 -0
- package/src/handles/meta.ts +247 -0
- package/src/href-client.ts +128 -0
- package/src/href.ts +139 -0
- package/src/index.rsc.ts +69 -0
- package/src/index.ts +84 -0
- package/src/loader.rsc.ts +204 -0
- package/src/loader.ts +47 -0
- package/src/network-error-thrower.tsx +21 -0
- package/src/outlet-context.ts +15 -0
- package/src/root-error-boundary.tsx +277 -0
- package/src/route-content-wrapper.tsx +198 -0
- package/src/route-definition.ts +1333 -0
- package/src/route-map-builder.ts +140 -0
- package/src/route-types.ts +148 -0
- package/src/route-utils.ts +89 -0
- package/src/router/__tests__/match-context.test.ts +104 -0
- package/src/router/__tests__/match-pipelines.test.ts +537 -0
- package/src/router/__tests__/match-result.test.ts +566 -0
- package/src/router/__tests__/on-error.test.ts +935 -0
- package/src/router/__tests__/pattern-matching.test.ts +577 -0
- package/src/router/error-handling.ts +287 -0
- package/src/router/handler-context.ts +60 -0
- package/src/router/loader-resolution.ts +326 -0
- package/src/router/manifest.ts +116 -0
- package/src/router/match-context.ts +261 -0
- package/src/router/match-middleware/background-revalidation.ts +236 -0
- package/src/router/match-middleware/cache-lookup.ts +261 -0
- package/src/router/match-middleware/cache-store.ts +250 -0
- package/src/router/match-middleware/index.ts +81 -0
- package/src/router/match-middleware/intercept-resolution.ts +268 -0
- package/src/router/match-middleware/segment-resolution.ts +174 -0
- package/src/router/match-pipelines.ts +214 -0
- package/src/router/match-result.ts +212 -0
- package/src/router/metrics.ts +62 -0
- package/src/router/middleware.test.ts +1355 -0
- package/src/router/middleware.ts +748 -0
- package/src/router/pattern-matching.ts +271 -0
- package/src/router/revalidation.ts +190 -0
- package/src/router/router-context.ts +299 -0
- package/src/router/types.ts +96 -0
- package/src/router.ts +3484 -0
- package/src/rsc/__tests__/helpers.test.ts +175 -0
- package/src/rsc/handler.ts +942 -0
- package/src/rsc/helpers.ts +64 -0
- package/src/rsc/index.ts +56 -0
- package/src/rsc/nonce.ts +18 -0
- package/src/rsc/types.ts +225 -0
- package/src/segment-system.tsx +405 -0
- package/src/server/__tests__/request-context.test.ts +171 -0
- package/src/server/context.ts +340 -0
- package/src/server/handle-store.ts +230 -0
- package/src/server/loader-registry.ts +174 -0
- package/src/server/request-context.ts +470 -0
- package/src/server/root-layout.tsx +10 -0
- package/src/server/tsconfig.json +14 -0
- package/src/server.ts +126 -0
- package/src/ssr/__tests__/ssr-handler.test.tsx +188 -0
- package/src/ssr/index.tsx +215 -0
- package/src/types.ts +1473 -0
- package/src/use-loader.tsx +346 -0
- package/src/vite/__tests__/expose-loader-id.test.ts +117 -0
- package/src/vite/expose-action-id.ts +344 -0
- package/src/vite/expose-handle-id.ts +209 -0
- package/src/vite/expose-loader-id.ts +357 -0
- package/src/vite/expose-location-state-id.ts +177 -0
- package/src/vite/index.ts +608 -0
- package/src/vite/version.d.ts +12 -0
- package/src/vite/virtual-entries.ts +109 -0
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shallow comparison utility for selector optimization
|
|
3
|
+
*
|
|
4
|
+
* Used by useNavigation hook to prevent unnecessary re-renders
|
|
5
|
+
* when the selected value hasn't changed.
|
|
6
|
+
*
|
|
7
|
+
* @param a - First value
|
|
8
|
+
* @param b - Second value
|
|
9
|
+
* @returns true if values are shallowly equal
|
|
10
|
+
*/
|
|
11
|
+
export function shallow<T>(a: T, b: T): boolean {
|
|
12
|
+
// Same reference or primitive equality
|
|
13
|
+
if (Object.is(a, b)) return true;
|
|
14
|
+
|
|
15
|
+
// Different types or non-objects
|
|
16
|
+
if (typeof a !== "object" || typeof b !== "object") return false;
|
|
17
|
+
|
|
18
|
+
// Null checks
|
|
19
|
+
if (a === null || b === null) return false;
|
|
20
|
+
|
|
21
|
+
// Compare object keys
|
|
22
|
+
const keysA = Object.keys(a);
|
|
23
|
+
const keysB = Object.keys(b);
|
|
24
|
+
|
|
25
|
+
if (keysA.length !== keysB.length) return false;
|
|
26
|
+
|
|
27
|
+
// Check each key's value with Object.is
|
|
28
|
+
for (const key of keysA) {
|
|
29
|
+
if (!Object.is((a as Record<string, unknown>)[key], (b as Record<string, unknown>)[key])) {
|
|
30
|
+
return false;
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
return true;
|
|
35
|
+
}
|
|
@@ -0,0 +1,443 @@
|
|
|
1
|
+
import type { ReactNode, ComponentType } from "react";
|
|
2
|
+
import type { ResolvedSegment, SlotState } from "../types.js";
|
|
3
|
+
import type { RenderSegmentsOptions } from "../segment-system.js";
|
|
4
|
+
|
|
5
|
+
// ============================================================================
|
|
6
|
+
// RSC Payload Types
|
|
7
|
+
// ============================================================================
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* RSC payload received from server
|
|
11
|
+
*/
|
|
12
|
+
export interface RscPayload<TMetadata = RscMetadata> {
|
|
13
|
+
root: ReactNode | Promise<ReactNode> | null;
|
|
14
|
+
metadata?: TMetadata;
|
|
15
|
+
returnValue?: ActionResult;
|
|
16
|
+
formState?: unknown;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Handle data structure: handleName -> segmentId -> entries[]
|
|
21
|
+
*/
|
|
22
|
+
export type HandleData = Record<string, Record<string, unknown[]>>;
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Metadata included in RSC responses
|
|
26
|
+
*/
|
|
27
|
+
export interface RscMetadata {
|
|
28
|
+
pathname: string;
|
|
29
|
+
segments: ResolvedSegment[];
|
|
30
|
+
isPartial?: boolean;
|
|
31
|
+
isError?: boolean;
|
|
32
|
+
matched?: string[];
|
|
33
|
+
diff?: string[];
|
|
34
|
+
/**
|
|
35
|
+
* State of named slots for this route match
|
|
36
|
+
* Key is slot name (e.g., "@modal"), value is slot state
|
|
37
|
+
* Slots are used for intercepting routes during soft navigation
|
|
38
|
+
*/
|
|
39
|
+
slots?: Record<string, SlotState>;
|
|
40
|
+
/** Root layout component for browser-side re-renders */
|
|
41
|
+
rootLayout?: ComponentType<{ children: ReactNode }>;
|
|
42
|
+
/** Handle data accumulated across route segments (async generator that yields on each push) */
|
|
43
|
+
handles?: AsyncGenerator<HandleData, void, unknown>;
|
|
44
|
+
/** Cached handle data (for back/forward navigation from cache) */
|
|
45
|
+
cachedHandleData?: HandleData;
|
|
46
|
+
/**
|
|
47
|
+
* RSC version string from the server.
|
|
48
|
+
* Used to detect version mismatches after HMR/deployment.
|
|
49
|
+
*/
|
|
50
|
+
version?: string;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* Result from server action execution
|
|
55
|
+
*/
|
|
56
|
+
export interface ActionResult {
|
|
57
|
+
ok: boolean;
|
|
58
|
+
data: unknown;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
// ============================================================================
|
|
62
|
+
// Navigation State Types
|
|
63
|
+
// ============================================================================
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* Location object representing current URL
|
|
67
|
+
* Uses URL for full URL parsing (origin, host, hostname, port, protocol, searchParams, etc.)
|
|
68
|
+
*/
|
|
69
|
+
export type NavigationLocation = URL;
|
|
70
|
+
|
|
71
|
+
/**
|
|
72
|
+
* Inflight server action being tracked
|
|
73
|
+
*/
|
|
74
|
+
export interface InflightAction {
|
|
75
|
+
/** Unique identifier for this action invocation */
|
|
76
|
+
id: string;
|
|
77
|
+
/** Server action function ID */
|
|
78
|
+
actionId: string;
|
|
79
|
+
/** Action arguments */
|
|
80
|
+
payload: unknown[];
|
|
81
|
+
/** Timestamp when action started */
|
|
82
|
+
startedAt: number;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
/**
|
|
86
|
+
* Internal navigation state (includes inflight actions for store use)
|
|
87
|
+
*/
|
|
88
|
+
export interface NavigationState {
|
|
89
|
+
/** Navigation lifecycle state (idle or loading during navigation) */
|
|
90
|
+
state: "idle" | "loading";
|
|
91
|
+
|
|
92
|
+
/** Whether RSC data is currently streaming (initial load or navigation) */
|
|
93
|
+
isStreaming: boolean;
|
|
94
|
+
|
|
95
|
+
/** Current location (updated optimistically) */
|
|
96
|
+
location: NavigationLocation;
|
|
97
|
+
|
|
98
|
+
/** URL being navigated to (null when idle) */
|
|
99
|
+
pendingUrl: string | null;
|
|
100
|
+
|
|
101
|
+
/** List of inflight server actions (internal use only) */
|
|
102
|
+
inflightActions: InflightAction[];
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
/**
|
|
106
|
+
* Public navigation state exposed via useNavigation hook
|
|
107
|
+
* Excludes internal properties like inflightActions
|
|
108
|
+
*/
|
|
109
|
+
export type PublicNavigationState = Omit<NavigationState, "inflightActions">;
|
|
110
|
+
|
|
111
|
+
// ============================================================================
|
|
112
|
+
// Action State Types (for useAction hook)
|
|
113
|
+
// ============================================================================
|
|
114
|
+
|
|
115
|
+
/**
|
|
116
|
+
* Action lifecycle state
|
|
117
|
+
*/
|
|
118
|
+
export type ActionLifecycleState = "idle" | "loading" | "streaming";
|
|
119
|
+
|
|
120
|
+
/**
|
|
121
|
+
* State for a tracked server action
|
|
122
|
+
* Used by useAction hook to observe action lifecycle
|
|
123
|
+
*/
|
|
124
|
+
export interface TrackedActionState {
|
|
125
|
+
/** Current lifecycle state of the action */
|
|
126
|
+
state: ActionLifecycleState;
|
|
127
|
+
|
|
128
|
+
/** Server action function ID (e.g., "addToCart") */
|
|
129
|
+
actionId: string | null;
|
|
130
|
+
|
|
131
|
+
/** Action arguments (array for JSON, FormData for form submissions) */
|
|
132
|
+
payload: unknown[] | FormData | null;
|
|
133
|
+
|
|
134
|
+
/** Error if action failed */
|
|
135
|
+
error: unknown | null;
|
|
136
|
+
|
|
137
|
+
/** Result data from the action (preserved after completion) */
|
|
138
|
+
result: unknown | null;
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
/**
|
|
142
|
+
* Listener for action state changes
|
|
143
|
+
*/
|
|
144
|
+
export type ActionStateListener = (state: TrackedActionState) => void;
|
|
145
|
+
|
|
146
|
+
/**
|
|
147
|
+
* Cache interface for storing segments
|
|
148
|
+
* Compatible with both Map and LRUCache
|
|
149
|
+
*/
|
|
150
|
+
export interface SegmentCache {
|
|
151
|
+
get(key: string): ResolvedSegment | undefined;
|
|
152
|
+
set(key: string, value: ResolvedSegment): void;
|
|
153
|
+
has(key: string): boolean;
|
|
154
|
+
delete(key: string): boolean;
|
|
155
|
+
keys(): IterableIterator<string>;
|
|
156
|
+
readonly size: number;
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
/**
|
|
160
|
+
* Internal segment state managed by the store
|
|
161
|
+
*/
|
|
162
|
+
export interface SegmentState {
|
|
163
|
+
path: string;
|
|
164
|
+
currentUrl: string;
|
|
165
|
+
currentSegmentIds: string[];
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
/**
|
|
169
|
+
* Navigation update emitted when UI should re-render
|
|
170
|
+
*/
|
|
171
|
+
export interface NavigationUpdate {
|
|
172
|
+
root: ReactNode | Promise<ReactNode>;
|
|
173
|
+
metadata: RscMetadata;
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
/**
|
|
177
|
+
* State value for navigate/Link
|
|
178
|
+
* - LocationStateEntry[]: Type-safe state entries (recommended)
|
|
179
|
+
* - unknown: Legacy format for backwards compatibility
|
|
180
|
+
*/
|
|
181
|
+
export type HistoryState = import("./react/location-state-shared.js").LocationStateEntry[] | unknown;
|
|
182
|
+
|
|
183
|
+
/**
|
|
184
|
+
* Options for navigation operations
|
|
185
|
+
*/
|
|
186
|
+
export interface NavigateOptions {
|
|
187
|
+
replace?: boolean;
|
|
188
|
+
scroll?: boolean;
|
|
189
|
+
/**
|
|
190
|
+
* State to pass to history.pushState/replaceState
|
|
191
|
+
* Accessible via useLocationState() hook.
|
|
192
|
+
*
|
|
193
|
+
* @example
|
|
194
|
+
* ```tsx
|
|
195
|
+
* // Type-safe state (recommended)
|
|
196
|
+
* const ProductState = createLocationState<{ name: string }>("product");
|
|
197
|
+
* navigate("/product/123", { state: [ProductState({ name: "Widget" })] });
|
|
198
|
+
*
|
|
199
|
+
* // Multiple states
|
|
200
|
+
* navigate("/checkout", { state: [ProductState(p), CartState(c)] });
|
|
201
|
+
*
|
|
202
|
+
* // Legacy format (backwards compatible)
|
|
203
|
+
* navigate("/product", { state: { from: "list" } });
|
|
204
|
+
* ```
|
|
205
|
+
*/
|
|
206
|
+
state?: HistoryState;
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
// ============================================================================
|
|
210
|
+
// RSC Browser Dependencies
|
|
211
|
+
// ============================================================================
|
|
212
|
+
|
|
213
|
+
/**
|
|
214
|
+
* RSC runtime functions from @vitejs/plugin-rsc/browser
|
|
215
|
+
*
|
|
216
|
+
* These are injected as dependencies to avoid direct coupling
|
|
217
|
+
* to the RSC runtime implementation.
|
|
218
|
+
*/
|
|
219
|
+
export interface RscBrowserDependencies {
|
|
220
|
+
createFromFetch: <T>(
|
|
221
|
+
response: Promise<Response>,
|
|
222
|
+
options?: { temporaryReferences?: any }
|
|
223
|
+
) => Promise<T>;
|
|
224
|
+
createFromReadableStream: <T>(stream: ReadableStream) => Promise<T>;
|
|
225
|
+
encodeReply: (
|
|
226
|
+
args: any[],
|
|
227
|
+
options?: { temporaryReferences?: any }
|
|
228
|
+
) => Promise<FormData | string>;
|
|
229
|
+
setServerCallback: (
|
|
230
|
+
callback: (id: string, args: any[]) => Promise<any>
|
|
231
|
+
) => void;
|
|
232
|
+
createTemporaryReferenceSet: () => any;
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
// ============================================================================
|
|
236
|
+
// Store Types
|
|
237
|
+
// ============================================================================
|
|
238
|
+
|
|
239
|
+
/**
|
|
240
|
+
* Update subscriber callback for UI updates
|
|
241
|
+
*/
|
|
242
|
+
export type UpdateSubscriber = (update: NavigationUpdate) => void;
|
|
243
|
+
|
|
244
|
+
/**
|
|
245
|
+
* State change listener for useNavigation hook subscriptions
|
|
246
|
+
*/
|
|
247
|
+
export type StateListener = () => void;
|
|
248
|
+
|
|
249
|
+
/**
|
|
250
|
+
* Navigation store interface
|
|
251
|
+
*
|
|
252
|
+
* Manages both:
|
|
253
|
+
* - NavigationState: Public state exposed via useNavigation hook
|
|
254
|
+
* - SegmentState: Internal segment management for partial updates
|
|
255
|
+
*/
|
|
256
|
+
export interface NavigationStore {
|
|
257
|
+
// Public state (for useNavigation hook)
|
|
258
|
+
getState(): NavigationState;
|
|
259
|
+
setState(partial: Partial<NavigationState>): void;
|
|
260
|
+
subscribe(listener: StateListener): () => void;
|
|
261
|
+
|
|
262
|
+
// Inflight action management
|
|
263
|
+
addInflightAction(action: InflightAction): void;
|
|
264
|
+
removeInflightAction(id: string): void;
|
|
265
|
+
|
|
266
|
+
// Action state (for controlling update behavior during server actions)
|
|
267
|
+
isActionInProgress(): boolean;
|
|
268
|
+
setActionInProgress(value: boolean): void;
|
|
269
|
+
|
|
270
|
+
// Internal segment state (for bridges)
|
|
271
|
+
getSegmentState(): SegmentState;
|
|
272
|
+
setPath(path: string): void;
|
|
273
|
+
setCurrentUrl(url: string): void;
|
|
274
|
+
setSegmentIds(ids: string[]): void;
|
|
275
|
+
|
|
276
|
+
// History-based segment cache (for back/forward navigation and partial merging)
|
|
277
|
+
getHistoryKey(): string;
|
|
278
|
+
setHistoryKey(key: string): void;
|
|
279
|
+
cacheSegmentsForHistory(
|
|
280
|
+
historyKey: string,
|
|
281
|
+
segments: ResolvedSegment[],
|
|
282
|
+
handleData?: HandleData
|
|
283
|
+
): void;
|
|
284
|
+
getCachedSegments(
|
|
285
|
+
historyKey: string
|
|
286
|
+
): { segments: ResolvedSegment[]; stale: boolean; handleData?: HandleData } | undefined;
|
|
287
|
+
hasHistoryCache(historyKey: string): boolean;
|
|
288
|
+
updateCacheHandleData(historyKey: string, handleData: HandleData): void;
|
|
289
|
+
markCacheAsStale(): void;
|
|
290
|
+
markCacheAsStaleAndBroadcast(): void;
|
|
291
|
+
clearHistoryCache(): void;
|
|
292
|
+
broadcastCacheInvalidation(): void;
|
|
293
|
+
|
|
294
|
+
// Cross-tab refresh callback (set by navigation bridge)
|
|
295
|
+
setCrossTabRefreshCallback(callback: () => void): void;
|
|
296
|
+
|
|
297
|
+
// Intercept context tracking (for action revalidation)
|
|
298
|
+
getInterceptSourceUrl(): string | null;
|
|
299
|
+
setInterceptSourceUrl(url: string | null): void;
|
|
300
|
+
|
|
301
|
+
// UI update notifications
|
|
302
|
+
onUpdate(callback: UpdateSubscriber): () => void;
|
|
303
|
+
emitUpdate(update: NavigationUpdate): void;
|
|
304
|
+
|
|
305
|
+
// Action state tracking (for useAction hook)
|
|
306
|
+
getActionState(actionId: string): TrackedActionState;
|
|
307
|
+
setActionState(actionId: string, state: Partial<TrackedActionState>): void;
|
|
308
|
+
subscribeToAction(
|
|
309
|
+
actionId: string,
|
|
310
|
+
listener: ActionStateListener
|
|
311
|
+
): () => void;
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
// ============================================================================
|
|
315
|
+
// Request Controller Types
|
|
316
|
+
// ============================================================================
|
|
317
|
+
|
|
318
|
+
/**
|
|
319
|
+
* Disposable abort controller with automatic cleanup
|
|
320
|
+
*/
|
|
321
|
+
export interface DisposableAbortController extends Disposable {
|
|
322
|
+
controller: AbortController;
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
/**
|
|
326
|
+
* Request controller for managing concurrent requests
|
|
327
|
+
*
|
|
328
|
+
* Separates navigation requests (aborted on new navigation) from
|
|
329
|
+
* action requests (complete independently of navigation).
|
|
330
|
+
*/
|
|
331
|
+
export interface RequestController {
|
|
332
|
+
create(): AbortController;
|
|
333
|
+
createDisposable(): DisposableAbortController;
|
|
334
|
+
/** Create a disposable controller for actions (not aborted by navigation) */
|
|
335
|
+
createActionDisposable(): DisposableAbortController;
|
|
336
|
+
/** Abort all navigation requests (not actions) */
|
|
337
|
+
abortAll(): void;
|
|
338
|
+
/** Abort all action requests (used for error handling) */
|
|
339
|
+
abortAllActions(): void;
|
|
340
|
+
remove(controller: AbortController): void;
|
|
341
|
+
}
|
|
342
|
+
|
|
343
|
+
// ============================================================================
|
|
344
|
+
// Navigation Client Types
|
|
345
|
+
// ============================================================================
|
|
346
|
+
|
|
347
|
+
/**
|
|
348
|
+
* Options for partial navigation fetch
|
|
349
|
+
*/
|
|
350
|
+
export interface FetchPartialOptions {
|
|
351
|
+
targetUrl: string;
|
|
352
|
+
segmentIds: string[];
|
|
353
|
+
previousUrl: string;
|
|
354
|
+
signal?: AbortSignal;
|
|
355
|
+
/** If true, this is a stale cache revalidation request - server should force revalidators */
|
|
356
|
+
staleRevalidation?: boolean;
|
|
357
|
+
interceptSourceUrl?: string;
|
|
358
|
+
/** RSC version for cache invalidation detection */
|
|
359
|
+
version?: string;
|
|
360
|
+
}
|
|
361
|
+
|
|
362
|
+
/**
|
|
363
|
+
* Result of a partial fetch including stream completion tracking
|
|
364
|
+
*/
|
|
365
|
+
export interface FetchPartialResult {
|
|
366
|
+
payload: RscPayload;
|
|
367
|
+
/** Promise that resolves when the response stream is fully consumed */
|
|
368
|
+
streamComplete: Promise<void>;
|
|
369
|
+
}
|
|
370
|
+
|
|
371
|
+
/**
|
|
372
|
+
* Navigation client for fetching RSC payloads
|
|
373
|
+
*/
|
|
374
|
+
export interface NavigationClient {
|
|
375
|
+
fetchPartial(options: FetchPartialOptions): Promise<FetchPartialResult>;
|
|
376
|
+
}
|
|
377
|
+
|
|
378
|
+
// ============================================================================
|
|
379
|
+
// Link Interceptor Types
|
|
380
|
+
// ============================================================================
|
|
381
|
+
|
|
382
|
+
/**
|
|
383
|
+
* Options for link interception
|
|
384
|
+
*/
|
|
385
|
+
export interface LinkInterceptorOptions {
|
|
386
|
+
shouldIntercept?: (link: HTMLAnchorElement) => boolean;
|
|
387
|
+
}
|
|
388
|
+
|
|
389
|
+
// ============================================================================
|
|
390
|
+
// Server Action Bridge Types
|
|
391
|
+
// ============================================================================
|
|
392
|
+
|
|
393
|
+
/**
|
|
394
|
+
* Server action bridge for handling server actions
|
|
395
|
+
*/
|
|
396
|
+
export interface ServerActionBridge {
|
|
397
|
+
register(): void;
|
|
398
|
+
unregister(): void;
|
|
399
|
+
}
|
|
400
|
+
|
|
401
|
+
/**
|
|
402
|
+
* Configuration for server action bridge
|
|
403
|
+
*/
|
|
404
|
+
export interface ServerActionBridgeConfig {
|
|
405
|
+
store: NavigationStore;
|
|
406
|
+
client: NavigationClient;
|
|
407
|
+
deps: RscBrowserDependencies;
|
|
408
|
+
onUpdate: UpdateSubscriber;
|
|
409
|
+
renderSegments: (
|
|
410
|
+
segments: ResolvedSegment[],
|
|
411
|
+
options?: RenderSegmentsOptions
|
|
412
|
+
) => Promise<ReactNode> | ReactNode;
|
|
413
|
+
}
|
|
414
|
+
|
|
415
|
+
// ============================================================================
|
|
416
|
+
// Navigation Bridge Types
|
|
417
|
+
// ============================================================================
|
|
418
|
+
|
|
419
|
+
/**
|
|
420
|
+
* Navigation bridge for handling client-side navigation
|
|
421
|
+
*/
|
|
422
|
+
export interface NavigationBridge {
|
|
423
|
+
navigate(url: string, options?: NavigateOptions): Promise<void>;
|
|
424
|
+
refresh(): Promise<void>;
|
|
425
|
+
handlePopstate(): Promise<void>;
|
|
426
|
+
registerLinkInterception(): () => void;
|
|
427
|
+
}
|
|
428
|
+
|
|
429
|
+
/**
|
|
430
|
+
* Configuration for navigation bridge
|
|
431
|
+
*/
|
|
432
|
+
export interface NavigationBridgeConfig {
|
|
433
|
+
store: NavigationStore;
|
|
434
|
+
client: NavigationClient;
|
|
435
|
+
onUpdate: UpdateSubscriber;
|
|
436
|
+
renderSegments: (
|
|
437
|
+
segments: ResolvedSegment[],
|
|
438
|
+
options?: RenderSegmentsOptions
|
|
439
|
+
) => Promise<ReactNode> | ReactNode;
|
|
440
|
+
}
|
|
441
|
+
|
|
442
|
+
// Re-export ResolvedSegment for convenience
|
|
443
|
+
export type { ResolvedSegment };
|