From fe37f64e6781c1dcd3b9f5e5cdc948ca149594d8 Mon Sep 17 00:00:00 2001 From: Onur Temizkan Date: Wed, 11 May 2022 15:32:09 +0100 Subject: [PATCH 1/3] feat: Add Remix SDK --- package.json | 1 + packages/remix/.eslintrc.js | 13 + packages/remix/LICENSE | 29 +++ packages/remix/README.md | 9 + packages/remix/jest.config.js | 1 + packages/remix/package.json | 82 ++++++ packages/remix/rollup.npm.config.js | 7 + packages/remix/src/flags.ts | 18 ++ packages/remix/src/index.client.tsx | 21 ++ packages/remix/src/index.server.ts | 34 +++ packages/remix/src/performance/client.tsx | 142 +++++++++++ packages/remix/src/utils/instrumentServer.ts | 195 +++++++++++++++ packages/remix/src/utils/metadata.ts | 23 ++ packages/remix/src/utils/remixOptions.ts | 5 + packages/remix/test/index.client.test.ts | 54 ++++ packages/remix/test/index.server.test.ts | 62 +++++ packages/remix/tsconfig.cjs.json | 8 + packages/remix/tsconfig.esm.json | 8 + packages/remix/tsconfig.json | 10 + packages/remix/tsconfig.test.json | 12 + packages/remix/tsconfig.types.json | 10 + yarn.lock | 249 ++++++++++++++++++- 22 files changed, 985 insertions(+), 8 deletions(-) create mode 100644 packages/remix/.eslintrc.js create mode 100644 packages/remix/LICENSE create mode 100644 packages/remix/README.md create mode 100644 packages/remix/jest.config.js create mode 100644 packages/remix/package.json create mode 100644 packages/remix/rollup.npm.config.js create mode 100644 packages/remix/src/flags.ts create mode 100644 packages/remix/src/index.client.tsx create mode 100644 packages/remix/src/index.server.ts create mode 100644 packages/remix/src/performance/client.tsx create mode 100644 packages/remix/src/utils/instrumentServer.ts create mode 100644 packages/remix/src/utils/metadata.ts create mode 100644 packages/remix/src/utils/remixOptions.ts create mode 100644 packages/remix/test/index.client.test.ts create mode 100644 packages/remix/test/index.server.test.ts create mode 100644 packages/remix/tsconfig.cjs.json create mode 100644 packages/remix/tsconfig.esm.json create mode 100644 packages/remix/tsconfig.json create mode 100644 packages/remix/tsconfig.test.json create mode 100644 packages/remix/tsconfig.types.json diff --git a/package.json b/package.json index 09848d739f99..36ea47acd9f3 100644 --- a/package.json +++ b/package.json @@ -45,6 +45,7 @@ "packages/node", "packages/node-integration-tests", "packages/react", + "packages/remix", "packages/serverless", "packages/tracing", "packages/types", diff --git a/packages/remix/.eslintrc.js b/packages/remix/.eslintrc.js new file mode 100644 index 000000000000..e682ebb55f7d --- /dev/null +++ b/packages/remix/.eslintrc.js @@ -0,0 +1,13 @@ +module.exports = { + env: { + browser: true, + node: true, + }, + parserOptions: { + jsx: true, + }, + extends: ['../../.eslintrc.js'], + rules: { + '@sentry-internal/sdk/no-async-await': 'off', + }, +}; diff --git a/packages/remix/LICENSE b/packages/remix/LICENSE new file mode 100644 index 000000000000..2405b5588e48 --- /dev/null +++ b/packages/remix/LICENSE @@ -0,0 +1,29 @@ +MIT License + +Copyright (c) 2021, Sentry +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +* Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + +* Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +* Neither the name of the copyright holder nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/packages/remix/README.md b/packages/remix/README.md new file mode 100644 index 000000000000..0a5f1a298d1b --- /dev/null +++ b/packages/remix/README.md @@ -0,0 +1,9 @@ +

+ + Sentry + +

+ +# Official Sentry SDK for Remix + +< TBD > diff --git a/packages/remix/jest.config.js b/packages/remix/jest.config.js new file mode 100644 index 000000000000..24f49ab59a4c --- /dev/null +++ b/packages/remix/jest.config.js @@ -0,0 +1 @@ +module.exports = require('../../jest/jest.config.js'); diff --git a/packages/remix/package.json b/packages/remix/package.json new file mode 100644 index 000000000000..b6db5c80af8d --- /dev/null +++ b/packages/remix/package.json @@ -0,0 +1,82 @@ +{ + "name": "@sentry/remix", + "version": "7.0.0-beta.0", + "description": "Official Sentry SDK for Remix", + "repository": "git://github.com/getsentry/sentry-javascript.git", + "homepage": "https://github.com/getsentry/sentry-javascript/tree/master/packages/remix", + "author": "Sentry", + "license": "MIT", + "engines": { + "node": ">=14" + }, + "main": "build/cjs/index.server.js", + "module": "build/esm/index.server.js", + "browser": "build/esm/index.client.js", + "types": "build/types/index.server.d.ts", + "private": true, + "dependencies": { + "@sentry/core": "7.0.0-beta.0", + "@sentry/hub": "7.0.0-beta.0", + "@sentry/integrations": "7.0.0-beta.0", + "@sentry/node": "7.0.0-beta.0", + "@sentry/react": "7.0.0-beta.0", + "@sentry/tracing": "7.0.0-beta.0", + "@sentry/utils": "7.0.0-beta.0", + "@sentry/webpack-plugin": "1.18.9", + "tslib": "^1.9.3" + }, + "devDependencies": { + "@sentry/types": "7.0.0-beta.0", + "@types/webpack": "^4.41.31", + "@remix-run/node": "^1.4.3", + "@remix-run/react": "^1.4.3" + }, + "peerDependencies": { + "@remix-run/node": "^1.4.3", + "@remix-run/react": "^1.4.3", + "react": "16.x || 17.x || 18.x", + "webpack": ">=4.0.0" + }, + "peerDependenciesMeta": { + "webpack": { + "optional": true + } + }, + "scripts": { + "build": "run-p build:rollup", + "build:cjs": "tsc -p tsconfig.cjs.json", + "build:dev": "run-s build", + "build:es5": "yarn build:cjs # *** backwards compatibility - remove in v7 ***", + "build:esm": "tsc -p tsconfig.esm.json", + "build:rollup": "rollup -c rollup.npm.config.js", + "build:types": "tsc -p tsconfig.types.json", + "build:watch": "run-p build:cjs:watch build:esm:watch", + "build:cjs:watch": "tsc -p tsconfig.cjs.json --watch", + "build:dev:watch": "run-s build:watch", + "build:es5:watch": "yarn build:cjs:watch # *** backwards compatibility - remove in v7 ***", + "build:esm:watch": "tsc -p tsconfig.esm.json --watch", + "build:rollup:watch": "rollup -c rollup.npm.config.js --watch", + "build:types:watch": "tsc -p tsconfig.types.json --watch", + "build:npm": "ts-node ../../scripts/prepack.ts && npm pack ./build", + "circularDepCheck": "madge --circular src/index.client.ts && madge --circular --exclude 'config/types\\.ts' src/index.server.ts # see https://github.com/pahen/madge/issues/306", + "clean": "rimraf build coverage", + "fix": "run-s fix:eslint fix:prettier", + "fix:eslint": "eslint . --format stylish --fix", + "fix:prettier": "prettier --write \"{src,test,scripts}/**/*.ts\"", + "link:yarn": "yarn link", + "lint": "run-s lint:prettier lint:eslint", + "lint:eslint": "eslint . --cache --cache-location '../../eslintcache/' --format stylish", + "lint:prettier": "prettier --check \"{src,test,scripts}/**/*.ts\"", + "test": "run-s test:unit", + "test:unit": "jest", + "test:watch": "jest --watch" + }, + "volta": { + "extends": "../../package.json" + }, + "sideEffects": [ + "./cjs/index.server.js", + "./esm/index.server.js", + "./src/index.server.ts" + ] +} diff --git a/packages/remix/rollup.npm.config.js b/packages/remix/rollup.npm.config.js new file mode 100644 index 000000000000..4689937a652c --- /dev/null +++ b/packages/remix/rollup.npm.config.js @@ -0,0 +1,7 @@ +import { makeBaseNPMConfig, makeNPMConfigVariants } from '../../rollup/index.js'; + +export default makeNPMConfigVariants( + makeBaseNPMConfig({ + entrypoints: ['src/index.server.ts', 'src/index.client.tsx'], + }), +); diff --git a/packages/remix/src/flags.ts b/packages/remix/src/flags.ts new file mode 100644 index 000000000000..fb99adbc2aa7 --- /dev/null +++ b/packages/remix/src/flags.ts @@ -0,0 +1,18 @@ +/* + * This file defines flags and constants that can be modified during compile time in order to facilitate tree shaking + * for users. + * + * Debug flags need to be declared in each package individually and must not be imported across package boundaries, + * because some build tools have trouble tree-shaking imported guards. + * + * As a convention, we define debug flags in a `flags.ts` file in the root of a package's `src` folder. + * + * Debug flag files will contain "magic strings" like `__SENTRY_DEBUG__` that may get replaced with actual values during + * our, or the user's build process. Take care when introducing new flags - they must not throw if they are not + * replaced. + */ + +declare const __SENTRY_DEBUG__: boolean; + +/** Flag that is true for debug builds, false otherwise. */ +export const IS_DEBUG_BUILD = typeof __SENTRY_DEBUG__ === 'undefined' ? true : __SENTRY_DEBUG__; diff --git a/packages/remix/src/index.client.tsx b/packages/remix/src/index.client.tsx new file mode 100644 index 000000000000..bd87458c993d --- /dev/null +++ b/packages/remix/src/index.client.tsx @@ -0,0 +1,21 @@ +/* eslint-disable import/export */ +import { configureScope, init as reactInit, Integrations } from '@sentry/react'; + +import { buildMetadata } from './utils/metadata'; +import { RemixOptions } from './utils/remixOptions'; +export { remixRouterInstrumentation, withSentryRouteTracing } from './performance/client'; +export { BrowserTracing } from '@sentry/tracing'; +export * from '@sentry/react'; + +export { Integrations }; + +export function init(options: RemixOptions): void { + buildMetadata(options, ['remix', 'react']); + options.environment = options.environment || process.env.NODE_ENV; + + reactInit(options); + + configureScope(scope => { + scope.setTag('runtime', 'browser'); + }); +} diff --git a/packages/remix/src/index.server.ts b/packages/remix/src/index.server.ts new file mode 100644 index 000000000000..ed4b28038381 --- /dev/null +++ b/packages/remix/src/index.server.ts @@ -0,0 +1,34 @@ +/* eslint-disable import/export */ +import { configureScope, getCurrentHub, init as nodeInit } from '@sentry/node'; + +import { instrumentServer } from './utils/instrumentServer'; +import { buildMetadata } from './utils/metadata'; +import { RemixOptions } from './utils/remixOptions'; + +function sdkAlreadyInitialized(): boolean { + const hub = getCurrentHub(); + return !!hub.getClient(); +} + +/** Initializes Sentry Remix SDK on Node. */ +export function init(options: RemixOptions): void { + buildMetadata(options, ['remix', 'node']); + + if (sdkAlreadyInitialized()) { + // TODO: Log something + return; + } + + instrumentServer(); + + nodeInit(options); + + configureScope(scope => { + scope.setTag('runtime', 'node'); + }); +} + +export { ErrorBoundary, withErrorBoundary } from '@sentry/react'; +export { remixRouterInstrumentation, withSentryRouteTracing } from './performance/client'; +export { BrowserTracing, Integrations } from '@sentry/tracing'; +export * from '@sentry/node'; diff --git a/packages/remix/src/performance/client.tsx b/packages/remix/src/performance/client.tsx new file mode 100644 index 000000000000..b88e059aa0f7 --- /dev/null +++ b/packages/remix/src/performance/client.tsx @@ -0,0 +1,142 @@ +import { Transaction, TransactionContext } from '@sentry/types'; +import { getGlobalObject, logger } from '@sentry/utils'; +import * as React from 'react'; + +import { IS_DEBUG_BUILD } from '../flags'; + +const DEFAULT_TAGS = { + 'routing.instrumentation': 'remix-router', +} as const; + +type Params = { + readonly [key in Key]: string | undefined; +}; + +interface RouteMatch { + params: Params; + pathname: string; + id: string; + handle: unknown; +} + +type UseEffect = (cb: () => void, deps: unknown[]) => void; +type UseLocation = () => { + pathname: string; + search?: string; + hash?: string; + state?: unknown; + key?: unknown; +}; +type UseMatches = () => RouteMatch[] | null; + +let activeTransaction: Transaction | undefined; + +let _useEffect: UseEffect; +let _useLocation: UseLocation; +let _useMatches: UseMatches; + +let _customStartTransaction: (context: TransactionContext) => Transaction | undefined; +let _startTransactionOnLocationChange: boolean; + +const global = getGlobalObject(); + +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/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" From 694b302fe652d0a2d65bd95032d4830f22fc5f8a Mon Sep 17 00:00:00 2001 From: Onur Temizkan Date: Fri, 10 Jun 2022 14:11:23 +0100 Subject: [PATCH 2/3] Skip Remix tests on Node <= 12. --- scripts/test.ts | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) 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 { From 051906f1f9bd81255ee2716817dd517ae7f03b42 Mon Sep 17 00:00:00 2001 From: Onur Temizkan Date: Fri, 10 Jun 2022 14:39:32 +0100 Subject: [PATCH 3/3] Check `index.client.tsx` for circular dependencies. --- packages/remix/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/remix/package.json b/packages/remix/package.json index b6db5c80af8d..576ebe224294 100644 --- a/packages/remix/package.json +++ b/packages/remix/package.json @@ -58,7 +58,7 @@ "build:rollup:watch": "rollup -c rollup.npm.config.js --watch", "build:types:watch": "tsc -p tsconfig.types.json --watch", "build:npm": "ts-node ../../scripts/prepack.ts && npm pack ./build", - "circularDepCheck": "madge --circular src/index.client.ts && madge --circular --exclude 'config/types\\.ts' src/index.server.ts # see https://github.com/pahen/madge/issues/306", + "circularDepCheck": "madge --circular src/index.client.tsx && madge --circular --exclude 'config/types\\.ts' src/index.server.ts # see https://github.com/pahen/madge/issues/306", "clean": "rimraf build coverage", "fix": "run-s fix:eslint fix:prettier", "fix:eslint": "eslint . --format stylish --fix",