rwsdk 1.0.0-beta.24-test.20251103154619 → 1.0.0-beta.26

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.
@@ -4,6 +4,39 @@ export { ClientOnly } from "./ClientOnly.js";
4
4
  export { initClientNavigation, navigate } from "./navigation.js";
5
5
  import type { HydrationOptions, Transport } from "./types";
6
6
  export declare const fetchTransport: Transport;
7
+ /**
8
+ * Initializes the React client and hydrates the RSC payload.
9
+ *
10
+ * This function sets up client-side hydration for React Server Components,
11
+ * making the page interactive. Call this from your client entry point.
12
+ *
13
+ * @param transport - Custom transport for server communication (defaults to fetchTransport)
14
+ * @param hydrateRootOptions - Options passed to React's hydrateRoot
15
+ * @param handleResponse - Custom response handler for navigation errors
16
+ *
17
+ * @example
18
+ * // Basic usage
19
+ * import { initClient } from "rwsdk/client";
20
+ *
21
+ * initClient();
22
+ *
23
+ * @example
24
+ * // With client-side navigation
25
+ * import { initClient, initClientNavigation } from "rwsdk/client";
26
+ *
27
+ * const { handleResponse } = initClientNavigation();
28
+ * initClient({ handleResponse });
29
+ *
30
+ * @example
31
+ * // With custom React hydration options
32
+ * initClient({
33
+ * hydrateRootOptions: {
34
+ * onRecoverableError: (error) => {
35
+ * console.warn("Recoverable error:", error);
36
+ * },
37
+ * },
38
+ * });
39
+ */
7
40
  export declare const initClient: ({ transport, hydrateRootOptions, handleResponse, }?: {
8
41
  transport?: Transport;
9
42
  hydrateRootOptions?: HydrationOptions;
@@ -50,6 +50,39 @@ export const fetchTransport = (transportContext) => {
50
50
  };
51
51
  return fetchCallServer;
52
52
  };
53
+ /**
54
+ * Initializes the React client and hydrates the RSC payload.
55
+ *
56
+ * This function sets up client-side hydration for React Server Components,
57
+ * making the page interactive. Call this from your client entry point.
58
+ *
59
+ * @param transport - Custom transport for server communication (defaults to fetchTransport)
60
+ * @param hydrateRootOptions - Options passed to React's hydrateRoot
61
+ * @param handleResponse - Custom response handler for navigation errors
62
+ *
63
+ * @example
64
+ * // Basic usage
65
+ * import { initClient } from "rwsdk/client";
66
+ *
67
+ * initClient();
68
+ *
69
+ * @example
70
+ * // With client-side navigation
71
+ * import { initClient, initClientNavigation } from "rwsdk/client";
72
+ *
73
+ * const { handleResponse } = initClientNavigation();
74
+ * initClient({ handleResponse });
75
+ *
76
+ * @example
77
+ * // With custom React hydration options
78
+ * initClient({
79
+ * hydrateRootOptions: {
80
+ * onRecoverableError: (error) => {
81
+ * console.warn("Recoverable error:", error);
82
+ * },
83
+ * },
84
+ * });
85
+ */
53
86
  export const initClient = async ({ transport = fetchTransport, hydrateRootOptions, handleResponse, } = {}) => {
54
87
  const transportContext = {
55
88
  setRscPayload: () => { },
@@ -12,6 +12,47 @@ export interface NavigateOptions {
12
12
  };
13
13
  }
14
14
  export declare function navigate(href: string, options?: NavigateOptions): Promise<void>;
15
+ /**
16
+ * Initializes client-side navigation for Single Page App (SPA) behavior.
17
+ *
18
+ * Intercepts clicks on internal links and fetches page content without full-page reloads.
19
+ * Returns a handleResponse function to pass to initClient.
20
+ *
21
+ * @param opts.scrollToTop - Scroll to top after navigation (default: true)
22
+ * @param opts.scrollBehavior - How to scroll: 'instant', 'smooth', or 'auto' (default: 'instant')
23
+ * @param opts.onNavigate - Callback executed after history push but before RSC fetch
24
+ *
25
+ * @example
26
+ * // Basic usage
27
+ * import { initClient, initClientNavigation } from "rwsdk/client";
28
+ *
29
+ * const { handleResponse } = initClientNavigation();
30
+ * initClient({ handleResponse });
31
+ *
32
+ * @example
33
+ * // With custom scroll behavior
34
+ * const { handleResponse } = initClientNavigation({
35
+ * scrollBehavior: "smooth",
36
+ * scrollToTop: true,
37
+ * });
38
+ * initClient({ handleResponse });
39
+ *
40
+ * @example
41
+ * // Preserve scroll position (e.g., for infinite scroll)
42
+ * const { handleResponse } = initClientNavigation({
43
+ * scrollToTop: false,
44
+ * });
45
+ * initClient({ handleResponse });
46
+ *
47
+ * @example
48
+ * // With navigation callback
49
+ * const { handleResponse } = initClientNavigation({
50
+ * onNavigate: () => {
51
+ * console.log("Navigating to:", window.location.href);
52
+ * },
53
+ * });
54
+ * initClient({ handleResponse });
55
+ */
15
56
  export declare function initClientNavigation(opts?: ClientNavigationOptions): {
16
57
  handleResponse: (response: Response) => boolean;
17
58
  };
@@ -64,6 +64,47 @@ function saveScrollPosition(x, y) {
64
64
  scrollY: y,
65
65
  }, "", window.location.href);
66
66
  }
67
+ /**
68
+ * Initializes client-side navigation for Single Page App (SPA) behavior.
69
+ *
70
+ * Intercepts clicks on internal links and fetches page content without full-page reloads.
71
+ * Returns a handleResponse function to pass to initClient.
72
+ *
73
+ * @param opts.scrollToTop - Scroll to top after navigation (default: true)
74
+ * @param opts.scrollBehavior - How to scroll: 'instant', 'smooth', or 'auto' (default: 'instant')
75
+ * @param opts.onNavigate - Callback executed after history push but before RSC fetch
76
+ *
77
+ * @example
78
+ * // Basic usage
79
+ * import { initClient, initClientNavigation } from "rwsdk/client";
80
+ *
81
+ * const { handleResponse } = initClientNavigation();
82
+ * initClient({ handleResponse });
83
+ *
84
+ * @example
85
+ * // With custom scroll behavior
86
+ * const { handleResponse } = initClientNavigation({
87
+ * scrollBehavior: "smooth",
88
+ * scrollToTop: true,
89
+ * });
90
+ * initClient({ handleResponse });
91
+ *
92
+ * @example
93
+ * // Preserve scroll position (e.g., for infinite scroll)
94
+ * const { handleResponse } = initClientNavigation({
95
+ * scrollToTop: false,
96
+ * });
97
+ * initClient({ handleResponse });
98
+ *
99
+ * @example
100
+ * // With navigation callback
101
+ * const { handleResponse } = initClientNavigation({
102
+ * onNavigate: () => {
103
+ * console.log("Navigating to:", window.location.href);
104
+ * },
105
+ * });
106
+ * initClient({ handleResponse });
107
+ */
67
108
  export function initClientNavigation(opts = {}) {
68
109
  IS_CLIENT_NAVIGATION = true;
69
110
  history.scrollRestoration = "auto";
@@ -1,5 +1,5 @@
1
1
  import { ColumnDefinitionNode, Expression, sql } from "kysely";
2
- type DefaultValueExpression = string | number | boolean | null | typeof sql;
2
+ type DefaultValueExpression = string | number | boolean | null | ReturnType<typeof sql>;
3
3
  export interface ColumnDefinitionBuilder<TType> {
4
4
  autoIncrement(): ColumnDefinitionBuilder<TType>;
5
5
  identity(): ColumnDefinitionBuilder<TType>;
@@ -1,3 +1,4 @@
1
+ import { sql } from "kysely";
1
2
  (_it = "createTable") => {
2
3
  const migrations = {
3
4
  "001_init": {
@@ -23,6 +24,7 @@
23
24
  .addColumn("username", "text", (col) => col.notNull())
24
25
  .addColumn("age", "integer", (col) => col.defaultTo(18))
25
26
  .addColumn("active", "boolean", (col) => col.defaultTo(true))
27
+ .addColumn("anotherBoolean", "boolean", (col) => col.defaultTo(sql `true`))
26
28
  .execute(),
27
29
  ];
28
30
  },
@@ -30,4 +32,3 @@
30
32
  };
31
33
  (_test) => { };
32
34
  };
33
- export {};
@@ -10,5 +10,23 @@ type ParseRoute<T extends string> = T extends `${infer Start}:${infer Param}/${i
10
10
  type LinkFunction<T extends readonly string[]> = {
11
11
  <Path extends T[number]>(path: Path, params?: ParseRoute<Path> extends Record<string, never> ? undefined : ParseRoute<Path>): string;
12
12
  };
13
+ /**
14
+ * Creates a type-safe link generation function from route patterns.
15
+ *
16
+ * @example
17
+ * // Define your routes
18
+ * const link = defineLinks([
19
+ * "/",
20
+ * "/about",
21
+ * "/users/:id",
22
+ * "/files/*",
23
+ * ] as const)
24
+ *
25
+ * // Generate links with type checking
26
+ * link("/") // "/"
27
+ * link("/about") // "/about"
28
+ * link("/users/:id", { id: "123" }) // "/users/123"
29
+ * link("/files/*", { $0: "docs/guide.pdf" }) // "/files/docs/guide.pdf"
30
+ */
13
31
  export declare function defineLinks<const T extends readonly string[]>(routes: T): LinkFunction<T>;
14
32
  export {};
@@ -1,3 +1,21 @@
1
+ /**
2
+ * Creates a type-safe link generation function from route patterns.
3
+ *
4
+ * @example
5
+ * // Define your routes
6
+ * const link = defineLinks([
7
+ * "/",
8
+ * "/about",
9
+ * "/users/:id",
10
+ * "/files/*",
11
+ * ] as const)
12
+ *
13
+ * // Generate links with type checking
14
+ * link("/") // "/"
15
+ * link("/about") // "/about"
16
+ * link("/users/:id", { id: "123" }) // "/users/123"
17
+ * link("/files/*", { $0: "docs/guide.pdf" }) // "/files/docs/guide.pdf"
18
+ */
1
19
  export function defineLinks(routes) {
2
20
  // Validate routes at runtime
3
21
  routes.forEach((route) => {
@@ -5,7 +5,7 @@ export type RouteMiddleware<T extends RequestInfo = RequestInfo> = (requestInfo:
5
5
  type RouteFunction<T extends RequestInfo = RequestInfo> = (requestInfo: T) => MaybePromise<Response>;
6
6
  type MaybePromise<T> = T | Promise<T>;
7
7
  type RouteComponent<T extends RequestInfo = RequestInfo> = (requestInfo: T) => MaybePromise<React.JSX.Element | Response | void>;
8
- type RouteHandler<T extends RequestInfo = RequestInfo> = RouteFunction<T> | RouteComponent<T> | [...RouteMiddleware<T>[], RouteFunction<T> | RouteComponent<T>];
8
+ type RouteHandler<T extends RequestInfo = RequestInfo> = RouteFunction<T> | RouteComponent<T> | readonly [...RouteMiddleware<T>[], RouteFunction<T> | RouteComponent<T>];
9
9
  declare const METHOD_VERBS: readonly ["delete", "get", "head", "patch", "post", "put"];
10
10
  export type MethodVerb = (typeof METHOD_VERBS)[number];
11
11
  export type MethodHandlers<T extends RequestInfo = RequestInfo> = {
@@ -37,18 +37,123 @@ export declare function defineRoutes<T extends RequestInfo = RequestInfo>(routes
37
37
  rscActionHandler: (request: Request) => Promise<unknown>;
38
38
  }) => Response | Promise<Response>;
39
39
  };
40
+ /**
41
+ * Defines a route handler for a path pattern.
42
+ *
43
+ * Supports three types of path patterns:
44
+ * - Static: /about, /contact
45
+ * - Parameters: /users/:id, /posts/:postId/edit
46
+ * - Wildcards: /files/*, /api/star/download
47
+ *
48
+ * @example
49
+ * // Static route
50
+ * route("/about", () => <AboutPage />)
51
+ *
52
+ * @example
53
+ * // Route with parameters
54
+ * route("/users/:id", ({ params }) => {
55
+ * return <UserProfile userId={params.id} />
56
+ * })
57
+ *
58
+ * @example
59
+ * // Route with wildcards
60
+ * route("/files/*", ({ params }) => {
61
+ * const filePath = params.$0
62
+ * return <FileViewer path={filePath} />
63
+ * })
64
+ *
65
+ * @example
66
+ * // Method-based routing
67
+ * route("/api/users", {
68
+ * get: () => Response.json(users),
69
+ * post: ({ request }) => Response.json({ status: "created" }, { status: 201 }),
70
+ * delete: () => new Response(null, { status: 204 }),
71
+ * })
72
+ *
73
+ * @example
74
+ * // Route with middleware array
75
+ * route("/admin", [isAuthenticated, isAdmin, () => <AdminDashboard />])
76
+ */
40
77
  export declare function route<T extends RequestInfo = RequestInfo>(path: string, handler: RouteHandler<T> | MethodHandlers<T>): RouteDefinition<T>;
78
+ /**
79
+ * Defines a route handler for the root path "/".
80
+ *
81
+ * @example
82
+ * // Homepage
83
+ * index(() => <HomePage />)
84
+ *
85
+ * @example
86
+ * // With middleware
87
+ * index([logRequest, () => <HomePage />])
88
+ */
41
89
  export declare function index<T extends RequestInfo = RequestInfo>(handler: RouteHandler<T>): RouteDefinition<T>;
90
+ /**
91
+ * Prefixes a group of routes with a path.
92
+ *
93
+ * @example
94
+ * // Organize blog routes under /blog
95
+ * const blogRoutes = [
96
+ * route("/", () => <BlogIndex />),
97
+ * route("/post/:id", ({ params }) => <BlogPost id={params.id} />),
98
+ * route("/admin", [isAuthenticated, () => <BlogAdmin />]),
99
+ * ]
100
+ *
101
+ * // In worker.tsx
102
+ * defineApp([
103
+ * render(Document, [
104
+ * route("/", () => <HomePage />),
105
+ * prefix("/blog", blogRoutes),
106
+ * ]),
107
+ * ])
108
+ */
42
109
  export declare function prefix<T extends RequestInfo = RequestInfo>(prefixPath: string, routes: Route<T>[]): Route<T>[];
43
110
  export declare const wrapHandlerToThrowResponses: <T extends RequestInfo = RequestInfo>(handler: RouteFunction<T> | RouteComponent<T>) => RouteHandler<T>;
111
+ /**
112
+ * Wraps routes with a layout component.
113
+ *
114
+ * @example
115
+ * // Define a layout component
116
+ * function BlogLayout({ children }: { children: React.ReactNode }) {
117
+ * return (
118
+ * <div>
119
+ * <nav>Blog Navigation</nav>
120
+ * <main>{children}</main>
121
+ * </div>
122
+ * )
123
+ * }
124
+ *
125
+ * // Apply layout to routes
126
+ * const blogRoutes = layout(BlogLayout, [
127
+ * route("/", () => <BlogIndex />),
128
+ * route("/post/:id", ({ params }) => <BlogPost id={params.id} />),
129
+ * ])
130
+ */
44
131
  export declare function layout<T extends RequestInfo = RequestInfo>(LayoutComponent: React.FC<LayoutProps<T>>, routes: Route<T>[]): Route<T>[];
45
- export declare function render<T extends RequestInfo = RequestInfo>(Document: React.FC<DocumentProps<T>>, routes: Route<T>[],
46
132
  /**
47
- * @param options - Configuration options for rendering.
133
+ * Wraps routes with a Document component and configures rendering options.
134
+ *
48
135
  * @param options.rscPayload - Toggle the RSC payload that's appended to the Document. Disabling this will mean that interactivity no longer works.
49
- * @param options.ssr - Disable sever side rendering for all these routes. This only allow client side rendering`, which requires `rscPayload` to be enabled.
136
+ * @param options.ssr - Disable sever side rendering for all these routes. This only allow client side rendering, which requires `rscPayload` to be enabled.
137
+ *
138
+ * @example
139
+ * // Basic usage
140
+ * defineApp([
141
+ * render(Document, [
142
+ * route("/", () => <HomePage />),
143
+ * route("/about", () => <AboutPage />),
144
+ * ]),
145
+ * ])
146
+ *
147
+ * @example
148
+ * // With custom rendering options
149
+ * render(Document, [
150
+ * route("/", () => <HomePage />),
151
+ * ], {
152
+ * rscPayload: true,
153
+ * ssr: true,
154
+ * })
50
155
  */
51
- options?: {
156
+ export declare function render<T extends RequestInfo = RequestInfo>(Document: React.FC<DocumentProps<T>>, routes: Route<T>[], options?: {
52
157
  rscPayload?: boolean;
53
158
  ssr?: boolean;
54
159
  }): Route<T>[];
@@ -221,6 +221,43 @@ export function defineRoutes(routes) {
221
221
  },
222
222
  };
223
223
  }
224
+ /**
225
+ * Defines a route handler for a path pattern.
226
+ *
227
+ * Supports three types of path patterns:
228
+ * - Static: /about, /contact
229
+ * - Parameters: /users/:id, /posts/:postId/edit
230
+ * - Wildcards: /files/*, /api/star/download
231
+ *
232
+ * @example
233
+ * // Static route
234
+ * route("/about", () => <AboutPage />)
235
+ *
236
+ * @example
237
+ * // Route with parameters
238
+ * route("/users/:id", ({ params }) => {
239
+ * return <UserProfile userId={params.id} />
240
+ * })
241
+ *
242
+ * @example
243
+ * // Route with wildcards
244
+ * route("/files/*", ({ params }) => {
245
+ * const filePath = params.$0
246
+ * return <FileViewer path={filePath} />
247
+ * })
248
+ *
249
+ * @example
250
+ * // Method-based routing
251
+ * route("/api/users", {
252
+ * get: () => Response.json(users),
253
+ * post: ({ request }) => Response.json({ status: "created" }, { status: 201 }),
254
+ * delete: () => new Response(null, { status: 204 }),
255
+ * })
256
+ *
257
+ * @example
258
+ * // Route with middleware array
259
+ * route("/admin", [isAuthenticated, isAdmin, () => <AdminDashboard />])
260
+ */
224
261
  export function route(path, handler) {
225
262
  if (!path.endsWith("/")) {
226
263
  path = path + "/";
@@ -240,9 +277,39 @@ export function route(path, handler) {
240
277
  handler,
241
278
  };
242
279
  }
280
+ /**
281
+ * Defines a route handler for the root path "/".
282
+ *
283
+ * @example
284
+ * // Homepage
285
+ * index(() => <HomePage />)
286
+ *
287
+ * @example
288
+ * // With middleware
289
+ * index([logRequest, () => <HomePage />])
290
+ */
243
291
  export function index(handler) {
244
292
  return route("/", handler);
245
293
  }
294
+ /**
295
+ * Prefixes a group of routes with a path.
296
+ *
297
+ * @example
298
+ * // Organize blog routes under /blog
299
+ * const blogRoutes = [
300
+ * route("/", () => <BlogIndex />),
301
+ * route("/post/:id", ({ params }) => <BlogPost id={params.id} />),
302
+ * route("/admin", [isAuthenticated, () => <BlogAdmin />]),
303
+ * ]
304
+ *
305
+ * // In worker.tsx
306
+ * defineApp([
307
+ * render(Document, [
308
+ * route("/", () => <HomePage />),
309
+ * prefix("/blog", blogRoutes),
310
+ * ]),
311
+ * ])
312
+ */
246
313
  export function prefix(prefixPath, routes) {
247
314
  return routes.map((r) => {
248
315
  if (typeof r === "function") {
@@ -308,6 +375,26 @@ export const wrapHandlerToThrowResponses = (handler) => {
308
375
  ComponentWrappedToThrowResponses.__rwsdk_route_component = true;
309
376
  return ComponentWrappedToThrowResponses;
310
377
  };
378
+ /**
379
+ * Wraps routes with a layout component.
380
+ *
381
+ * @example
382
+ * // Define a layout component
383
+ * function BlogLayout({ children }: { children: React.ReactNode }) {
384
+ * return (
385
+ * <div>
386
+ * <nav>Blog Navigation</nav>
387
+ * <main>{children}</main>
388
+ * </div>
389
+ * )
390
+ * }
391
+ *
392
+ * // Apply layout to routes
393
+ * const blogRoutes = layout(BlogLayout, [
394
+ * route("/", () => <BlogIndex />),
395
+ * route("/post/:id", ({ params }) => <BlogPost id={params.id} />),
396
+ * ])
397
+ */
311
398
  export function layout(LayoutComponent, routes) {
312
399
  // Attach layouts directly to route definitions
313
400
  return routes.map((route) => {
@@ -326,13 +413,31 @@ export function layout(LayoutComponent, routes) {
326
413
  };
327
414
  });
328
415
  }
329
- export function render(Document, routes,
330
416
  /**
331
- * @param options - Configuration options for rendering.
417
+ * Wraps routes with a Document component and configures rendering options.
418
+ *
332
419
  * @param options.rscPayload - Toggle the RSC payload that's appended to the Document. Disabling this will mean that interactivity no longer works.
333
- * @param options.ssr - Disable sever side rendering for all these routes. This only allow client side rendering`, which requires `rscPayload` to be enabled.
420
+ * @param options.ssr - Disable sever side rendering for all these routes. This only allow client side rendering, which requires `rscPayload` to be enabled.
421
+ *
422
+ * @example
423
+ * // Basic usage
424
+ * defineApp([
425
+ * render(Document, [
426
+ * route("/", () => <HomePage />),
427
+ * route("/about", () => <AboutPage />),
428
+ * ]),
429
+ * ])
430
+ *
431
+ * @example
432
+ * // With custom rendering options
433
+ * render(Document, [
434
+ * route("/", () => <HomePage />),
435
+ * ], {
436
+ * rscPayload: true,
437
+ * ssr: true,
438
+ * })
334
439
  */
335
- options = {}) {
440
+ export function render(Document, routes, options = {}) {
336
441
  options = {
337
442
  rscPayload: true,
338
443
  ssr: true,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "rwsdk",
3
- "version": "1.0.0-beta.24-test.20251103154619",
3
+ "version": "1.0.0-beta.26",
4
4
  "description": "Build fast, server-driven webapps on Cloudflare with SSR, RSC, and realtime",
5
5
  "type": "module",
6
6
  "bin": {