Skip to content

Commit 443beca

Browse files
committed
chore: refactor revalidate handling for easier testing
1 parent f691362 commit 443beca

File tree

3 files changed

+64
-49
lines changed

3 files changed

+64
-49
lines changed

packages/runtime/src/templates/getHandler.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ const {
2121
getPrefetchResponse,
2222
normalizePath,
2323
} = require('./handlerUtils')
24-
const { NetlifyNextServer } = require('./server')
24+
const NetlifyNextServer = require('./server')
2525
/* eslint-enable @typescript-eslint/no-var-requires */
2626

2727
type Mutable<T> = {
@@ -177,7 +177,7 @@ export const getHandler = ({ isODB = false, publishDir = '../../../.next', appDi
177177
// We copy the file here rather than requiring from the node module
178178
const { Bridge } = require("./bridge");
179179
const { augmentFsModule, getMaxAge, getMultiValueHeaders, getPrefetchResponse, getNextServer, normalizePath } = require('./handlerUtils')
180-
const { NetlifyNextServer } = require('./server')
180+
const NetlifyNextServer = require('./server')
181181
182182
${isODB ? `const { builder } = require("@netlify/functions")` : ''}
183183
const { config } = require("${publishDir}/required-server-files.json")

packages/runtime/src/templates/handlerUtils.ts

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import fs, { createWriteStream, existsSync } from 'fs'
2+
import { ServerResponse } from 'http'
23
import { tmpdir } from 'os'
34
import path from 'path'
45
import { pipeline } from 'stream'
@@ -222,3 +223,46 @@ export const normalizePath = (event: HandlerEvent) => {
222223
// Ensure that paths are encoded - but don't double-encode them
223224
return new URL(event.rawUrl).pathname
224225
}
226+
227+
export const netlifyApiFetch = <T>({
228+
endpoint,
229+
payload,
230+
token,
231+
method = 'GET',
232+
}: {
233+
endpoint: string
234+
payload: unknown
235+
token: string
236+
method: 'GET' | 'POST'
237+
}): Promise<T> =>
238+
new Promise((resolve, reject) => {
239+
const body = JSON.stringify(payload)
240+
241+
const req = https.request(
242+
{
243+
hostname: 'api.netlify.com',
244+
port: 443,
245+
path: `/api/v1/${endpoint}`,
246+
method,
247+
headers: {
248+
'Content-Type': 'application/json',
249+
'Content-Length': body.length,
250+
Authorization: `Bearer ${token}`,
251+
},
252+
},
253+
(res: ServerResponse) => {
254+
let data = ''
255+
res.on('data', (chunk) => {
256+
data += chunk
257+
})
258+
res.on('end', () => {
259+
resolve(JSON.parse(data))
260+
})
261+
},
262+
)
263+
264+
req.on('error', reject)
265+
266+
req.write(body)
267+
req.end()
268+
})
Lines changed: 18 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,14 @@
1-
import https from 'https'
2-
31
import { NodeRequestHandler, Options } from 'next/dist/server/next-server'
42

5-
import { getNextServer, NextServerType } from './handlerUtils'
3+
import { netlifyApiFetch, getNextServer, NextServerType } from './handlerUtils'
64

75
const NextServer: NextServerType = getNextServer()
86

97
interface NetlifyNextServerOptions extends Options {
10-
netlifyRevalidateToken: string
8+
netlifyRevalidateToken?: string
119
}
1210

13-
class NetlifyNextServer extends NextServer {
11+
export default class NetlifyNextServer extends NextServer {
1412
private netlifyRevalidateToken?: string
1513

1614
public constructor(options: NetlifyNextServerOptions) {
@@ -22,52 +20,25 @@ class NetlifyNextServer extends NextServer {
2220
const handler = super.getRequestHandler()
2321
return async (req, res, parsedUrl) => {
2422
if (req.headers['x-prerender-revalidate']) {
25-
if (this.netlifyRevalidateToken) {
26-
await this.netlifyRevalidate(req.url)
27-
} else {
28-
throw new Error(`Missing revalidate token`)
29-
}
23+
await this.netlifyRevalidate(req.url)
3024
}
3125
return handler(req, res, parsedUrl)
3226
}
3327
}
3428

35-
private netlifyRevalidate(url: string) {
36-
const domain = this.hostname
37-
const siteId = process.env.SITE_ID
38-
39-
return new Promise((resolve, reject) => {
40-
const body = JSON.stringify({ paths: [url], domain })
41-
42-
const req = https
43-
.request(
44-
{
45-
hostname: 'api.netlify.com',
46-
port: 443,
47-
path: `/api/v1/sites/${siteId}/refresh_on_demand_builders`,
48-
method: 'POST',
49-
headers: {
50-
'Content-Type': 'application/json',
51-
'Content-Length': body.length,
52-
Authorization: `Bearer ${this.netlifyRevalidateToken}`,
53-
},
54-
},
55-
(res) => {
56-
let data = ''
57-
res.on('data', (chunk) => {
58-
data += chunk
59-
})
60-
res.on('end', () => {
61-
resolve(JSON.parse(data))
62-
})
63-
},
64-
)
65-
.on('error', reject)
66-
67-
req.write(body)
68-
req.end()
69-
})
29+
private async netlifyRevalidate(url: string) {
30+
try {
31+
const result = await netlifyApiFetch<{ code: number; message: string }>({
32+
endpoint: `sites/${process.env.SITE_ID}/refresh_on_demand_builders`,
33+
payload: { paths: [url], domain: this.hostname },
34+
token: this.netlifyRevalidateToken,
35+
method: 'POST',
36+
})
37+
if (result.code !== 200) {
38+
throw result
39+
}
40+
} catch (error) {
41+
throw new Error(`Unsuccessful revalidate - ${error.message}`)
42+
}
7043
}
7144
}
72-
73-
export { NetlifyNextServer }

0 commit comments

Comments
 (0)