rwsdk 1.0.0-beta.27-test.20251116215153 → 1.0.0-beta.29

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 (30) hide show
  1. package/dist/lib/e2e/environment.mjs +6 -1
  2. package/dist/lib/e2e/release.d.mts +1 -0
  3. package/dist/lib/e2e/release.mjs +16 -3
  4. package/dist/lib/e2e/tarball.mjs +3 -10
  5. package/dist/lib/e2e/testHarness.mjs +6 -3
  6. package/dist/runtime/lib/db/typeInference/builders/alterTable.d.ts +13 -3
  7. package/dist/runtime/lib/db/typeInference/builders/columnDefinition.d.ts +34 -20
  8. package/dist/runtime/lib/db/typeInference/builders/createTable.d.ts +9 -2
  9. package/dist/runtime/lib/db/typeInference/database.d.ts +16 -2
  10. package/dist/runtime/lib/db/typeInference/typetests/alterTable.typetest.js +80 -5
  11. package/dist/runtime/lib/db/typeInference/typetests/createTable.typetest.js +102 -1
  12. package/dist/runtime/lib/db/typeInference/typetests/testUtils.d.ts +1 -0
  13. package/dist/runtime/lib/db/typeInference/utils.d.ts +59 -9
  14. package/dist/runtime/lib/links.d.ts +18 -25
  15. package/dist/runtime/lib/links.js +70 -42
  16. package/dist/runtime/lib/links.test.d.ts +1 -0
  17. package/dist/runtime/lib/links.test.js +20 -0
  18. package/dist/runtime/lib/realtime/worker.d.ts +1 -1
  19. package/dist/runtime/lib/router.d.ts +23 -9
  20. package/dist/runtime/lib/router.js +14 -36
  21. package/dist/runtime/lib/stitchDocumentAndAppStreams.d.ts +66 -0
  22. package/dist/runtime/lib/stitchDocumentAndAppStreams.js +167 -28
  23. package/dist/runtime/lib/stitchDocumentAndAppStreams.test.js +43 -9
  24. package/dist/runtime/worker.d.ts +3 -1
  25. package/dist/runtime/worker.js +1 -0
  26. package/dist/use-synced-state/worker.d.mts +1 -1
  27. package/dist/vite/constants.d.mts +1 -0
  28. package/dist/vite/constants.mjs +1 -0
  29. package/dist/vite/ssrBridgePlugin.mjs +9 -0
  30. package/package.json +2 -2
@@ -1,32 +1,25 @@
1
- type ParseRoute<T extends string> = T extends `${infer Start}:${infer Param}/${infer Rest}` ? {
1
+ import type { RouteDefinition, RouteMiddleware } from "./router";
2
+ type PathParams<Path extends string> = Path extends `${string}:${infer Param}/${infer Rest}` ? {
2
3
  [K in Param]: string;
3
- } & ParseRoute<Rest> : T extends `${infer Start}:${infer Param}` ? {
4
+ } & PathParams<Rest> : Path extends `${string}:${infer Param}` ? {
4
5
  [K in Param]: string;
5
- } : T extends `${infer Start}*${infer Rest}` ? {
6
+ } : Path extends `${string}*${infer Rest}` ? {
6
7
  $0: string;
7
- } & ParseRoute<Rest> : T extends `${infer Start}*` ? {
8
+ } & PathParams<Rest> : Path extends `${string}*` ? {
8
9
  $0: string;
9
10
  } : {};
10
- type LinkFunction<T extends readonly string[]> = {
11
- <Path extends T[number]>(path: Path, params?: ParseRoute<Path> extends Record<string, never> ? undefined : ParseRoute<Path>): string;
11
+ type ParamsForPath<Path extends string> = PathParams<Path> extends Record<string, never> ? undefined : PathParams<Path>;
12
+ export type LinkFunction<Paths extends string> = {
13
+ <Path extends Paths>(path: Path, params?: ParamsForPath<Path>): string;
12
14
  };
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
- */
31
- export declare function defineLinks<const T extends readonly string[]>(routes: T): LinkFunction<T>;
15
+ type RoutePaths<Value> = Value extends RouteDefinition<infer Path, any> ? Path : Value extends readonly (infer Item)[] ? RouteArrayPaths<Value> : Value extends RouteMiddleware<any> ? never : never;
16
+ type RouteArrayPaths<Routes extends readonly any[]> = number extends Routes["length"] ? RoutePaths<Routes[number]> : Routes extends readonly [infer Head, ...infer Tail] ? RoutePaths<Head> | RouteArrayPaths<Tail> : never;
17
+ type AppRoutes<App> = App extends {
18
+ __rwRoutes: infer Routes;
19
+ } ? Routes : never;
20
+ export type AppRoutePaths<App> = RoutePaths<AppRoutes<App>>;
21
+ export type AppLink<App> = LinkFunction<AppRoutePaths<App>>;
22
+ export declare function linkFor<App>(): AppLink<App>;
23
+ export declare function createLinks<App>(_app?: App): AppLink<App>;
24
+ export declare function defineLinks<const T extends readonly string[]>(routes: T): LinkFunction<T[number]>;
32
25
  export {};
@@ -1,56 +1,84 @@
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
+ export function linkFor() {
2
+ return createLinkFunction();
3
+ }
4
+ export function createLinks(_app) {
5
+ return linkFor();
6
+ }
19
7
  export function defineLinks(routes) {
20
- // Validate routes at runtime
21
8
  routes.forEach((route) => {
22
9
  if (typeof route !== "string") {
23
10
  throw new Error(`Invalid route: ${route}. Routes must be strings.`);
24
11
  }
25
12
  });
26
- return (path, params) => {
13
+ const link = createLinkFunction();
14
+ return ((path, params) => {
27
15
  if (!routes.includes(path)) {
28
16
  throw new Error(`Invalid route: ${path}`);
29
17
  }
30
- if (!params)
18
+ return link(path, params);
19
+ });
20
+ }
21
+ const TOKEN_REGEX = /:([a-zA-Z0-9_]+)|\*/g;
22
+ function createLinkFunction() {
23
+ return ((path, params) => {
24
+ const expectsParams = hasRouteParameters(path);
25
+ if (!params || Object.keys(params).length === 0) {
26
+ if (expectsParams) {
27
+ throw new Error(`Route ${path} requires an object of parameters`);
28
+ }
31
29
  return path;
32
- let result = path;
33
- // Replace named parameters
34
- for (const [key, value] of Object.entries(params)) {
35
- if (key.startsWith("$")) {
36
- // Replace each star with its corresponding $ parameter
37
- const starIndex = parseInt(key.slice(1));
38
- const stars = result.match(/\*/g) || [];
39
- if (starIndex >= stars.length) {
40
- throw new Error(`Parameter ${key} has no corresponding * in route`);
41
- }
42
- // Replace the nth star with the value
43
- let count = 0;
44
- result = result.replace(/\*/g, (match) => count++ === starIndex ? value : match);
30
+ }
31
+ return interpolate(path, params);
32
+ });
33
+ }
34
+ function hasRouteParameters(path) {
35
+ TOKEN_REGEX.lastIndex = 0;
36
+ const result = TOKEN_REGEX.test(path);
37
+ TOKEN_REGEX.lastIndex = 0;
38
+ return result;
39
+ }
40
+ function interpolate(template, params) {
41
+ let result = "";
42
+ let lastIndex = 0;
43
+ let wildcardIndex = 0;
44
+ const consumed = new Set();
45
+ TOKEN_REGEX.lastIndex = 0;
46
+ let match;
47
+ while ((match = TOKEN_REGEX.exec(template)) !== null) {
48
+ result += template.slice(lastIndex, match.index);
49
+ if (match[1]) {
50
+ const name = match[1];
51
+ const value = params[name];
52
+ if (value === undefined) {
53
+ throw new Error(`Missing parameter "${name}" for route ${template}`);
45
54
  }
46
- else {
47
- // Handle named parameters
48
- if (typeof value !== "string") {
49
- throw new Error(`Parameter ${key} must be a string`);
50
- }
51
- result = result.replace(`:${key}`, value);
55
+ result += encodeURIComponent(value);
56
+ consumed.add(name);
57
+ }
58
+ else {
59
+ const key = `$${wildcardIndex}`;
60
+ const value = params[key];
61
+ if (value === undefined) {
62
+ throw new Error(`Missing parameter "${key}" for route ${template}`);
52
63
  }
64
+ result += encodeWildcardValue(value);
65
+ consumed.add(key);
66
+ wildcardIndex += 1;
67
+ }
68
+ lastIndex = TOKEN_REGEX.lastIndex;
69
+ }
70
+ result += template.slice(lastIndex);
71
+ for (const key of Object.keys(params)) {
72
+ if (!consumed.has(key)) {
73
+ throw new Error(`Parameter "${key}" is not used by route ${template}`);
53
74
  }
54
- return result;
55
- };
75
+ }
76
+ TOKEN_REGEX.lastIndex = 0;
77
+ return result;
78
+ }
79
+ function encodeWildcardValue(value) {
80
+ return value
81
+ .split("/")
82
+ .map((segment) => encodeURIComponent(segment))
83
+ .join("/");
56
84
  }
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,20 @@
1
+ import { describe, expect, it } from "vitest";
2
+ import { defineLinks } from "./links";
3
+ const link = defineLinks(["/", "/users/:id", "/files/*"]);
4
+ describe("link helpers", () => {
5
+ it("returns static routes without parameters", () => {
6
+ expect(link("/")).toBe("/");
7
+ });
8
+ it("replaces named parameters with encoded values", () => {
9
+ expect(link("/users/:id", { id: "user id" })).toBe("/users/user%20id");
10
+ });
11
+ it("replaces wildcard parameters preserving path segments", () => {
12
+ expect(link("/files/*", { $0: "docs/Guide Document.md" })).toBe("/files/docs/Guide%20Document.md");
13
+ });
14
+ it("throws when parameters are missing", () => {
15
+ expect(() => link("/users/:id")).toThrowError(/requires an object of parameters/i);
16
+ });
17
+ it("throws when extra parameters are supplied", () => {
18
+ expect(() => link("/users/:id", { id: "123", extra: "value" })).toThrowError(/is not used by route/i);
19
+ });
20
+ });
@@ -1,3 +1,3 @@
1
1
  import type { RealtimeDurableObject } from "./durableObject";
2
2
  export { renderRealtimeClients } from "./renderRealtimeClients";
3
- export declare const realtimeRoute: (getDurableObjectNamespace: (env: Cloudflare.Env) => DurableObjectNamespace<RealtimeDurableObject>) => import("../router").RouteDefinition<import("../../worker").RequestInfo<any, import("../../worker").DefaultAppContext>>;
3
+ export declare const realtimeRoute: (getDurableObjectNamespace: (env: Cloudflare.Env) => DurableObjectNamespace<RealtimeDurableObject>) => import("../router").RouteDefinition<"/__realtime", import("../../worker").RequestInfo<any, import("../../worker").DefaultAppContext>>;
@@ -19,14 +19,27 @@ export type MethodHandlers<T extends RequestInfo = RequestInfo> = {
19
19
  [method: string]: RouteHandler<T>;
20
20
  };
21
21
  };
22
- export type Route<T extends RequestInfo = RequestInfo> = RouteMiddleware<T> | RouteDefinition<T> | Array<Route<T>>;
23
- export type RouteDefinition<T extends RequestInfo = RequestInfo> = {
22
+ export type Route<T extends RequestInfo = RequestInfo> = RouteMiddleware<T> | RouteDefinition<string, T> | readonly Route<T>[];
23
+ type NormalizedRouteDefinition<T extends RequestInfo = RequestInfo> = {
24
24
  path: string;
25
25
  handler: RouteHandler<T> | MethodHandlers<T>;
26
26
  layouts?: React.FC<LayoutProps<T>>[];
27
27
  };
28
+ export type RouteDefinition<Path extends string = string, T extends RequestInfo = RequestInfo> = NormalizedRouteDefinition<T> & {
29
+ readonly __rwPath?: Path;
30
+ };
31
+ type TrimTrailingSlash<S extends string> = S extends `${infer Head}/` ? TrimTrailingSlash<Head> : S;
32
+ type TrimLeadingSlash<S extends string> = S extends `/${infer Rest}` ? TrimLeadingSlash<Rest> : S;
33
+ type NormalizePrefix<Prefix extends string> = TrimTrailingSlash<TrimLeadingSlash<Prefix>> extends "" ? "" : `/${TrimTrailingSlash<TrimLeadingSlash<Prefix>>}`;
34
+ type NormalizePath<Path extends string> = TrimTrailingSlash<Path> extends "/" ? "/" : `/${TrimTrailingSlash<TrimLeadingSlash<Path>>}`;
35
+ type JoinPaths<Prefix extends string, Path extends string> = NormalizePrefix<Prefix> extends "" ? NormalizePath<Path> : Path extends "/" ? NormalizePrefix<Prefix> : `${NormalizePrefix<Prefix>}${NormalizePath<Path>}`;
36
+ type PrefixedRouteValue<Prefix extends string, Value> = Value extends RouteDefinition<infer Path, infer Req> ? RouteDefinition<JoinPaths<Prefix, Path>, Req> : Value extends readonly Route<any>[] ? PrefixedRouteArray<Prefix, Value> : Value;
37
+ type PrefixedRouteArray<Prefix extends string, Routes extends readonly Route<any>[]> = Routes extends readonly [] ? [] : Routes extends readonly [infer Head, ...infer Tail] ? readonly [
38
+ PrefixedRouteValue<Prefix, Head>,
39
+ ...PrefixedRouteArray<Prefix, Tail extends readonly Route<any>[] ? Tail : []>
40
+ ] : ReadonlyArray<PrefixedRouteValue<Prefix, Routes[number]>>;
28
41
  export declare function matchPath<T extends RequestInfo = RequestInfo>(routePath: string, requestPath: string): T["params"] | null;
29
- export declare function defineRoutes<T extends RequestInfo = RequestInfo>(routes: Route<T>[]): {
42
+ export declare function defineRoutes<T extends RequestInfo = RequestInfo>(routes: readonly Route<T>[]): {
30
43
  routes: Route<T>[];
31
44
  handle: ({ request, renderPage, getRequestInfo, onError, runWithRequestInfoOverrides, rscActionHandler, }: {
32
45
  request: Request;
@@ -74,7 +87,7 @@ export declare function defineRoutes<T extends RequestInfo = RequestInfo>(routes
74
87
  * // Route with middleware array
75
88
  * route("/admin", [isAuthenticated, isAdmin, () => <AdminDashboard />])
76
89
  */
77
- export declare function route<T extends RequestInfo = RequestInfo>(path: string, handler: RouteHandler<T> | MethodHandlers<T>): RouteDefinition<T>;
90
+ export declare function route<Path extends string, T extends RequestInfo = RequestInfo>(path: Path, handler: RouteHandler<T> | MethodHandlers<T>): RouteDefinition<NormalizePath<Path>, T>;
78
91
  /**
79
92
  * Defines a route handler for the root path "/".
80
93
  *
@@ -86,7 +99,7 @@ export declare function route<T extends RequestInfo = RequestInfo>(path: string,
86
99
  * // With middleware
87
100
  * index([logRequest, () => <HomePage />])
88
101
  */
89
- export declare function index<T extends RequestInfo = RequestInfo>(handler: RouteHandler<T>): RouteDefinition<T>;
102
+ export declare function index<T extends RequestInfo = RequestInfo>(handler: RouteHandler<T>): RouteDefinition<"/", T>;
90
103
  /**
91
104
  * Prefixes a group of routes with a path.
92
105
  *
@@ -106,7 +119,7 @@ export declare function index<T extends RequestInfo = RequestInfo>(handler: Rout
106
119
  * ]),
107
120
  * ])
108
121
  */
109
- export declare function prefix<T extends RequestInfo = RequestInfo>(prefixPath: string, routes: Route<T>[]): Route<T>[];
122
+ export declare function prefix<Prefix extends string, T extends RequestInfo = RequestInfo, Routes extends readonly Route<T>[] = readonly Route<T>[]>(prefixPath: Prefix, routes: Routes): PrefixedRouteArray<Prefix, Routes>;
110
123
  export declare const wrapHandlerToThrowResponses: <T extends RequestInfo = RequestInfo>(handler: RouteFunction<T> | RouteComponent<T>) => RouteHandler<T>;
111
124
  /**
112
125
  * Wraps routes with a layout component.
@@ -128,7 +141,7 @@ export declare const wrapHandlerToThrowResponses: <T extends RequestInfo = Reque
128
141
  * route("/post/:id", ({ params }) => <BlogPost id={params.id} />),
129
142
  * ])
130
143
  */
131
- export declare function layout<T extends RequestInfo = RequestInfo>(LayoutComponent: React.FC<LayoutProps<T>>, routes: Route<T>[]): Route<T>[];
144
+ export declare function layout<T extends RequestInfo = RequestInfo, Routes extends readonly Route<T>[] = readonly Route<T>[]>(LayoutComponent: React.FC<LayoutProps<T>>, routes: Routes): Routes;
132
145
  /**
133
146
  * Wraps routes with a Document component and configures rendering options.
134
147
  *
@@ -153,9 +166,10 @@ export declare function layout<T extends RequestInfo = RequestInfo>(LayoutCompon
153
166
  * ssr: true,
154
167
  * })
155
168
  */
156
- export declare function render<T extends RequestInfo = RequestInfo>(Document: React.FC<DocumentProps<T>>, routes: Route<T>[], options?: {
169
+ type RenderedRoutes<T extends RequestInfo, Routes extends readonly Route<T>[]> = readonly [RouteMiddleware<T>, ...Routes];
170
+ export declare function render<T extends RequestInfo = RequestInfo, Routes extends readonly Route<T>[] = readonly Route<T>[]>(Document: React.FC<DocumentProps<T>>, routes: Routes, options?: {
157
171
  rscPayload?: boolean;
158
172
  ssr?: boolean;
159
- }): Route<T>[];
173
+ }): RenderedRoutes<T, Routes>;
160
174
  export declare const isClientReference: (value: any) => boolean;
161
175
  export {};
@@ -259,8 +259,9 @@ export function defineRoutes(routes) {
259
259
  * route("/admin", [isAuthenticated, isAdmin, () => <AdminDashboard />])
260
260
  */
261
261
  export function route(path, handler) {
262
- if (!path.endsWith("/")) {
263
- path = path + "/";
262
+ let normalizedPath = path;
263
+ if (!normalizedPath.endsWith("/")) {
264
+ normalizedPath = normalizedPath + "/";
264
265
  }
265
266
  // Normalize custom method keys to lowercase
266
267
  if (isMethodHandlers(handler) && handler.custom) {
@@ -273,8 +274,9 @@ export function route(path, handler) {
273
274
  };
274
275
  }
275
276
  return {
276
- path,
277
+ path: normalizedPath,
277
278
  handler,
279
+ __rwPath: normalizedPath,
278
280
  };
279
281
  }
280
282
  /**
@@ -311,7 +313,7 @@ export function index(handler) {
311
313
  * ])
312
314
  */
313
315
  export function prefix(prefixPath, routes) {
314
- return routes.map((r) => {
316
+ const prefixed = routes.map((r) => {
315
317
  if (typeof r === "function") {
316
318
  const middleware = (requestInfo) => {
317
319
  const url = new URL(requestInfo.request.url);
@@ -326,13 +328,14 @@ export function prefix(prefixPath, routes) {
326
328
  // Recursively process nested route arrays
327
329
  return prefix(prefixPath, r);
328
330
  }
329
- // For RouteDefinition objects, update the path and preserve layouts
331
+ const routeDef = r;
330
332
  return {
331
- path: prefixPath + r.path,
332
- handler: r.handler,
333
- ...(r.layouts && { layouts: r.layouts }),
333
+ path: prefixPath + routeDef.path,
334
+ handler: routeDef.handler,
335
+ ...(routeDef.layouts && { layouts: routeDef.layouts }),
334
336
  };
335
337
  });
338
+ return prefixed;
336
339
  }
337
340
  function wrapWithLayouts(Component, layouts = [], requestInfo) {
338
341
  if (layouts.length === 0) {
@@ -396,7 +399,6 @@ export const wrapHandlerToThrowResponses = (handler) => {
396
399
  * ])
397
400
  */
398
401
  export function layout(LayoutComponent, routes) {
399
- // Attach layouts directly to route definitions
400
402
  return routes.map((route) => {
401
403
  if (typeof route === "function") {
402
404
  // Pass through middleware as-is
@@ -406,37 +408,13 @@ export function layout(LayoutComponent, routes) {
406
408
  // Recursively process nested route arrays
407
409
  return layout(LayoutComponent, route);
408
410
  }
409
- // For RouteDefinition objects, prepend the layout so outer layouts come first
411
+ const routeDef = route;
410
412
  return {
411
- ...route,
412
- layouts: [LayoutComponent, ...(route.layouts || [])],
413
+ ...routeDef,
414
+ layouts: [LayoutComponent, ...(routeDef.layouts || [])],
413
415
  };
414
416
  });
415
417
  }
416
- /**
417
- * Wraps routes with a Document component and configures rendering options.
418
- *
419
- * @param options.rscPayload - Toggle the RSC payload that's appended to the Document. Disabling this will mean that interactivity no longer works.
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
- * })
439
- */
440
418
  export function render(Document, routes, options = {}) {
441
419
  options = {
442
420
  rscPayload: true,
@@ -15,4 +15,70 @@
15
15
  * @param startMarker The marker in the document to start injecting the app.
16
16
  * @param endMarker The marker in the app stream that signals the end of the initial, non-suspended render.
17
17
  */
18
+ /**
19
+ * A utility that orchestrates and interleaves three ReadableStreams to produce a
20
+ * single, valid HTML response stream. It uses two special markers:
21
+ *
22
+ * - `startMarker`: Placed in the `outerHtml` stream (the document shell) to
23
+ * designate where the application's content should be injected.
24
+ * - `endMarker`: Injected into the `innerHtml` stream's RSC payload to signal
25
+ * the end of the initial, non-suspended render. This marker is needed for
26
+ * non-blocking hydration, as it allows the stitching process to send the
27
+ * client `<script>` tags before all suspended content has resolved.
28
+ *
29
+ * It manages three main stream readers:
30
+ *
31
+ * - `hoistedTagsReader`: Reads from the `hoistedTagsStream`, which contains only
32
+ * the hoisted meta tags (e.g., `<title>`, `<meta>`).
33
+ * - `outerReader`: Reads from the `outerHtml` stream, which is the server-rendered
34
+ * document shell (containing `<html>`, `<head>`, etc.).
35
+ * - `innerReader`: Reads from the `appBodyStream`, which contains the main
36
+ * application content, stripped of its hoisted tags.
37
+ *
38
+ * The function proceeds through a multi-phase state machine, managed by the
39
+ * `pump` function, to correctly interleave these streams.
40
+ *
41
+ * The state machine moves through the following phases:
42
+ *
43
+ * 1. `read-hoisted`:
44
+ * - **Goal:** Buffer all hoisted tags from the `hoistedTagsStream`.
45
+ * - **Action:** Reads from `hoistedTagsReader` and appends all content into
46
+ * the `hoistedTagsBuffer`. Does not enqueue anything yet.
47
+ * - **Transition:** Moves to `outer-head` when the stream is exhausted.
48
+ *
49
+ * 2. `outer-head`:
50
+ * - **Goal:** Stream the document up to the closing `</head>` tag, inject the
51
+ * hoisted tags, and then continue until the app `startMarker`.
52
+ * - **Action:** Reads from `outerReader`. When it finds `</head>`, it enqueues
53
+ * the content before it, then enqueues the `hoistedTagsBuffer`, and finally
54
+ * enqueues the `</head>` tag itself. It then continues reading from
55
+ * `outerReader` until it finds the `startMarker`.
56
+ * - **Transition:** Moves to `inner-shell` after finding and discarding the
57
+ * `startMarker`.
58
+ *
59
+ * 3. `inner-shell`:
60
+ * - **Goal:** Stream the initial, non-suspended part of the application.
61
+ * - **Action:** Switches to `innerReader`. It enqueues chunks until it finds
62
+ * the `endMarker`. Any content after the marker is stored in
63
+ * `innerSuspendedRemains`.
64
+ * - **Transition:** Moves to `outer-tail` after finding the `endMarker`.
65
+ *
66
+ * 4. `outer-tail`:
67
+ * - **Goal:** Stream the rest of the document's `<body>`, including client
68
+ * `<script>` tags.
69
+ * - **Action:** Switches back to `outerReader` and enqueues chunks until it
70
+ * finds the `</body>` tag.
71
+ * - **Transition:** Moves to `inner-suspended` after finding `</body>`.
72
+ *
73
+ * 5. `inner-suspended`:
74
+ * - **Goal:** Stream any suspended content from the React app.
75
+ * - **Action:** First enqueues any content from `innerSuspendedRemains`, then
76
+ * continues reading from `innerReader` until the stream is exhausted.
77
+ * - **Transition:** Moves to `outer-end` when the stream is exhausted.
78
+ *
79
+ * 6. `outer-end`:
80
+ * - **Goal:** Finish the document.
81
+ * - **Action:** Switches back to `outerReader` for the last time to send the
82
+ * closing `</body>` and `</html>` tags.
83
+ */
18
84
  export declare function stitchDocumentAndAppStreams(outerHtml: ReadableStream<Uint8Array>, innerHtml: ReadableStream<Uint8Array>, startMarker: string, endMarker: string): ReadableStream<Uint8Array>;