Skip to content

Commit cdcf60e

Browse files
fix: handle v1 edge function definition (#1903)
Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com>
1 parent 1af512d commit cdcf60e

File tree

2 files changed

+116
-4
lines changed

2 files changed

+116
-4
lines changed

packages/runtime/src/helpers/edge.ts

+9-3
Original file line numberDiff line numberDiff line change
@@ -348,21 +348,27 @@ export const writeRscDataEdgeFunction = async ({
348348
]
349349
}
350350

351-
const getEdgeFunctionPatternForPage = ({
351+
export const getEdgeFunctionPatternForPage = ({
352352
edgeFunctionDefinition,
353353
pageRegexMap,
354354
appPathRoutesManifest,
355355
}: {
356-
edgeFunctionDefinition: EdgeFunctionDefinitionV2
356+
edgeFunctionDefinition: EdgeFunctionDefinition
357357
pageRegexMap: Map<string, string>
358358
appPathRoutesManifest?: Record<string, string>
359359
}): string => {
360360
// We don't just use the matcher from the edge function definition, because it doesn't handle trailing slashes
361361

362362
// appDir functions have a name that _isn't_ the route name, but rather the route with `/page` appended
363363
const regexp = pageRegexMap.get(appPathRoutesManifest?.[edgeFunctionDefinition.page] ?? edgeFunctionDefinition.page)
364+
if (regexp) {
365+
return regexp
366+
}
367+
if ('regexp' in edgeFunctionDefinition) {
368+
return edgeFunctionDefinition.regexp.replace(/([^/])\$$/, '$1/?$')
369+
}
364370
// If we need to fall back to the matcher, we need to add an optional trailing slash
365-
return regexp ?? edgeFunctionDefinition.matchers[0].regexp.replace(/([^/])\$$/, '$1/?$')
371+
return edgeFunctionDefinition.matchers?.[0].regexp.replace(/([^/])\$$/, '$1/?$')
366372
}
367373

368374
/**

test/matchers.spec.ts

+107-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { makeLocaleOptional, stripLookahead } from '../packages/runtime/src/helpers/matchers'
2-
2+
import { getEdgeFunctionPatternForPage } from '../packages/runtime/src/helpers/edge'
33
const makeDataPath = (path: string) => `/_next/data/build-id${path === '/' ? '/index' : path}.json`
44

55
function checkPath(path: string, regex: string) {
@@ -68,3 +68,109 @@ describe('the middleware path matcher', () => {
6868
expect(checkPath('/shows/888', stripped)).toBe(true)
6969
})
7070
})
71+
72+
const pageRegexMap = new Map([
73+
['/api/shows/[id]', '^/api/shows/([^/]+?)(?:/)?$'],
74+
['/api/shows/[...params]', '^/api/shows/(.+?)(?:/)?$'],
75+
['/app-edge/[id]', '^/app\\-edge/([^/]+?)(?:/)?$'],
76+
['/blog/[author]', '^/blog/([^/]+?)(?:/)?$'],
77+
['/blog/[author]/[slug]', '^/blog/([^/]+?)/([^/]+?)(?:/)?$'],
78+
['/getServerSideProps/all/[[...slug]]', '^/getServerSideProps/all(?:/(.+?))?(?:/)?$'],
79+
['/getServerSideProps/[id]', '^/getServerSideProps/([^/]+?)(?:/)?$'],
80+
])
81+
82+
const appPathRoutesManifest = {
83+
'/app-edge/[id]/page': '/app-edge/[id]',
84+
'/blog/[author]/[slug]/page': '/blog/[author]/[slug]',
85+
'/blog/[author]/page': '/blog/[author]',
86+
}
87+
88+
describe('the edge function matcher helpers', () => {
89+
it('finds the correct regex for an edge API route', () => {
90+
const regex = getEdgeFunctionPatternForPage({
91+
pageRegexMap,
92+
appPathRoutesManifest,
93+
edgeFunctionDefinition: {
94+
name: 'pages/api/og',
95+
page: '/api/og',
96+
env: [],
97+
files: [],
98+
matchers: [
99+
{
100+
regexp: '^/api/og$',
101+
},
102+
],
103+
wasm: [],
104+
assets: [],
105+
},
106+
})
107+
expect(regex).toBe('^/api/og/?$')
108+
expect('/api/og').toMatch(new RegExp(regex))
109+
expect('/api/og/').toMatch(new RegExp(regex))
110+
})
111+
112+
it('finds the correct regex for an appDir page with a dynamic route', () => {
113+
const regex = getEdgeFunctionPatternForPage({
114+
pageRegexMap,
115+
appPathRoutesManifest,
116+
edgeFunctionDefinition: {
117+
env: [],
118+
files: [],
119+
name: 'app/app-edge/[id]/page',
120+
page: '/app-edge/[id]/page',
121+
matchers: [
122+
{
123+
regexp: '^/app\\-edge/(?<id>[^/]+?)$',
124+
},
125+
],
126+
wasm: [],
127+
assets: [],
128+
},
129+
})
130+
expect(regex).toBe('^/app\\-edge/([^/]+?)(?:/)?$')
131+
expect('/app-edge/1').toMatch(new RegExp(regex))
132+
expect('/app-edge/1/').toMatch(new RegExp(regex))
133+
})
134+
135+
it('finds the correct regex for a pages edge route', () => {
136+
const regex = getEdgeFunctionPatternForPage({
137+
pageRegexMap,
138+
appPathRoutesManifest,
139+
edgeFunctionDefinition: {
140+
env: [],
141+
files: [],
142+
name: 'pages/edge/[id]',
143+
page: '/edge/[id]',
144+
matchers: [
145+
{
146+
regexp: '^/edge/(?<id>[^/]+?)$',
147+
},
148+
],
149+
wasm: [],
150+
assets: [],
151+
},
152+
})
153+
expect(regex).toBe('^/edge/(?<id>[^/]+?)/?$')
154+
expect('/edge/1').toMatch(new RegExp(regex))
155+
expect('/edge/1/').toMatch(new RegExp(regex))
156+
})
157+
158+
it('finds the correct regex for a pages edge route with a v1 definition', () => {
159+
const regex = getEdgeFunctionPatternForPage({
160+
pageRegexMap,
161+
appPathRoutesManifest,
162+
edgeFunctionDefinition: {
163+
env: [],
164+
files: [],
165+
name: 'pages/edge/[id]',
166+
page: '/edge/[id]',
167+
regexp: '^/edge/(?<id>[^/]+?)$',
168+
wasm: [],
169+
assets: [],
170+
},
171+
})
172+
expect(regex).toBe('^/edge/(?<id>[^/]+?)/?$')
173+
expect('/edge/1').toMatch(new RegExp(regex))
174+
expect('/edge/1/').toMatch(new RegExp(regex))
175+
})
176+
})

0 commit comments

Comments
 (0)