Skip to content

fix(remix): Remove vendored types #16218

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
May 8, 2025
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions packages/remix/package.json
Original file line number Diff line number Diff line change
@@ -78,12 +78,14 @@
"devDependencies": {
"@remix-run/node": "^2.15.2",
"@remix-run/react": "^2.15.2",
"@remix-run/server-runtime": "2.15.2",
"@types/express": "^4.17.14",
"vite": "^5.4.11"
},
"peerDependencies": {
"@remix-run/node": "2.x",
"@remix-run/react": "2.x",
"@remix-run/server-runtime": "2.x",
"react": "18.x"
},
"scripts": {
10 changes: 7 additions & 3 deletions packages/remix/src/server/errors.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,12 @@
import type {
ActionFunction,
ActionFunctionArgs,
EntryContext,
HandleDocumentRequestFunction,
LoaderFunction,
LoaderFunctionArgs,
} from '@remix-run/node';
import { isRouteErrorResponse } from '@remix-run/router';
import type { RequestEventData, Span } from '@sentry/core';
import {
addExceptionMechanism,
@@ -17,8 +20,9 @@ import {
import { DEBUG_BUILD } from '../utils/debug-build';
import type { RemixOptions } from '../utils/remixOptions';
import { storeFormDataKeys } from '../utils/utils';
import { extractData, isResponse, isRouteErrorResponse } from '../utils/vendor/response';
import type { DataFunction, RemixRequest } from '../utils/vendor/types';
import { extractData, isResponse } from '../utils/vendor/response';

type DataFunction = LoaderFunction | ActionFunction;

/**
* Captures an exception happened in the Remix server.
@@ -87,7 +91,7 @@ export function errorHandleDocumentRequestFunction(
this: unknown,
origDocumentRequestFunction: HandleDocumentRequestFunction,
requestContext: {
request: RemixRequest;
request: Request;
responseStatusCode: number;
responseHeaders: Headers;
context: EntryContext;
40 changes: 23 additions & 17 deletions packages/remix/src/server/instrumentServer.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,18 @@
/* eslint-disable max-lines */
import type { AgnosticRouteObject } from '@remix-run/router';
import { isDeferredData, isRouteErrorResponse } from '@remix-run/router';
import type {
ActionFunction,
ActionFunctionArgs,
AppLoadContext,
CreateRequestHandlerFunction,
EntryContext,
HandleDocumentRequestFunction,
LoaderFunction,
LoaderFunctionArgs,
RequestHandler,
ServerBuild,
} from '@remix-run/server-runtime';
import type { RequestEventData, Span, TransactionSource, WrappedFunction } from '@sentry/core';
import {
continueTrace,
@@ -22,23 +36,15 @@ import {
} from '@sentry/core';
import { DEBUG_BUILD } from '../utils/debug-build';
import { createRoutes, getTransactionName } from '../utils/utils';
import { extractData, isDeferredData, isResponse, isRouteErrorResponse, json } from '../utils/vendor/response';
import type {
AppData,
AppLoadContext,
CreateRequestHandlerFunction,
DataFunction,
DataFunctionArgs,
EntryContext,
HandleDocumentRequestFunction,
RemixRequest,
RequestHandler,
ServerBuild,
ServerRoute,
ServerRouteManifest,
} from '../utils/vendor/types';
import { extractData, isResponse, json } from '../utils/vendor/response';
import { captureRemixServerException, errorHandleDataFunction, errorHandleDocumentRequestFunction } from './errors';

type AppData = unknown;
type RemixRequest = Parameters<RequestHandler>[0];
type ServerRouteManifest = ServerBuild['routes'];
type DataFunction = LoaderFunction | ActionFunction;
type DataFunctionArgs = LoaderFunctionArgs | ActionFunctionArgs;

const redirectStatusCodes = new Set([301, 302, 303, 307, 308]);
function isRedirectResponse(response: Response): boolean {
return redirectStatusCodes.has(response.status);
@@ -261,7 +267,7 @@ function wrapRequestHandler(
return origRequestHandler.call(this, request, loadContext);
}

let resolvedRoutes: ServerRoute[] | undefined;
let resolvedRoutes: AgnosticRouteObject[] | undefined;

if (options?.instrumentTracing) {
if (typeof build === 'function') {
@@ -428,7 +434,7 @@ export const makeWrappedCreateRequestHandler = (options?: { instrumentTracing?:
function (origCreateRequestHandler: CreateRequestHandlerFunction): CreateRequestHandlerFunction {
return function (
this: unknown,
build: ServerBuild | (() => Promise<ServerBuild>),
build: ServerBuild | (() => ServerBuild | Promise<ServerBuild>),
...args: unknown[]
): RequestHandler {
const newBuild = instrumentBuild(build, options);
12 changes: 7 additions & 5 deletions packages/remix/src/utils/utils.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
import type { ActionFunctionArgs, LoaderFunctionArgs } from '@remix-run/node';
import type { ActionFunctionArgs, LoaderFunctionArgs, ServerBuild } from '@remix-run/node';
import type { AgnosticRouteObject } from '@remix-run/router';
import type { Span, TransactionSource } from '@sentry/core';
import { logger } from '@sentry/core';
import { DEBUG_BUILD } from './debug-build';
import { getRequestMatch, matchServerRoutes } from './vendor/response';
import type { ServerRoute, ServerRouteManifest } from './vendor/types';

type ServerRouteManifest = ServerBuild['routes'];

/**
*
@@ -29,7 +31,7 @@ export async function storeFormDataKeys(args: LoaderFunctionArgs | ActionFunctio
/**
* Get transaction name from routes and url
*/
export function getTransactionName(routes: ServerRoute[], url: URL): [string, TransactionSource] {
export function getTransactionName(routes: AgnosticRouteObject[], url: URL): [string, TransactionSource] {
const matches = matchServerRoutes(routes, url.pathname);
const match = matches && getRequestMatch(url, matches);
return match === null ? [url.pathname, 'url'] : [match.route.id || 'no-route-id', 'route'];
@@ -41,11 +43,11 @@ export function getTransactionName(routes: ServerRoute[], url: URL): [string, Tr
* @param manifest
* @param parentId
*/
export function createRoutes(manifest: ServerRouteManifest, parentId?: string): ServerRoute[] {
export function createRoutes(manifest: ServerRouteManifest, parentId?: string): AgnosticRouteObject[] {
return Object.entries(manifest)
.filter(([, route]) => route.parentId === parentId)
.map(([id, route]) => ({
...route,
children: createRoutes(manifest, id),
}));
})) as AgnosticRouteObject[];
}
39 changes: 1 addition & 38 deletions packages/remix/src/utils/vendor/response.ts
Original file line number Diff line number Diff line change
@@ -8,8 +8,6 @@

import type { AgnosticRouteMatch, AgnosticRouteObject } from '@remix-run/router';
import { matchRoutes } from '@remix-run/router';
import type { DeferredData, ErrorResponse, ServerRoute } from './types';

/**
* Based on Remix Implementation
*
@@ -76,7 +74,7 @@ export const json: JsonFunction = (data, init = {}) => {
* Changed so that `matchRoutes` function is passed in.
*/
export function matchServerRoutes(
routes: ServerRoute[],
routes: AgnosticRouteObject[],
pathname: string,
): AgnosticRouteMatch<string, AgnosticRouteObject>[] | null {
const matches = matchRoutes(routes, pathname);
@@ -126,38 +124,3 @@ export function getRequestMatch(

return match;
}

/**
* https://github.com/remix-run/remix/blob/3e589152bc717d04e2054c31bea5a1056080d4b9/packages/remix-server-runtime/responses.ts#L75-L85
*/
// eslint-disable-next-line @typescript-eslint/no-explicit-any
export function isDeferredData(value: any): value is DeferredData {
const deferred: DeferredData = value;
return (
deferred &&
typeof deferred === 'object' &&
typeof deferred.data === 'object' &&
typeof deferred.subscribe === 'function' &&
typeof deferred.cancel === 'function' &&
typeof deferred.resolveData === 'function'
);
}

/**
* https://github.com/remix-run/react-router/blob/f9b3dbd9cbf513366c456b33d95227f42f36da63/packages/router/utils.ts#L1574
*
* Check if the given error is an ErrorResponse generated from a 4xx/5xx
* Response thrown from an action/loader
*/
// eslint-disable-next-line @typescript-eslint/no-explicit-any
export function isRouteErrorResponse(value: any): value is ErrorResponse {
const error: ErrorResponse = value;

return (
error != null &&
typeof error.status === 'number' &&
typeof error.statusText === 'string' &&
typeof error.internal === 'boolean' &&
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks like error.internal does not exist in the latest types

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

should we keep it around for backwards compatibility?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Turns out this function is already exported. So I removed it and isDeferredData to use the peerDependency.
7ef5353

'data' in error
);
}
235 changes: 0 additions & 235 deletions packages/remix/src/utils/vendor/types.ts

This file was deleted.

Loading