1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
|
// Keep at the top
import './polyfill.js';
import type { Context } from '@netlify/functions';
import type { SSRManifest } from 'astro';
import { App } from 'astro/app';
import { setGetEnv } from 'astro/env/setup';
setGetEnv((key) => process.env[key]);
export interface Args {
middlewareSecret: string;
}
const clientAddressSymbol = Symbol.for('astro.clientAddress');
export const createExports = (manifest: SSRManifest, { middlewareSecret }: Args) => {
const app = new App(manifest);
function createHandler(integrationConfig: {
cacheOnDemandPages: boolean;
notFoundContent?: string;
}) {
return async function handler(request: Request, context: Context) {
const routeData = app.match(request);
if (!routeData && typeof integrationConfig.notFoundContent !== 'undefined') {
return new Response(integrationConfig.notFoundContent, {
status: 404,
headers: { 'Content-Type': 'text/html; charset=utf-8' },
});
}
Reflect.set(request, clientAddressSymbol, context.ip);
let locals: Record<string, unknown> = {};
const astroLocalsHeader = request.headers.get('x-astro-locals');
const middlewareSecretHeader = request.headers.get('x-astro-middleware-secret');
if (astroLocalsHeader) {
if (middlewareSecretHeader !== middlewareSecret) {
return new Response('Forbidden', { status: 403 });
}
// hide the secret from the rest of user and library code
request.headers.delete('x-astro-middleware-secret');
locals = JSON.parse(astroLocalsHeader);
}
locals.netlify = { context };
const response = await app.render(request, { routeData, locals });
if (app.setCookieHeaders) {
for (const setCookieHeader of app.setCookieHeaders(response)) {
response.headers.append('Set-Cookie', setCookieHeader);
}
}
if (integrationConfig.cacheOnDemandPages) {
const isCacheableMethod = ['GET', 'HEAD'].includes(request.method);
// any user-provided Cache-Control headers take precedence
const hasCacheControl = [
'Cache-Control',
'CDN-Cache-Control',
'Netlify-CDN-Cache-Control',
].some((header) => response.headers.has(header));
if (isCacheableMethod && !hasCacheControl) {
// caches this page for up to a year
response.headers.append('CDN-Cache-Control', 'public, max-age=31536000, must-revalidate');
}
}
return response;
};
}
return { default: createHandler };
};
|