amplify-astro-adapter 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.ts +7 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +211 -0
- package/dist/index.js.map +1 -0
- package/dist/log-listening-on.d.ts +5 -0
- package/dist/log-listening-on.d.ts.map +1 -0
- package/dist/log-listening-on.js +55 -0
- package/dist/log-listening-on.js.map +1 -0
- package/dist/middleware.d.ts +19 -0
- package/dist/middleware.d.ts.map +1 -0
- package/dist/middleware.js +98 -0
- package/dist/middleware.js.map +1 -0
- package/dist/node-middleware.d.ts +12 -0
- package/dist/node-middleware.d.ts.map +1 -0
- package/dist/node-middleware.js +41 -0
- package/dist/node-middleware.js.map +1 -0
- package/dist/polyfill.d.ts +2 -0
- package/dist/polyfill.d.ts.map +1 -0
- package/dist/polyfill.js +3 -0
- package/dist/polyfill.js.map +1 -0
- package/dist/serve-app.d.ts +9 -0
- package/dist/serve-app.d.ts.map +1 -0
- package/dist/serve-app.js +123 -0
- package/dist/serve-app.js.map +1 -0
- package/dist/serve-static.d.ts +11 -0
- package/dist/serve-static.d.ts.map +1 -0
- package/dist/serve-static.js +130 -0
- package/dist/serve-static.js.map +1 -0
- package/dist/server.d.ts +20 -0
- package/dist/server.d.ts.map +1 -0
- package/dist/server.js +60 -0
- package/dist/server.js.map +1 -0
- package/dist/session-driver.d.ts +89 -0
- package/dist/session-driver.d.ts.map +1 -0
- package/dist/session-driver.js +154 -0
- package/dist/session-driver.js.map +1 -0
- package/dist/shared.d.ts +2 -0
- package/dist/shared.d.ts.map +1 -0
- package/dist/shared.js +2 -0
- package/dist/shared.js.map +1 -0
- package/dist/standalone.d.ts +24 -0
- package/dist/standalone.d.ts.map +1 -0
- package/dist/standalone.js +77 -0
- package/dist/standalone.js.map +1 -0
- package/dist/types.d.ts +22 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +2 -0
- package/dist/types.js.map +1 -0
- package/dist/utils/polyfills.d.ts +3 -0
- package/dist/utils/polyfills.d.ts.map +1 -0
- package/dist/utils/polyfills.js +11 -0
- package/dist/utils/polyfills.js.map +1 -0
- package/package.json +54 -0
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { AstroIntegration } from 'astro';
|
|
2
|
+
export { createCookieSessionDriver, generateSessionPassword, type CookieSessionDriverOptions, type CookieSetOptions, } from './session-driver.js';
|
|
3
|
+
export interface AwsAmplifyOptions {
|
|
4
|
+
runtime?: 'nodejs20.x' | 'nodejs22.x';
|
|
5
|
+
}
|
|
6
|
+
export default function awsAmplify(options?: AwsAmplifyOptions): AstroIntegration;
|
|
7
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAe,gBAAgB,EAAE,MAAM,OAAO,CAAC;AAS3D,OAAO,EACL,yBAAyB,EACzB,uBAAuB,EACvB,KAAK,0BAA0B,EAC/B,KAAK,gBAAgB,GACtB,MAAM,qBAAqB,CAAC;AAE7B,MAAM,WAAW,iBAAiB;IAChC,OAAO,CAAC,EAAE,YAAY,GAAG,YAAY,CAAC;CACvC;AA+FD,MAAM,CAAC,OAAO,UAAU,UAAU,CAAC,OAAO,GAAE,iBAAsB,GAAG,gBAAgB,CAiIpF"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,211 @@
|
|
|
1
|
+
import { existsSync } from 'node:fs';
|
|
2
|
+
import { writeFile } from 'node:fs/promises';
|
|
3
|
+
import { join } from 'node:path';
|
|
4
|
+
import { fileURLToPath } from 'node:url';
|
|
5
|
+
import { readdir } from 'node:fs/promises';
|
|
6
|
+
// Re-export session driver for convenience
|
|
7
|
+
export { createCookieSessionDriver, generateSessionPassword, } from './session-driver.js';
|
|
8
|
+
async function detectPackageManager(root) {
|
|
9
|
+
const rootPath = fileURLToPath(root);
|
|
10
|
+
const entries = await readdir(rootPath);
|
|
11
|
+
if (entries.includes('pnpm-lock.yaml'))
|
|
12
|
+
return 'pnpm';
|
|
13
|
+
if (entries.includes('yarn.lock'))
|
|
14
|
+
return 'yarn';
|
|
15
|
+
if (entries.includes('package-lock.json'))
|
|
16
|
+
return 'npm';
|
|
17
|
+
if (entries.includes('bun.lockb'))
|
|
18
|
+
return 'bun';
|
|
19
|
+
return 'unknown';
|
|
20
|
+
}
|
|
21
|
+
function getAmplifyYaml(packageManager) {
|
|
22
|
+
const commonBase = `version: 1
|
|
23
|
+
frontend:
|
|
24
|
+
phases:
|
|
25
|
+
preBuild:
|
|
26
|
+
commands:
|
|
27
|
+
`;
|
|
28
|
+
const configs = {
|
|
29
|
+
npm: `${commonBase} - npm ci --cache .npm --prefer-offline
|
|
30
|
+
build:
|
|
31
|
+
commands:
|
|
32
|
+
- npm run build
|
|
33
|
+
- mv node_modules ./.amplify-hosting/compute/default
|
|
34
|
+
artifacts:
|
|
35
|
+
baseDirectory: .amplify-hosting
|
|
36
|
+
files:
|
|
37
|
+
- '**/*'
|
|
38
|
+
cache:
|
|
39
|
+
paths:
|
|
40
|
+
- .npm/**/*`,
|
|
41
|
+
pnpm: `${commonBase} - npm i -g pnpm
|
|
42
|
+
- pnpm config set store-dir .pnpm-store
|
|
43
|
+
- pnpm i
|
|
44
|
+
build:
|
|
45
|
+
commands:
|
|
46
|
+
- pnpm run build
|
|
47
|
+
artifacts:
|
|
48
|
+
baseDirectory: .amplify-hosting
|
|
49
|
+
files:
|
|
50
|
+
- '**/*'
|
|
51
|
+
cache:
|
|
52
|
+
paths:
|
|
53
|
+
- .pnpm-store/**/*`,
|
|
54
|
+
yarn: `${commonBase} - yarn install
|
|
55
|
+
build:
|
|
56
|
+
commands:
|
|
57
|
+
- yarn run build
|
|
58
|
+
- mv node_modules ./.amplify-hosting/compute/default
|
|
59
|
+
artifacts:
|
|
60
|
+
baseDirectory: .amplify-hosting
|
|
61
|
+
files:
|
|
62
|
+
- '**/*'
|
|
63
|
+
cache:
|
|
64
|
+
paths:
|
|
65
|
+
- node_modules/**/*`,
|
|
66
|
+
bun: `${commonBase} - bun install
|
|
67
|
+
build:
|
|
68
|
+
commands:
|
|
69
|
+
- bun run build
|
|
70
|
+
- mv node_modules ./.amplify-hosting/compute/default
|
|
71
|
+
artifacts:
|
|
72
|
+
baseDirectory: .amplify-hosting
|
|
73
|
+
files:
|
|
74
|
+
- '**/*'
|
|
75
|
+
cache:
|
|
76
|
+
paths:
|
|
77
|
+
- node_modules/**/*`,
|
|
78
|
+
unknown: `${commonBase} - npm ci --cache .npm --prefer-offline
|
|
79
|
+
build:
|
|
80
|
+
commands:
|
|
81
|
+
- npm run build
|
|
82
|
+
- mv node_modules ./.amplify-hosting/compute/default
|
|
83
|
+
artifacts:
|
|
84
|
+
baseDirectory: .amplify-hosting
|
|
85
|
+
files:
|
|
86
|
+
- '**/*'
|
|
87
|
+
cache:
|
|
88
|
+
paths:
|
|
89
|
+
- .npm/**/*`,
|
|
90
|
+
};
|
|
91
|
+
return configs[packageManager] || configs.unknown;
|
|
92
|
+
}
|
|
93
|
+
export default function awsAmplify(options = {}) {
|
|
94
|
+
let _config;
|
|
95
|
+
const { runtime = 'nodejs20.x' } = options;
|
|
96
|
+
return {
|
|
97
|
+
name: 'amplify-astro-adapter',
|
|
98
|
+
hooks: {
|
|
99
|
+
'astro:config:setup': async ({ config, updateConfig, logger, addMiddleware }) => {
|
|
100
|
+
// Generate amplify.yml if it doesn't exist
|
|
101
|
+
const amplifyYmlPath = join(fileURLToPath(config.root), 'amplify.yml');
|
|
102
|
+
const ymlExists = existsSync(amplifyYmlPath);
|
|
103
|
+
if (!ymlExists) {
|
|
104
|
+
const packageManager = await detectPackageManager(config.root);
|
|
105
|
+
const yamlContent = getAmplifyYaml(packageManager);
|
|
106
|
+
await writeFile(amplifyYmlPath, yamlContent);
|
|
107
|
+
logger.info(`Created amplify.yml for ${packageManager} - commit this file to your repository!`);
|
|
108
|
+
}
|
|
109
|
+
// Check if we're using our session driver (auto or manual)
|
|
110
|
+
const isServerMode = config.output === 'server';
|
|
111
|
+
const hasNoDriver = !config.session?.driver;
|
|
112
|
+
const usesOurDriver = config.session?.driver === 'amplify-astro-adapter/session';
|
|
113
|
+
// Add middleware if using our session driver
|
|
114
|
+
if (isServerMode && (hasNoDriver || usesOurDriver)) {
|
|
115
|
+
addMiddleware({
|
|
116
|
+
entrypoint: 'amplify-astro-adapter/middleware',
|
|
117
|
+
order: 'pre',
|
|
118
|
+
});
|
|
119
|
+
}
|
|
120
|
+
// Auto-configure session driver if none specified
|
|
121
|
+
if (isServerMode && hasNoDriver) {
|
|
122
|
+
logger.info('Auto-configuring cookie-based session driver for serverless environment');
|
|
123
|
+
updateConfig({
|
|
124
|
+
build: {
|
|
125
|
+
client: new URL(`./.amplify-hosting/static${config.base}`, config.root),
|
|
126
|
+
server: new URL('./.amplify-hosting/compute/default/', config.root),
|
|
127
|
+
},
|
|
128
|
+
session: {
|
|
129
|
+
driver: 'amplify-astro-adapter/session',
|
|
130
|
+
},
|
|
131
|
+
});
|
|
132
|
+
}
|
|
133
|
+
else {
|
|
134
|
+
updateConfig({
|
|
135
|
+
build: {
|
|
136
|
+
client: new URL(`./.amplify-hosting/static${config.base}`, config.root),
|
|
137
|
+
server: new URL('./.amplify-hosting/compute/default/', config.root),
|
|
138
|
+
},
|
|
139
|
+
});
|
|
140
|
+
}
|
|
141
|
+
},
|
|
142
|
+
'astro:config:done': ({ config, setAdapter }) => {
|
|
143
|
+
setAdapter({
|
|
144
|
+
name: 'amplify-astro-adapter',
|
|
145
|
+
serverEntrypoint: 'amplify-astro-adapter/server',
|
|
146
|
+
supportedAstroFeatures: {
|
|
147
|
+
serverOutput: 'stable',
|
|
148
|
+
hybridOutput: 'stable',
|
|
149
|
+
staticOutput: 'stable',
|
|
150
|
+
sharpImageService: 'stable',
|
|
151
|
+
envGetSecret: 'stable',
|
|
152
|
+
},
|
|
153
|
+
args: {
|
|
154
|
+
mode: 'standalone',
|
|
155
|
+
client: config.build.client?.toString(),
|
|
156
|
+
server: config.build.server?.toString(),
|
|
157
|
+
host: config.server.host,
|
|
158
|
+
port: 3000,
|
|
159
|
+
assets: config.build.assets,
|
|
160
|
+
experimentalStaticHeaders: false,
|
|
161
|
+
},
|
|
162
|
+
});
|
|
163
|
+
_config = config;
|
|
164
|
+
},
|
|
165
|
+
'astro:build:done': async () => {
|
|
166
|
+
const deployManifestConfig = {
|
|
167
|
+
version: 1,
|
|
168
|
+
routes: [
|
|
169
|
+
{
|
|
170
|
+
path: `${_config.base}assets/*`,
|
|
171
|
+
target: {
|
|
172
|
+
kind: 'Static',
|
|
173
|
+
},
|
|
174
|
+
},
|
|
175
|
+
{
|
|
176
|
+
path: `${_config.base}*.*`,
|
|
177
|
+
target: {
|
|
178
|
+
kind: 'Static',
|
|
179
|
+
},
|
|
180
|
+
fallback: {
|
|
181
|
+
kind: 'Compute',
|
|
182
|
+
src: 'default',
|
|
183
|
+
},
|
|
184
|
+
},
|
|
185
|
+
{
|
|
186
|
+
path: '/*',
|
|
187
|
+
target: {
|
|
188
|
+
kind: 'Compute',
|
|
189
|
+
src: 'default',
|
|
190
|
+
},
|
|
191
|
+
},
|
|
192
|
+
],
|
|
193
|
+
computeResources: [
|
|
194
|
+
{
|
|
195
|
+
name: 'default',
|
|
196
|
+
entrypoint: 'entry.mjs',
|
|
197
|
+
runtime,
|
|
198
|
+
},
|
|
199
|
+
],
|
|
200
|
+
framework: {
|
|
201
|
+
name: 'astro',
|
|
202
|
+
version: '4.0.0',
|
|
203
|
+
},
|
|
204
|
+
};
|
|
205
|
+
const functionsConfigPath = join(fileURLToPath(_config.root), '/.amplify-hosting/deploy-manifest.json');
|
|
206
|
+
await writeFile(functionsConfigPath, JSON.stringify(deployManifestConfig));
|
|
207
|
+
},
|
|
208
|
+
},
|
|
209
|
+
};
|
|
210
|
+
}
|
|
211
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import type http from 'node:http';
|
|
2
|
+
import https from 'node:https';
|
|
3
|
+
import type { AstroIntegrationLogger } from 'astro';
|
|
4
|
+
export declare function logListeningOn(logger: AstroIntegrationLogger, server: http.Server | https.Server, configuredHost: string | boolean | undefined): Promise<void>;
|
|
5
|
+
//# sourceMappingURL=log-listening-on.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"log-listening-on.d.ts","sourceRoot":"","sources":["../src/log-listening-on.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,IAAI,MAAM,WAAW,CAAC;AAClC,OAAO,KAAK,MAAM,YAAY,CAAC;AAG/B,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,OAAO,CAAC;AAIpD,wBAAsB,cAAc,CAClC,MAAM,EAAE,sBAAsB,EAC9B,MAAM,EAAE,IAAI,CAAC,MAAM,GAAG,KAAK,CAAC,MAAM,EAClC,cAAc,EAAE,MAAM,GAAG,OAAO,GAAG,SAAS,iBAe7C"}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import https from 'node:https';
|
|
2
|
+
import os from 'node:os';
|
|
3
|
+
const wildcardHosts = new Set(['0.0.0.0', '::', '0000:0000:0000:0000:0000:0000:0000:0000']);
|
|
4
|
+
export async function logListeningOn(logger, server, configuredHost) {
|
|
5
|
+
await new Promise((resolve) => server.once('listening', resolve));
|
|
6
|
+
const protocol = server instanceof https.Server ? 'https' : 'http';
|
|
7
|
+
const host = getResolvedHostForHttpServer(configuredHost);
|
|
8
|
+
const { port } = server.address();
|
|
9
|
+
const address = getNetworkAddress(protocol, host, port);
|
|
10
|
+
if (host === undefined || wildcardHosts.has(host)) {
|
|
11
|
+
logger.info(`Server listening on \n local: ${address.local[0]} \t\n network: ${address.network[0]}\n`);
|
|
12
|
+
}
|
|
13
|
+
else {
|
|
14
|
+
logger.info(`Server listening on ${address.local[0]}`);
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
function getResolvedHostForHttpServer(host) {
|
|
18
|
+
if (host === false) {
|
|
19
|
+
return 'localhost';
|
|
20
|
+
}
|
|
21
|
+
else if (host === true) {
|
|
22
|
+
return undefined;
|
|
23
|
+
}
|
|
24
|
+
else {
|
|
25
|
+
return host;
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
function getNetworkAddress(protocol = 'http', hostname, port, base) {
|
|
29
|
+
const NetworkAddress = {
|
|
30
|
+
local: [],
|
|
31
|
+
network: [],
|
|
32
|
+
};
|
|
33
|
+
Object.values(os.networkInterfaces())
|
|
34
|
+
.flatMap((nInterface) => nInterface ?? [])
|
|
35
|
+
.filter((detail) => detail &&
|
|
36
|
+
detail.address &&
|
|
37
|
+
(detail.family === 'IPv4' ||
|
|
38
|
+
// @ts-expect-error Node 18.0 - 18.3 returns number
|
|
39
|
+
detail.family === 4))
|
|
40
|
+
.forEach((detail) => {
|
|
41
|
+
let host = detail.address.replace('127.0.0.1', hostname === undefined || wildcardHosts.has(hostname) ? 'localhost' : hostname);
|
|
42
|
+
if (host.includes(':')) {
|
|
43
|
+
host = `[${host}]`;
|
|
44
|
+
}
|
|
45
|
+
const url = `${protocol}://${host}:${port}${base ? base : ''}`;
|
|
46
|
+
if (detail.address.includes('127.0.0.1')) {
|
|
47
|
+
NetworkAddress.local.push(url);
|
|
48
|
+
}
|
|
49
|
+
else {
|
|
50
|
+
NetworkAddress.network.push(url);
|
|
51
|
+
}
|
|
52
|
+
});
|
|
53
|
+
return NetworkAddress;
|
|
54
|
+
}
|
|
55
|
+
//# sourceMappingURL=log-listening-on.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"log-listening-on.js","sourceRoot":"","sources":["../src/log-listening-on.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import type { MiddlewareHandler } from 'astro';
|
|
2
|
+
/**
|
|
3
|
+
* Middleware that handles cookie-based session storage.
|
|
4
|
+
*
|
|
5
|
+
* Flow:
|
|
6
|
+
* 1. BEFORE next(): Load existing session data from cookie into sessionStore
|
|
7
|
+
* - If dirty in-memory data exists without cookie, mark for deferred sync
|
|
8
|
+
* 2. During request: Astro's session system uses our driver (reads/writes sessionStore)
|
|
9
|
+
* 3. AFTER next(): Write dirty session data from sessionStore back to cookie
|
|
10
|
+
*
|
|
11
|
+
* Deferred Cookie Sync (handles 302 redirect race condition):
|
|
12
|
+
* - POST /api/login -> sets session, returns 302, persist() writes to sessionStore
|
|
13
|
+
* - GET / -> BEFORE detects dirty entry + no cookie -> needsCookieSync=true
|
|
14
|
+
* - Page renders (driver reads from sessionStore)
|
|
15
|
+
* - AFTER phase injects cookie into response
|
|
16
|
+
* - Future requests have the cookie
|
|
17
|
+
*/
|
|
18
|
+
export declare const onRequest: MiddlewareHandler;
|
|
19
|
+
//# sourceMappingURL=middleware.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"middleware.d.ts","sourceRoot":"","sources":["../src/middleware.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,OAAO,CAAC;AAK/C;;;;;;;;;;;;;;;GAeG;AACH,eAAO,MAAM,SAAS,EAAE,iBAyFvB,CAAC"}
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
import { sessionStore, getDriverConfig } from './session-driver.js';
|
|
2
|
+
const SESSION_DATA_COOKIE = 'astro-session-data';
|
|
3
|
+
/**
|
|
4
|
+
* Middleware that handles cookie-based session storage.
|
|
5
|
+
*
|
|
6
|
+
* Flow:
|
|
7
|
+
* 1. BEFORE next(): Load existing session data from cookie into sessionStore
|
|
8
|
+
* - If dirty in-memory data exists without cookie, mark for deferred sync
|
|
9
|
+
* 2. During request: Astro's session system uses our driver (reads/writes sessionStore)
|
|
10
|
+
* 3. AFTER next(): Write dirty session data from sessionStore back to cookie
|
|
11
|
+
*
|
|
12
|
+
* Deferred Cookie Sync (handles 302 redirect race condition):
|
|
13
|
+
* - POST /api/login -> sets session, returns 302, persist() writes to sessionStore
|
|
14
|
+
* - GET / -> BEFORE detects dirty entry + no cookie -> needsCookieSync=true
|
|
15
|
+
* - Page renders (driver reads from sessionStore)
|
|
16
|
+
* - AFTER phase injects cookie into response
|
|
17
|
+
* - Future requests have the cookie
|
|
18
|
+
*/
|
|
19
|
+
export const onRequest = async (context, next) => {
|
|
20
|
+
// BEFORE: Load existing session data from cookie into sessionStore
|
|
21
|
+
const sessionId = context.cookies.get('astro-session')?.value;
|
|
22
|
+
const existingDataCookie = context.cookies.get(SESSION_DATA_COOKIE)?.value;
|
|
23
|
+
let needsCookieSync = false;
|
|
24
|
+
if (sessionId) {
|
|
25
|
+
let inMemoryEntry = sessionStore.get(sessionId);
|
|
26
|
+
// If we have a sessionId but no cookie and no in-memory entry,
|
|
27
|
+
// the persist() from a previous request might still be running.
|
|
28
|
+
// Wait briefly for it to complete (up to 50ms).
|
|
29
|
+
if (!inMemoryEntry && !existingDataCookie) {
|
|
30
|
+
for (let i = 0; i < 5 && !inMemoryEntry; i++) {
|
|
31
|
+
await new Promise((resolve) => setTimeout(resolve, 10));
|
|
32
|
+
inMemoryEntry = sessionStore.get(sessionId);
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
if (inMemoryEntry?.dirty && !existingDataCookie) {
|
|
36
|
+
// We have in-memory data that wasn't written to cookie yet
|
|
37
|
+
// This is the deferred cookie sync case (happens after redirect)
|
|
38
|
+
needsCookieSync = true;
|
|
39
|
+
}
|
|
40
|
+
else if (!inMemoryEntry && existingDataCookie) {
|
|
41
|
+
// No in-memory data, but cookie exists - load from cookie
|
|
42
|
+
sessionStore.set(sessionId, {
|
|
43
|
+
data: existingDataCookie,
|
|
44
|
+
dirty: false,
|
|
45
|
+
timestamp: Date.now(),
|
|
46
|
+
});
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
// Run the request - session.persist() happens during this via Astro's finally block
|
|
50
|
+
const response = await next();
|
|
51
|
+
// AFTER: Write dirty session data back to cookie
|
|
52
|
+
// Check for session ID again - it may have been created during the request
|
|
53
|
+
const finalSessionId = context.cookies.get('astro-session')?.value;
|
|
54
|
+
if (finalSessionId) {
|
|
55
|
+
const entry = sessionStore.get(finalSessionId);
|
|
56
|
+
// Write cookie if:
|
|
57
|
+
// 1. Entry is dirty (new/modified session data from this request), OR
|
|
58
|
+
// 2. We detected deferred sync needed in BEFORE phase
|
|
59
|
+
const shouldWriteCookie = entry?.dirty || (needsCookieSync && sessionId === finalSessionId);
|
|
60
|
+
if (shouldWriteCookie && entry) {
|
|
61
|
+
const config = getDriverConfig();
|
|
62
|
+
const ttl = config?.ttl ?? 604800;
|
|
63
|
+
const cookieOptions = config?.cookieOptions;
|
|
64
|
+
if (entry.data) {
|
|
65
|
+
// Auto-detect secure from protocol
|
|
66
|
+
const isSecure = context.request.url.startsWith('https://');
|
|
67
|
+
// Determine domain: undefined for localhost, .domain.com for production
|
|
68
|
+
let domain = cookieOptions?.domain;
|
|
69
|
+
if (domain === undefined) {
|
|
70
|
+
const url = new URL(context.request.url);
|
|
71
|
+
const isLocalhost = url.hostname === 'localhost' || url.hostname === '127.0.0.1';
|
|
72
|
+
domain = isLocalhost ? undefined : `.${url.hostname}`;
|
|
73
|
+
}
|
|
74
|
+
// Set the session data cookie
|
|
75
|
+
context.cookies.set(SESSION_DATA_COOKIE, entry.data, {
|
|
76
|
+
httpOnly: cookieOptions?.httpOnly ?? true,
|
|
77
|
+
secure: cookieOptions?.secure ?? isSecure,
|
|
78
|
+
sameSite: cookieOptions?.sameSite ?? 'lax',
|
|
79
|
+
path: cookieOptions?.path ?? '/',
|
|
80
|
+
domain,
|
|
81
|
+
maxAge: ttl,
|
|
82
|
+
});
|
|
83
|
+
// Mark as clean after writing cookie
|
|
84
|
+
sessionStore.set(finalSessionId, { ...entry, dirty: false, timestamp: Date.now() });
|
|
85
|
+
}
|
|
86
|
+
else {
|
|
87
|
+
// Empty data means destroy - delete cookie AND sessionStore entry
|
|
88
|
+
context.cookies.delete(SESSION_DATA_COOKIE, {
|
|
89
|
+
path: cookieOptions?.path ?? '/',
|
|
90
|
+
domain: cookieOptions?.domain,
|
|
91
|
+
});
|
|
92
|
+
sessionStore.delete(finalSessionId);
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
return response;
|
|
97
|
+
};
|
|
98
|
+
//# sourceMappingURL=middleware.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"middleware.js","sourceRoot":"","sources":["../src/middleware.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { NodeApp } from 'astro/app/node';
|
|
2
|
+
import type { Options, RequestHandler } from './types.js';
|
|
3
|
+
/**
|
|
4
|
+
* Creates a middleware that can be used with Express, Connect, etc.
|
|
5
|
+
*
|
|
6
|
+
* Similar to `createAppHandler` but can additionally be placed in the express
|
|
7
|
+
* chain as an error middleware.
|
|
8
|
+
*
|
|
9
|
+
* https://expressjs.com/en/guide/using-middleware.html#middleware.error-handling
|
|
10
|
+
*/
|
|
11
|
+
export default function createMiddleware(app: NodeApp, options: Options): RequestHandler;
|
|
12
|
+
//# sourceMappingURL=node-middleware.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"node-middleware.d.ts","sourceRoot":"","sources":["../src/node-middleware.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,gBAAgB,CAAC;AAE9C,OAAO,KAAK,EAAE,OAAO,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAE1D;;;;;;;GAOG;AACH,MAAM,CAAC,OAAO,UAAU,gBAAgB,CAAC,GAAG,EAAE,OAAO,EAAE,OAAO,EAAE,OAAO,GAAG,cAAc,CA4BvF"}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { createAppHandler } from './serve-app.js';
|
|
2
|
+
/**
|
|
3
|
+
* Creates a middleware that can be used with Express, Connect, etc.
|
|
4
|
+
*
|
|
5
|
+
* Similar to `createAppHandler` but can additionally be placed in the express
|
|
6
|
+
* chain as an error middleware.
|
|
7
|
+
*
|
|
8
|
+
* https://expressjs.com/en/guide/using-middleware.html#middleware.error-handling
|
|
9
|
+
*/
|
|
10
|
+
export default function createMiddleware(app, options) {
|
|
11
|
+
const handler = createAppHandler(app, options);
|
|
12
|
+
const logger = app.getAdapterLogger();
|
|
13
|
+
// using spread args because express trips up if the function's
|
|
14
|
+
// stringified body includes req, res, next, locals directly
|
|
15
|
+
return async (...args) => {
|
|
16
|
+
// assume normal invocation at first
|
|
17
|
+
const [req, res, next, locals] = args;
|
|
18
|
+
// short circuit if it is an error invocation
|
|
19
|
+
if (req instanceof Error) {
|
|
20
|
+
const error = req;
|
|
21
|
+
if (next) {
|
|
22
|
+
return next(error);
|
|
23
|
+
}
|
|
24
|
+
else {
|
|
25
|
+
throw error;
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
try {
|
|
29
|
+
await handler(req, res, next, locals);
|
|
30
|
+
}
|
|
31
|
+
catch (err) {
|
|
32
|
+
logger.error(`Could not render ${req.url}`);
|
|
33
|
+
console.error(err);
|
|
34
|
+
if (!res.headersSent) {
|
|
35
|
+
res.writeHead(500, `Server error`);
|
|
36
|
+
res.end();
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
};
|
|
40
|
+
}
|
|
41
|
+
//# sourceMappingURL=node-middleware.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"node-middleware.js","sourceRoot":"","sources":["../src/node-middleware.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,gBAAgB,EAAE,MAAM,gBAAgB,CAAC;AAGlD;;;;;;;GAOG;AACH,MAAM,CAAC,OAAO,UAAU,gBAAgB,CAAC,GAAY,EAAE,OAAgB;IACrE,MAAM,OAAO,GAAG,gBAAgB,CAAC,GAAG,EAAE,OAAO,CAAC,CAAC;IAC/C,MAAM,MAAM,GAAG,GAAG,CAAC,gBAAgB,EAAE,CAAC;IACtC,+DAA+D;IAC/D,4DAA4D;IAC5D,OAAO,KAAK,EAAE,GAAG,IAAI,EAAE,EAAE;QACvB,oCAAoC;QACpC,MAAM,CAAC,GAAG,EAAE,GAAG,EAAE,IAAI,EAAE,MAAM,CAAC,GAAG,IAAI,CAAC;QACtC,6CAA6C;QAC7C,IAAI,GAAG,YAAY,KAAK,EAAE,CAAC;YACzB,MAAM,KAAK,GAAG,GAAG,CAAC;YAClB,IAAI,IAAI,EAAE,CAAC;gBACT,OAAO,IAAI,CAAC,KAAK,CAAC,CAAC;YACrB,CAAC;iBAAM,CAAC;gBACN,MAAM,KAAK,CAAC;YACd,CAAC;QACH,CAAC;QACD,IAAI,CAAC;YACH,MAAM,OAAO,CAAC,GAAG,EAAE,GAAG,EAAE,IAAI,EAAE,MAAM,CAAC,CAAC;QACxC,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,MAAM,CAAC,KAAK,CAAC,oBAAoB,GAAG,CAAC,GAAG,EAAE,CAAC,CAAC;YAC5C,OAAO,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;YACnB,IAAI,CAAC,GAAG,CAAC,WAAW,EAAE,CAAC;gBACrB,GAAG,CAAC,SAAS,CAAC,GAAG,EAAE,cAAc,CAAC,CAAC;gBACnC,GAAG,CAAC,GAAG,EAAE,CAAC;YACZ,CAAC;QACH,CAAC;IACH,CAAC,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"polyfill.d.ts","sourceRoot":"","sources":["../src/polyfill.ts"],"names":[],"mappings":""}
|
package/dist/polyfill.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"polyfill.js","sourceRoot":"","sources":["../src/polyfill.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAC;AAChD,cAAc,EAAE,CAAC"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { NodeApp } from 'astro/app/node';
|
|
2
|
+
import type { Options, RequestHandler } from './types.js';
|
|
3
|
+
/**
|
|
4
|
+
* Create a request handler for the Astro app.
|
|
5
|
+
* Session cookie handling is primarily done by middleware.
|
|
6
|
+
* This handler provides a fallback for direct responses (e.g., API routes with redirects).
|
|
7
|
+
*/
|
|
8
|
+
export declare function createAppHandler(app: NodeApp, options: Options): RequestHandler;
|
|
9
|
+
//# sourceMappingURL=serve-app.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"serve-app.d.ts","sourceRoot":"","sources":["../src/serve-app.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,OAAO,EAAE,MAAM,gBAAgB,CAAC;AACzC,OAAO,KAAK,EAAE,OAAO,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAK1D;;;;GAIG;AACH,wBAAgB,gBAAgB,CAAC,GAAG,EAAE,OAAO,EAAE,OAAO,EAAE,OAAO,GAAG,cAAc,CAiE/E"}
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
import { AsyncLocalStorage } from 'node:async_hooks';
|
|
2
|
+
import { NodeApp } from 'astro/app/node';
|
|
3
|
+
import { sessionStore, getDriverConfig } from './session-driver.js';
|
|
4
|
+
/**
|
|
5
|
+
* Create a request handler for the Astro app.
|
|
6
|
+
* Session cookie handling is primarily done by middleware.
|
|
7
|
+
* This handler provides a fallback for direct responses (e.g., API routes with redirects).
|
|
8
|
+
*/
|
|
9
|
+
export function createAppHandler(app, options) {
|
|
10
|
+
const als = new AsyncLocalStorage();
|
|
11
|
+
const logger = app.getAdapterLogger();
|
|
12
|
+
process.on('unhandledRejection', (reason) => {
|
|
13
|
+
const requestUrl = als.getStore();
|
|
14
|
+
logger.error(`Unhandled rejection while rendering ${requestUrl}`);
|
|
15
|
+
console.error(reason);
|
|
16
|
+
});
|
|
17
|
+
const originUrl = options.experimentalErrorPageHost
|
|
18
|
+
? new URL(options.experimentalErrorPageHost)
|
|
19
|
+
: undefined;
|
|
20
|
+
const prerenderedErrorPageFetch = originUrl
|
|
21
|
+
? (url) => {
|
|
22
|
+
const errorPageUrl = new URL(url);
|
|
23
|
+
errorPageUrl.protocol = originUrl.protocol;
|
|
24
|
+
errorPageUrl.host = originUrl.host;
|
|
25
|
+
return fetch(errorPageUrl);
|
|
26
|
+
}
|
|
27
|
+
: undefined;
|
|
28
|
+
return async (req, res, next, locals) => {
|
|
29
|
+
let request;
|
|
30
|
+
try {
|
|
31
|
+
request = NodeApp.createRequest(req, {
|
|
32
|
+
allowedDomains: app.getAllowedDomains?.() ?? [],
|
|
33
|
+
});
|
|
34
|
+
}
|
|
35
|
+
catch (err) {
|
|
36
|
+
logger.error(`Could not render ${req.url}`);
|
|
37
|
+
console.error(err);
|
|
38
|
+
res.statusCode = 500;
|
|
39
|
+
res.end('Internal Server Error');
|
|
40
|
+
return;
|
|
41
|
+
}
|
|
42
|
+
const routeData = app.match(request, true);
|
|
43
|
+
if (routeData) {
|
|
44
|
+
// Run render with URL tracking for error reporting
|
|
45
|
+
const response = await als.run(request.url, () => app.render(request, {
|
|
46
|
+
addCookieHeader: true,
|
|
47
|
+
locals,
|
|
48
|
+
routeData,
|
|
49
|
+
prerenderedErrorPageFetch,
|
|
50
|
+
}));
|
|
51
|
+
const finalResponse = await injectSessionCookieIfNeeded(request, response);
|
|
52
|
+
await NodeApp.writeResponse(finalResponse, res);
|
|
53
|
+
}
|
|
54
|
+
else if (next) {
|
|
55
|
+
return next();
|
|
56
|
+
}
|
|
57
|
+
else {
|
|
58
|
+
// Unmatched route
|
|
59
|
+
const response = await app.render(request, {
|
|
60
|
+
addCookieHeader: true,
|
|
61
|
+
prerenderedErrorPageFetch,
|
|
62
|
+
});
|
|
63
|
+
const finalResponse = await injectSessionCookieIfNeeded(request, response);
|
|
64
|
+
await NodeApp.writeResponse(finalResponse, res);
|
|
65
|
+
}
|
|
66
|
+
};
|
|
67
|
+
}
|
|
68
|
+
/**
|
|
69
|
+
* Inject session data cookie into response if needed.
|
|
70
|
+
* Waits for one microtask tick to allow Astro's session.persist() to complete,
|
|
71
|
+
* then checks if session data needs to be written to cookie.
|
|
72
|
+
* If not available yet, middleware will handle it on the next request
|
|
73
|
+
* via deferred cookie sync.
|
|
74
|
+
*/
|
|
75
|
+
async function injectSessionCookieIfNeeded(request, response) {
|
|
76
|
+
const setCookieHeaders = response.headers.getSetCookie?.() ?? [];
|
|
77
|
+
let sessionId = null;
|
|
78
|
+
for (const cookie of setCookieHeaders) {
|
|
79
|
+
const match = cookie.match(/^astro-session=([^;]+)/);
|
|
80
|
+
if (match) {
|
|
81
|
+
sessionId = match[1];
|
|
82
|
+
break;
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
if (!sessionId) {
|
|
86
|
+
return response;
|
|
87
|
+
}
|
|
88
|
+
// Wait for next event loop tick to allow Astro's session.persist() to complete
|
|
89
|
+
// persist() runs in a finally block after render completes
|
|
90
|
+
await new Promise((resolve) => setImmediate(resolve));
|
|
91
|
+
const entry = sessionStore.get(sessionId);
|
|
92
|
+
// Only inject if we have dirty data ready
|
|
93
|
+
if (!entry?.dirty || !entry.data) {
|
|
94
|
+
return response;
|
|
95
|
+
}
|
|
96
|
+
const config = getDriverConfig();
|
|
97
|
+
const ttl = config?.ttl ?? 604800;
|
|
98
|
+
const cookieOptions = config?.cookieOptions;
|
|
99
|
+
const url = new URL(request.url);
|
|
100
|
+
const isLocalhost = url.hostname === 'localhost' || url.hostname === '127.0.0.1';
|
|
101
|
+
const isSecure = request.url.startsWith('https://');
|
|
102
|
+
const cookieParts = [
|
|
103
|
+
`astro-session-data=${entry.data}`,
|
|
104
|
+
`Path=${cookieOptions?.path ?? '/'}`,
|
|
105
|
+
`Max-Age=${ttl}`,
|
|
106
|
+
cookieOptions?.httpOnly !== false ? 'HttpOnly' : '',
|
|
107
|
+
(cookieOptions?.secure ?? isSecure) ? 'Secure' : '',
|
|
108
|
+
`SameSite=${cookieOptions?.sameSite ?? 'Lax'}`,
|
|
109
|
+
!isLocalhost && cookieOptions?.domain ? `Domain=${cookieOptions.domain}` : '',
|
|
110
|
+
]
|
|
111
|
+
.filter(Boolean)
|
|
112
|
+
.join('; ');
|
|
113
|
+
const newHeaders = new Headers(response.headers);
|
|
114
|
+
newHeaders.append('Set-Cookie', cookieParts);
|
|
115
|
+
// Mark as clean after writing cookie
|
|
116
|
+
sessionStore.set(sessionId, { ...entry, dirty: false, timestamp: Date.now() });
|
|
117
|
+
return new Response(response.body, {
|
|
118
|
+
status: response.status,
|
|
119
|
+
statusText: response.statusText,
|
|
120
|
+
headers: newHeaders,
|
|
121
|
+
});
|
|
122
|
+
}
|
|
123
|
+
//# sourceMappingURL=serve-app.js.map
|