From 4cbeb16b8d18887d2761355b865f09b147f7ab1e Mon Sep 17 00:00:00 2001 From: Charly Gomez Date: Tue, 4 Feb 2025 15:36:52 +0100 Subject: [PATCH 01/15] add rr package with basic exports --- .../e2e-tests/verdaccio-config/config.yaml | 6 ++ package.json | 1 + packages/react-router/.eslintrc.js | 8 +++ packages/react-router/.gitignore | 0 packages/react-router/LICENSE | 16 +++++ packages/react-router/README.md | 24 +++++++ packages/react-router/package.json | 70 +++++++++++++++++++ packages/react-router/rollup.npm.config.mjs | 22 ++++++ packages/react-router/src/client/index.ts | 1 + packages/react-router/src/client/sdk.ts | 21 ++++++ .../react-router/src/common/debug-build.ts | 8 +++ packages/react-router/src/index.client.ts | 1 + packages/react-router/src/index.server.ts | 1 + packages/react-router/src/index.types.ts | 16 +++++ packages/react-router/src/server/index.ts | 1 + packages/react-router/src/server/sdk.ts | 20 ++++++ packages/react-router/tsconfig.json | 7 ++ packages/react-router/tsconfig.test.json | 11 +++ packages/react-router/tsconfig.types.json | 10 +++ yarn.lock | 35 ++++++++++ 20 files changed, 279 insertions(+) create mode 100644 packages/react-router/.eslintrc.js create mode 100644 packages/react-router/.gitignore create mode 100644 packages/react-router/LICENSE create mode 100644 packages/react-router/README.md create mode 100644 packages/react-router/package.json create mode 100644 packages/react-router/rollup.npm.config.mjs create mode 100644 packages/react-router/src/client/index.ts create mode 100644 packages/react-router/src/client/sdk.ts create mode 100644 packages/react-router/src/common/debug-build.ts create mode 100644 packages/react-router/src/index.client.ts create mode 100644 packages/react-router/src/index.server.ts create mode 100644 packages/react-router/src/index.types.ts create mode 100644 packages/react-router/src/server/index.ts create mode 100644 packages/react-router/src/server/sdk.ts create mode 100644 packages/react-router/tsconfig.json create mode 100644 packages/react-router/tsconfig.test.json create mode 100644 packages/react-router/tsconfig.types.json diff --git a/dev-packages/e2e-tests/verdaccio-config/config.yaml b/dev-packages/e2e-tests/verdaccio-config/config.yaml index ee65c5218d4a..cbb73201eebf 100644 --- a/dev-packages/e2e-tests/verdaccio-config/config.yaml +++ b/dev-packages/e2e-tests/verdaccio-config/config.yaml @@ -122,6 +122,12 @@ packages: unpublish: $all # proxy: npmjs # Don't proxy for E2E tests! + '@sentry/react-router': + access: $all + publish: $all + unpublish: $all + # proxy: npmjs # Don't proxy for E2E tests! + '@sentry/remix': access: $all publish: $all diff --git a/package.json b/package.json index 73ae7f18495d..d6ec5b9f297b 100644 --- a/package.json +++ b/package.json @@ -73,6 +73,7 @@ "packages/opentelemetry", "packages/profiling-node", "packages/react", + "packages/react-router", "packages/remix", "packages/replay-internal", "packages/replay-canvas", diff --git a/packages/react-router/.eslintrc.js b/packages/react-router/.eslintrc.js new file mode 100644 index 000000000000..b5f457022111 --- /dev/null +++ b/packages/react-router/.eslintrc.js @@ -0,0 +1,8 @@ +module.exports = { + env: { + browser: true, + node: true, + }, + overrides: [], + extends: ['../../.eslintrc.js'], +}; diff --git a/packages/react-router/.gitignore b/packages/react-router/.gitignore new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/packages/react-router/LICENSE b/packages/react-router/LICENSE new file mode 100644 index 000000000000..5f9dced3c1f5 --- /dev/null +++ b/packages/react-router/LICENSE @@ -0,0 +1,16 @@ +MIT License + +Copyright (c) 2024 Functional Software, Inc. dba Sentry + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated +documentation files (the "Software"), to deal in the Software without restriction, including without limitation the +rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit +persons to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the +Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE +WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/packages/react-router/README.md b/packages/react-router/README.md new file mode 100644 index 000000000000..7910b5082f4a --- /dev/null +++ b/packages/react-router/README.md @@ -0,0 +1,24 @@ +

+ + Sentry + +

+ +# Official Sentry SDK for React Router (framework) (EXPERIMENTAL) + +[![npm version](https://img.shields.io/npm/v/@sentry/react-router.svg)](https://www.npmjs.com/package/@sentry/react-router) +[![npm dm](https://img.shields.io/npm/dm/@sentry/react-router.svg)](https://www.npmjs.com/package/@sentry/react-router) +[![npm dt](https://img.shields.io/npm/dt/@sentry/react-router.svg)](https://www.npmjs.com/package/@sentry/react-router) + +This SDK is considered ⚠️ **experimental and in an alpha state**. It may experience breaking changes. Please reach out +on [GitHub](https://github.com/getsentry/sentry-javascript/issues/) if you have any feedback or concerns. This +SDK is for [React Router (framework)](https://reactrouter.com/start/framework/installation). If you're using [React Router (library)](https://reactrouter.com/start/library/installation) see our +[React SDK here](https://docs.sentry.io/platforms/javascript/guides/react/features/react-router/v7/). + +## Links + +- [Official SDK Docs](https://docs.sentry.io/platforms/javascript/guides/react-router/) + +## General + +This package is a wrapper around `@sentry/node` for the server and `@sentry/browser` for the client side. diff --git a/packages/react-router/package.json b/packages/react-router/package.json new file mode 100644 index 000000000000..48a53e2e122a --- /dev/null +++ b/packages/react-router/package.json @@ -0,0 +1,70 @@ +{ + "name": "@sentry/react-router", + "version": "9.0.0-alpha.1", + "description": "Official Sentry SDK for React Router v7 (Framework)", + "repository": "git://github.com/getsentry/sentry-javascript.git", + "homepage": "https://github.com/getsentry/sentry-javascript/tree/master/packages/react-router", + "author": "Sentry", + "license": "MIT", + "engines": { + "node": ">=20" + }, + "files": [ + "/build" + ], + "exports": { + "./package.json": "./package.json", + ".": { + "types": "./build/types/index.types.d.ts", + "browser": { + "import": "./build/esm/index.client.js", + "require": "./build/cjs/index.client.js" + }, + "node": { + "import": "./build/esm/index.server.js", + "require": "./build/cjs/index.server.js" + } + } + }, + "publishConfig": { + "access": "public" + }, + "dependencies": { + "@sentry/core": "9.0.0-alpha.1", + "@sentry/browser": "9.0.0-alpha.1", + "@sentry/node": "9.0.0-alpha.1" + }, + "devDependencies": { + "@react-router/node": "^7.1.5", + "react-router": "^7.1.5" + }, + "peerDependencies": { + "@react-router/node": "7.x", + "react-router": "7.x", + "react": ">=18" + }, + "scripts": { + "build": "run-p build:transpile build:types", + "build:dev": "yarn build", + "build:transpile": "rollup -c rollup.npm.config.mjs", + "build:types": "run-s build:types:core", + "build:types:core": "tsc -p tsconfig.types.json", + "build:watch": "run-p build:transpile:watch build:types:watch", + "build:dev:watch": "yarn build:watch", + "build:transpile:watch": "rollup -c rollup.npm.config.mjs --watch", + "build:types:watch": "tsc -p tsconfig.types.json --watch", + "build:tarball": "npm pack", + "circularDepCheck": "madge --circular src/index.server.ts", + "clean": "rimraf build coverage sentry-react-router-*.tgz", + "fix": "eslint . --format stylish --fix", + "lint": "eslint . --format stylish", + "test": "yarn test:unit", + "test:unit": "vitest run", + "test:watch": "vitest --watch", + "yalc:publish": "yalc publish --push --sig" + }, + "volta": { + "node": "20.18.2", + "extends": "../../package.json" + } +} diff --git a/packages/react-router/rollup.npm.config.mjs b/packages/react-router/rollup.npm.config.mjs new file mode 100644 index 000000000000..65e6b0a0dd9a --- /dev/null +++ b/packages/react-router/rollup.npm.config.mjs @@ -0,0 +1,22 @@ +import { makeBaseNPMConfig, makeNPMConfigVariants } from '@sentry-internal/rollup-utils'; + +export default [ + ...makeNPMConfigVariants( + makeBaseNPMConfig({ + entrypoints: ['src/index.server.ts', 'src/index.client.ts'], + packageSpecificConfig: { + external: ['react-router', 'react-router-dom', 'react', 'react/jsx-runtime'], + output: { + // make it so Rollup calms down about the fact that we're combining default and named exports + exports: 'named', + }, + }, + sucrase: { + // React 19 emits a warning if we don't use the newer jsx transform: https://legacy.reactjs.org/blog/2020/09/22/introducing-the-new-jsx-transform.html + // but this breaks react 17, so we keep it at `classic` for now + jsxRuntime: 'classic', + production: true, // This is needed so that sucrase uses the production jsx runtime (ie `import { jsx } from 'react/jsx-runtime'` instead of `import { jsxDEV as _jsxDEV } from 'react/jsx-dev-runtime'`) + }, + }), + ), +]; diff --git a/packages/react-router/src/client/index.ts b/packages/react-router/src/client/index.ts new file mode 100644 index 000000000000..a4081b6e100a --- /dev/null +++ b/packages/react-router/src/client/index.ts @@ -0,0 +1 @@ +export * from '@sentry/browser'; diff --git a/packages/react-router/src/client/sdk.ts b/packages/react-router/src/client/sdk.ts new file mode 100644 index 000000000000..688a8ba460f1 --- /dev/null +++ b/packages/react-router/src/client/sdk.ts @@ -0,0 +1,21 @@ +import type { BrowserOptions } from '@sentry/browser'; +import { init as browserInit } from '@sentry/browser'; +import type { Client } from '@sentry/core'; +import { applySdkMetadata, setTag } from '@sentry/core'; + +/** + * Initializes the client side of the React Router SDK. + */ +export function init(options: BrowserOptions): Client | undefined { + const opts = { + ...options, + }; + + applySdkMetadata(opts, 'react-router', ['react-router', 'browser']); + + const client = browserInit(opts); + + setTag('runtime', 'browser'); + + return client; +} diff --git a/packages/react-router/src/common/debug-build.ts b/packages/react-router/src/common/debug-build.ts new file mode 100644 index 000000000000..60aa50940582 --- /dev/null +++ b/packages/react-router/src/common/debug-build.ts @@ -0,0 +1,8 @@ +declare const __DEBUG_BUILD__: boolean; + +/** + * This serves as a build time flag that will be true by default, but false in non-debug builds or if users replace `__SENTRY_DEBUG__` in their generated code. + * + * ATTENTION: This constant must never cross package boundaries (i.e. be exported) to guarantee that it can be used for tree shaking. + */ +export const DEBUG_BUILD = __DEBUG_BUILD__; diff --git a/packages/react-router/src/index.client.ts b/packages/react-router/src/index.client.ts new file mode 100644 index 000000000000..4f1cce44fa36 --- /dev/null +++ b/packages/react-router/src/index.client.ts @@ -0,0 +1 @@ +export * from './client'; diff --git a/packages/react-router/src/index.server.ts b/packages/react-router/src/index.server.ts new file mode 100644 index 000000000000..0ce5251aa327 --- /dev/null +++ b/packages/react-router/src/index.server.ts @@ -0,0 +1 @@ +export * from './server'; diff --git a/packages/react-router/src/index.types.ts b/packages/react-router/src/index.types.ts new file mode 100644 index 000000000000..aceff59e27a1 --- /dev/null +++ b/packages/react-router/src/index.types.ts @@ -0,0 +1,16 @@ +// re-define colliding type exports below + +export * from './client'; +export * from './server'; + +import type { Integration, Options, StackParser } from '@sentry/core'; +import type * as clientSdk from './client'; +import type * as serverSdk from './server'; + +/** Initializes Sentry Solid Start SDK */ +export declare function init(options: Options | clientSdk.BrowserOptions | serverSdk.NodeOptions): void; + +export declare const contextLinesIntegration: typeof clientSdk.contextLinesIntegration; +export declare const linkedErrorsIntegration: typeof clientSdk.linkedErrorsIntegration; +export declare const defaultStackParser: StackParser; +export declare const getDefaultIntegrations: (options: Options) => Integration[]; diff --git a/packages/react-router/src/server/index.ts b/packages/react-router/src/server/index.ts new file mode 100644 index 000000000000..d61c75b7bfb4 --- /dev/null +++ b/packages/react-router/src/server/index.ts @@ -0,0 +1 @@ +export * from '@sentry/node'; diff --git a/packages/react-router/src/server/sdk.ts b/packages/react-router/src/server/sdk.ts new file mode 100644 index 000000000000..bae99dee4983 --- /dev/null +++ b/packages/react-router/src/server/sdk.ts @@ -0,0 +1,20 @@ +import { applySdkMetadata, setTag } from '@sentry/core'; +import type { NodeClient, NodeOptions } from '@sentry/node'; +import { init as initNodeSdk } from '@sentry/node'; + +/** + * Initializes the server side of the React Router SDK + */ +export function init(options: NodeOptions): NodeClient | undefined { + const opts = { + ...options, + }; + + applySdkMetadata(opts, 'react-router', ['react-router', 'node']); + + const client = initNodeSdk(opts); + + setTag('runtime', 'node'); + + return client; +} diff --git a/packages/react-router/tsconfig.json b/packages/react-router/tsconfig.json new file mode 100644 index 000000000000..b0eb9ecb6476 --- /dev/null +++ b/packages/react-router/tsconfig.json @@ -0,0 +1,7 @@ +{ + "extends": "../../tsconfig.json", + + "include": ["src/**/*"], + + "compilerOptions": {} +} diff --git a/packages/react-router/tsconfig.test.json b/packages/react-router/tsconfig.test.json new file mode 100644 index 000000000000..eee3366554e7 --- /dev/null +++ b/packages/react-router/tsconfig.test.json @@ -0,0 +1,11 @@ +{ + "extends": "./tsconfig.json", + + "include": ["test/**/*", "vitest.config.ts"], + + "compilerOptions": { + "lib": ["DOM", "ES2018"], + "types": ["node", "vitest/globals", "vite/client"], + "esModuleInterop": true + } +} diff --git a/packages/react-router/tsconfig.types.json b/packages/react-router/tsconfig.types.json new file mode 100644 index 000000000000..65455f66bd75 --- /dev/null +++ b/packages/react-router/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 83ff270a83f9..4c9896a0923e 100644 --- a/yarn.lock +++ b/yarn.lock @@ -4759,6 +4759,11 @@ semver "^7.3.5" tar "^6.1.11" +"@mjackson/node-fetch-server@^0.2.0": + version "0.2.0" + resolved "https://registry.yarnpkg.com/@mjackson/node-fetch-server/-/node-fetch-server-0.2.0.tgz#577c0c25d8aae9f69a97738b7b0d03d1471cdc49" + integrity sha512-EMlH1e30yzmTpGLQjlFmaDAjyOeZhng1/XCd7DExR8PNAnG/G1tyruZxEoUe11ClnwGhGrtsdnyyUx1frSzjng== + "@nestjs/common@10.4.6": version "10.4.6" resolved "https://registry.yarnpkg.com/@nestjs/common/-/common-10.4.6.tgz#952e8fd0ceafeffcc4eaf47effd67fb395844ae0" @@ -6162,6 +6167,16 @@ resolved "https://registry.yarnpkg.com/@protobufjs/utf8/-/utf8-1.1.0.tgz#a777360b5b39a1a2e5106f8e858f2fd2d060c570" integrity sha512-Vvn3zZrhQZkkBE8LSuW3em98c0FwgO4nxzv6OdSxPKJIEKY2bGbHn+mhGIPerzI4twdxaP8/0+06HBpwf345Lw== +"@react-router/node@^7.1.5": + version "7.1.5" + resolved "https://registry.yarnpkg.com/@react-router/node/-/node-7.1.5.tgz#fe4bdb708bb574cbf21b359d1263f6accde737bd" + integrity sha512-Ga8xFHxO2yt5TpGwV5xYx4LC3eUDmhT6jYfTbMFb6F7hBA9sLdHxNfYZCe2WEfVZ4/BM7I8989Qzq6BWilV2LA== + dependencies: + "@mjackson/node-fetch-server" "^0.2.0" + source-map-support "^0.5.21" + stream-slice "^0.1.2" + undici "^6.19.2" + "@redis/bloom@1.2.0": version "1.2.0" resolved "https://registry.yarnpkg.com/@redis/bloom/-/bloom-1.2.0.tgz#d3fd6d3c0af3ef92f26767b56414a370c7b63b71" @@ -12576,6 +12591,11 @@ cookie@^0.6.0: resolved "https://registry.yarnpkg.com/cookie/-/cookie-0.6.0.tgz#2798b04b071b0ecbff0dbb62a505a8efa4e19051" integrity sha512-U71cyTamuh1CRNCfpGY6to28lxvNwPG4Guz/EVjgf3Jmzv0vlDp1atT9eS5dDjMYHucpHbWns6Lwf3BKz6svdw== +cookie@^1.0.1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/cookie/-/cookie-1.0.2.tgz#27360701532116bd3f1f9416929d176afe1e4610" + integrity sha512-9Kr/j4O16ISv8zBBhJoi4bXOYNTkFLOqSL3UDB0njXxCXNezjeyVrJyGOWtgfs/q2km1gwBcfH8q1yEGoMYunA== + cookie@~0.7.2: version "0.7.2" resolved "https://registry.yarnpkg.com/cookie/-/cookie-0.7.2.tgz#556369c472a2ba910f2979891b526b3436237ed7" @@ -25215,6 +25235,16 @@ react-router@6.28.1: dependencies: "@remix-run/router" "1.21.0" +react-router@^7.1.5: + version "7.1.5" + resolved "https://registry.yarnpkg.com/react-router/-/react-router-7.1.5.tgz#c9e19d329d9ce2215fdae844ab6b023b911094db" + integrity sha512-8BUF+hZEU4/z/JD201yK6S+UYhsf58bzYIDq2NS1iGpwxSXDu7F+DeGSkIXMFBuHZB21FSiCzEcUb18cQNdRkA== + dependencies: + "@types/cookie" "^0.6.0" + cookie "^1.0.1" + set-cookie-parser "^2.6.0" + turbo-stream "2.4.0" + react@^18.0.0: version "18.0.0" resolved "https://registry.yarnpkg.com/react/-/react-18.0.0.tgz#b468736d1f4a5891f38585ba8e8fb29f91c3cb96" @@ -28879,6 +28909,11 @@ undici@^6.11.1: resolved "https://registry.yarnpkg.com/undici/-/undici-6.21.0.tgz#4b3d3afaef984e07b48e7620c34ed8a285ed4cd4" integrity sha512-BUgJXc752Kou3oOIuU1i+yZZypyZRqNPW0vqoMPl8VaoalSfeR0D8/t4iAS3yirs79SSMTxTag+ZC86uswv+Cw== +undici@^6.19.2: + version "6.21.1" + resolved "https://registry.yarnpkg.com/undici/-/undici-6.21.1.tgz#336025a14162e6837e44ad7b819b35b6c6af0e05" + integrity sha512-q/1rj5D0/zayJB2FraXdaWxbhWiNKDvu8naDT2dl1yTlvJp4BLtOcp2a5BvgGNQpYYJzau7tf1WgKv3b+7mqpQ== + unenv@^1.10.0, unenv@^1.9.0: version "1.10.0" resolved "https://registry.yarnpkg.com/unenv/-/unenv-1.10.0.tgz#c3394a6c6e4cfe68d699f87af456fe3f0db39571" From b662c1fc67227038b28207fe293bdaddde29c923 Mon Sep 17 00:00:00 2001 From: Charly Gomez Date: Tue, 4 Feb 2025 16:07:32 +0100 Subject: [PATCH 02/15] add unit tests --- packages/react-router/src/client/index.ts | 2 + packages/react-router/src/server/index.ts | 2 + packages/react-router/test/client/sdk.test.ts | 47 ++++++++++++++++++ packages/react-router/test/server/sdk.test.ts | 48 +++++++++++++++++++ packages/react-router/test/tsconfig.json | 3 ++ packages/react-router/vite.config.ts | 9 ++++ 6 files changed, 111 insertions(+) create mode 100644 packages/react-router/test/client/sdk.test.ts create mode 100644 packages/react-router/test/server/sdk.test.ts create mode 100644 packages/react-router/test/tsconfig.json create mode 100644 packages/react-router/vite.config.ts diff --git a/packages/react-router/src/client/index.ts b/packages/react-router/src/client/index.ts index a4081b6e100a..8e25b84c4a0c 100644 --- a/packages/react-router/src/client/index.ts +++ b/packages/react-router/src/client/index.ts @@ -1 +1,3 @@ export * from '@sentry/browser'; + +export { init } from './sdk'; diff --git a/packages/react-router/src/server/index.ts b/packages/react-router/src/server/index.ts index d61c75b7bfb4..6ac8d97b4241 100644 --- a/packages/react-router/src/server/index.ts +++ b/packages/react-router/src/server/index.ts @@ -1 +1,3 @@ export * from '@sentry/node'; + +export { init } from './sdk'; diff --git a/packages/react-router/test/client/sdk.test.ts b/packages/react-router/test/client/sdk.test.ts new file mode 100644 index 000000000000..9ae55de69d4c --- /dev/null +++ b/packages/react-router/test/client/sdk.test.ts @@ -0,0 +1,47 @@ +import { afterEach, describe, expect, it, vi } from 'vitest'; + +import * as SentryBrowser from '@sentry/browser'; +import { SDK_VERSION, getCurrentScope, getGlobalScope, getIsolationScope } from '@sentry/browser'; + +import { init } from '../../src/client'; + +const browserInit = vi.spyOn(SentryBrowser, 'init'); + +describe('React Router client SDK', () => { + describe('init', () => { + afterEach(() => { + vi.clearAllMocks(); + + getGlobalScope().clear(); + getIsolationScope().clear(); + getCurrentScope().clear(); + getCurrentScope().setClient(undefined); + }); + + it('adds React Router metadata to the SDK options', () => { + expect(browserInit).not.toHaveBeenCalled(); + + init({}); + + const expectedMetadata = { + _metadata: { + sdk: { + name: 'sentry.javascript.react-router', + version: SDK_VERSION, + packages: [ + { name: 'npm:@sentry/react-router', version: SDK_VERSION }, + { name: 'npm:@sentry/browser', version: SDK_VERSION }, + ], + }, + }, + }; + + expect(browserInit).toHaveBeenCalledTimes(1); + expect(browserInit).toHaveBeenCalledWith(expect.objectContaining(expectedMetadata)); + }); + + it('returns client from init', () => { + expect(init({})).not.toBeUndefined(); + }); + }); +}); diff --git a/packages/react-router/test/server/sdk.test.ts b/packages/react-router/test/server/sdk.test.ts new file mode 100644 index 000000000000..8f2bf796057b --- /dev/null +++ b/packages/react-router/test/server/sdk.test.ts @@ -0,0 +1,48 @@ +import { afterEach, describe, expect, it, vi } from 'vitest'; + +import * as SentryNode from '@sentry/node'; + +import { SDK_VERSION } from '@sentry/node'; + +import { init } from '../../src/server/sdk'; + +const nodeInit = vi.spyOn(SentryNode, 'init'); + +describe('React Router server SDK', () => { + describe('init', () => { + afterEach(() => { + vi.clearAllMocks(); + + SentryNode.getGlobalScope().clear(); + SentryNode.getIsolationScope().clear(); + SentryNode.getCurrentScope().clear(); + SentryNode.getCurrentScope().setClient(undefined); + }); + + it('adds React Router metadata to the SDK options', () => { + expect(nodeInit).not.toHaveBeenCalled(); + + init({}); + + expect(nodeInit).toHaveBeenCalledTimes(1); + expect(nodeInit).toHaveBeenCalledWith( + expect.objectContaining({ + _metadata: { + sdk: { + name: 'sentry.javascript.react-router', + version: SDK_VERSION, + packages: [ + { name: 'npm:@sentry/react-router', version: SDK_VERSION }, + { name: 'npm:@sentry/node', version: SDK_VERSION }, + ], + }, + }, + }), + ); + }); + + it('returns client from init', () => { + expect(init({})).not.toBeUndefined(); + }); + }); +}); diff --git a/packages/react-router/test/tsconfig.json b/packages/react-router/test/tsconfig.json new file mode 100644 index 000000000000..120c3aff3716 --- /dev/null +++ b/packages/react-router/test/tsconfig.json @@ -0,0 +1,3 @@ +{ + "extends": "../tsconfig.test.json", +} diff --git a/packages/react-router/vite.config.ts b/packages/react-router/vite.config.ts new file mode 100644 index 000000000000..1094fe0d79da --- /dev/null +++ b/packages/react-router/vite.config.ts @@ -0,0 +1,9 @@ +import baseConfig from '../../vite/vite.config'; + +export default { + ...baseConfig, + test: { + ...baseConfig.test, + environment: 'jsdom', + }, +}; From 7af5db615274694ca34c5ad2b53a150b9ad10e3b Mon Sep 17 00:00:00 2001 From: Charly Gomez Date: Thu, 6 Feb 2025 14:28:48 +0100 Subject: [PATCH 03/15] update lint config --- packages/react-router/.eslintrc.js | 9 ++++++++- packages/react-router/package.json | 8 ++++---- packages/react-router/tsconfig.test.json | 2 +- 3 files changed, 13 insertions(+), 6 deletions(-) diff --git a/packages/react-router/.eslintrc.js b/packages/react-router/.eslintrc.js index b5f457022111..a22f9710cf6b 100644 --- a/packages/react-router/.eslintrc.js +++ b/packages/react-router/.eslintrc.js @@ -3,6 +3,13 @@ module.exports = { browser: true, node: true, }, - overrides: [], + overrides: [ + { + files: ['vite.config.ts'], + parserOptions: { + project: ['tsconfig.test.json'], + }, + }, + ], extends: ['../../.eslintrc.js'], }; diff --git a/packages/react-router/package.json b/packages/react-router/package.json index 48a53e2e122a..4442eed3ec77 100644 --- a/packages/react-router/package.json +++ b/packages/react-router/package.json @@ -1,6 +1,6 @@ { "name": "@sentry/react-router", - "version": "9.0.0-alpha.1", + "version": "9.0.0-alpha.2", "description": "Official Sentry SDK for React Router v7 (Framework)", "repository": "git://github.com/getsentry/sentry-javascript.git", "homepage": "https://github.com/getsentry/sentry-javascript/tree/master/packages/react-router", @@ -30,9 +30,9 @@ "access": "public" }, "dependencies": { - "@sentry/core": "9.0.0-alpha.1", - "@sentry/browser": "9.0.0-alpha.1", - "@sentry/node": "9.0.0-alpha.1" + "@sentry/core": "9.0.0-alpha.2", + "@sentry/browser": "9.0.0-alpha.2", + "@sentry/node": "9.0.0-alpha.2" }, "devDependencies": { "@react-router/node": "^7.1.5", diff --git a/packages/react-router/tsconfig.test.json b/packages/react-router/tsconfig.test.json index eee3366554e7..e6e9452a6662 100644 --- a/packages/react-router/tsconfig.test.json +++ b/packages/react-router/tsconfig.test.json @@ -1,7 +1,7 @@ { "extends": "./tsconfig.json", - "include": ["test/**/*", "vitest.config.ts"], + "include": ["test/**/*", "vite.config.ts"], "compilerOptions": { "lib": ["DOM", "ES2018"], From ff9dec738524aaca171733459d86ef1ca46b2b9f Mon Sep 17 00:00:00 2001 From: Charly Gomez Date: Thu, 6 Feb 2025 17:15:30 +0100 Subject: [PATCH 04/15] update readme --- packages/react-router/README.md | 130 +++++++++++++++++++++++++++++++- 1 file changed, 126 insertions(+), 4 deletions(-) diff --git a/packages/react-router/README.md b/packages/react-router/README.md index 7910b5082f4a..139b7b57a676 100644 --- a/packages/react-router/README.md +++ b/packages/react-router/README.md @@ -10,10 +10,11 @@ [![npm dm](https://img.shields.io/npm/dm/@sentry/react-router.svg)](https://www.npmjs.com/package/@sentry/react-router) [![npm dt](https://img.shields.io/npm/dt/@sentry/react-router.svg)](https://www.npmjs.com/package/@sentry/react-router) -This SDK is considered ⚠️ **experimental and in an alpha state**. It may experience breaking changes. Please reach out -on [GitHub](https://github.com/getsentry/sentry-javascript/issues/) if you have any feedback or concerns. This -SDK is for [React Router (framework)](https://reactrouter.com/start/framework/installation). If you're using [React Router (library)](https://reactrouter.com/start/library/installation) see our -[React SDK here](https://docs.sentry.io/platforms/javascript/guides/react/features/react-router/v7/). +> [!WARNING] +> This SDK is considered ⚠️ **experimental and in an alpha state**. It may experience breaking changes. Please reach out +> on [GitHub](https://github.com/getsentry/sentry-javascript/issues/) if you have any feedback or concerns. This +> SDK is for [React Router (framework)](https://reactrouter.com/start/framework/installation). If you're using [React Router (library)](https://reactrouter.com/start/library/installation) see our +> [React SDK here](https://docs.sentry.io/platforms/javascript/guides/react/features/react-router/v7/). ## Links @@ -22,3 +23,124 @@ SDK is for [React Router (framework)](https://reactrouter.com/start/framework/in ## General This package is a wrapper around `@sentry/node` for the server and `@sentry/browser` for the client side. + +## Manual Setup + +### Expose Hooks + +React Router exposes two hooks in your `app` folder (`entry.client.tsx` and `entry.server.tsx`). +If you do not see these two files, expose them with the following command: + +```bash +npx react-router reveal +``` + +### Client-Side Setup + +Initialize the SDK in your `entry.client.tsx` file: + +```tsx +import * as Sentry from '@sentry/react-router'; +import { startTransition, StrictMode } from 'react'; +import { hydrateRoot } from 'react-dom/client'; +import { HydratedRouter } from 'react-router/dom'; + +Sentry.init({ + dsn: '___PUBLIC_DSN___', + integrations: [Sentry.browserTracingIntegration()], + + tracesSampleRate: 1.0, // Capture 100% of the transactions + + // Set `tracePropagationTargets` to declare which URL(s) should have trace propagation enabled + tracePropagationTargets: [/^\//, /^https:\/\/yourserver\.io\/api/], +}); + +startTransition(() => { + hydrateRoot( + document, + + + , + ); +}); +``` + +Now, update your `app/root.tsx` file to report any unhandled errors from your global error boundary: + +```tsx {diff} {filename: app/root.tsx} +import * as Sentry from '@sentry/react-router'; + +export function ErrorBoundary({ error }: Route.ErrorBoundaryProps) { + let message = 'Oops!'; + let details = 'An unexpected error occurred.'; + let stack: string | undefined; + + if (isRouteErrorResponse(error)) { + message = error.status === 404 ? '404' : 'Error'; + details = error.status === 404 ? 'The requested page could not be found.' : error.statusText || details; + } else if (error && error instanceof Error) { + // you only want to capture non 404-errors that reach the boundary + Sentry.captureException(error); + if (import.meta.env.DEV) { + details = error.message; + stack = error.stack; + } + } + + return ( +
+

{message}

+

{details}

+ {stack && ( +
+          {stack}
+        
+ )} +
+ ); +} +// ... +``` + +### Server-Side Setup + +Create an `instrument.server.mjs` file in the root of your app: + +```js {filename: instrument.server.mjs} {"onboardingOptions": {"performance": "7", "profiling": "2, 6, 8"}} +import * as Sentry from '@sentry/node'; + +Sentry.init({ + dsn: '___PUBLIC_DSN___', + tracesSampleRate: 1.0, // Capture 100% of the transactions +}); +``` + +In your `entry.server.tsx` file, export the `handleError` function: + +```tsx {diff} {filename: entry.server.tsx} +import * as Sentry from '@sentry/node'; +import { type HandleErrorFunction } from 'react-router'; + +export const handleError: HandleErrorFunction = (error, { request }) => { + // React Router may abort some interrupted requests, report those + if (!request.signal.aborted) { + Sentry.captureException(error); + + // make sure to still log the error so you can see it + console.error(error); + } +}; +// ... rest of your server entry +``` + +### Update Scripts + +Since React Router is running in ESM mode, you need to use the `--import` command line options to load our server-side instrumentation module before the application starts. +Update the `start` and `dev` script to include the instrumentation file: + +```json {filename: package.json} +"scripts": { + "dev": "NODE_OPTIONS='--import ./instrument.server.mjs' react-router dev", + "start": "NODE_OPTIONS='--import ./instrument.server.mjs' react-router-serve ./build/server/index.js", +} +``` From 6cbbb90cb5a0173352d4f0094f6a73468c1e5eab Mon Sep 17 00:00:00 2001 From: Charly Gomez Date: Thu, 6 Feb 2025 18:58:54 +0100 Subject: [PATCH 05/15] skip node 18 tests for rr --- scripts/ci-unit-tests.ts | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/scripts/ci-unit-tests.ts b/scripts/ci-unit-tests.ts index 13cbc6957d5c..cd53df2dfd68 100644 --- a/scripts/ci-unit-tests.ts +++ b/scripts/ci-unit-tests.ts @@ -4,6 +4,7 @@ import * as path from 'path'; const UNIT_TEST_ENV = process.env.UNIT_TEST_ENV as 'node' | 'browser' | undefined; const RUN_AFFECTED = process.argv.includes('--affected'); +const NODE_VERSION = process.env.NODE_VERSION as '18' | '20' | '22'; // These packages are tested separately in CI, so no need to run them here const DEFAULT_SKIP_PACKAGES = ['@sentry/bun', '@sentry/deno']; @@ -25,6 +26,9 @@ const BROWSER_TEST_PACKAGES = [ '@sentry/wasm', ]; +// Packages that cannot run in Node 18 +const SKIP_NODE_18_PACKAGES = ['@sentry/react-router']; + function getAllPackages(): string[] { const { workspaces }: { workspaces: string[] } = JSON.parse( fs.readFileSync(path.join(process.cwd(), 'package.json'), 'utf-8'), @@ -55,6 +59,10 @@ function runTests(): void { }); } else if (UNIT_TEST_ENV === 'node') { BROWSER_TEST_PACKAGES.forEach(pkg => ignores.add(pkg)); + + if (NODE_VERSION === '18') { + SKIP_NODE_18_PACKAGES.forEach(pkg => ignores.add(pkg)); + } } if (RUN_AFFECTED) { From 5ed2197fdcecdbcc44121a1b4bf263451547d1bd Mon Sep 17 00:00:00 2001 From: Charly Gomez Date: Fri, 7 Feb 2025 11:25:52 +0100 Subject: [PATCH 06/15] init tests --- packages/react-router/src/index.types.ts | 2 +- packages/react-router/test/client/sdk.test.ts | 4 ++-- packages/react-router/test/server/sdk.test.ts | 6 +++--- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/packages/react-router/src/index.types.ts b/packages/react-router/src/index.types.ts index aceff59e27a1..8d246451eb7d 100644 --- a/packages/react-router/src/index.types.ts +++ b/packages/react-router/src/index.types.ts @@ -7,7 +7,7 @@ import type { Integration, Options, StackParser } from '@sentry/core'; import type * as clientSdk from './client'; import type * as serverSdk from './server'; -/** Initializes Sentry Solid Start SDK */ +/** Initializes Sentry React Router SDK */ export declare function init(options: Options | clientSdk.BrowserOptions | serverSdk.NodeOptions): void; export declare const contextLinesIntegration: typeof clientSdk.contextLinesIntegration; diff --git a/packages/react-router/test/client/sdk.test.ts b/packages/react-router/test/client/sdk.test.ts index 9ae55de69d4c..57546e091989 100644 --- a/packages/react-router/test/client/sdk.test.ts +++ b/packages/react-router/test/client/sdk.test.ts @@ -3,7 +3,7 @@ import { afterEach, describe, expect, it, vi } from 'vitest'; import * as SentryBrowser from '@sentry/browser'; import { SDK_VERSION, getCurrentScope, getGlobalScope, getIsolationScope } from '@sentry/browser'; -import { init } from '../../src/client'; +import { init as reactRouterInit } from '../../src/client'; const browserInit = vi.spyOn(SentryBrowser, 'init'); @@ -21,7 +21,7 @@ describe('React Router client SDK', () => { it('adds React Router metadata to the SDK options', () => { expect(browserInit).not.toHaveBeenCalled(); - init({}); + reactRouterInit({}); const expectedMetadata = { _metadata: { diff --git a/packages/react-router/test/server/sdk.test.ts b/packages/react-router/test/server/sdk.test.ts index 8f2bf796057b..06ff871d07f9 100644 --- a/packages/react-router/test/server/sdk.test.ts +++ b/packages/react-router/test/server/sdk.test.ts @@ -4,7 +4,7 @@ import * as SentryNode from '@sentry/node'; import { SDK_VERSION } from '@sentry/node'; -import { init } from '../../src/server/sdk'; +import { init as reactRouterInit } from '../../src/server/sdk'; const nodeInit = vi.spyOn(SentryNode, 'init'); @@ -22,7 +22,7 @@ describe('React Router server SDK', () => { it('adds React Router metadata to the SDK options', () => { expect(nodeInit).not.toHaveBeenCalled(); - init({}); + reactRouterInit({}); expect(nodeInit).toHaveBeenCalledTimes(1); expect(nodeInit).toHaveBeenCalledWith( @@ -42,7 +42,7 @@ describe('React Router server SDK', () => { }); it('returns client from init', () => { - expect(init({})).not.toBeUndefined(); + expect(reactRouterInit({})).not.toBeUndefined(); }); }); }); From 5c5d9a67c914f9f6e0e2ad5e48842c5f0ad87305 Mon Sep 17 00:00:00 2001 From: Charly Gomez Date: Fri, 7 Feb 2025 11:37:36 +0100 Subject: [PATCH 07/15] . --- packages/react-router/test/client/sdk.test.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/react-router/test/client/sdk.test.ts b/packages/react-router/test/client/sdk.test.ts index 57546e091989..e63fe0cf51cf 100644 --- a/packages/react-router/test/client/sdk.test.ts +++ b/packages/react-router/test/client/sdk.test.ts @@ -41,7 +41,7 @@ describe('React Router client SDK', () => { }); it('returns client from init', () => { - expect(init({})).not.toBeUndefined(); + expect(reactRouterInit({})).not.toBeUndefined(); }); }); }); From db233a3b2d1051fb4eb6c9b1e17a86bc69765081 Mon Sep 17 00:00:00 2001 From: Charly Gomez Date: Fri, 7 Feb 2025 11:42:53 +0100 Subject: [PATCH 08/15] define entry points --- packages/react-router/package.json | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/packages/react-router/package.json b/packages/react-router/package.json index 4442eed3ec77..2bb0bdac85f7 100644 --- a/packages/react-router/package.json +++ b/packages/react-router/package.json @@ -12,6 +12,10 @@ "files": [ "/build" ], + "main": "build/cjs/index.server.js", + "module": "build/esm/index.server.js", + "browser": "build/esm/index.client.js", + "types": "build/types/index.types.d.ts", "exports": { "./package.json": "./package.json", ".": { @@ -54,7 +58,7 @@ "build:transpile:watch": "rollup -c rollup.npm.config.mjs --watch", "build:types:watch": "tsc -p tsconfig.types.json --watch", "build:tarball": "npm pack", - "circularDepCheck": "madge --circular src/index.server.ts", + "circularDepCheck": "madge --circular src/index.client.ts && madge --circular src/index.server.ts && madge --circular src/index.types.ts", "clean": "rimraf build coverage sentry-react-router-*.tgz", "fix": "eslint . --format stylish --fix", "lint": "eslint . --format stylish", @@ -64,7 +68,6 @@ "yalc:publish": "yalc publish --push --sig" }, "volta": { - "node": "20.18.2", "extends": "../../package.json" } } From 58a2a61650d2e75152f1fe48e48db72009ec0bfe Mon Sep 17 00:00:00 2001 From: Charly Gomez Date: Fri, 7 Feb 2025 12:04:57 +0100 Subject: [PATCH 09/15] update test ts config --- packages/react-router/tsconfig.test.json | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/packages/react-router/tsconfig.test.json b/packages/react-router/tsconfig.test.json index e6e9452a6662..b3625cd0bd3f 100644 --- a/packages/react-router/tsconfig.test.json +++ b/packages/react-router/tsconfig.test.json @@ -4,8 +4,6 @@ "include": ["test/**/*", "vite.config.ts"], "compilerOptions": { - "lib": ["DOM", "ES2018"], - "types": ["node", "vitest/globals", "vite/client"], - "esModuleInterop": true + "types": ["node", "vitest/globals"], } } From 20a91b886dd70aa712e7e281ab720e28c59ba9a4 Mon Sep 17 00:00:00 2001 From: Charly Gomez Date: Fri, 7 Feb 2025 13:31:54 +0100 Subject: [PATCH 10/15] Update packages/react-router/README.md Co-authored-by: Sigrid Huemer <32902192+s1gr1d@users.noreply.github.com> --- packages/react-router/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/react-router/README.md b/packages/react-router/README.md index 139b7b57a676..f89eb60aa840 100644 --- a/packages/react-router/README.md +++ b/packages/react-router/README.md @@ -4,7 +4,7 @@

-# Official Sentry SDK for React Router (framework) (EXPERIMENTAL) +# Official Sentry SDK for React Router (Framework) (EXPERIMENTAL) [![npm version](https://img.shields.io/npm/v/@sentry/react-router.svg)](https://www.npmjs.com/package/@sentry/react-router) [![npm dm](https://img.shields.io/npm/dm/@sentry/react-router.svg)](https://www.npmjs.com/package/@sentry/react-router) From a006b3c95270c4cf37b24665c60804e47a87f0e6 Mon Sep 17 00:00:00 2001 From: Charly Gomez Date: Fri, 7 Feb 2025 13:32:31 +0100 Subject: [PATCH 11/15] Update packages/react-router/LICENSE Co-authored-by: Andrei <168741329+andreiborza@users.noreply.github.com> --- packages/react-router/LICENSE | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/react-router/LICENSE b/packages/react-router/LICENSE index 5f9dced3c1f5..5251db3eaaca 100644 --- a/packages/react-router/LICENSE +++ b/packages/react-router/LICENSE @@ -1,6 +1,6 @@ MIT License -Copyright (c) 2024 Functional Software, Inc. dba Sentry +Copyright (c) 2025 Functional Software, Inc. dba Sentry Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the From 686a49cefab286b9b6262260c904cfd291a07f72 Mon Sep 17 00:00:00 2001 From: Charly Gomez Date: Fri, 7 Feb 2025 13:37:30 +0100 Subject: [PATCH 12/15] pr review feedback --- packages/react-router/README.md | 8 ++++---- packages/react-router/package.json | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/packages/react-router/README.md b/packages/react-router/README.md index f89eb60aa840..368f3ee4b717 100644 --- a/packages/react-router/README.md +++ b/packages/react-router/README.md @@ -67,7 +67,7 @@ startTransition(() => { Now, update your `app/root.tsx` file to report any unhandled errors from your global error boundary: -```tsx {diff} {filename: app/root.tsx} +```tsx import * as Sentry from '@sentry/react-router'; export function ErrorBoundary({ error }: Route.ErrorBoundaryProps) { @@ -106,7 +106,7 @@ export function ErrorBoundary({ error }: Route.ErrorBoundaryProps) { Create an `instrument.server.mjs` file in the root of your app: -```js {filename: instrument.server.mjs} {"onboardingOptions": {"performance": "7", "profiling": "2, 6, 8"}} +```js import * as Sentry from '@sentry/node'; Sentry.init({ @@ -117,7 +117,7 @@ Sentry.init({ In your `entry.server.tsx` file, export the `handleError` function: -```tsx {diff} {filename: entry.server.tsx} +```tsx import * as Sentry from '@sentry/node'; import { type HandleErrorFunction } from 'react-router'; @@ -138,7 +138,7 @@ export const handleError: HandleErrorFunction = (error, { request }) => { Since React Router is running in ESM mode, you need to use the `--import` command line options to load our server-side instrumentation module before the application starts. Update the `start` and `dev` script to include the instrumentation file: -```json {filename: package.json} +```json "scripts": { "dev": "NODE_OPTIONS='--import ./instrument.server.mjs' react-router dev", "start": "NODE_OPTIONS='--import ./instrument.server.mjs' react-router-serve ./build/server/index.js", diff --git a/packages/react-router/package.json b/packages/react-router/package.json index 2bb0bdac85f7..8db3107ecffb 100644 --- a/packages/react-router/package.json +++ b/packages/react-router/package.json @@ -1,7 +1,7 @@ { "name": "@sentry/react-router", "version": "9.0.0-alpha.2", - "description": "Official Sentry SDK for React Router v7 (Framework)", + "description": "Official Sentry SDK for React Router (Framework)", "repository": "git://github.com/getsentry/sentry-javascript.git", "homepage": "https://github.com/getsentry/sentry-javascript/tree/master/packages/react-router", "author": "Sentry", From 8a4eff829885f240f41cec2e3cb8f4694d8e9251 Mon Sep 17 00:00:00 2001 From: Charly Gomez Date: Fri, 7 Feb 2025 13:38:31 +0100 Subject: [PATCH 13/15] . --- packages/react-router/.gitignore | 0 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100644 packages/react-router/.gitignore diff --git a/packages/react-router/.gitignore b/packages/react-router/.gitignore deleted file mode 100644 index e69de29bb2d1..000000000000 From 028104b97ed028b814ac1a72575c639a4ceba124 Mon Sep 17 00:00:00 2001 From: Charly Gomez Date: Fri, 7 Feb 2025 13:52:07 +0100 Subject: [PATCH 14/15] changelog entry --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index fa61e8c6c70a..7e20df4aa539 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -170,6 +170,7 @@ A comprehensive migration guide outlining all changes for all the frameworks can - ref(react): Adapt tanstack router type (#15241) - ref(svelte): Remove SvelteKit detection (#15313) - ref(sveltekit): Clean up sub-request check (#15251) +- feat(react-router): Add basic package (#15289) Work in this release was contributed by @tjhiggins, @chris-basebone, @GrizliK1988, @davidturissini, @nwalters512, @aloisklink, @arturovt, @benjick, @maximepvrt, @mstrokin, @kunal-511, @jahands, @jrandolf, @tannerlinsley, @Zen-cronic, @maxmaxme and @nathankleyn. Thank you for your contributions! From 4b96ac4bf3e9246d6662d422ebfe12ce543e6a4d Mon Sep 17 00:00:00 2001 From: Charly Gomez Date: Fri, 7 Feb 2025 14:08:03 +0100 Subject: [PATCH 15/15] no changelog entry for now --- CHANGELOG.md | 1 - 1 file changed, 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 7e20df4aa539..fa61e8c6c70a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -170,7 +170,6 @@ A comprehensive migration guide outlining all changes for all the frameworks can - ref(react): Adapt tanstack router type (#15241) - ref(svelte): Remove SvelteKit detection (#15313) - ref(sveltekit): Clean up sub-request check (#15251) -- feat(react-router): Add basic package (#15289) Work in this release was contributed by @tjhiggins, @chris-basebone, @GrizliK1988, @davidturissini, @nwalters512, @aloisklink, @arturovt, @benjick, @maximepvrt, @mstrokin, @kunal-511, @jahands, @jrandolf, @tannerlinsley, @Zen-cronic, @maxmaxme and @nathankleyn. Thank you for your contributions!