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
20 changes: 20 additions & 0 deletions .changeset/nuxt-deprecate-route-matcher.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
---
'@clerk/nuxt': patch
---

Deprecate `createRouteMatcher()` in favor of Nuxt's native route matching.

To protect API routes, match paths natively inside `clerkMiddleware()`:

```ts
export default clerkMiddleware(event => {
const { isAuthenticated } = event.context.auth();
const { pathname } = getRequestURL(event);

if (!isAuthenticated && pathname.startsWith('/api/admin')) {
throw createError({ statusCode: 401, statusMessage: 'Unauthorized' });
}
});
```

To protect pages, use Nuxt's built-in route middleware with `definePageMeta({ middleware: 'auth' })`.
26 changes: 26 additions & 0 deletions packages/nuxt/src/runtime/client/__tests__/routeMatcher.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import { beforeEach, describe, expect, it, vi } from 'vitest';

import { createRouteMatcher } from '../routeMatcher';

const { mockDeprecated } = vi.hoisted(() => ({
mockDeprecated: vi.fn(),
}));

vi.mock('@clerk/shared/deprecated', () => ({
deprecated: mockDeprecated,
}));

describe('createRouteMatcher', () => {
beforeEach(() => {
mockDeprecated.mockClear();
});

it('should emit a deprecation warning when called', () => {
createRouteMatcher(['/dashboard(.*)']);

expect(mockDeprecated).toHaveBeenCalledWith(
'createRouteMatcher',
"Use Nuxt's built-in route middleware to protect pages instead: create a named middleware that checks the user's authentication status and opt pages into it with `definePageMeta({ middleware: 'auth' })`.",
);
});
});
22 changes: 22 additions & 0 deletions packages/nuxt/src/runtime/client/routeMatcher.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { deprecated } from '@clerk/shared/deprecated';
import { createPathMatcher, type PathMatcherParam } from '@clerk/shared/pathMatcher';
import type { RouteMiddleware } from 'nuxt/app';

Expand All @@ -14,8 +15,29 @@ export type RouteMatcherParam = PathMatcherParam;
* ['/foo', '/bar(.*)']
* @example
* [/^\/foo\/.*$/]
*
* @deprecated This function will be removed in the next major version. Use Nuxt's built-in
* route middleware to protect pages instead: create a named middleware that checks the user's
* authentication status and opt pages into it with `definePageMeta()`. Child routes inherit
* the middleware applied to their parent, so a single declaration can protect a whole section.
*
* ```ts
* // app/middleware/auth.ts
* export default defineNuxtRouteMiddleware(() => {
* const { isSignedIn } = useAuth();
*
* if (!isSignedIn.value) {
* return navigateTo('/sign-in');
* }
* });
* ```
*/
export const createRouteMatcher = (routes: RouteMatcherParam) => {
deprecated(
'createRouteMatcher',
"Use Nuxt's built-in route middleware to protect pages instead: create a named middleware that checks the user's authentication status and opt pages into it with `definePageMeta({ middleware: 'auth' })`.",
);

const matcher = createPathMatcher(routes);
return (to: RouteLocation) => matcher(to.path);
};
31 changes: 31 additions & 0 deletions packages/nuxt/src/runtime/server/__tests__/routeMatcher.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import { getRequestURL } from 'h3';
import { beforeEach, describe, expect, it, vi } from 'vitest';

import { createRouteMatcher } from '../routeMatcher';

const { mockDeprecated } = vi.hoisted(() => ({
mockDeprecated: vi.fn(),
}));

vi.mock('@clerk/shared/deprecated', () => ({
deprecated: mockDeprecated,
}));

vi.mock('#imports', () => ({
getRequestURL,
}));

describe('createRouteMatcher', () => {
beforeEach(() => {
mockDeprecated.mockClear();
});

it('should emit a deprecation warning when called', () => {
createRouteMatcher(['/api/admin(.*)']);

expect(mockDeprecated).toHaveBeenCalledWith(
'createRouteMatcher',
"Match API route paths natively inside `clerkMiddleware()` instead, for example: `getRequestURL(event).pathname.startsWith('/api/admin')`. To protect pages, use Nuxt's built-in route middleware.",
);
});
});
22 changes: 22 additions & 0 deletions packages/nuxt/src/runtime/server/routeMatcher.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { deprecated } from '@clerk/shared/deprecated';
import type { PathMatcherParam } from '@clerk/shared/pathMatcher';
import { createPathMatcher } from '@clerk/shared/pathMatcher';
import type { H3Event } from 'h3';
Expand All @@ -15,8 +16,29 @@ export type RouteMatcherParam = PathMatcherParam;
* ['/foo', '/bar(.*)']
* @example
* [/^\/foo\/.*$/]
*
* @deprecated This function will be removed in the next major version. Match API route paths natively
* inside `clerkMiddleware()` instead, and protect pages with Nuxt's built-in route middleware:
*
* ```ts
* import { clerkMiddleware } from '@clerk/nuxt/server';
*
* export default clerkMiddleware(event => {
* const { isAuthenticated } = event.context.auth();
* const { pathname } = getRequestURL(event);
*
* if (!isAuthenticated && pathname.startsWith('/api/admin')) {
* throw createError({ statusCode: 401, statusMessage: 'Unauthorized' });
* }
* });
* ```
*/
export const createRouteMatcher = (routes: RouteMatcherParam) => {
deprecated(
'createRouteMatcher',
"Match API route paths natively inside `clerkMiddleware()` instead, for example: `getRequestURL(event).pathname.startsWith('/api/admin')`. To protect pages, use Nuxt's built-in route middleware.",
);

const matcher = createPathMatcher(routes);
return (event: H3Event) => {
const url = getRequestURL(event);
Expand Down
Loading