Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,8 @@
"dev:bun": "bun src/entry.bun.ts",
"dev:deno": "deno run --allow-net --allow-env --allow-read src/entry.deno.ts",
"build": "wrangler deploy --dry-run",
"test:build": "pnpm install && pnpm build",
"test:build": "pnpm install && pnpm typecheck && pnpm build",
"typecheck": "tsc --noEmit -p tsconfig.typecheck.json",
"test:assert": "TEST_ENV=production playwright test"
},
"dependencies": {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
// Only `tsc` in `test:build` reads this file. Nothing runs it.
import { sentry as sentryBun } from '@sentry/hono/bun';
import { sentry as sentryCloudflare } from '@sentry/hono/cloudflare';
import { sentry as sentryDeno } from '@sentry/hono/deno';
import { sentry as sentryNode } from '@sentry/hono/node';
import { Hono } from 'hono';

type AppEnv = { Bindings: { E2E_TEST_DSN: string }; Variables: { user: string } };

const dsn = 'https://public@dsn.ingest.sentry.io/1337';

const app = new Hono<AppEnv>();
app.use(sentryNode(app));
app.use(sentryBun(app, { dsn }));
app.use(sentryDeno(app, { dsn }));
app.use(sentryCloudflare(app, env => ({ dsn: env.E2E_TEST_DSN })));

const api = app.basePath('/api');
api.use(sentryNode(api));
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{
// The rest of `src` needs Node, Bun and Deno types, which this app does not install.
"extends": "./tsconfig.json",
"include": ["src/*.typecheck.ts"]
}
3 changes: 2 additions & 1 deletion dev-packages/e2e-tests/test-applications/hono-4/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,8 @@
"dev:bun": "bun run dist/entry.bun.js",
"dev:deno": "deno run --allow-net --allow-env --allow-read --preload=npm:@sentry/deno/import src/entry.deno.ts",
"dev:cloudflare": "wrangler dev --config ./dist/hono_4/wrangler.json --var \"E2E_TEST_DSN:$E2E_TEST_DSN\" --log-level=$(test $CI && echo 'none' || echo 'log')",
"test:build": "pnpm install",
"test:build": "pnpm install && pnpm typecheck",
"typecheck": "tsc --noEmit -p tsconfig.typecheck.json",
"test": "TEST_ENV=production playwright test",
"test:assert": "pnpm test:assert:node",
"test:assert:node": "RUNTIME=node pnpm test",
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
// Only `tsc` in `test:build` reads this file. Nothing runs it.
import * as Sentry from '@sentry/node';
import { Hono } from 'hono';

type AppEnv = { Bindings: { E2E_TEST_DSN: string }; Variables: { user: string } };

const app = new Hono<AppEnv>();
app.use(Sentry.honoMiddleware(app));
app.use('*', Sentry.honoMiddleware(app));

const api = app.basePath('/api');
api.use(Sentry.honoMiddleware(api));
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{
// The rest of `src` needs Node, Bun and Deno types, which this app does not install.
"extends": "./tsconfig.json",
"include": ["src/*.typecheck.ts"]
}
3 changes: 2 additions & 1 deletion packages/hono/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -110,7 +110,8 @@
"@sentry/deno": "11.9.0",
"@sentry/node": "11.9.0",
"@types/node": "^20.19.0",
"hono": "^4.13.7",
"hono": "4.13.9",
"hono-5": "npm:hono@5.0.0-rc.1",
"wrangler": "4.62.0"
},
"scripts": {
Expand Down
57 changes: 57 additions & 0 deletions packages/hono/test/types.test-d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
import { honoMiddleware } from '@sentry/server-utils';
import { Hono } from 'hono';
import type { Hono as Hono5 } from 'hono-5';
import { describe, it } from 'vitest';
import { sentry as sentryBun } from '../src/bun/middleware';
import { sentry as sentryCloudflare } from '../src/cloudflare/middleware';
import { sentry as sentryDeno } from '../src/deno/middleware';
import { sentry as sentryNode } from '../src/node/middleware';

type AppEnv = { Bindings: { SENTRY_DSN: string }; Variables: { user: string } };

declare const app5: Hono5<AppEnv>;

const dsn = 'https://public@dsn.ingest.sentry.io/1337';

describe('Hono 4', () => {
it('accepts honoMiddleware(app)', () => {
const app = new Hono<AppEnv>();
app.use(honoMiddleware(app));

const api = app.basePath('/api');
api.use(honoMiddleware(api));
});

it('accepts sentry(app) from each runtime entry', () => {
const app = new Hono<AppEnv>();
app.use(sentryNode(app));
app.use(sentryBun(app, { dsn }));
app.use(sentryDeno(app, { dsn }));
app.use(sentryCloudflare(app, env => ({ dsn: env.SENTRY_DSN })));

const api = app.basePath('/api');
api.use(sentryNode(api));
});
});

describe('Hono 5', () => {
it('accepts honoMiddleware(app)', () => {
app5.use(honoMiddleware(app5));

const api = app5.basePath('/api');
api.use(honoMiddleware(api));
});

// In this package, `sentry()` gets its `Hono` type from Hono 4. That class has private members, so a
// Hono 5 app cannot match it. In a real Hono 5 app, `sentry()` gets the Hono 5 types.
it('rejects sentry(app) here, because `hono` is Hono 4 in this package', () => {
// @ts-expect-error -- Hono 5 app, Hono 4 types
app5.use(sentryNode(app5));
// @ts-expect-error -- Hono 5 app, Hono 4 types
app5.use(sentryBun(app5, { dsn }));
// @ts-expect-error -- Hono 5 app, Hono 4 types
app5.use(sentryDeno(app5, { dsn }));
// @ts-expect-error -- Hono 5 app, Hono 4 types
app5.use(sentryCloudflare(app5, env => ({ dsn: env.SENTRY_DSN })));
});
});
8 changes: 8 additions & 0 deletions packages/hono/vite.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,12 @@ import baseConfig from '../../vite/vite.config';

export default defineConfig({
...baseConfig,
test: {
...baseConfig.test,
typecheck: {
enabled: true,
tsconfig: './tsconfig.test.json',
ignoreSourceErrors: true,
},
},
});
10 changes: 10 additions & 0 deletions packages/server-utils/.oxlintrc.json
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,16 @@
"name": "diagnostics_channel",
"allowTypeImports": true,
"message": "Bun garbage-collects a channel that no code references, together with its subscribers. Import the wrappers from `src/utils/diagnosticsChannel.ts` instead. See https://github.com/oven-sh/bun/issues/43086"
},
{
"name": "hono",
"message": "`@sentry/server-utils` has no `hono` dependency and must work on every Hono major. Use the vendored types in `src/integrations/hono/honoTypes.ts`."
}
],
"patterns": [
{
"group": ["hono/*"],
"message": "`@sentry/server-utils` has no `hono` dependency and must work on every Hono major. Use the vendored types in `src/integrations/hono/honoTypes.ts`."
}
]
}
Expand Down
6 changes: 2 additions & 4 deletions packages/server-utils/src/integrations/hono/honoTypes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,10 +34,8 @@ export interface HonoRequest {
method: string;
path: string;
routeIndex: number;
// These are public (though deprecated) getters on Hono's request. Reading them avoids a runtime
// import of the `hono/route` helpers, which are their non-deprecated replacements.
matchedRoutes: HonoRoute[];
routePath: string;
// Deprecated getter that Hono 5 removes.
matchedRoutes?: HonoRoute[];
[key: string]: any;
}

Expand Down
2 changes: 2 additions & 0 deletions packages/server-utils/src/orchestrion/config/hono.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ const honoInstrumentationConfig: InstrumentationConfig[] = [
{
// `new Context()` runs once per request: where the Sentry middleware is injected and matched
// middleware handlers are wrapped for spans.
// TODO(v12): Raise the minimum Hono version to 4.4.9, here and in the `@sentry/hono` peer range.
// Before 4.4.9, Hono passes `matchResult` to `new HonoRequest()`, so this hook does nothing.
channelName: 'context',
module: { name: 'hono', versionRange: '>=4.0.0 <5', filePath: /^dist\/(?:cjs\/)?context\.js$/ },
functionQuery: { className: 'Context' },
Expand Down
31 changes: 20 additions & 11 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading