();
+
+function getInitPathName(): string | undefined {
+ if (global && global.location) {
+ return global.location.pathname;
+ }
+
+ return undefined;
+}
+
+/**
+ * Creates a react-router v6 instrumention for Remix applications.
+ *
+ * This implementation is slightly different (and simpler) from the react-router instrumentation
+ * as in Remix, `useMatches` hook is available where in react-router-v6 it's not yet.
+ */
+export function remixRouterInstrumentation(useEffect: UseEffect, useLocation: UseLocation, useMatches: UseMatches) {
+ return (
+ customStartTransaction: (context: TransactionContext) => Transaction | undefined,
+ startTransactionOnPageLoad = true,
+ startTransactionOnLocationChange = true,
+ ): void => {
+ const initPathName = getInitPathName();
+ if (startTransactionOnPageLoad && initPathName) {
+ activeTransaction = customStartTransaction({
+ name: initPathName,
+ op: 'pageload',
+ tags: DEFAULT_TAGS,
+ });
+ }
+
+ _useEffect = useEffect;
+ _useLocation = useLocation;
+ _useMatches = useMatches;
+
+ _customStartTransaction = customStartTransaction;
+ _startTransactionOnLocationChange = startTransactionOnLocationChange;
+ };
+}
+
+/**
+ * Wraps a remix `root` (see: https://remix.run/docs/en/v1/guides/migrating-react-router-app#creating-the-root-route)
+ * To enable pageload/navigation tracing on every route.
+ */
+export function withSentryRouteTracing, R extends React.FC
>(OrigApp: R): R {
+ const SentryRoot: React.FC
= (props: P) => {
+ // Early return when any of the required functions is not available.
+ if (!_useEffect || !_useLocation || !_useMatches || !_customStartTransaction) {
+ IS_DEBUG_BUILD &&
+ logger.warn('Remix SDK was unable to wrap your root because of one or more missing parameters.');
+
+ // @ts-ignore Setting more specific React Component typing for `R` generic above
+ // will break advanced type inference done by react router params
+ return ;
+ }
+
+ let isBaseLocation: boolean = false;
+
+ const location = _useLocation();
+ const matches = _useMatches();
+
+ _useEffect(() => {
+ if (activeTransaction && matches && matches.length) {
+ activeTransaction.setName(matches[matches.length - 1].id);
+ }
+
+ isBaseLocation = true;
+ }, []);
+
+ _useEffect(() => {
+ if (isBaseLocation) {
+ if (activeTransaction) {
+ activeTransaction.finish();
+ }
+
+ return;
+ }
+
+ if (_startTransactionOnLocationChange && matches && matches.length) {
+ if (activeTransaction) {
+ activeTransaction.finish();
+ }
+
+ activeTransaction = _customStartTransaction({
+ name: matches[matches.length - 1].id,
+ op: 'navigation',
+ tags: DEFAULT_TAGS,
+ });
+ }
+ }, [location]);
+
+ isBaseLocation = false;
+
+ // @ts-ignore Setting more specific React Component typing for `R` generic above
+ // will break advanced type inference done by react router params
+ return ;
+ };
+
+ // @ts-ignore Setting more specific React Component typing for `R` generic above
+ // will break advanced type inference done by react router params
+ return SentryRoot;
+}
diff --git a/packages/remix/src/utils/instrumentServer.ts b/packages/remix/src/utils/instrumentServer.ts
new file mode 100644
index 000000000000..cbfc5892b185
--- /dev/null
+++ b/packages/remix/src/utils/instrumentServer.ts
@@ -0,0 +1,195 @@
+import { captureException, configureScope, getCurrentHub, startTransaction } from '@sentry/node';
+import { getActiveTransaction, hasTracingEnabled } from '@sentry/tracing';
+import { addExceptionMechanism, fill, loadModule, logger } from '@sentry/utils';
+
+import { IS_DEBUG_BUILD } from '../flags';
+
+type AppLoadContext = unknown;
+type AppData = unknown;
+type RequestHandler = (request: Request, loadContext?: AppLoadContext) => Promise;
+type CreateRequestHandlerFunction = (build: ServerBuild, mode?: string) => RequestHandler;
+type ServerRouteManifest = RouteManifest>;
+type Params = {
+ readonly [key in Key]: string | undefined;
+};
+
+interface Route {
+ index?: boolean;
+ caseSensitive?: boolean;
+ id: string;
+ parentId?: string;
+ path?: string;
+}
+
+interface ServerRouteModule {
+ action?: DataFunction;
+ headers?: unknown;
+ loader?: DataFunction;
+}
+
+interface ServerRoute extends Route {
+ children: ServerRoute[];
+ module: ServerRouteModule;
+}
+
+interface RouteManifest {
+ [routeId: string]: Route;
+}
+
+interface ServerBuild {
+ entry: {
+ module: ServerEntryModule;
+ };
+ routes: ServerRouteManifest;
+ assets: unknown;
+}
+
+interface HandleDocumentRequestFunction {
+ (request: Request, responseStatusCode: number, responseHeaders: Headers, context: Record):
+ | Promise
+ | Response;
+}
+
+interface HandleDataRequestFunction {
+ (response: Response, args: DataFunctionArgs): Promise | Response;
+}
+
+interface ServerEntryModule {
+ default: HandleDocumentRequestFunction;
+ handleDataRequest?: HandleDataRequestFunction;
+}
+
+interface DataFunctionArgs {
+ request: Request;
+ context: AppLoadContext;
+ params: Params;
+}
+
+interface DataFunction {
+ (args: DataFunctionArgs): Promise | Response | Promise | AppData;
+}
+
+function makeWrappedDataFunction(origFn: DataFunction, name: 'action' | 'loader'): DataFunction {
+ return async function (this: unknown, args: DataFunctionArgs): Promise {
+ let res: Response | AppData;
+ const activeTransaction = getActiveTransaction();
+ const currentScope = getCurrentHub().getScope();
+
+ try {
+ const span = activeTransaction?.startChild({
+ op: `remix.server.${name}`,
+ description: activeTransaction.name,
+ tags: {
+ name,
+ },
+ });
+
+ if (span) {
+ // Assign data function to hub to be able to see `db` transactions (if any) as children.
+ currentScope?.setSpan(span);
+ }
+
+ res = await origFn.call(this, args);
+ span?.finish();
+ } catch (err) {
+ configureScope(scope => {
+ scope.addEventProcessor(event => {
+ addExceptionMechanism(event, {
+ type: 'instrument',
+ handled: true,
+ data: {
+ function: name,
+ },
+ });
+
+ return event;
+ });
+ });
+
+ captureException(err);
+
+ // Rethrow for other handlers
+ throw err;
+ }
+
+ return res;
+ };
+}
+
+function makeWrappedAction(origAction: DataFunction): DataFunction {
+ return makeWrappedDataFunction(origAction, 'action');
+}
+
+function makeWrappedLoader(origAction: DataFunction): DataFunction {
+ return makeWrappedDataFunction(origAction, 'loader');
+}
+
+function wrapRequestHandler(origRequestHandler: RequestHandler): RequestHandler {
+ return async function (this: unknown, request: Request, loadContext?: unknown): Promise {
+ const currentScope = getCurrentHub().getScope();
+
+ // debugger;
+ const transaction = hasTracingEnabled()
+ ? startTransaction({
+ name: request.url,
+ op: 'remix.server.requesthandler',
+ tags: {
+ method: request.method,
+ },
+ })
+ : undefined;
+
+ if (transaction) {
+ currentScope?.setSpan(transaction);
+ }
+
+ const res = (await origRequestHandler.call(this, request, loadContext)) as Response;
+
+ transaction?.setHttpStatus(res.status);
+ transaction?.finish();
+
+ return res;
+ };
+}
+
+function makeWrappedCreateRequestHandler(
+ origCreateRequestHandler: CreateRequestHandlerFunction,
+): CreateRequestHandlerFunction {
+ return function (this: unknown, build: ServerBuild, mode: string | undefined): RequestHandler {
+ const routes: ServerRouteManifest = {};
+
+ for (const [id, route] of Object.entries(build.routes)) {
+ const wrappedRoute = { ...route, module: { ...route.module } };
+
+ if (wrappedRoute.module.action) {
+ fill(wrappedRoute.module, 'action', makeWrappedAction);
+ }
+
+ if (wrappedRoute.module.loader) {
+ fill(wrappedRoute.module, 'loader', makeWrappedLoader);
+ }
+
+ routes[id] = wrappedRoute;
+ }
+
+ const requestHandler = origCreateRequestHandler.call(this, { ...build, routes }, mode);
+
+ return wrapRequestHandler(requestHandler);
+ };
+}
+
+/**
+ * Monkey-patch Remix's `createRequestHandler` from `@remix-run/server-runtime`
+ * which Remix Adapters (https://remix.run/docs/en/v1/api/remix) use underneath.
+ */
+export function instrumentServer(): void {
+ const pkg = loadModule<{ createRequestHandler: CreateRequestHandlerFunction }>('@remix-run/server-runtime');
+
+ if (!pkg) {
+ IS_DEBUG_BUILD && logger.warn('Remix SDK was unable to require `@remix-run/server-runtime` package.');
+
+ return;
+ }
+
+ fill(pkg, 'createRequestHandler', makeWrappedCreateRequestHandler);
+}
diff --git a/packages/remix/src/utils/metadata.ts b/packages/remix/src/utils/metadata.ts
new file mode 100644
index 000000000000..243cdcc3826f
--- /dev/null
+++ b/packages/remix/src/utils/metadata.ts
@@ -0,0 +1,23 @@
+import { SDK_VERSION } from '@sentry/core';
+import { Options, SdkInfo } from '@sentry/types';
+
+const PACKAGE_NAME_PREFIX = 'npm:@sentry/';
+
+/**
+ * A builder for the SDK metadata in the options for the SDK initialization.
+ * @param options sdk options object that gets mutated
+ * @param names list of package names
+ */
+export function buildMetadata(options: Options, names: string[]): void {
+ options._metadata = options._metadata || {};
+ options._metadata.sdk =
+ options._metadata.sdk ||
+ ({
+ name: 'sentry.javascript.remix',
+ packages: names.map(name => ({
+ name: `${PACKAGE_NAME_PREFIX}${name}`,
+ version: SDK_VERSION,
+ })),
+ version: SDK_VERSION,
+ } as SdkInfo);
+}
diff --git a/packages/remix/src/utils/remixOptions.ts b/packages/remix/src/utils/remixOptions.ts
new file mode 100644
index 000000000000..9534ed57de3b
--- /dev/null
+++ b/packages/remix/src/utils/remixOptions.ts
@@ -0,0 +1,5 @@
+import { NodeOptions } from '@sentry/node';
+import { BrowserOptions } from '@sentry/react';
+import { Options } from '@sentry/types';
+
+export type RemixOptions = Options | BrowserOptions | NodeOptions;
diff --git a/packages/remix/test/index.client.test.ts b/packages/remix/test/index.client.test.ts
new file mode 100644
index 000000000000..eaca0b58c0f5
--- /dev/null
+++ b/packages/remix/test/index.client.test.ts
@@ -0,0 +1,54 @@
+import { getCurrentHub } from '@sentry/hub';
+import * as SentryReact from '@sentry/react';
+import { getGlobalObject } from '@sentry/utils';
+
+import { init } from '../src/index.client';
+
+const global = getGlobalObject();
+
+const reactInit = jest.spyOn(SentryReact, 'init');
+
+describe('Client init()', () => {
+ afterEach(() => {
+ jest.clearAllMocks();
+ global.__SENTRY__.hub = undefined;
+ });
+
+ it('inits the React SDK', () => {
+ expect(reactInit).toHaveBeenCalledTimes(0);
+ init({});
+ expect(reactInit).toHaveBeenCalledTimes(1);
+ expect(reactInit).toHaveBeenCalledWith(
+ expect.objectContaining({
+ _metadata: {
+ sdk: {
+ name: 'sentry.javascript.remix',
+ version: expect.any(String),
+ packages: [
+ {
+ name: 'npm:@sentry/remix',
+ version: expect.any(String),
+ },
+ {
+ name: 'npm:@sentry/react',
+ version: expect.any(String),
+ },
+ ],
+ },
+ },
+ }),
+ );
+ });
+
+ it('sets runtime on scope', () => {
+ const currentScope = getCurrentHub().getScope();
+
+ // @ts-ignore need access to protected _tags attribute
+ expect(currentScope._tags).toEqual({});
+
+ init({});
+
+ // @ts-ignore need access to protected _tags attribute
+ expect(currentScope._tags).toEqual({ runtime: 'browser' });
+ });
+});
diff --git a/packages/remix/test/index.server.test.ts b/packages/remix/test/index.server.test.ts
new file mode 100644
index 000000000000..2bfe118fcc5f
--- /dev/null
+++ b/packages/remix/test/index.server.test.ts
@@ -0,0 +1,62 @@
+import * as SentryNode from '@sentry/node';
+import { getCurrentHub } from '@sentry/node';
+import { getGlobalObject } from '@sentry/utils';
+
+import { init } from '../src/index.server';
+
+const global = getGlobalObject();
+
+const nodeInit = jest.spyOn(SentryNode, 'init');
+
+describe('Server init()', () => {
+ afterEach(() => {
+ jest.clearAllMocks();
+ global.__SENTRY__.hub = undefined;
+ });
+
+ it('inits the Node SDK', () => {
+ expect(nodeInit).toHaveBeenCalledTimes(0);
+ init({});
+ expect(nodeInit).toHaveBeenCalledTimes(1);
+ expect(nodeInit).toHaveBeenLastCalledWith(
+ expect.objectContaining({
+ _metadata: {
+ sdk: {
+ name: 'sentry.javascript.remix',
+ version: expect.any(String),
+ packages: [
+ {
+ name: 'npm:@sentry/remix',
+ version: expect.any(String),
+ },
+ {
+ name: 'npm:@sentry/node',
+ version: expect.any(String),
+ },
+ ],
+ },
+ },
+ }),
+ );
+ });
+
+ it("doesn't reinitialize the node SDK if already initialized", () => {
+ expect(nodeInit).toHaveBeenCalledTimes(0);
+ init({});
+ expect(nodeInit).toHaveBeenCalledTimes(1);
+ init({});
+ expect(nodeInit).toHaveBeenCalledTimes(1);
+ });
+
+ it('sets runtime on scope', () => {
+ const currentScope = getCurrentHub().getScope();
+
+ // @ts-ignore need access to protected _tags attribute
+ expect(currentScope._tags).toEqual({});
+
+ init({});
+
+ // @ts-ignore need access to protected _tags attribute
+ expect(currentScope._tags).toEqual({ runtime: 'node' });
+ });
+});
diff --git a/packages/remix/tsconfig.cjs.json b/packages/remix/tsconfig.cjs.json
new file mode 100644
index 000000000000..c1edc81a9657
--- /dev/null
+++ b/packages/remix/tsconfig.cjs.json
@@ -0,0 +1,8 @@
+{
+ "extends": "./tsconfig.json",
+
+ "compilerOptions": {
+ "module": "commonjs",
+ "outDir": "build/cjs"
+ }
+}
diff --git a/packages/remix/tsconfig.esm.json b/packages/remix/tsconfig.esm.json
new file mode 100644
index 000000000000..0b86c52918cc
--- /dev/null
+++ b/packages/remix/tsconfig.esm.json
@@ -0,0 +1,8 @@
+{
+ "extends": "./tsconfig.json",
+
+ "compilerOptions": {
+ "module": "es6",
+ "outDir": "build/esm"
+ }
+}
diff --git a/packages/remix/tsconfig.json b/packages/remix/tsconfig.json
new file mode 100644
index 000000000000..ae8bb2f9c363
--- /dev/null
+++ b/packages/remix/tsconfig.json
@@ -0,0 +1,10 @@
+{
+ "extends": "../../tsconfig.json",
+
+ "include": ["src/**/*"],
+
+ "compilerOptions": {
+ "jsx": "react"
+ // package-specific options
+ }
+}
diff --git a/packages/remix/tsconfig.test.json b/packages/remix/tsconfig.test.json
new file mode 100644
index 000000000000..87f6afa06b86
--- /dev/null
+++ b/packages/remix/tsconfig.test.json
@@ -0,0 +1,12 @@
+{
+ "extends": "./tsconfig.json",
+
+ "include": ["test/**/*"],
+
+ "compilerOptions": {
+ // should include all types from `./tsconfig.json` plus types for all test frameworks used
+ "types": ["node", "jest"]
+
+ // other package-specific, test-specific options
+ }
+}
diff --git a/packages/remix/tsconfig.types.json b/packages/remix/tsconfig.types.json
new file mode 100644
index 000000000000..65455f66bd75
--- /dev/null
+++ b/packages/remix/tsconfig.types.json
@@ -0,0 +1,10 @@
+{
+ "extends": "./tsconfig.json",
+
+ "compilerOptions": {
+ "declaration": true,
+ "declarationMap": true,
+ "emitDeclarationOnly": true,
+ "outDir": "build/types"
+ }
+}
diff --git a/scripts/test.ts b/scripts/test.ts
index e7058f2b66a8..582a67732b55 100644
--- a/scripts/test.ts
+++ b/scripts/test.ts
@@ -16,6 +16,7 @@ const NODE_8_SKIP_TESTS_PACKAGES = [
'@sentry/serverless',
'@sentry/nextjs',
'@sentry/angular',
+ '@sentry/remix',
];
// We have to downgrade some of our dependencies in order to run tests in Node 8 and 10.
@@ -26,8 +27,12 @@ const NODE_8_LEGACY_DEPENDENCIES = [
'jest-environment-node@25.x',
'ts-jest@25.x',
];
+
+const NODE_10_SKIP_TESTS_PACKAGES = [...DEFAULT_SKIP_TESTS_PACKAGES, '@sentry/remix'];
const NODE_10_LEGACY_DEPENDENCIES = ['jsdom@16.x'];
+const NODE_12_SKIP_TESTS_PACKAGES = [...DEFAULT_SKIP_TESTS_PACKAGES, '@sentry/remix'];
+
type JSONValue = string | number | boolean | null | JSONArray | JSONObject;
type JSONObject = {
@@ -157,12 +162,12 @@ function runTests(): void {
else if (CURRENT_NODE_VERSION === '10') {
installLegacyDeps(NODE_10_LEGACY_DEPENDENCIES);
es6ifyTestTSConfig('utils');
- runWithIgnores(DEFAULT_SKIP_TESTS_PACKAGES);
+ runWithIgnores(NODE_10_SKIP_TESTS_PACKAGES);
}
//
else if (CURRENT_NODE_VERSION === '12') {
es6ifyTestTSConfig('utils');
- runWithIgnores(DEFAULT_SKIP_TESTS_PACKAGES);
+ runWithIgnores(NODE_12_SKIP_TESTS_PACKAGES);
}
//
else {
diff --git a/yarn.lock b/yarn.lock
index 1ee8f4cd1349..078edd8d11df 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -2248,9 +2248,9 @@
regenerator-runtime "^0.13.4"
"@babel/runtime@^7.7.6":
- version "7.17.9"
- resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.17.9.tgz#d19fbf802d01a8cb6cf053a64e472d42c434ba72"
- integrity sha512-lSiBBvodq29uShpWGNbgFdKYNiFDo5/HIYsaCEY9ff4sb10x9jizo2+pRrSyF4jKZCXqgzuqBOQKbUm90gQwJg==
+ version "7.18.0"
+ resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.18.0.tgz#6d77142a19cb6088f0af662af1ada37a604d34ae"
+ integrity sha512-YMQvx/6nKEaucl0MY56mwIG483xk8SDNdlUwb2Ts6FUpr7fm85DxEmsY18LXBNhcTz6tO6JwZV8w1W06v8UKeg==
dependencies:
regenerator-runtime "^0.13.4"
@@ -4151,6 +4151,83 @@
resolved "https://registry.yarnpkg.com/@protobufjs/utf8/-/utf8-1.1.0.tgz#a777360b5b39a1a2e5106f8e858f2fd2d060c570"
integrity sha512-Vvn3zZrhQZkkBE8LSuW3em98c0FwgO4nxzv6OdSxPKJIEKY2bGbHn+mhGIPerzI4twdxaP8/0+06HBpwf345Lw==
+"@remix-run/node@^1.4.3":
+ version "1.5.1"
+ resolved "https://registry.yarnpkg.com/@remix-run/node/-/node-1.5.1.tgz#1c367d4035baaef8f0ea66962a826456d62f0030"
+ integrity sha512-yl4bd1nl7MiJp4tI3+4ygObeMU3txM4Uo09IdHLRa4NMdBQnacUJ47kqCahny01MerC2JL2d9NPjdVPwRCRZvQ==
+ dependencies:
+ "@remix-run/server-runtime" "1.5.1"
+ "@remix-run/web-fetch" "^4.1.3"
+ "@remix-run/web-file" "^3.0.2"
+ "@remix-run/web-stream" "^1.0.3"
+ "@web3-storage/multipart-parser" "^1.0.0"
+ abort-controller "^3.0.0"
+ cookie-signature "^1.1.0"
+ source-map-support "^0.5.21"
+ stream-slice "^0.1.2"
+
+"@remix-run/react@^1.4.3":
+ version "1.5.1"
+ resolved "https://registry.yarnpkg.com/@remix-run/react/-/react-1.5.1.tgz#372e5e80f3f10a638b0567c4e03307dfb0a28dc0"
+ integrity sha512-p4t6tC/WyPeLW7DO4g7ZSyH9EpWO37c4wD2np3rDwtv3WtsTZ70bU/+NOWE9nv74mH8i1C50eJ3/OR+8Ll8UbA==
+ dependencies:
+ history "^5.3.0"
+ react-router-dom "^6.2.2"
+
+"@remix-run/server-runtime@1.5.1":
+ version "1.5.1"
+ resolved "https://registry.yarnpkg.com/@remix-run/server-runtime/-/server-runtime-1.5.1.tgz#5272b01e6dce109dc10bd68447ceae2d039315b2"
+ integrity sha512-FQbCCdW+qzE3wpoCwUKdwcL8yZVYNPiyHS9JS/6r6qmd/yvZfbj44E48wEQ6trbWE2TUiEh/EQqNMyrZWEs4bw==
+ dependencies:
+ "@types/cookie" "^0.4.0"
+ "@web3-storage/multipart-parser" "^1.0.0"
+ cookie "^0.4.1"
+ jsesc "^3.0.1"
+ react-router-dom "^6.2.2"
+ set-cookie-parser "^2.4.8"
+ source-map "^0.7.3"
+
+"@remix-run/web-blob@^3.0.3", "@remix-run/web-blob@^3.0.4":
+ version "3.0.4"
+ resolved "https://registry.yarnpkg.com/@remix-run/web-blob/-/web-blob-3.0.4.tgz#99c67b9d0fb641bd0c07d267fd218ae5aa4ae5ed"
+ integrity sha512-AfegzZvSSDc+LwnXV+SwROTrDtoLiPxeFW+jxgvtDAnkuCX1rrzmVJ6CzqZ1Ai0bVfmJadkG5GxtAfYclpPmgw==
+ dependencies:
+ "@remix-run/web-stream" "^1.0.0"
+ web-encoding "1.1.5"
+
+"@remix-run/web-fetch@^4.1.3":
+ version "4.1.3"
+ resolved "https://registry.yarnpkg.com/@remix-run/web-fetch/-/web-fetch-4.1.3.tgz#8ad3077c1b5bd9fe2a8813d0ad3c84970a495c04"
+ integrity sha512-D3KXAEkzhR248mu7wCHReQrMrIo3Y9pDDa7TrlISnsOEvqkfWkJJF+PQWmOIKpOSHAhDg7TCb2tzvW8lc/MfHw==
+ dependencies:
+ "@remix-run/web-blob" "^3.0.4"
+ "@remix-run/web-form-data" "^3.0.2"
+ "@remix-run/web-stream" "^1.0.3"
+ "@web3-storage/multipart-parser" "^1.0.0"
+ data-uri-to-buffer "^3.0.1"
+ mrmime "^1.0.0"
+
+"@remix-run/web-file@^3.0.2":
+ version "3.0.2"
+ resolved "https://registry.yarnpkg.com/@remix-run/web-file/-/web-file-3.0.2.tgz#1a6cc0900a1310ede4bc96abad77ac6eb27a2131"
+ integrity sha512-eFC93Onh/rZ5kUNpCQersmBtxedGpaXK2/gsUl49BYSGK/DvuPu3l06vmquEDdcPaEuXcsdGP0L7zrmUqrqo4A==
+ dependencies:
+ "@remix-run/web-blob" "^3.0.3"
+
+"@remix-run/web-form-data@^3.0.2":
+ version "3.0.2"
+ resolved "https://registry.yarnpkg.com/@remix-run/web-form-data/-/web-form-data-3.0.2.tgz#733a4c8f8176523b7b60a8bd0dc6704fd4d498f3"
+ integrity sha512-F8tm3iB1sPxMpysK6Js7lV3gvLfTNKGmIW38t/e6dtPEB5L1WdbRG1cmLyhsonFc7rT1x1JKdz+2jCtoSdnIUw==
+ dependencies:
+ web-encoding "1.1.5"
+
+"@remix-run/web-stream@^1.0.0", "@remix-run/web-stream@^1.0.3":
+ version "1.0.3"
+ resolved "https://registry.yarnpkg.com/@remix-run/web-stream/-/web-stream-1.0.3.tgz#3284a6a45675d1455c4d9c8f31b89225c9006438"
+ integrity sha512-wlezlJaA5NF6SsNMiwQnnAW6tnPzQ5I8qk0Y0pSohm0eHKa2FQ1QhEKLVVcDDu02TmkfHgnux0igNfeYhDOXiA==
+ dependencies:
+ web-streams-polyfill "^3.1.1"
+
"@rollup/plugin-commonjs@^15.0.0":
version "15.1.0"
resolved "https://registry.yarnpkg.com/@rollup/plugin-commonjs/-/plugin-commonjs-15.1.0.tgz#1e7d076c4f1b2abf7e65248570e555defc37c238"
@@ -4272,6 +4349,16 @@
semver "7.3.2"
semver-intersect "1.4.0"
+"@sentry/browser@7.0.0-beta.0":
+ version "7.0.0-beta.0"
+ resolved "https://registry.yarnpkg.com/@sentry/browser/-/browser-7.0.0-beta.0.tgz#2b937753900f312d0b1f23b1d6c00a801dfe2c76"
+ integrity sha512-bj6zwvEc3q9GEYirHNvCdVe3DPrH/YjuO0Tey6LKLsfcgU97v4hUh69JxFU+TKDVexqJN/+r2gYKR66Qg0eOBA==
+ dependencies:
+ "@sentry/core" "7.0.0-beta.0"
+ "@sentry/types" "7.0.0-beta.0"
+ "@sentry/utils" "7.0.0-beta.0"
+ tslib "^1.9.3"
+
"@sentry/cli@^1.74.4":
version "1.74.4"
resolved "https://registry.yarnpkg.com/@sentry/cli/-/cli-1.74.4.tgz#7df82f68045a155e1885bfcbb5d303e5259eb18e"
@@ -4285,6 +4372,83 @@
proxy-from-env "^1.1.0"
which "^2.0.2"
+"@sentry/core@7.0.0-beta.0":
+ version "7.0.0-beta.0"
+ resolved "https://registry.yarnpkg.com/@sentry/core/-/core-7.0.0-beta.0.tgz#609af1e6611cabc07e34d9021cc1c1d84d610ecd"
+ integrity sha512-c/XOz/XPIvdGvuos/LZ5HkPd01TH5zu00DcSWONJ3IlvdaBp5kNJYBRrKKfUc1rQCHnWZNmiboBOXQapL5Cg7Q==
+ dependencies:
+ "@sentry/hub" "7.0.0-beta.0"
+ "@sentry/types" "7.0.0-beta.0"
+ "@sentry/utils" "7.0.0-beta.0"
+ tslib "^1.9.3"
+
+"@sentry/hub@7.0.0-beta.0":
+ version "7.0.0-beta.0"
+ resolved "https://registry.yarnpkg.com/@sentry/hub/-/hub-7.0.0-beta.0.tgz#bf24675d5878d3dc7bc913ab5b59de0210134fd6"
+ integrity sha512-MTORzE9SgLpiiPZ6UBQz2Pwm3U7Ebb3RQxP1JJdxt1IpzaomUMr5yfPE1NXagqvTWpLuTUoegf5xKEJsPd5gHQ==
+ dependencies:
+ "@sentry/types" "7.0.0-beta.0"
+ "@sentry/utils" "7.0.0-beta.0"
+ tslib "^1.9.3"
+
+"@sentry/integrations@7.0.0-beta.0":
+ version "7.0.0-beta.0"
+ resolved "https://registry.yarnpkg.com/@sentry/integrations/-/integrations-7.0.0-beta.0.tgz#e0855a9934255bd2c6f7ea04dfdb35bc8306d3f0"
+ integrity sha512-NxBQ2zJFeMDrtgFIXSDj8V21/CkgtVovfPM8UN8Ovo5xwNov9p08SvjS0LaKtnI2aCCYRYOwJMH2E1Ti5UcZiQ==
+ dependencies:
+ "@sentry/types" "7.0.0-beta.0"
+ "@sentry/utils" "7.0.0-beta.0"
+ localforage "^1.8.1"
+ tslib "^1.9.3"
+
+"@sentry/node@7.0.0-beta.0":
+ version "7.0.0-beta.0"
+ resolved "https://registry.yarnpkg.com/@sentry/node/-/node-7.0.0-beta.0.tgz#8256a086535ca5a98466b0fd361cbcef53d28adf"
+ integrity sha512-vclhHGr1xuvtgCfT/xOf9S5W0PwZp1w2+8j2W4VH8m5PUaQ09AEcDIfFrrjbZzdJpn82zS03+5aW0L0svBovOw==
+ dependencies:
+ "@sentry/core" "7.0.0-beta.0"
+ "@sentry/hub" "7.0.0-beta.0"
+ "@sentry/types" "7.0.0-beta.0"
+ "@sentry/utils" "7.0.0-beta.0"
+ cookie "^0.4.1"
+ https-proxy-agent "^5.0.0"
+ lru_map "^0.3.3"
+ tslib "^1.9.3"
+
+"@sentry/react@7.0.0-beta.0":
+ version "7.0.0-beta.0"
+ resolved "https://registry.yarnpkg.com/@sentry/react/-/react-7.0.0-beta.0.tgz#cd0f7e08168c997a1b5d61a329ab9c7546dd9b76"
+ integrity sha512-KZktMzSyOiN4xj41iB3za+hXNkVT6AWBELj6xqfxPf4ePHhteq0MqN1QbBEzwS2vWHwd4bbgQOvx55Tw/FsiiA==
+ dependencies:
+ "@sentry/browser" "7.0.0-beta.0"
+ "@sentry/types" "7.0.0-beta.0"
+ "@sentry/utils" "7.0.0-beta.0"
+ hoist-non-react-statics "^3.3.2"
+ tslib "^1.9.3"
+
+"@sentry/tracing@7.0.0-beta.0":
+ version "7.0.0-beta.0"
+ resolved "https://registry.yarnpkg.com/@sentry/tracing/-/tracing-7.0.0-beta.0.tgz#d60aff59c4f73bca920f29b42c65e33df8eb0b7e"
+ integrity sha512-kNGFlawbyaQrqFs7yKB4UWyeN+lC4GJsgPclQKTuYpLYXMU5B2PZD65c54AuK4f01AbouI2lLJS44WXKW0lREA==
+ dependencies:
+ "@sentry/hub" "7.0.0-beta.0"
+ "@sentry/types" "7.0.0-beta.0"
+ "@sentry/utils" "7.0.0-beta.0"
+ tslib "^1.9.3"
+
+"@sentry/types@7.0.0-beta.0":
+ version "7.0.0-beta.0"
+ resolved "https://registry.yarnpkg.com/@sentry/types/-/types-7.0.0-beta.0.tgz#ebd7616436f8f8c97b36e5126af2f514dd4f7b48"
+ integrity sha512-7FYN8C2YXVWH8meGVTPR3EcF46e2wds6+jIEE0fW/hsPhMGmzTgslbx/GRpyB1aP25p9MOKV0Aww/ld+zkBSxQ==
+
+"@sentry/utils@7.0.0-beta.0":
+ version "7.0.0-beta.0"
+ resolved "https://registry.yarnpkg.com/@sentry/utils/-/utils-7.0.0-beta.0.tgz#ffb2e8a92778c3507692cf3780d86f2ec1e3f3a5"
+ integrity sha512-dAgd7e4TGEBrqjhhuo0a3opAfKQhW3I66PDIYgHq7Y7KXmUBKKuQpHQrOQLJ13JvNLB37a18d+1m+fRbwV+qnQ==
+ dependencies:
+ "@sentry/types" "7.0.0-beta.0"
+ tslib "^1.9.3"
+
"@sentry/webpack-plugin@1.18.9":
version "1.18.9"
resolved "https://registry.yarnpkg.com/@sentry/webpack-plugin/-/webpack-plugin-1.18.9.tgz#acb48c0f96fdb9e73f1e1db374ea31ded6d883a8"
@@ -4569,7 +4733,7 @@
resolved "https://registry.yarnpkg.com/@types/cookie/-/cookie-0.3.2.tgz#453f4b14b25da6a8ea4494842dedcbf0151deef9"
integrity sha512-aHQA072E10/8iUQsPH7mQU/KUyQBZAGzTVRCUvnSz8mSvbrYsP4xEO2RSA0Pjltolzi0j8+8ixrm//Hr4umPzw==
-"@types/cookie@^0.4.1":
+"@types/cookie@^0.4.0", "@types/cookie@^0.4.1":
version "0.4.1"
resolved "https://registry.yarnpkg.com/@types/cookie/-/cookie-0.4.1.tgz#bfd02c1f2224567676c1545199f87c3a861d878d"
integrity sha512-XW/Aa8APYr6jSVVA1y/DEIZX0/GMKLEVekNG727R8cs56ahETkRAy/3DR7+fJyh7oUgGwNQaRfXCun0+KbWY7Q==
@@ -5379,6 +5543,11 @@
"@typescript-eslint/types" "4.23.0"
eslint-visitor-keys "^2.0.0"
+"@web3-storage/multipart-parser@^1.0.0":
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/@web3-storage/multipart-parser/-/multipart-parser-1.0.0.tgz#6b69dc2a32a5b207ba43e556c25cc136a56659c4"
+ integrity sha512-BEO6al7BYqcnfX15W2cnGR+Q566ACXAT9UQykORCWW80lmkpWsnEob6zJS1ZVBKsSJC8+7vJkHwlp+lXG1UCdw==
+
"@webassemblyjs/ast@1.11.1":
version "1.11.1"
resolved "https://registry.yarnpkg.com/@webassemblyjs/ast/-/ast-1.11.1.tgz#2bfd767eae1a6996f432ff7e8d7fc75679c0b6a7"
@@ -5670,6 +5839,11 @@
resolved "https://registry.yarnpkg.com/@yarnpkg/lockfile/-/lockfile-1.1.0.tgz#e77a97fbd345b76d83245edcd17d393b1b41fb31"
integrity sha512-GpSwvyXOcOOlV70vbnzjj4fW5xW/FdUF6nQEt1ENy7m4ZCczi1+/buVUPAqmGfqznsORNFzUMjctTIp8a9tuCQ==
+"@zxing/text-encoding@0.9.0":
+ version "0.9.0"
+ resolved "https://registry.yarnpkg.com/@zxing/text-encoding/-/text-encoding-0.9.0.tgz#fb50ffabc6c7c66a0c96b4c03e3d9be74864b70b"
+ integrity sha512-U/4aVJ2mxI0aDNI8Uq0wEhMgY+u4CNtEb0om3+y3+niDAsoTCOB33UF0sxpzqzdqXLqmvc+vZyAt4O8pPdfkwA==
+
JSONStream@^1.0.4, JSONStream@^1.3.4:
version "1.3.5"
resolved "https://registry.yarnpkg.com/JSONStream/-/JSONStream-1.3.5.tgz#3208c1f08d3a4d99261ab64f92302bc15e111ca0"
@@ -9451,6 +9625,11 @@ cookie-signature@1.0.6:
resolved "https://registry.yarnpkg.com/cookie-signature/-/cookie-signature-1.0.6.tgz#e303a882b342cc3ee8ca513a79999734dab3ae2c"
integrity sha1-4wOogrNCzD7oylE6eZmXNNqzriw=
+cookie-signature@^1.1.0:
+ version "1.2.0"
+ resolved "https://registry.yarnpkg.com/cookie-signature/-/cookie-signature-1.2.0.tgz#4deed303f5f095e7a02c979e3fcb19157f5eaeea"
+ integrity sha512-R0BOPfLGTitaKhgKROKZQN6iyq2iDQcH1DOF8nJoaWapguX5bC2w+Q/I9NmmM5lfcvEarnLZr+cCvmEYYSXvYA==
+
cookie@0.4.0:
version "0.4.0"
resolved "https://registry.yarnpkg.com/cookie/-/cookie-0.4.0.tgz#beb437e7022b3b6d49019d088665303ebe9c14ba"
@@ -10000,7 +10179,7 @@ dashdash@^1.12.0:
dependencies:
assert-plus "^1.0.0"
-data-uri-to-buffer@3.0.1:
+data-uri-to-buffer@3.0.1, data-uri-to-buffer@^3.0.1:
version "3.0.1"
resolved "https://registry.yarnpkg.com/data-uri-to-buffer/-/data-uri-to-buffer-3.0.1.tgz#594b8973938c5bc2c33046535785341abc4f3636"
integrity sha512-WboRycPNsVw3B3TL559F7kuBUM4d8CgMEvk6xEJlOp7OBPjt6G7z8WMWlD2rOFZLk6OYfFIUGsCOWzcQH9K2og==
@@ -14176,7 +14355,7 @@ history@^4.6.0, history@^4.9.0:
tiny-warning "^1.0.0"
value-equal "^1.0.1"
-history@^5.2.0:
+history@^5.2.0, history@^5.3.0:
version "5.3.0"
resolved "https://registry.yarnpkg.com/history/-/history-5.3.0.tgz#1548abaa245ba47992f063a0783db91ef201c73b"
integrity sha512-ZqaKwjjrAYUYfLG+htGaIIZ4nioX2L70ZUMIFysS3xvBsSG4x/n1V6TXV3N8ZYNuFGlDirFg32T7B6WOUPDYcQ==
@@ -16331,6 +16510,11 @@ jsesc@^2.5.1:
resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-2.5.2.tgz#80564d2e483dacf6e8ef209650a67df3f0c283a4"
integrity sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==
+jsesc@^3.0.1:
+ version "3.0.2"
+ resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-3.0.2.tgz#bb8b09a6597ba426425f2e4a07245c3d00b9343e"
+ integrity sha512-xKqzzWXDttJuOcawBt4KnKHHIf5oQ/Cxax+0PWFG+DFDgHNAdi+TXECADI+RYiFUMmx8792xsMbbgXj4CwnP4g==
+
jsesc@~0.3.x:
version "0.3.0"
resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-0.3.0.tgz#1bf5ee63b4539fe2e26d0c1e99c240b97a457972"
@@ -18193,6 +18377,11 @@ move-concurrently@^1.0.1:
rimraf "^2.5.4"
run-queue "^1.0.3"
+mrmime@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/mrmime/-/mrmime-1.0.0.tgz#14d387f0585a5233d291baba339b063752a2398b"
+ integrity sha512-a70zx7zFfVO7XpnQ2IX1Myh9yY4UYvfld/dikWRnsXxbyvMcfz+u6UfgNAtH+k2QqtJuzVpv6eLTx1G2+WKZbQ==
+
ms@2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8"
@@ -21110,13 +21299,21 @@ react-refresh@0.8.3:
tiny-invariant "^1.0.2"
tiny-warning "^1.0.0"
-"react-router-6@npm:react-router@6.3.0":
+"react-router-6@npm:react-router@6.3.0", react-router@6.3.0:
version "6.3.0"
resolved "https://registry.yarnpkg.com/react-router/-/react-router-6.3.0.tgz#3970cc64b4cb4eae0c1ea5203a80334fdd175557"
integrity sha512-7Wh1DzVQ+tlFjkeo+ujvjSqSJmkt1+8JO+T5xklPlgrh70y7ogx75ODRW0ThWhY7S+6yEDks8TYrtQe/aoboBQ==
dependencies:
history "^5.2.0"
+react-router-dom@^6.2.2:
+ version "6.3.0"
+ resolved "https://registry.yarnpkg.com/react-router-dom/-/react-router-dom-6.3.0.tgz#a0216da813454e521905b5fa55e0e5176123f43d"
+ integrity sha512-uaJj7LKytRxZNQV8+RbzJWnJ8K2nPsOOEuX7aQstlMZKQT0164C+X2w6bnkqU3sjtLvpd5ojrezAyfZ1+0sStw==
+ dependencies:
+ history "^5.2.0"
+ react-router "6.3.0"
+
react@^18.0.0:
version "18.0.0"
resolved "https://registry.yarnpkg.com/react/-/react-18.0.0.tgz#b468736d1f4a5891f38585ba8e8fb29f91c3cb96"
@@ -22446,6 +22643,11 @@ set-blocking@^2.0.0, set-blocking@~2.0.0:
resolved "https://registry.yarnpkg.com/set-blocking/-/set-blocking-2.0.0.tgz#045f9782d011ae9a6803ddd382b24392b3d890f7"
integrity sha1-BF+XgtARrppoA93TgrJDkrPYkPc=
+set-cookie-parser@^2.4.8:
+ version "2.4.8"
+ resolved "https://registry.yarnpkg.com/set-cookie-parser/-/set-cookie-parser-2.4.8.tgz#d0da0ed388bc8f24e706a391f9c9e252a13c58b2"
+ integrity sha512-edRH8mBKEWNVIVMKejNnuJxleqYE/ZSdcT8/Nem9/mmosx12pctd80s2Oy00KNZzrogMZS5mauK2/ymL1bvlvg==
+
set-value@^2.0.0, set-value@^2.0.1:
version "2.0.1"
resolved "https://registry.yarnpkg.com/set-value/-/set-value-2.0.1.tgz#a18d40530e6f07de4228c7defe4227af8cad005b"
@@ -22928,7 +23130,7 @@ source-map-support@^0.4.15, source-map-support@^0.4.18:
dependencies:
source-map "^0.5.6"
-source-map-support@^0.5.5, source-map-support@~0.5.20:
+source-map-support@^0.5.21, source-map-support@^0.5.5, source-map-support@~0.5.20:
version "0.5.21"
resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.5.21.tgz#04fe7c7f9e1ed2d662233c28cb2b35b9f63f6e4f"
integrity sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==
@@ -23323,6 +23525,11 @@ stream-shift@^1.0.0:
resolved "https://registry.yarnpkg.com/stream-shift/-/stream-shift-1.0.1.tgz#d7088281559ab2778424279b0877da3c392d5a3d"
integrity sha512-AiisoFqQ0vbGcZgQPY1cdP2I76glaVA/RauYR4G4thNFgkTqr90yXTo4LYX60Jl+sIlPNHHdGSwo01AvbKUSVQ==
+stream-slice@^0.1.2:
+ version "0.1.2"
+ resolved "https://registry.yarnpkg.com/stream-slice/-/stream-slice-0.1.2.tgz#2dc4f4e1b936fb13f3eb39a2def1932798d07a4b"
+ integrity sha1-LcT04bk2+xPz6zmi3vGTJ5jQeks=
+
streamroller@^1.0.6:
version "1.0.6"
resolved "https://registry.yarnpkg.com/streamroller/-/streamroller-1.0.6.tgz#8167d8496ed9f19f05ee4b158d9611321b8cacd9"
@@ -25053,6 +25260,18 @@ util@^0.11.0:
dependencies:
inherits "2.0.3"
+util@^0.12.3:
+ version "0.12.4"
+ resolved "https://registry.yarnpkg.com/util/-/util-0.12.4.tgz#66121a31420df8f01ca0c464be15dfa1d1850253"
+ integrity sha512-bxZ9qtSlGUWSOy9Qa9Xgk11kSslpuZwaxCg4sNIDj6FLucDab2JxnHwyNTCpHMtK1MjoQiWQ6DiUMZYbSrO+Sw==
+ dependencies:
+ inherits "^2.0.3"
+ is-arguments "^1.0.4"
+ is-generator-function "^1.0.7"
+ is-typed-array "^1.1.3"
+ safe-buffer "^5.1.2"
+ which-typed-array "^1.1.2"
+
utila@~0.4:
version "0.4.0"
resolved "https://registry.yarnpkg.com/utila/-/utila-0.4.0.tgz#8a16a05d445657a3aea5eecc5b12a4fa5379772c"
@@ -25324,6 +25543,20 @@ wcwidth@^1.0.0, wcwidth@^1.0.1:
dependencies:
defaults "^1.0.3"
+web-encoding@1.1.5:
+ version "1.1.5"
+ resolved "https://registry.yarnpkg.com/web-encoding/-/web-encoding-1.1.5.tgz#fc810cf7667364a6335c939913f5051d3e0c4864"
+ integrity sha512-HYLeVCdJ0+lBYV2FvNZmv3HJ2Nt0QYXqZojk3d9FJOLkwnuhzM9tmamh8d7HPM8QqjKH8DeHkFTx+CFlWpZZDA==
+ dependencies:
+ util "^0.12.3"
+ optionalDependencies:
+ "@zxing/text-encoding" "0.9.0"
+
+web-streams-polyfill@^3.1.1:
+ version "3.2.1"
+ resolved "https://registry.yarnpkg.com/web-streams-polyfill/-/web-streams-polyfill-3.2.1.tgz#71c2718c52b45fd49dbeee88634b3a60ceab42a6"
+ integrity sha512-e0MO3wdXWKrLbL0DgGnUV7WHVuw9OUvL4hjgnPkIeEvESk74gAITi5G606JtZPp39cd8HA9VQzCIvA49LpPN5Q==
+
webidl-conversions@^3.0.0:
version "3.0.1"
resolved "https://registry.yarnpkg.com/webidl-conversions/-/webidl-conversions-3.0.1.tgz#24534275e2a7bc6be7bc86611cc16ae0a5654871"