@uniflowed/router 0.33.0 → 0.35.0

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 (45) hide show
  1. package/action.js +5 -5
  2. package/client.js +20 -20
  3. package/handler.js +6 -6
  4. package/http-client.js +10 -10
  5. package/index.js +3 -3
  6. package/instrumentation.js +5 -5
  7. package/internal/action-endpoint.js +7 -7
  8. package/internal/action-wire.js +3 -3
  9. package/internal/base-path.js +3 -3
  10. package/internal/boundaries.js +8 -8
  11. package/internal/boundary-data.js +12 -12
  12. package/internal/compose.js +4 -4
  13. package/internal/devtools.js +1 -1
  14. package/internal/diagnostics.js +8 -8
  15. package/internal/error-view.js +6 -6
  16. package/internal/flight-browser.js +6 -6
  17. package/internal/flight-rows.js +4 -4
  18. package/internal/flight-ssr.js +3 -3
  19. package/internal/flight.js +26 -26
  20. package/internal/form-action.js +11 -11
  21. package/internal/hydrate-options.js +1 -1
  22. package/internal/hydration.js +37 -37
  23. package/internal/inspector.js +15 -15
  24. package/internal/native-links.js +3 -3
  25. package/internal/native-tree.js +11 -11
  26. package/internal/navigation-cache.js +12 -12
  27. package/internal/payload-rows.js +2 -2
  28. package/internal/payload.js +10 -10
  29. package/internal/resolve.js +103 -103
  30. package/internal/resolved-summary.js +76 -76
  31. package/internal/routing.js +52 -52
  32. package/internal/runtime.js +47 -47
  33. package/internal/search-params.js +1 -1
  34. package/internal/shell.js +8 -8
  35. package/internal/stream.js +44 -44
  36. package/middleware.js +11 -11
  37. package/native-navigation.js +21 -21
  38. package/native.js +45 -45
  39. package/package.json +4 -4
  40. package/rsc-client.js +5 -5
  41. package/rsc-ssr.js +31 -31
  42. package/rsc.js +17 -17
  43. package/server-components.js +5 -5
  44. package/server.js +33 -33
  45. package/testing.js +62 -62
package/server.js CHANGED
@@ -55,8 +55,8 @@ import { redirectDocument, redirectResult, shellFor } from "./internal/shell.js"
55
55
 
56
56
  /** Asset URLs to reference from the document. */
57
57
  export type RenderAssets = {|
58
- readonly scripts: $ReadOnlyArray<string>,
59
- readonly styles: $ReadOnlyArray<string>,
58
+ readonly scripts : $ReadOnlyArray<string>,
59
+ readonly styles : $ReadOnlyArray<string>,
60
60
  readonly preloads: $ReadOnlyArray<string>,
61
61
  /**
62
62
  * The build the document belongs to, written into its head as
@@ -76,7 +76,7 @@ export type RenderAssets = {|
76
76
  * copies of the document.
77
77
  */
78
78
  export type RenderResult = {|
79
- readonly status: number,
79
+ readonly status : number,
80
80
  readonly headers?: { readonly [string]: string },
81
81
  /** Write the document into a Node response. */
82
82
  readonly pipe: (destination: WritableLike) => Promise<void>,
@@ -107,8 +107,8 @@ export type RenderResult = {|
107
107
 
108
108
  /** A document that is finished: every boundary resolved, nothing left to wait for. */
109
109
  export type PrerenderResult = {|
110
- readonly status: number,
111
- readonly html: string,
110
+ readonly status : number,
111
+ readonly html : string,
112
112
  readonly headers?: { readonly [string]: string },
113
113
  /** The exception this render fell back to its error boundary for; see [`RenderResult`]. */
114
114
  readonly error?: mixed,
@@ -143,9 +143,9 @@ export type PrerenderResult = {|
143
143
  * on a payload.
144
144
  */
145
145
  export type FlightResponse = {|
146
- readonly status: number,
146
+ readonly status : number,
147
147
  readonly headers: { readonly [string]: string },
148
- readonly stream: ReadableStream<Uint8Array> | null,
148
+ readonly stream : ReadableStream<Uint8Array> | null,
149
149
  /** The exception the route resolved to its error boundary for; see [`RenderResult`]. */
150
150
  readonly error?: mixed,
151
151
  |};
@@ -314,13 +314,13 @@ type Resolution =
314
314
  /** The two ways one app answers for a URL. */
315
315
  export type Renderer = {|
316
316
  readonly render: (
317
- url: string,
318
- assets: RenderAssets,
317
+ url : string,
318
+ assets : RenderAssets,
319
319
  options?: RenderOptions,
320
320
  ) => Promise<RenderResult>,
321
321
  readonly prerender: (
322
- url: string,
323
- assets: RenderAssets,
322
+ url : string,
323
+ assets : RenderAssets,
324
324
  options?: RenderOptions,
325
325
  ) => Promise<PrerenderResult>,
326
326
  /**
@@ -330,7 +330,7 @@ export type Renderer = {|
330
330
  readonly flight?: (
331
331
  url: string,
332
332
  options?: {|
333
- readonly onError?: (error: mixed) => void,
333
+ readonly onError? : (error: mixed) => void,
334
334
  readonly interceptedFrom?: string,
335
335
  |},
336
336
  ) => Promise<FlightResponse>,
@@ -340,23 +340,23 @@ export type Renderer = {|
340
340
  * has one, because only it writes a shell.
341
341
  */
342
342
  readonly resume?: (
343
- url: string,
344
- assets: RenderAssets,
345
- shell: PrerenderedShell,
343
+ url : string,
344
+ assets : RenderAssets,
345
+ shell : PrerenderedShell,
346
346
  options?: RenderOptions,
347
347
  ) => Promise<RenderResult>,
348
348
  |};
349
349
 
350
350
  export function createRenderer(options: {|
351
- readonly App: React.ComponentType<AppProps>,
352
- readonly routes: RouteTable["routes"],
351
+ readonly App : React.ComponentType<AppProps>,
352
+ readonly routes : RouteTable["routes"],
353
353
  readonly notFound: RouteTable["notFound"],
354
- readonly errors: RouteTable["errors"],
354
+ readonly errors : RouteTable["errors"],
355
355
  |}): Renderer {
356
356
  const table: RouteTable = {
357
- routes: options.routes,
357
+ routes : options.routes,
358
358
  notFound: options.notFound,
359
- errors: options.errors,
359
+ errors : options.errors,
360
360
  };
361
361
  installRoutes(table);
362
362
  const { App } = options;
@@ -390,7 +390,7 @@ export function createRenderer(options: {|
390
390
  kind: "route",
391
391
  route: await resolveMatch(table, url, {
392
392
  defer,
393
- onMatch: noteRoute,
393
+ onMatch : noteRoute,
394
394
  runLoader: traceLoader,
395
395
  }),
396
396
  };
@@ -403,8 +403,8 @@ export function createRenderer(options: {|
403
403
  }
404
404
 
405
405
  async function render(
406
- url: string,
407
- assets: RenderAssets,
406
+ url : string,
407
+ assets : RenderAssets,
408
408
  settings?: RenderOptions,
409
409
  ): Promise<RenderResult> {
410
410
  const resolution = await resolve(url, true);
@@ -488,16 +488,16 @@ export function createRenderer(options: {|
488
488
 
489
489
  return {
490
490
  status: resolved.status,
491
- pipe: body.pipe,
491
+ pipe : body.pipe,
492
492
  stream: body.stream,
493
- text: body.text,
494
- error: renderFailure(resolved),
493
+ text : body.text,
494
+ error : renderFailure(resolved),
495
495
  };
496
496
  }
497
497
 
498
498
  async function prerender(
499
- url: string,
500
- assets: RenderAssets,
499
+ url : string,
500
+ assets : RenderAssets,
501
501
  settings?: RenderOptions,
502
502
  ): Promise<PrerenderResult> {
503
503
  const resolution = await resolve(url, false);
@@ -510,7 +510,7 @@ export function createRenderer(options: {|
510
510
  let html: string;
511
511
  try {
512
512
  html = await prerenderDocument(<App url={url} initial={resolved} />, {
513
- shell: shellFor(assets),
513
+ shell : shellFor(assets),
514
514
  onError: report,
515
515
  });
516
516
  } catch (error) {
@@ -519,7 +519,7 @@ export function createRenderer(options: {|
519
519
  }
520
520
  resolved = await resolveFailure(table, url, error);
521
521
  html = await prerenderDocument(<App url={url} initial={resolved} />, {
522
- shell: shellFor(assets),
522
+ shell : shellFor(assets),
523
523
  onError: report,
524
524
  });
525
525
  }
@@ -537,9 +537,9 @@ function renderFailure(resolved: ResolvedRoute): mixed {
537
537
  }
538
538
  return match (resolved.error) {
539
539
  {kind: "thrown", error: const error} => error,
540
- {kind: "badRequest", ...} => undefined,
541
- {kind: "unauthorized"} => undefined,
542
- {kind: "forbidden"} => undefined,
540
+ {kind: "badRequest", ...} => undefined,
541
+ {kind: "unauthorized"} => undefined,
542
+ {kind: "forbidden"} => undefined,
543
543
  };
544
544
  }
545
545
 
package/testing.js CHANGED
@@ -112,11 +112,11 @@ export const TEST_ACTION_ID: string = "7e57ac7107e57ac7".repeat(4);
112
112
  */
113
113
  export type TestRequestInit = {|
114
114
  /** A path on [`TEST_ORIGIN`], or an absolute URL. Defaults to `/`. */
115
- readonly url?: string,
116
- readonly method?: string,
115
+ readonly url? : string,
116
+ readonly method? : string,
117
117
  readonly headers?: { readonly [string]: string },
118
118
  readonly cookies?: { readonly [string]: string },
119
- readonly body?: string | URLSearchParams | FormData,
119
+ readonly body? : string | URLSearchParams | FormData,
120
120
  /**
121
121
  * The cache the host would install for this request, which is what
122
122
  * `revalidateTag`, `revalidatePath` and `cacheFunction` reach.
@@ -191,7 +191,7 @@ export function testRequest(init?: TestRequestInit): Request {
191
191
  */
192
192
  export async function withRequest<T>(
193
193
  request: Request | TestRequestInit,
194
- body: () => T | Promise<T>,
194
+ body : () => T | Promise<T>,
195
195
  ): Promise<T> {
196
196
  const cache = request instanceof Request ? undefined : request.cache;
197
197
  const built = request instanceof Request ? request : testRequest(request);
@@ -212,7 +212,7 @@ export type ActionCallInit = {|
212
212
  /** Headers beyond the ones the browser's reference sends. Override to test a refusal. */
213
213
  readonly headers?: { readonly [string]: string },
214
214
  readonly cookies?: { readonly [string]: string },
215
- readonly cache?: CacheStore | CacheOptions,
215
+ readonly cache? : CacheStore | CacheOptions,
216
216
  /**
217
217
  * Which door the call comes through.
218
218
  *
@@ -249,36 +249,36 @@ export type ActionOutcome<R> =
249
249
  * a new one. Through `"form"`, the value the action returned, which a
250
250
  * browser never sees.
251
251
  */
252
- readonly value: R,
253
- readonly response: Response,
252
+ readonly value : R,
253
+ readonly response : Response,
254
254
  readonly revalidated: Revalidations,
255
255
  |}
256
256
  | {|
257
- readonly kind: "redirect",
258
- readonly to: string,
259
- readonly permanent: boolean,
260
- readonly response: Response,
257
+ readonly kind : "redirect",
258
+ readonly to : string,
259
+ readonly permanent : boolean,
260
+ readonly response : Response,
261
261
  readonly revalidated: Revalidations,
262
262
  |}
263
263
  | {|
264
- readonly kind: "not-found",
265
- readonly response: Response,
264
+ readonly kind : "not-found",
265
+ readonly response : Response,
266
266
  readonly revalidated: Revalidations,
267
267
  |}
268
268
  | {|
269
- readonly kind: "unauthorized",
270
- readonly response: Response,
269
+ readonly kind : "unauthorized",
270
+ readonly response : Response,
271
271
  readonly revalidated: Revalidations,
272
272
  |}
273
273
  | {|
274
- readonly kind: "forbidden",
275
- readonly response: Response,
274
+ readonly kind : "forbidden",
275
+ readonly response : Response,
276
276
  readonly revalidated: Revalidations,
277
277
  |}
278
278
  | {|
279
- readonly kind: "threw",
280
- readonly error: mixed,
281
- readonly response: Response,
279
+ readonly kind : "threw",
280
+ readonly error : mixed,
281
+ readonly response : Response,
282
282
  readonly revalidated: Revalidations,
283
283
  |}
284
284
  | {|
@@ -287,9 +287,9 @@ export type ActionOutcome<R> =
287
287
  * `Map`, a class instance. `error` is the `ActionValueError` naming
288
288
  * where it was; the browser got a `500`.
289
289
  */
290
- readonly kind: "unsendable",
291
- readonly error: ActionValueError,
292
- readonly response: Response,
290
+ readonly kind : "unsendable",
291
+ readonly error : ActionValueError,
292
+ readonly response : Response,
293
293
  readonly revalidated: Revalidations,
294
294
  |}
295
295
  | {|
@@ -298,8 +298,8 @@ export type ActionOutcome<R> =
298
298
  * the test's `headers` overrode, or a payload over a limit only the
299
299
  * decoder counts. `response.status` says which.
300
300
  */
301
- readonly kind: "refused",
302
- readonly response: Response,
301
+ readonly kind : "refused",
302
+ readonly response : Response,
303
303
  readonly revalidated: Revalidations,
304
304
  |};
305
305
 
@@ -328,8 +328,8 @@ export type ActionOutcome<R> =
328
328
  */
329
329
  export async function callAction<Args extends $ReadOnlyArray<ActionArgument>, R>(
330
330
  action: (...args: Args) => Promise<R>,
331
- args: Args,
332
- init?: ActionCallInit,
331
+ args : Args,
332
+ init? : ActionCallInit,
333
333
  ): Promise<ActionOutcome<R>> {
334
334
  const door = init?.door ?? "fetch";
335
335
  const request = door === "form" ? formActionRequest(args, init) : fetchActionRequest(args, init);
@@ -354,10 +354,10 @@ export async function callAction<Args extends $ReadOnlyArray<ActionArgument>, R>
354
354
  const dispatch = createActionDispatcher({
355
355
  actions: [
356
356
  {
357
- id: TEST_ACTION_ID,
357
+ id : TEST_ACTION_ID,
358
358
  module: init?.name ?? "server action under test",
359
359
  export: "action",
360
- load: async () => ({ action: observed }),
360
+ load : async () => ({ action: observed }),
361
361
  },
362
362
  ],
363
363
  });
@@ -423,7 +423,7 @@ export async function callAction<Args extends $ReadOnlyArray<ActionArgument>, R>
423
423
  */
424
424
  export function serverReferences<M extends { readonly [string]: mixed }>(
425
425
  module: M,
426
- init?: ActionCallInit | (() => ActionCallInit),
426
+ init? : ActionCallInit | (() => ActionCallInit),
427
427
  ): M {
428
428
  const references: { [string]: mixed } = {};
429
429
  for (const [name, exported] of Object.entries(module)) {
@@ -440,12 +440,12 @@ export function serverReferences<M extends { readonly [string]: mixed }>(
440
440
  const given: ActionCallInit = (typeof init === "function" ? init() : init) ?? {};
441
441
  const label = given.name ?? name;
442
442
  const outcome = await callAction(action, args, {
443
- url: given.url,
443
+ url : given.url,
444
444
  headers: given.headers,
445
445
  cookies: given.cookies,
446
- cache: given.cache,
447
- name: label,
448
- door: "fetch",
446
+ cache : given.cache,
447
+ name : label,
448
+ door : "fetch",
449
449
  });
450
450
  // What the browser's reference does with each outcome: a redirect
451
451
  // resolves with nothing once it has navigated (there is no navigation
@@ -480,7 +480,7 @@ function fetchActionRequest(args: $ReadOnlyArray<ActionArgument>, init?: ActionC
480
480
  init?.headers,
481
481
  );
482
482
  return testRequest({
483
- url: url.href,
483
+ url : url.href,
484
484
  method: "POST",
485
485
  headers,
486
486
  cookies: init?.cookies,
@@ -516,18 +516,18 @@ function formActionRequest(args: $ReadOnlyArray<ActionArgument>, init?: ActionCa
516
516
  }
517
517
  const url = new URL(init?.url ?? "/", TEST_ORIGIN);
518
518
  return testRequest({
519
- url: url.href,
519
+ url : url.href,
520
520
  method: "POST",
521
521
  headers: merged(
522
522
  {
523
- origin: url.origin,
523
+ origin : url.origin,
524
524
  "sec-fetch-site": "same-origin",
525
- "content-type": FORM_ACTION_CONTENT_TYPE,
525
+ "content-type" : FORM_ACTION_CONTENT_TYPE,
526
526
  },
527
527
  init?.headers,
528
528
  ),
529
529
  cookies: init?.cookies,
530
- body: fields.toString(),
530
+ body : fields.toString(),
531
531
  });
532
532
  }
533
533
 
@@ -573,8 +573,8 @@ function unsendable(value: mixed): ActionValueError {
573
573
  */
574
574
  async function withLifecycle<T>(
575
575
  request: Request,
576
- cache: CacheStore | CacheOptions | void,
577
- body: () => Promise<T>,
576
+ cache : CacheStore | CacheOptions | void,
577
+ body : () => Promise<T>,
578
578
  ): Promise<{| readonly value: T, readonly revalidated: Revalidations |}> {
579
579
  const lifecycle = beginRequest(request);
580
580
  const tags: Array<string> = [];
@@ -606,7 +606,7 @@ async function withLifecycle<T>(
606
606
  */
607
607
  function watchInvalidations(
608
608
  store: CacheStore,
609
- tags: Array<string>,
609
+ tags : Array<string>,
610
610
  paths: Array<string>,
611
611
  ): () => void {
612
612
  // Taken off the instance and called with it below, which is the binding the
@@ -639,10 +639,10 @@ function watchInvalidations(
639
639
 
640
640
  /** A request to a built application, described by what a test cares about. */
641
641
  export type BuiltRequestInit = {|
642
- readonly method?: string,
642
+ readonly method? : string,
643
643
  readonly headers?: { readonly [string]: string },
644
644
  readonly cookies?: { readonly [string]: string },
645
- readonly body?: string | URLSearchParams | FormData,
645
+ readonly body? : string | URLSearchParams | FormData,
646
646
  |};
647
647
 
648
648
  /**
@@ -676,7 +676,7 @@ export type BuiltApp = {|
676
676
  */
677
677
  readonly submit: (
678
678
  pathname: string,
679
- fields: { readonly [string]: string },
679
+ fields : { readonly [string]: string },
680
680
  options?: {| readonly form?: number, readonly cookies?: { readonly [string]: string } |},
681
681
  ) => Promise<Response>,
682
682
  /** Resolves once every request answered so far has settled (`after()` has run). */
@@ -695,7 +695,7 @@ export type BuiltApp = {|
695
695
  type Handler = {|
696
696
  readonly fetch: (request: Request) => Promise<Response>,
697
697
  readonly beginRequest: (request: Request) => {|
698
- readonly run: <T>(body: () => Promise<T>) => Promise<T>,
698
+ readonly run : <T>(body: () => Promise<T>) => Promise<T>,
699
699
  readonly settle: () => Promise<void>,
700
700
  |},
701
701
  readonly routing?: mixed,
@@ -726,7 +726,7 @@ export async function openBuild(directory: string | URL): Promise<BuiltApp> {
726
726
  const { createServeHandler } = await import("@uniflowed/server/node");
727
727
  const serve = createServeHandler({
728
728
  staticDir: path.join(root, "static"),
729
- handle: handler.fetch,
729
+ handle : handler.fetch,
730
730
  // The build's own rules, whatever their shape; `createServeHandler` reads them.
731
731
  routing: handler.routing as $FlowFixMe,
732
732
  });
@@ -743,7 +743,7 @@ export async function openBuild(directory: string | URL): Promise<BuiltApp> {
743
743
  // The error goes where a host's error reporting would put it: `errors()`.
744
744
  thrown.push(error);
745
745
  response = new Response("500 Internal Server Error\n", {
746
- status: 500,
746
+ status : 500,
747
747
  headers: { "content-type": "text/plain; charset=utf-8" },
748
748
  });
749
749
  }
@@ -780,16 +780,16 @@ export async function openBuild(directory: string | URL): Promise<BuiltApp> {
780
780
  },
781
781
  });
782
782
  return new Response(watched, {
783
- status: response.status,
783
+ status : response.status,
784
784
  statusText: response.statusText,
785
- headers: response.headers,
785
+ headers : response.headers,
786
786
  });
787
787
  }
788
788
 
789
789
  function request(
790
790
  pathname: string,
791
- init?: BuiltRequestInit,
792
- extra?: { readonly [string]: string },
791
+ init? : BuiltRequestInit,
792
+ extra? : { readonly [string]: string },
793
793
  ): Request {
794
794
  if (!pathname.startsWith("/") || pathname.startsWith("//")) {
795
795
  throw new TypeError(
@@ -797,18 +797,18 @@ export async function openBuild(directory: string | URL): Promise<BuiltApp> {
797
797
  );
798
798
  }
799
799
  return testRequest({
800
- url: pathname,
801
- method: init?.method,
800
+ url : pathname,
801
+ method : init?.method,
802
802
  headers: merged(extra, init?.headers),
803
803
  cookies: init?.cookies,
804
- body: init?.body,
804
+ body : init?.body,
805
805
  });
806
806
  }
807
807
 
808
808
  return {
809
809
  directory: root,
810
- fetch: (pathname, init) => answer(request(pathname, init)),
811
- render: (pathname, init) => answer(request(pathname, init, { accept: "text/html" })),
810
+ fetch : (pathname, init) => answer(request(pathname, init)),
811
+ render : (pathname, init) => answer(request(pathname, init, { accept: "text/html" })),
812
812
  flight: async (pathname, init) => {
813
813
  const url = new URL(pathname, TEST_ORIGIN);
814
814
  url.pathname = `${url.pathname.replace(/\/$/, "")}/__uf.flight`;
@@ -839,15 +839,15 @@ export async function openBuild(directory: string | URL): Promise<BuiltApp> {
839
839
  const target = new URL(form.action === "" ? pathname : form.action, TEST_ORIGIN);
840
840
  return answer(
841
841
  testRequest({
842
- url: `${target.pathname}${target.search}`,
842
+ url : `${target.pathname}${target.search}`,
843
843
  method: "POST",
844
844
  headers: {
845
- origin: TEST_ORIGIN,
845
+ origin : TEST_ORIGIN,
846
846
  "sec-fetch-site": "same-origin",
847
- "content-type": FORM_ACTION_CONTENT_TYPE,
847
+ "content-type" : FORM_ACTION_CONTENT_TYPE,
848
848
  },
849
849
  cookies: options?.cookies,
850
- body: body.toString(),
850
+ body : body.toString(),
851
851
  }),
852
852
  );
853
853
  },
@@ -891,7 +891,7 @@ export async function buildApp(options: BuildAppOptions): Promise<BuiltApp> {
891
891
  );
892
892
  const binary = options.binary ?? process.env.UF_BINARY ?? "uf";
893
893
  const child = spawn(binary, ["--cwd", root, "build", "--adapter", "node", "--color", "never"], {
894
- env: { ...process.env, ...options.env },
894
+ env : { ...process.env, ...options.env },
895
895
  stdio: ["ignore", "pipe", "pipe"],
896
896
  });
897
897
  let transcript = "";