Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

remix-utils

Package Overview
Dependencies
Maintainers
1
Versions
59
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

remix-utils - npm Package Compare versions

Comparing version 5.3.0 to 6.0.0

browser/server/json-hash.d.ts

11

browser/common/promise.d.ts

@@ -1,2 +0,1 @@

import type { PromiseValue } from "type-fest";
/**

@@ -7,3 +6,3 @@ * @see https://twitter.com/buildsghost/status/1507109734519750680

export declare type AwaitedPromiseHash<Hash extends PromiseHash> = {
[Key in keyof Hash]: PromiseValue<Hash[Key]>;
[Key in keyof Hash]: Awaited<Hash[Key]>;
};

@@ -14,3 +13,3 @@ /**

* @example
* export let loader: LoaderFunction = async ({ request }) => {
* export async function loader({ request }: LoaderArgs) {
* return json(

@@ -22,5 +21,5 @@ * promiseHash({

* );
* };
* }
* @example
* export let loader: LoaderFunction = async ({ request }) => {
* export async function loader({ request }: LoaderArgs) {
* return json(

@@ -38,4 +37,4 @@ * promiseHash({

* );
* };
* }
*/
export declare function promiseHash<Hash extends PromiseHash>(hash: Hash): Promise<AwaitedPromiseHash<Hash>>;

@@ -5,3 +5,3 @@ /**

* @example
* export let loader: LoaderFunction = async ({ request }) => {
* export async function loader({ request }: LoaderArgs) {
* return json(

@@ -13,5 +13,5 @@ * promiseHash({

* );
* };
* }
* @example
* export let loader: LoaderFunction = async ({ request }) => {
* export async function loader({ request }: LoaderArgs) {
* return json(

@@ -29,3 +29,3 @@ * promiseHash({

* );
* };
* }
*/

@@ -32,0 +32,0 @@ export async function promiseHash(hash) {

@@ -8,3 +8,2 @@ export * from "./react/cache-assets";

export * from "./react/structured-data";
export * from "./react/use-data-refresh";
export * from "./react/use-event-source";

@@ -14,3 +13,2 @@ export * from "./react/use-global-pending-state";

export * from "./react/use-locales";
export * from "./react/use-route-data";
export * from "./react/use-should-hydrate";

@@ -8,3 +8,2 @@ export * from "./react/cache-assets";

export * from "./react/structured-data";
export * from "./react/use-data-refresh";
export * from "./react/use-event-source";

@@ -14,3 +13,2 @@ export * from "./react/use-global-pending-state";

export * from "./react/use-locales";
export * from "./react/use-route-data";
export * from "./react/use-should-hydrate";

@@ -11,3 +11,3 @@ import type { Locales } from "../server/get-client-locales";

* // in the root loader
* export let loader: LoaderFunction = async ({ request }) => {
* export async function loader({ request }: LoaderArgs) {
* let locales = getClientLocales(request);

@@ -17,3 +17,3 @@ * return json({ locales });

* // in any route (including root!)
* export default function Screen() {
* export default function Component() {
* let locales = useLocales();

@@ -20,0 +20,0 @@ * let date = new Date();

@@ -11,3 +11,3 @@ import { useMatches } from "@remix-run/react";

* // in the root loader
* export let loader: LoaderFunction = async ({ request }) => {
* export async function loader({ request }: LoaderArgs) {
* let locales = getClientLocales(request);

@@ -17,3 +17,3 @@ * return json({ locales });

* // in any route (including root!)
* export default function Screen() {
* export default function Component() {
* let locales = useLocales();

@@ -20,0 +20,0 @@ * let date = new Date();

@@ -8,6 +8,8 @@ export * from "./server/cors";

export * from "./server/named-action";
export * from "./server/preload-route-assets";
export * from "./server/json-hash";
export * from "./server/responses";
export * from "./server/rolling-cookie";
export * from "./server/safe-redirect";
export * from "./server/typed-cookie";
export * from "./server/typed-session";
export * from "./server/preload-route-assets";

@@ -8,6 +8,8 @@ export * from "./server/cors";

export * from "./server/named-action";
export * from "./server/preload-route-assets";
export * from "./server/json-hash";
export * from "./server/responses";
export * from "./server/rolling-cookie";
export * from "./server/safe-redirect";
export * from "./server/typed-cookie";
export * from "./server/typed-session";
export * from "./server/preload-route-assets";

@@ -64,3 +64,3 @@ import { Promisable } from "type-fest";

* // Create a response, then setup CORS for it
* export let loader: LoaderFunction = async ({ request }) => {
* export async function loader({ request }: LoaderArgs) {
* let data = await getData(request);

@@ -72,3 +72,3 @@ * let response = json<LoaderData>(data);

* // Create response and setup CORS in a single line
* export let loader: LoaderFunction = async ({ request }) => {
* export async function loader({ request }: LoaderArgs) {
* let data = await getData(request);

@@ -87,3 +87,3 @@ * return await cors(request, json<LoaderData>(data));

* // Pass a configuration object to setup CORS
* export let loader: LoaderFunction = async ({ request }) => {
* export async function loader({ request }: LoaderArgs) {
* let data = await getData(request);

@@ -96,3 +96,3 @@ * return await cors(request, json<LoaderData>(data), {

* // Mutate response and then return it
* export let loader: LoaderFunction = async ({ request }) => {
* export async function loader({ request }: LoaderArgs) {
* let data = await getData(request);

@@ -99,0 +99,0 @@ * let response = json<LoaderData>(data);

@@ -144,3 +144,3 @@ const DEFAULT_OPTIONS = {

* // Create a response, then setup CORS for it
* export let loader: LoaderFunction = async ({ request }) => {
* export async function loader({ request }: LoaderArgs) {
* let data = await getData(request);

@@ -152,3 +152,3 @@ * let response = json<LoaderData>(data);

* // Create response and setup CORS in a single line
* export let loader: LoaderFunction = async ({ request }) => {
* export async function loader({ request }: LoaderArgs) {
* let data = await getData(request);

@@ -167,3 +167,3 @@ * return await cors(request, json<LoaderData>(data));

* // Pass a configuration object to setup CORS
* export let loader: LoaderFunction = async ({ request }) => {
* export async function loader({ request }: LoaderArgs) {
* let data = await getData(request);

@@ -176,3 +176,3 @@ * return await cors(request, json<LoaderData>(data), {

* // Mutate response and then return it
* export let loader: LoaderFunction = async ({ request }) => {
* export async function loader({ request }: LoaderArgs) {
* let data = await getData(request);

@@ -179,0 +179,0 @@ * let response = json<LoaderData>(data);

@@ -17,3 +17,3 @@ import { Session } from "@remix-run/server-runtime";

* @example
* let action: ActionFunction = async ({ request }) => {
* export async function action({ request }: ActionArgs) {
* let session = await getSession(request.headers.get("Cookie"));

@@ -24,3 +24,3 @@ * await verifyAuthenticityToken(request, session);

* @example
* let action: ActionFunction = async ({ request }) => {
* export async function action({ request }: ActionArgs) {
* let session = await getSession(request.headers.get("Cookie"));

@@ -31,3 +31,3 @@ * await verifyAuthenticityToken(request, session, "csrfToken");

* @example
* let action: ActionFunction = async ({ request }) => {
* export async function action({ request }: ActionArgs) {
* let session = await getSession(request.headers.get("Cookie"));

@@ -34,0 +34,0 @@ * let formData = await unstable_parseMultipartFormData(request, uploadHandler);

@@ -25,3 +25,3 @@ import { v4 as uuid } from "uuid";

* @example
* let action: ActionFunction = async ({ request }) => {
* export async function action({ request }: ActionArgs) {
* let session = await getSession(request.headers.get("Cookie"));

@@ -32,3 +32,3 @@ * await verifyAuthenticityToken(request, session);

* @example
* let action: ActionFunction = async ({ request }) => {
* export async function action({ request }: ActionArgs) {
* let session = await getSession(request.headers.get("Cookie"));

@@ -39,3 +39,3 @@ * await verifyAuthenticityToken(request, session, "csrfToken");

* @example
* let action: ActionFunction = async ({ request }) => {
* export async function action({ request }: ActionArgs) {
* let session = await getSession(request.headers.get("Cookie"));

@@ -42,0 +42,0 @@ * let formData = await unstable_parseMultipartFormData(request, uploadHandler);

@@ -9,3 +9,3 @@ export declare type Locales = string[] | undefined;

* @example
* export let loader: LoaderFunction = async ({ request }) => {
* export async function loader({ request }: LoaderArgs) {
* let locales = getClientLocales(request)

@@ -12,0 +12,0 @@ * let date = new Date().toLocaleDateString(locales, {

@@ -6,3 +6,3 @@ /**

* @example
* export let loader: LoaderFunction = async ({ request }) => {
* export async function loader({ request }: LoaderArgs) {
* let data = await getData(request)

@@ -9,0 +9,0 @@ * let headers = new Headers()

@@ -1,2 +0,7 @@

declare type Actions = Record<string, () => Promise<Response>>;
import type { TypedResponse } from "@remix-run/server-runtime";
declare type ActionsRecord = Record<string, () => Promise<TypedResponse<unknown>>>;
declare type ResponsesRecord<Actions extends ActionsRecord> = {
[Action in keyof Actions]: Actions[Action] extends () => Promise<TypedResponse<infer Result>> ? Result : never;
};
declare type ResponsesUnion<Actions extends ActionsRecord> = ResponsesRecord<Actions>[keyof Actions];
/**

@@ -10,6 +15,6 @@ * Runs an action based on the request's action name

*/
export declare function namedAction(request: Request, actions: Actions): Promise<Response>;
export declare function namedAction(url: URL, actions: Actions): Promise<Response>;
export declare function namedAction(searchParams: URLSearchParams, actions: Actions): Promise<Response>;
export declare function namedAction(formData: FormData, actions: Actions): Promise<Response>;
export declare function namedAction<Actions extends ActionsRecord>(request: Request, actions: Actions): Promise<TypedResponse<ResponsesUnion<Actions>>>;
export declare function namedAction<Actions extends ActionsRecord>(url: URL, actions: Actions): Promise<TypedResponse<ResponsesUnion<Actions>>>;
export declare function namedAction<Actions extends ActionsRecord>(searchParams: URLSearchParams, actions: Actions): Promise<TypedResponse<ResponsesUnion<Actions>>>;
export declare function namedAction<Actions extends ActionsRecord>(formData: FormData, actions: Actions): Promise<TypedResponse<ResponsesUnion<Actions>>>;
export {};
export async function namedAction(input, actions) {
let name = await getActionName(input);
if (name && name in actions)
if (name && name in actions) {
return actions[name]();
if (name === null && "default" in actions)
}
if (name === null && "default" in actions) {
return actions["default"]();
}
if (name === null)

@@ -8,0 +10,0 @@ throw new ReferenceError("Action name not found");

@@ -57,3 +57,3 @@ /**

export function preloadLinkedAssets(context, headers) {
let links = context.matches
let links = context.staticHandlerContext.matches
.flatMap((match) => {

@@ -115,4 +115,5 @@ let route = context.routeModules[match.route.id];

];
for (let match of context.matches) {
urls.push(match.route.module, ...((_a = match.route.imports) !== null && _a !== void 0 ? _a : []));
for (let match of context.staticHandlerContext.matches) {
let route = context.manifest.routes[match.route.id];
urls.push(route.module, ...((_a = route.imports) !== null && _a !== void 0 ? _a : []));
}

@@ -119,0 +120,0 @@ for (let url of urls) {

@@ -5,3 +5,3 @@ /// <reference types="node" />

* @example
* export let action: ActionFunction = async ({ request }) => {
* export async function action({ request }: ActionArgs) {
* let result = await doSomething(request);

@@ -18,3 +18,3 @@ * return created(result);

* @example
* export let action: ActionFunction = async ({ request }) => {
* export async function action({ request }: ActionArgs) {
* await doSomething(request);

@@ -33,3 +33,3 @@ * // If the user was on `/search?query=something` we redirect to that URL

* @example
* export let loader: LoaderFunction = async ({ request }) => {
* export async function loader({ request }: LoaderArgs) {
* let user = await getUser(request);

@@ -43,3 +43,3 @@ * throw badRequest<BoundaryData>({ user });

* @example
* export let loader: LoaderFunction = async ({ request }) => {
* export async function loader({ request }: LoaderArgs) {
* let user = await getUser(request);

@@ -53,3 +53,3 @@ * throw unauthorized<BoundaryData>({ user });

* @example
* export let loader: LoaderFunction = async ({ request }) => {
* export async function loader({ request }: LoaderArgs) {
* let user = await getUser(request);

@@ -63,3 +63,3 @@ * if (!user.idAdmin) throw forbidden<BoundaryData>({ user });

* @example
* export let loader: LoaderFunction = async ({ request, params }) => {
* export async function loader({ request, params }: LoaderArgs) {
* let user = await getUser(request);

@@ -73,3 +73,3 @@ * if (!db.exists(params.id)) throw notFound<BoundaryData>({ user });

* @example
* export let loader: LoaderFunction = async ({ request, params }) => {
* export async function loader({ request, params }: LoaderArgs) {
* let user = await getUser(request);

@@ -83,3 +83,3 @@ * throw unprocessableEntity<BoundaryData>({ user });

* @example
* export let loader: LoaderFunction = async ({ request }) => {
* export async function loader({ request }: LoaderArgs) {
* let user = await getUser(request);

@@ -94,3 +94,3 @@ * throw serverError<BoundaryData>({ user });

* @example
* export let loader: LoaderFunction = async ({ request }) => {
* export async function loader({ request }: LoaderArgs) {
* return notModified();

@@ -107,3 +107,3 @@ * }

* @example
* export let loader: LoaderFunction = async ({ request }) => {
* export async function loader({ request }: LoaderArgs) {
* return javascript("console.log('Hello World')");

@@ -120,3 +120,3 @@ * }

* @example
* export let loader: LoaderFunction = async ({ request }) => {
* export async function loader({ request }: LoaderArgs) {
* return css("body { color: red; }");

@@ -133,3 +133,3 @@ * }

* @example
* export let loader: LoaderFunction = async ({ request }) => {
* export async function loader({ request }: LoaderArgs) {
* return pdf(await generatePDF(request.formData()));

@@ -146,3 +146,3 @@ * }

* @example
* export let loader: LoaderFunction = async ({ request }) => {
* export async function loader({ request }: LoaderArgs) {
* return html("<h1>Hello World</h1>");

@@ -152,2 +152,29 @@ * }

export declare function html(content: string, init?: number | ResponseInit): Response;
/**
* Create a response with a XML file response.
* It receives a string with the XML content and set the Content-Type header to
* `application/xml; charset=utf-8` always.
*
* This is useful to dynamically create a XML file from a Resource Route.
* @example
* export let loader: LoaderFunction = async ({ request }) => {
* return xml("<?xml version='1.0'?><catalog></catalog>");
* }
*/
export declare function xml(content: string, init?: number | ResponseInit): Response;
/**
* Create a response with a TXT file response.
* It receives a string with the TXT content and set the Content-Type header to
* `text/plain; charset=utf-8` always.
*
* This is useful to dynamically create a TXT file from a Resource Route.
* @example
* export let loader: LoaderFunction = async ({ request }) => {
* return txt(`
* User-agent: *
* Allow: /
* `);
* }
*/
export declare function txt(content: string, init?: number | ResponseInit): Response;
export declare type ImageType = "image/jpeg" | "image/png" | "image/gif" | "image/svg+xml" | "image/webp" | "image/bmp" | "image/avif";

@@ -161,3 +188,3 @@ /**

* @example
* export let loader: LoaderFunction = async ({ request }) => {
* export async function loader({ request }: LoaderArgs) {
* return image(await takeScreenshot(), { type: "image/avif" });

@@ -164,0 +191,0 @@ * }

@@ -5,3 +5,3 @@ import { json, redirect } from "@remix-run/server-runtime";

* @example
* export let action: ActionFunction = async ({ request }) => {
* export async function action({ request }: ActionArgs) {
* let result = await doSomething(request);

@@ -20,3 +20,3 @@ * return created(result);

* @example
* export let action: ActionFunction = async ({ request }) => {
* export async function action({ request }: ActionArgs) {
* await doSomething(request);

@@ -36,3 +36,3 @@ * // If the user was on `/search?query=something` we redirect to that URL

* @example
* export let loader: LoaderFunction = async ({ request }) => {
* export async function loader({ request }: LoaderArgs) {
* let user = await getUser(request);

@@ -48,3 +48,3 @@ * throw badRequest<BoundaryData>({ user });

* @example
* export let loader: LoaderFunction = async ({ request }) => {
* export async function loader({ request }: LoaderArgs) {
* let user = await getUser(request);

@@ -60,3 +60,3 @@ * throw unauthorized<BoundaryData>({ user });

* @example
* export let loader: LoaderFunction = async ({ request }) => {
* export async function loader({ request }: LoaderArgs) {
* let user = await getUser(request);

@@ -72,3 +72,3 @@ * if (!user.idAdmin) throw forbidden<BoundaryData>({ user });

* @example
* export let loader: LoaderFunction = async ({ request, params }) => {
* export async function loader({ request, params }: LoaderArgs) {
* let user = await getUser(request);

@@ -84,3 +84,3 @@ * if (!db.exists(params.id)) throw notFound<BoundaryData>({ user });

* @example
* export let loader: LoaderFunction = async ({ request, params }) => {
* export async function loader({ request, params }: LoaderArgs) {
* let user = await getUser(request);

@@ -96,3 +96,3 @@ * throw unprocessableEntity<BoundaryData>({ user });

* @example
* export let loader: LoaderFunction = async ({ request }) => {
* export async function loader({ request }: LoaderArgs) {
* let user = await getUser(request);

@@ -109,3 +109,3 @@ * throw serverError<BoundaryData>({ user });

* @example
* export let loader: LoaderFunction = async ({ request }) => {
* export async function loader({ request }: LoaderArgs) {
* return notModified();

@@ -124,3 +124,3 @@ * }

* @example
* export let loader: LoaderFunction = async ({ request }) => {
* export async function loader({ request }: LoaderArgs) {
* return javascript("console.log('Hello World')");

@@ -147,3 +147,3 @@ * }

* @example
* export let loader: LoaderFunction = async ({ request }) => {
* export async function loader({ request }: LoaderArgs) {
* return css("body { color: red; }");

@@ -170,3 +170,3 @@ * }

* @example
* export let loader: LoaderFunction = async ({ request }) => {
* export async function loader({ request }: LoaderArgs) {
* return pdf(await generatePDF(request.formData()));

@@ -193,3 +193,3 @@ * }

* @example
* export let loader: LoaderFunction = async ({ request }) => {
* export async function loader({ request }: LoaderArgs) {
* return html("<h1>Hello World</h1>");

@@ -210,2 +210,49 @@ * }

/**
* Create a response with a XML file response.
* It receives a string with the XML content and set the Content-Type header to
* `application/xml; charset=utf-8` always.
*
* This is useful to dynamically create a XML file from a Resource Route.
* @example
* export let loader: LoaderFunction = async ({ request }) => {
* return xml("<?xml version='1.0'?><catalog></catalog>");
* }
*/
export function xml(content, init = {}) {
let responseInit = typeof init === "number" ? { status: init } : init;
let headers = new Headers(responseInit.headers);
if (!headers.has("Content-Type")) {
headers.set("Content-Type", "application/xml; charset=utf-8");
}
return new Response(content, {
...responseInit,
headers,
});
}
/**
* Create a response with a TXT file response.
* It receives a string with the TXT content and set the Content-Type header to
* `text/plain; charset=utf-8` always.
*
* This is useful to dynamically create a TXT file from a Resource Route.
* @example
* export let loader: LoaderFunction = async ({ request }) => {
* return txt(`
* User-agent: *
* Allow: /
* `);
* }
*/
export function txt(content, init = {}) {
let responseInit = typeof init === "number" ? { status: init } : init;
let headers = new Headers(responseInit.headers);
if (!headers.has("Content-Type")) {
headers.set("Content-Type", "text/plain; charset=utf-8");
}
return new Response(content, {
...responseInit,
headers,
});
}
/**
* Create a response with a image file response.

@@ -217,3 +264,3 @@ * It receives a Buffer, ArrayBuffer or ReadableStream with the image content

* @example
* export let loader: LoaderFunction = async ({ request }) => {
* export async function loader({ request }: LoaderArgs) {
* return image(await takeScreenshot(), { type: "image/avif" });

@@ -220,0 +267,0 @@ * }

@@ -1,2 +0,1 @@

import type { PromiseValue } from "type-fest";
/**

@@ -7,3 +6,3 @@ * @see https://twitter.com/buildsghost/status/1507109734519750680

export declare type AwaitedPromiseHash<Hash extends PromiseHash> = {
[Key in keyof Hash]: PromiseValue<Hash[Key]>;
[Key in keyof Hash]: Awaited<Hash[Key]>;
};

@@ -14,3 +13,3 @@ /**

* @example
* export let loader: LoaderFunction = async ({ request }) => {
* export async function loader({ request }: LoaderArgs) {
* return json(

@@ -22,5 +21,5 @@ * promiseHash({

* );
* };
* }
* @example
* export let loader: LoaderFunction = async ({ request }) => {
* export async function loader({ request }: LoaderArgs) {
* return json(

@@ -38,4 +37,4 @@ * promiseHash({

* );
* };
* }
*/
export declare function promiseHash<Hash extends PromiseHash>(hash: Hash): Promise<AwaitedPromiseHash<Hash>>;

@@ -8,3 +8,3 @@ "use strict";

* @example
* export let loader: LoaderFunction = async ({ request }) => {
* export async function loader({ request }: LoaderArgs) {
* return json(

@@ -16,5 +16,5 @@ * promiseHash({

* );
* };
* }
* @example
* export let loader: LoaderFunction = async ({ request }) => {
* export async function loader({ request }: LoaderArgs) {
* return json(

@@ -32,3 +32,3 @@ * promiseHash({

* );
* };
* }
*/

@@ -35,0 +35,0 @@ async function promiseHash(hash) {

@@ -8,3 +8,2 @@ export * from "./react/cache-assets";

export * from "./react/structured-data";
export * from "./react/use-data-refresh";
export * from "./react/use-event-source";

@@ -14,3 +13,2 @@ export * from "./react/use-global-pending-state";

export * from "./react/use-locales";
export * from "./react/use-route-data";
export * from "./react/use-should-hydrate";

@@ -24,3 +24,2 @@ "use strict";

__exportStar(require("./react/structured-data"), exports);
__exportStar(require("./react/use-data-refresh"), exports);
__exportStar(require("./react/use-event-source"), exports);

@@ -30,3 +29,2 @@ __exportStar(require("./react/use-global-pending-state"), exports);

__exportStar(require("./react/use-locales"), exports);
__exportStar(require("./react/use-route-data"), exports);
__exportStar(require("./react/use-should-hydrate"), exports);

@@ -11,3 +11,3 @@ import type { Locales } from "../server/get-client-locales";

* // in the root loader
* export let loader: LoaderFunction = async ({ request }) => {
* export async function loader({ request }: LoaderArgs) {
* let locales = getClientLocales(request);

@@ -17,3 +17,3 @@ * return json({ locales });

* // in any route (including root!)
* export default function Screen() {
* export default function Component() {
* let locales = useLocales();

@@ -20,0 +20,0 @@ * let date = new Date();

@@ -14,3 +14,3 @@ "use strict";

* // in the root loader
* export let loader: LoaderFunction = async ({ request }) => {
* export async function loader({ request }: LoaderArgs) {
* let locales = getClientLocales(request);

@@ -20,3 +20,3 @@ * return json({ locales });

* // in any route (including root!)
* export default function Screen() {
* export default function Component() {
* let locales = useLocales();

@@ -23,0 +23,0 @@ * let date = new Date();

@@ -8,6 +8,8 @@ export * from "./server/cors";

export * from "./server/named-action";
export * from "./server/preload-route-assets";
export * from "./server/json-hash";
export * from "./server/responses";
export * from "./server/rolling-cookie";
export * from "./server/safe-redirect";
export * from "./server/typed-cookie";
export * from "./server/typed-session";
export * from "./server/preload-route-assets";

@@ -24,6 +24,8 @@ "use strict";

__exportStar(require("./server/named-action"), exports);
__exportStar(require("./server/preload-route-assets"), exports);
__exportStar(require("./server/json-hash"), exports);
__exportStar(require("./server/responses"), exports);
__exportStar(require("./server/rolling-cookie"), exports);
__exportStar(require("./server/safe-redirect"), exports);
__exportStar(require("./server/typed-cookie"), exports);
__exportStar(require("./server/typed-session"), exports);
__exportStar(require("./server/preload-route-assets"), exports);

@@ -64,3 +64,3 @@ import { Promisable } from "type-fest";

* // Create a response, then setup CORS for it
* export let loader: LoaderFunction = async ({ request }) => {
* export async function loader({ request }: LoaderArgs) {
* let data = await getData(request);

@@ -72,3 +72,3 @@ * let response = json<LoaderData>(data);

* // Create response and setup CORS in a single line
* export let loader: LoaderFunction = async ({ request }) => {
* export async function loader({ request }: LoaderArgs) {
* let data = await getData(request);

@@ -87,3 +87,3 @@ * return await cors(request, json<LoaderData>(data));

* // Pass a configuration object to setup CORS
* export let loader: LoaderFunction = async ({ request }) => {
* export async function loader({ request }: LoaderArgs) {
* let data = await getData(request);

@@ -96,3 +96,3 @@ * return await cors(request, json<LoaderData>(data), {

* // Mutate response and then return it
* export let loader: LoaderFunction = async ({ request }) => {
* export async function loader({ request }: LoaderArgs) {
* let data = await getData(request);

@@ -99,0 +99,0 @@ * let response = json<LoaderData>(data);

@@ -147,3 +147,3 @@ "use strict";

* // Create a response, then setup CORS for it
* export let loader: LoaderFunction = async ({ request }) => {
* export async function loader({ request }: LoaderArgs) {
* let data = await getData(request);

@@ -155,3 +155,3 @@ * let response = json<LoaderData>(data);

* // Create response and setup CORS in a single line
* export let loader: LoaderFunction = async ({ request }) => {
* export async function loader({ request }: LoaderArgs) {
* let data = await getData(request);

@@ -170,3 +170,3 @@ * return await cors(request, json<LoaderData>(data));

* // Pass a configuration object to setup CORS
* export let loader: LoaderFunction = async ({ request }) => {
* export async function loader({ request }: LoaderArgs) {
* let data = await getData(request);

@@ -179,3 +179,3 @@ * return await cors(request, json<LoaderData>(data), {

* // Mutate response and then return it
* export let loader: LoaderFunction = async ({ request }) => {
* export async function loader({ request }: LoaderArgs) {
* let data = await getData(request);

@@ -182,0 +182,0 @@ * let response = json<LoaderData>(data);

@@ -17,3 +17,3 @@ import { Session } from "@remix-run/server-runtime";

* @example
* let action: ActionFunction = async ({ request }) => {
* export async function action({ request }: ActionArgs) {
* let session = await getSession(request.headers.get("Cookie"));

@@ -24,3 +24,3 @@ * await verifyAuthenticityToken(request, session);

* @example
* let action: ActionFunction = async ({ request }) => {
* export async function action({ request }: ActionArgs) {
* let session = await getSession(request.headers.get("Cookie"));

@@ -31,3 +31,3 @@ * await verifyAuthenticityToken(request, session, "csrfToken");

* @example
* let action: ActionFunction = async ({ request }) => {
* export async function action({ request }: ActionArgs) {
* let session = await getSession(request.headers.get("Cookie"));

@@ -34,0 +34,0 @@ * let formData = await unstable_parseMultipartFormData(request, uploadHandler);

@@ -29,3 +29,3 @@ "use strict";

* @example
* let action: ActionFunction = async ({ request }) => {
* export async function action({ request }: ActionArgs) {
* let session = await getSession(request.headers.get("Cookie"));

@@ -36,3 +36,3 @@ * await verifyAuthenticityToken(request, session);

* @example
* let action: ActionFunction = async ({ request }) => {
* export async function action({ request }: ActionArgs) {
* let session = await getSession(request.headers.get("Cookie"));

@@ -43,3 +43,3 @@ * await verifyAuthenticityToken(request, session, "csrfToken");

* @example
* let action: ActionFunction = async ({ request }) => {
* export async function action({ request }: ActionArgs) {
* let session = await getSession(request.headers.get("Cookie"));

@@ -46,0 +46,0 @@ * let formData = await unstable_parseMultipartFormData(request, uploadHandler);

@@ -9,3 +9,3 @@ export declare type Locales = string[] | undefined;

* @example
* export let loader: LoaderFunction = async ({ request }) => {
* export async function loader({ request }: LoaderArgs) {
* let locales = getClientLocales(request)

@@ -12,0 +12,0 @@ * let date = new Date().toLocaleDateString(locales, {

@@ -6,3 +6,3 @@ /**

* @example
* export let loader: LoaderFunction = async ({ request }) => {
* export async function loader({ request }: LoaderArgs) {
* let data = await getData(request)

@@ -9,0 +9,0 @@ * let headers = new Headers()

@@ -1,2 +0,7 @@

declare type Actions = Record<string, () => Promise<Response>>;
import type { TypedResponse } from "@remix-run/server-runtime";
declare type ActionsRecord = Record<string, () => Promise<TypedResponse<unknown>>>;
declare type ResponsesRecord<Actions extends ActionsRecord> = {
[Action in keyof Actions]: Actions[Action] extends () => Promise<TypedResponse<infer Result>> ? Result : never;
};
declare type ResponsesUnion<Actions extends ActionsRecord> = ResponsesRecord<Actions>[keyof Actions];
/**

@@ -10,6 +15,6 @@ * Runs an action based on the request's action name

*/
export declare function namedAction(request: Request, actions: Actions): Promise<Response>;
export declare function namedAction(url: URL, actions: Actions): Promise<Response>;
export declare function namedAction(searchParams: URLSearchParams, actions: Actions): Promise<Response>;
export declare function namedAction(formData: FormData, actions: Actions): Promise<Response>;
export declare function namedAction<Actions extends ActionsRecord>(request: Request, actions: Actions): Promise<TypedResponse<ResponsesUnion<Actions>>>;
export declare function namedAction<Actions extends ActionsRecord>(url: URL, actions: Actions): Promise<TypedResponse<ResponsesUnion<Actions>>>;
export declare function namedAction<Actions extends ActionsRecord>(searchParams: URLSearchParams, actions: Actions): Promise<TypedResponse<ResponsesUnion<Actions>>>;
export declare function namedAction<Actions extends ActionsRecord>(formData: FormData, actions: Actions): Promise<TypedResponse<ResponsesUnion<Actions>>>;
export {};

@@ -6,6 +6,8 @@ "use strict";

let name = await getActionName(input);
if (name && name in actions)
if (name && name in actions) {
return actions[name]();
if (name === null && "default" in actions)
}
if (name === null && "default" in actions) {
return actions["default"]();
}
if (name === null)

@@ -12,0 +14,0 @@ throw new ReferenceError("Action name not found");

@@ -61,3 +61,3 @@ "use strict";

function preloadLinkedAssets(context, headers) {
let links = context.matches
let links = context.staticHandlerContext.matches
.flatMap((match) => {

@@ -120,4 +120,5 @@ let route = context.routeModules[match.route.id];

];
for (let match of context.matches) {
urls.push(match.route.module, ...((_a = match.route.imports) !== null && _a !== void 0 ? _a : []));
for (let match of context.staticHandlerContext.matches) {
let route = context.manifest.routes[match.route.id];
urls.push(route.module, ...((_a = route.imports) !== null && _a !== void 0 ? _a : []));
}

@@ -124,0 +125,0 @@ for (let url of urls) {

@@ -5,3 +5,3 @@ /// <reference types="node" />

* @example
* export let action: ActionFunction = async ({ request }) => {
* export async function action({ request }: ActionArgs) {
* let result = await doSomething(request);

@@ -18,3 +18,3 @@ * return created(result);

* @example
* export let action: ActionFunction = async ({ request }) => {
* export async function action({ request }: ActionArgs) {
* await doSomething(request);

@@ -33,3 +33,3 @@ * // If the user was on `/search?query=something` we redirect to that URL

* @example
* export let loader: LoaderFunction = async ({ request }) => {
* export async function loader({ request }: LoaderArgs) {
* let user = await getUser(request);

@@ -43,3 +43,3 @@ * throw badRequest<BoundaryData>({ user });

* @example
* export let loader: LoaderFunction = async ({ request }) => {
* export async function loader({ request }: LoaderArgs) {
* let user = await getUser(request);

@@ -53,3 +53,3 @@ * throw unauthorized<BoundaryData>({ user });

* @example
* export let loader: LoaderFunction = async ({ request }) => {
* export async function loader({ request }: LoaderArgs) {
* let user = await getUser(request);

@@ -63,3 +63,3 @@ * if (!user.idAdmin) throw forbidden<BoundaryData>({ user });

* @example
* export let loader: LoaderFunction = async ({ request, params }) => {
* export async function loader({ request, params }: LoaderArgs) {
* let user = await getUser(request);

@@ -73,3 +73,3 @@ * if (!db.exists(params.id)) throw notFound<BoundaryData>({ user });

* @example
* export let loader: LoaderFunction = async ({ request, params }) => {
* export async function loader({ request, params }: LoaderArgs) {
* let user = await getUser(request);

@@ -83,3 +83,3 @@ * throw unprocessableEntity<BoundaryData>({ user });

* @example
* export let loader: LoaderFunction = async ({ request }) => {
* export async function loader({ request }: LoaderArgs) {
* let user = await getUser(request);

@@ -94,3 +94,3 @@ * throw serverError<BoundaryData>({ user });

* @example
* export let loader: LoaderFunction = async ({ request }) => {
* export async function loader({ request }: LoaderArgs) {
* return notModified();

@@ -107,3 +107,3 @@ * }

* @example
* export let loader: LoaderFunction = async ({ request }) => {
* export async function loader({ request }: LoaderArgs) {
* return javascript("console.log('Hello World')");

@@ -120,3 +120,3 @@ * }

* @example
* export let loader: LoaderFunction = async ({ request }) => {
* export async function loader({ request }: LoaderArgs) {
* return css("body { color: red; }");

@@ -133,3 +133,3 @@ * }

* @example
* export let loader: LoaderFunction = async ({ request }) => {
* export async function loader({ request }: LoaderArgs) {
* return pdf(await generatePDF(request.formData()));

@@ -146,3 +146,3 @@ * }

* @example
* export let loader: LoaderFunction = async ({ request }) => {
* export async function loader({ request }: LoaderArgs) {
* return html("<h1>Hello World</h1>");

@@ -152,2 +152,29 @@ * }

export declare function html(content: string, init?: number | ResponseInit): Response;
/**
* Create a response with a XML file response.
* It receives a string with the XML content and set the Content-Type header to
* `application/xml; charset=utf-8` always.
*
* This is useful to dynamically create a XML file from a Resource Route.
* @example
* export let loader: LoaderFunction = async ({ request }) => {
* return xml("<?xml version='1.0'?><catalog></catalog>");
* }
*/
export declare function xml(content: string, init?: number | ResponseInit): Response;
/**
* Create a response with a TXT file response.
* It receives a string with the TXT content and set the Content-Type header to
* `text/plain; charset=utf-8` always.
*
* This is useful to dynamically create a TXT file from a Resource Route.
* @example
* export let loader: LoaderFunction = async ({ request }) => {
* return txt(`
* User-agent: *
* Allow: /
* `);
* }
*/
export declare function txt(content: string, init?: number | ResponseInit): Response;
export declare type ImageType = "image/jpeg" | "image/png" | "image/gif" | "image/svg+xml" | "image/webp" | "image/bmp" | "image/avif";

@@ -161,3 +188,3 @@ /**

* @example
* export let loader: LoaderFunction = async ({ request }) => {
* export async function loader({ request }: LoaderArgs) {
* return image(await takeScreenshot(), { type: "image/avif" });

@@ -164,0 +191,0 @@ * }

"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.image = exports.html = exports.pdf = exports.stylesheet = exports.javascript = exports.notModified = exports.serverError = exports.unprocessableEntity = exports.notFound = exports.forbidden = exports.unauthorized = exports.badRequest = exports.redirectBack = exports.created = void 0;
exports.image = exports.txt = exports.xml = exports.html = exports.pdf = exports.stylesheet = exports.javascript = exports.notModified = exports.serverError = exports.unprocessableEntity = exports.notFound = exports.forbidden = exports.unauthorized = exports.badRequest = exports.redirectBack = exports.created = void 0;
const server_runtime_1 = require("@remix-run/server-runtime");

@@ -8,3 +8,3 @@ /**

* @example
* export let action: ActionFunction = async ({ request }) => {
* export async function action({ request }: ActionArgs) {
* let result = await doSomething(request);

@@ -24,3 +24,3 @@ * return created(result);

* @example
* export let action: ActionFunction = async ({ request }) => {
* export async function action({ request }: ActionArgs) {
* await doSomething(request);

@@ -41,3 +41,3 @@ * // If the user was on `/search?query=something` we redirect to that URL

* @example
* export let loader: LoaderFunction = async ({ request }) => {
* export async function loader({ request }: LoaderArgs) {
* let user = await getUser(request);

@@ -54,3 +54,3 @@ * throw badRequest<BoundaryData>({ user });

* @example
* export let loader: LoaderFunction = async ({ request }) => {
* export async function loader({ request }: LoaderArgs) {
* let user = await getUser(request);

@@ -67,3 +67,3 @@ * throw unauthorized<BoundaryData>({ user });

* @example
* export let loader: LoaderFunction = async ({ request }) => {
* export async function loader({ request }: LoaderArgs) {
* let user = await getUser(request);

@@ -80,3 +80,3 @@ * if (!user.idAdmin) throw forbidden<BoundaryData>({ user });

* @example
* export let loader: LoaderFunction = async ({ request, params }) => {
* export async function loader({ request, params }: LoaderArgs) {
* let user = await getUser(request);

@@ -93,3 +93,3 @@ * if (!db.exists(params.id)) throw notFound<BoundaryData>({ user });

* @example
* export let loader: LoaderFunction = async ({ request, params }) => {
* export async function loader({ request, params }: LoaderArgs) {
* let user = await getUser(request);

@@ -106,3 +106,3 @@ * throw unprocessableEntity<BoundaryData>({ user });

* @example
* export let loader: LoaderFunction = async ({ request }) => {
* export async function loader({ request }: LoaderArgs) {
* let user = await getUser(request);

@@ -120,3 +120,3 @@ * throw serverError<BoundaryData>({ user });

* @example
* export let loader: LoaderFunction = async ({ request }) => {
* export async function loader({ request }: LoaderArgs) {
* return notModified();

@@ -136,3 +136,3 @@ * }

* @example
* export let loader: LoaderFunction = async ({ request }) => {
* export async function loader({ request }: LoaderArgs) {
* return javascript("console.log('Hello World')");

@@ -160,3 +160,3 @@ * }

* @example
* export let loader: LoaderFunction = async ({ request }) => {
* export async function loader({ request }: LoaderArgs) {
* return css("body { color: red; }");

@@ -184,3 +184,3 @@ * }

* @example
* export let loader: LoaderFunction = async ({ request }) => {
* export async function loader({ request }: LoaderArgs) {
* return pdf(await generatePDF(request.formData()));

@@ -208,3 +208,3 @@ * }

* @example
* export let loader: LoaderFunction = async ({ request }) => {
* export async function loader({ request }: LoaderArgs) {
* return html("<h1>Hello World</h1>");

@@ -226,2 +226,51 @@ * }

/**
* Create a response with a XML file response.
* It receives a string with the XML content and set the Content-Type header to
* `application/xml; charset=utf-8` always.
*
* This is useful to dynamically create a XML file from a Resource Route.
* @example
* export let loader: LoaderFunction = async ({ request }) => {
* return xml("<?xml version='1.0'?><catalog></catalog>");
* }
*/
function xml(content, init = {}) {
let responseInit = typeof init === "number" ? { status: init } : init;
let headers = new Headers(responseInit.headers);
if (!headers.has("Content-Type")) {
headers.set("Content-Type", "application/xml; charset=utf-8");
}
return new Response(content, {
...responseInit,
headers,
});
}
exports.xml = xml;
/**
* Create a response with a TXT file response.
* It receives a string with the TXT content and set the Content-Type header to
* `text/plain; charset=utf-8` always.
*
* This is useful to dynamically create a TXT file from a Resource Route.
* @example
* export let loader: LoaderFunction = async ({ request }) => {
* return txt(`
* User-agent: *
* Allow: /
* `);
* }
*/
function txt(content, init = {}) {
let responseInit = typeof init === "number" ? { status: init } : init;
let headers = new Headers(responseInit.headers);
if (!headers.has("Content-Type")) {
headers.set("Content-Type", "text/plain; charset=utf-8");
}
return new Response(content, {
...responseInit,
headers,
});
}
exports.txt = txt;
/**
* Create a response with a image file response.

@@ -233,3 +282,3 @@ * It receives a Buffer, ArrayBuffer or ReadableStream with the image content

* @example
* export let loader: LoaderFunction = async ({ request }) => {
* export async function loader({ request }: LoaderArgs) {
* return image(await takeScreenshot(), { type: "image/avif" });

@@ -236,0 +285,0 @@ * }

{
"name": "remix-utils",
"version": "5.3.0",
"version": "6.0.0",
"license": "MIT",

@@ -43,4 +43,4 @@ "engines": {

"peerDependencies": {
"@remix-run/react": "^1.5.1",
"@remix-run/server-runtime": "^1.5.1",
"@remix-run/react": "^1.10.0",
"@remix-run/server-runtime": "^1.10.0",
"react": "^16.8.0 || ^17.0.0 || ^18.0.0",

@@ -55,5 +55,5 @@ "zod": "^3.19.1"

"@jest/types": "^27.2.5",
"@remix-run/node": "^1.5.1",
"@remix-run/react": "^1.5.1",
"@remix-run/server-runtime": "^1.5.1",
"@remix-run/node": "^1.10.0",
"@remix-run/react": "^1.10.0",
"@remix-run/server-runtime": "^1.10.0",
"@testing-library/jest-dom": "^5.15.0",

@@ -60,0 +60,0 @@ "@testing-library/react": "^12.1.2",

@@ -20,3 +20,3 @@ # Remix Utils

```ts
export let loader: LoaderFunction = async ({ request }) => {
export async function loader({ request }: LoaderArgs) {
return json(

@@ -28,3 +28,3 @@ promiseHash({

);
};
}
```

@@ -35,3 +35,3 @@

```ts
export let loader: LoaderFunction = async ({ request }) => {
export async function loader({ request }: LoaderArgs) {
return json(

@@ -49,3 +49,3 @@ promiseHash({

);
};
}
```

@@ -94,3 +94,3 @@

export default function View() {
export default function Component() {
return (

@@ -127,7 +127,7 @@ <ClientOnly fallback={<SimplerStaticVersion />}>

```ts
export let loader: LoaderFunction = async ({ request }) => {
export async function loader({ request }: LoaderArgs) {
let data = await getData(request);
let response = json<LoaderData>(data);
return await cors(request, response);
};
}
```

@@ -138,6 +138,6 @@

```ts
export let loader: LoaderFunction = async ({ request }) => {
export async function loader({ request }: LoaderArgs) {
let data = await getData(request);
return await cors(request, json<LoaderData>(data));
};
}
```

@@ -148,3 +148,3 @@

```ts
export let loader: LoaderFunction = async ({ request }) => {
export async function loader({ request }: LoaderArgs) {
let data = await getData(request);

@@ -154,3 +154,3 @@ let response = json<LoaderData>(data);

return response; // so you can return it here
};
}
```

@@ -202,3 +202,2 @@

```ts
import type { LoaderFunction } from "remix";
import { createAuthenticityToken, json } from "remix-utils";

@@ -211,3 +210,3 @@ import { getSession, commitSession } from "~/services/session.server";

export let loader: LoaderFunction = async ({ request }) => {
export async function loader({ request }: LoaderArgs) {
let session = await getSession(request.headers.get("cookie"));

@@ -219,3 +218,3 @@ let token = createAuthenticityToken(session);

);
};
}
```

@@ -230,6 +229,6 @@

```tsx
import { Outlet, useLoaderData } from "remix";
import { Outlet, useLoaderData } from "@remix-run/react";
import { Document } from "~/components/document";
export default function Root() {
export default function Component() {
let { csrf } = useLoaderData<LoaderData>();

@@ -253,6 +252,6 @@ return (

```tsx
import { Form } from "remix";
import { Form } from "@remix-run/react";
import { AuthenticityTokenInput } from "remix-utils";
export default function SomeRoute() {
export default function Component() {
return (

@@ -298,8 +297,7 @@ <Form method="post">

```ts
import type { ActionFunction } from "remix";
```t
import { verifyAuthenticityToken, redirectBack } from "remix-utils";
import { getSession, commitSession } from "~/services/session.server";
export let action: ActionFunction = async ({ request }) => {
export async function action({ request }: ActionArgs) {
let session = await getSession(request.headers.get("Cookie"));

@@ -309,3 +307,3 @@ await verifyAuthenticityToken(request, session);

return redirectBack(request, { fallback: "/fallback" });
};
}
```

@@ -509,41 +507,2 @@

### useDataRefresh
This hook lets you trigger a refresh of the loaders in the current URL.
The way this works is by sending a fetcher.submit to `/dev/null` to trigger all loaders to run.
You need to create `app/routes/dev/null.ts` and define an action that returns null.
```ts
// app/routes/dev/null.ts
export function action() {
return null;
}
```
This Hook is mostly useful if you want to trigger the refresh manually from an effect, examples of this are:
- Set an interval to trigger the refresh
- Refresh when the browser tab is focused again
- Refresh when the user is online again
```ts
import { useDataRefresh } from "remix-utils";
function useDataRefreshOnInterval() {
let { refresh } = useDataRefresh();
useEffect(() => {
let interval = setInterval(refresh, 5000);
return () => clearInterval(interval);
}, [refresh]);
}
```
The return value of `useDataRefresh` is an object with the following keys:
- refresh: a function that trigger the refresh
- type: a string which can be `init`, `refreshRedirect` or `refresh`
- status: a string which can be `loading` or `idle`
### useGlobalTransitionStates

@@ -662,9 +621,9 @@

// in the root loader
export let loader: LoaderFunction = async ({ request }) => {
export async function loader({ request }: LoaderArgs) {
let locales = getClientLocales(request);
return json({ locales });
};
}
// in any route (including root!)
export default function Screen() {
export default function Component() {
let locales = useLocales();

@@ -680,31 +639,2 @@ let date = new Date();

### useRouteData
This hook lets you access the data of any route in the current page. This can include child or parent routes.
To use it, call `useRouteData` in your component and pass the route ID as a string. As an example, if you had the following routes:
```
routes/articles/$slug.tsx
routes/articles/index.tsx
routes/articles.tsx
```
Then you need to pass `useRouteData("routes/articles")` to get the data of `routes/articles.tsx`, `useRouteData("routes/articles/index")` to get the data of `routes/articles/index.tsx` and `routes/articles/$slug` to get the data of `routes/articles/$slug.tsx`.
As you can see, the ID is the route file without the extension.
```ts
let parentData = useRouteData("routes/articles");
let indexData = useRouteData("routes/articles/index");
```
The `useRouteData` hook receives a generic to be used as the type of the route data. Because the route may not be found the return type is `Data | undefined`. This means if you do the following:
```ts
let data = useRouteData<ArticleShowData>("routes/articles");
```
The type of `data` will be `ArticleShowData | undefined`, so you will need to check if it's not undefined before being able to use it.
### useShouldHydrate

@@ -718,3 +648,3 @@

import type { ReactNode } from "react";
import { Links, LiveReload, Meta, Scripts } from "remix";
import { Links, LiveReload, Meta, Scripts } from "@remix-run/react";
import { useShouldHydrate } from "remix-utils";

@@ -773,3 +703,3 @@

```ts
export let loader: LoaderFunction = async ({ request }) => {
export async function loader({ request }: LoaderArgs) {
// using the request

@@ -779,3 +709,3 @@ let ipAddress = getClientIPAddress(request);

let ipAddress = getClientIPAddress(request.headers);
};
}
```

@@ -806,3 +736,3 @@

```ts
export let loader: LoaderFunction = async ({ request }) => {
export async function loader({ request }: LoaderArgs) {
// using the request

@@ -812,3 +742,3 @@ let locales = getClientLocales(request);

let locales = getClientLocales(request.headers);
};
}
```

@@ -822,3 +752,3 @@

import { getClientLocales } from "remix-utils";
export let loader: LoaderFunction = async ({ request }) => {
export async function loader({ request }: LoaderArgs) {
let locales = getClientLocales(request);

@@ -832,3 +762,3 @@ let nowDate = new Date();

return json({ now: formatter.format(nowDate) });
};
}
```

@@ -845,3 +775,3 @@

```ts
export let loader: LoaderFunction = async ({ request }) => {
export async function loader({ request }: LoaderArgs) {
let data = await getData(request);

@@ -855,3 +785,3 @@ let headers = new Headers();

return json(data, { headers });
};
}
```

@@ -869,7 +799,6 @@

import { redirectBack } from "remix-utils";
import type { ActionFunction } from "remix";
export let action: ActionFunction = async ({ request }) => {
export async function action({ request }: ActionArgs) {
await redirectBack(request, { fallback: "/" });
};
}
```

@@ -885,8 +814,7 @@

import { created } from "remix-utils";
import type { ActionFunction } from "remix";
export let action: ActionFunction = async ({ request }) => {
export async function action({ request }: ActionArgs) {
let result = await doSomething(request);
return created(result);
};
}
```

@@ -900,7 +828,6 @@

import { badRequest } from "remix-utils";
import type { ActionFunction } from "remix";
export let action: ActionFunction = async () => {
export async function action() {
throw badRequest({ message: "You forgot something in the form." });
};
}
```

@@ -914,8 +841,7 @@

import { unauthorized } from "remix-utils";
import type { LoaderFunction } from "remix";
export let loader: LoaderFunction = async () => {
export async function loader() {
// usually what you really want is to throw a redirect to the login page
throw unauthorized({ message: "You need to login." });
};
}
```

@@ -929,7 +855,6 @@

import { forbidden } from "remix-utils";
import type { LoaderFunction } from "remix";
export let loader: LoaderFunction = async () => {
export async function loader() {
throw forbidden({ message: "You don't have access for this." });
};
}
```

@@ -943,7 +868,6 @@

import { notFound } from "remix-utils";
import type { LoaderFunction } from "remix";
export let loader: LoaderFunction = async () => {
export async function loader() {
throw notFound({ message: "This doesn't exists." });
};
}
```

@@ -957,7 +881,6 @@

import { unprocessableEntity } from "remix-utils";
import type { LoaderFunction } from "remix";
export let loader: LoaderFunction = async () => {
export async function loader() {
throw unprocessableEntity({ message: "This doesn't exists." });
};
}
```

@@ -973,7 +896,6 @@

import { serverError } from "remix-utils";
import type { LoaderFunction } from "remix";
export let loader: LoaderFunction = async () => {
export async function loader() {
throw serverError({ message: "Something unexpected happened." });
};
}
```

@@ -986,5 +908,5 @@

```ts
export let loader: LoaderFunction = async ({ request }) => {
export async function loader({ request }: LoaderArgs) {
return notModified();
};
}
```

@@ -999,5 +921,5 @@

```ts
export let loader: LoaderFunction = async ({ request }) => {
export async function loader({ request }: LoaderArgs) {
return javascript("console.log('Hello World')");
};
}
```

@@ -1012,5 +934,5 @@

```ts
export let loader: LoaderFunction = async ({ request }) => {
export async function loader({ request }: LoaderArgs) {
return stylesheet("body { color: red; }");
};
}
```

@@ -1025,5 +947,5 @@

```ts
export let loader: LoaderFunction = async ({ request }) => {
export async function loader({ request }: LoaderArgs) {
return pdf(await generatePDF(request.formData()));
};
}
```

@@ -1038,7 +960,34 @@

```ts
export let loader: LoaderFunction = async ({ request }) => {
export async function loader({ request }: LoaderArgs) {
return html("<h1>Hello World</h1>");
};
}
```
#### XML
Helper function to create a XML file response with any header.
This is useful to create XML files based on data inside a Resource Route.
```ts
export async function loader({ request }: LoaderArgs) {
return xml("<?xml version='1.0'?><catalog></catalog>");
}
```
#### TXT
Helper function to create a TXT file response with any header.
This is useful to create TXT files based on data inside a Resource Route.
```ts
export async function loader({ request }: LoaderArgs) {
return txt(`
User-agent: *
Allow: /
`);
}
```
### Typed Cookies

@@ -1049,3 +998,3 @@

```ts
import { createCookie } from "remix";
import { createCookie } from "@remix-run/node";
import { createTypedCookie } from "remix-utils";

@@ -1117,3 +1066,3 @@ import { z } from "zod";

```ts
import { createCookieSessionStorage } from "remix";
import { createCookieSessionStorage } from "@remix-run/node";
import { createTypedSessionStorage } from "remix-utils";

@@ -1240,3 +1189,3 @@ import { z } from "zod";

export default function handleRequest(
export default function Component(
request: Request,

@@ -1370,3 +1319,3 @@ responseStatusCode: number,

// entry.server.tsx
export default function handleRequest(
export default function Component(
request: Request,

@@ -1399,2 +1348,96 @@ statusCode: number,

### Safe Redirects
When performing a redirect, if the URL is user provided we can't trust it, if you do you're opening a vulnerability to phishing scam by allowing bad actors to redirect the user to malicious websites.
```
https://remix.utills/?redirectTo=https://malicious.app
```
To help you prevent this Remix Utils gives you a `safeRedirect` function which can be used to check if the URL is "safe".
> **Note**: In this context, safe means the URL starts with `/` but not `//`, this means the URL is a pathname inside the same app and not an external link.
```ts
export async function loader({ request }: LoaderArgs) {
let { searchParams } = new URL(request.url);
let redirectTo = searchParams.get("redirectTo");
return redirect(safeRedirect(redirectTo, "/home"));
}
```
The second argumento of `safeRedirect` is the default redirect which by when not configured is `/`, this lets you tell `safeRedirect` where to redirect the user if the value is not safe.
### JSON Hash Response
When returning a `json` from a `loader` function, you may need to get data from different DB queries or API requests, typically you would something like this
```ts
export async function loader({ params }: LoaderData) {
let postId = z.string().parse(params.postId);
let [post, comments] = await Promise.all([getPost(), getComments()]);
return json({ post, comments });
async function getPost() {
/* … */
}
async function getComments() {
/* … */
}
}
```
The `jsonHash` function lets you define those functions directly in the `json`, reducing the need to create extra functions and variables.
```ts
export async function loader({ params }: LoaderData) {
let postId = z.string().parse(params.postId);
return jsonHash({
async post() {
// Implement me
},
async comments() {
// Implement me
},
});
}
```
It also calls your functions using `Promise.all` so you can be sure the data is retrieved in parallel.
Additionally, you can pass non-async functions, values and promises.
```ts
export async function loader({ params }: LoaderData) {
let postId = z.string().parse(params.postId);
return jsonHash({
postId, // value
comments: getComments(), // Promise
slug() {
// Non-async function
return postId.split("-").at(1); // get slug from postId param
},
async post() {
// Async function
// Implement me
},
});
async function getComments() {
/* … */
}
}
```
The result of `jsonHash` is a `TypedResponse` and it's correctly typed so using it with `typeof loader` works flawlessly.
```ts
export default function Component() {
// all correctly typed
let { postId, comments, slug, post } = useLoaderData<typeof loader>();
// more code…
}
```
## Author

@@ -1401,0 +1444,0 @@

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc