From 42cecb9069dd64f282bc4a1530ad425289a27217 Mon Sep 17 00:00:00 2001 From: Jacek Date: Tue, 30 Jun 2026 22:21:13 -0500 Subject: [PATCH 1/4] fix(shared): suggest :path* subtree form in createRouteMatcher path types WithPathPatternWildcard now suggests `/dashboard/:path*` instead of `/dashboard(.*)`. The `:path*` form matches on path-segment boundaries, so it covers `/dashboard` and its subtree without also matching sibling routes like `/dashboardxyz`. Root is special-cased to `/:path*` to avoid a malformed `//:path*`. Backward compatible: the param is Autocomplete-wrapped, so existing `(.*)` patterns still type-check, and there is no runtime change. --- .changeset/path-matcher-segment-wildcard.md | 5 +++++ packages/shared/src/pathMatcher.ts | 4 +++- 2 files changed, 8 insertions(+), 1 deletion(-) create mode 100644 .changeset/path-matcher-segment-wildcard.md diff --git a/.changeset/path-matcher-segment-wildcard.md b/.changeset/path-matcher-segment-wildcard.md new file mode 100644 index 00000000000..7ad08ff33cd --- /dev/null +++ b/.changeset/path-matcher-segment-wildcard.md @@ -0,0 +1,5 @@ +--- +'@clerk/shared': patch +--- + +`createRouteMatcher()` route suggestions now use the `:path*` subtree form (e.g. `/dashboard/:path*`) instead of `(.*)`. Unlike `/dashboard(.*)`, which also matches sibling routes such as `/dashboardxyz`, `/dashboard/:path*` matches only `/dashboard` and its path-segment subtree. Existing `(.*)` patterns keep working; this only changes the type-level autocomplete suggestion. diff --git a/packages/shared/src/pathMatcher.ts b/packages/shared/src/pathMatcher.ts index d5e6e49f516..4ee5ccf42fc 100644 --- a/packages/shared/src/pathMatcher.ts +++ b/packages/shared/src/pathMatcher.ts @@ -1,7 +1,9 @@ import { pathToRegexp } from './pathToRegexp'; import type { Autocomplete } from './types'; -export type WithPathPatternWildcard = `${T & string}(.*)`; +// Suggests the `:path*` subtree form (e.g. `/dashboard/:path*`), which matches on +// path-segment boundaries. `/` is special-cased to `/:path*` to avoid a malformed `//:path*`. +export type WithPathPatternWildcard = T extends '/' ? '/:path*' : `${T & string}/:path*`; export type PathPattern = Autocomplete; export type PathMatcherParam = Array | RegExp | PathPattern; From 53a83bec8f5e98c828a59c24e408d6c88b3c9b75 Mon Sep 17 00:00:00 2001 From: Jacek Date: Thu, 2 Jul 2026 09:27:30 -0500 Subject: [PATCH 2/4] fix(shared): keep WithPathPatternWildcard intact, add WithPathSegmentWildcard --- .changeset/path-matcher-segment-wildcard.md | 3 ++- packages/nextjs/src/server/routeMatcher.ts | 4 ++-- packages/shared/src/pathMatcher.ts | 9 +++++++-- 3 files changed, 11 insertions(+), 5 deletions(-) diff --git a/.changeset/path-matcher-segment-wildcard.md b/.changeset/path-matcher-segment-wildcard.md index 7ad08ff33cd..aedd7fca173 100644 --- a/.changeset/path-matcher-segment-wildcard.md +++ b/.changeset/path-matcher-segment-wildcard.md @@ -1,5 +1,6 @@ --- '@clerk/shared': patch +'@clerk/nextjs': patch --- -`createRouteMatcher()` route suggestions now use the `:path*` subtree form (e.g. `/dashboard/:path*`) instead of `(.*)`. Unlike `/dashboard(.*)`, which also matches sibling routes such as `/dashboardxyz`, `/dashboard/:path*` matches only `/dashboard` and its path-segment subtree. Existing `(.*)` patterns keep working; this only changes the type-level autocomplete suggestion. +`createPathMatcher()` and `createRouteMatcher()` route suggestions now use the `:path*` subtree form (e.g. `/dashboard/:path*`) instead of `(.*)`. Unlike `/dashboard(.*)`, which also matches sibling routes such as `/dashboardxyz`, `/dashboard/:path*` matches only `/dashboard` and its path-segment subtree. The new suggestion type is exported as `WithPathSegmentWildcard`; the existing `WithPathPatternWildcard` type is unchanged (now deprecated), and `(.*)` patterns keep working. This only changes the type-level autocomplete suggestion. diff --git a/packages/nextjs/src/server/routeMatcher.ts b/packages/nextjs/src/server/routeMatcher.ts index 428fc3e9dec..15dd32cc8aa 100644 --- a/packages/nextjs/src/server/routeMatcher.ts +++ b/packages/nextjs/src/server/routeMatcher.ts @@ -1,10 +1,10 @@ -import { createPathMatcher, type WithPathPatternWildcard } from '@clerk/shared/pathMatcher'; +import { createPathMatcher, type WithPathSegmentWildcard } from '@clerk/shared/pathMatcher'; import type { Autocomplete } from '@clerk/shared/types'; import type Link from 'next/link'; import type { NextRequest } from 'next/server'; type NextTypedRoute['0']['href']> = T extends string ? T : never; -type RouteMatcherWithNextTypedRoutes = Autocomplete | NextTypedRoute>; +type RouteMatcherWithNextTypedRoutes = Autocomplete | NextTypedRoute>; export type RouteMatcherParam = | Array diff --git a/packages/shared/src/pathMatcher.ts b/packages/shared/src/pathMatcher.ts index 4ee5ccf42fc..d7a87a44cdf 100644 --- a/packages/shared/src/pathMatcher.ts +++ b/packages/shared/src/pathMatcher.ts @@ -1,10 +1,15 @@ import { pathToRegexp } from './pathToRegexp'; import type { Autocomplete } from './types'; +/** + * @deprecated Prefer {@link WithPathSegmentWildcard}; `(.*)` also matches sibling routes + * (e.g. `/dashboard(.*)` matches `/dashboardxyz`). + */ +export type WithPathPatternWildcard = `${T & string}(.*)`; // Suggests the `:path*` subtree form (e.g. `/dashboard/:path*`), which matches on // path-segment boundaries. `/` is special-cased to `/:path*` to avoid a malformed `//:path*`. -export type WithPathPatternWildcard = T extends '/' ? '/:path*' : `${T & string}/:path*`; -export type PathPattern = Autocomplete; +export type WithPathSegmentWildcard = T extends '/' ? '/:path*' : `${T & string}/:path*`; +export type PathPattern = Autocomplete; export type PathMatcherParam = Array | RegExp | PathPattern; export class MalformedURLError extends Error { From 42aee20a49d41e8da8f9e2f3843e1cd0638c2ef3 Mon Sep 17 00:00:00 2001 From: Jacek Date: Thu, 2 Jul 2026 12:22:30 -0500 Subject: [PATCH 3/4] fix(shared): address path wildcard review comments --- packages/shared/src/pathMatcher.ts | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/packages/shared/src/pathMatcher.ts b/packages/shared/src/pathMatcher.ts index d7a87a44cdf..dc9c901f4a1 100644 --- a/packages/shared/src/pathMatcher.ts +++ b/packages/shared/src/pathMatcher.ts @@ -6,9 +6,20 @@ import type { Autocomplete } from './types'; * (e.g. `/dashboard(.*)` matches `/dashboardxyz`). */ export type WithPathPatternWildcard = `${T & string}(.*)`; -// Suggests the `:path*` subtree form (e.g. `/dashboard/:path*`), which matches on -// path-segment boundaries. `/` is special-cased to `/:path*` to avoid a malformed `//:path*`. -export type WithPathSegmentWildcard = T extends '/' ? '/:path*' : `${T & string}/:path*`; + +type StripTrailingSlash = T extends '/' + ? T + : T extends `${infer Prefix}/` + ? StripTrailingSlash + : T; + +/** + * Suggests the `:path*` subtree form (e.g. `/dashboard/:path*`), which matches on + * path-segment boundaries. `/` is special-cased to `/:path*` to avoid a malformed `//:path*`. + */ +export type WithPathSegmentWildcard = T extends '/' + ? '/:path*' + : `${StripTrailingSlash}/:path*`; export type PathPattern = Autocomplete; export type PathMatcherParam = Array | RegExp | PathPattern; From 19186b4dd0821703da35d99207e94283ce223cae Mon Sep 17 00:00:00 2001 From: Jacek Date: Sun, 5 Jul 2026 22:30:21 -0500 Subject: [PATCH 4/4] ci(repo): bump break-check to 0.6.0 0.6.0 deterministically downgrades suggestion-only absorbing-arm union changes (the Autocomplete / `string & Record` idiom): a union whose absorbing arm accepts every string is unchanged, so swapping its literal arms only moves editor autocomplete. Without this, the PathPattern change in this PR (`(.*)` to `:path*`) was flagged a phantom breaking change. Bumps the action ref, the break-check-version input, and the publish-baseline snapshot command. --- .github/workflows/api-changes.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/api-changes.yml b/.github/workflows/api-changes.yml index f5657d74394..66b72f6bb69 100644 --- a/.github/workflows/api-changes.yml +++ b/.github/workflows/api-changes.yml @@ -107,7 +107,7 @@ jobs: - name: Generate API snapshot run: | - npx --yes "@clerk/break-check@0.5.0" snapshot \ + npx --yes "@clerk/break-check@0.6.0" snapshot \ --output "$GITHUB_WORKSPACE/.api-snapshots-baseline" - name: Upload baseline artifact @@ -172,9 +172,9 @@ jobs: run: echo "BREAK_CHECK_FILTERS=$BREAK_CHECK_FILTERS" >> "$GITHUB_ENV" - name: Break Check - uses: clerk/break-check@28f2635be18aa1127189f088a564645efb3aad90 # v0.5.0 + uses: clerk/break-check@92be9cc726c848b9567c7b869e9b11dc761ddd6e # v0.6.0 with: - break-check-version: '0.5.0' + break-check-version: '0.6.0' # The PR head is already checked out, so build it in place rather than # in a second head worktree. head-ref: ''