From dd0909358930b1dfb775880c5b99cc81f82b7311 Mon Sep 17 00:00:00 2001 From: Matt Kane Date: Thu, 6 Feb 2025 12:11:57 +0000 Subject: [PATCH 01/22] feat: add support for automatic session driver config --- .changeset/tricky-insects-argue.md | 41 ++++ .../src/core/build/plugins/plugin-manifest.ts | 4 +- packages/astro/src/core/config/schema.ts | 53 ++--- packages/astro/src/core/errors/errors-data.ts | 118 ++++++++--- packages/astro/src/core/session.ts | 24 ++- packages/astro/src/integrations/hooks.ts | 2 + packages/astro/src/types/public/config.ts | 55 ++++-- .../src/vite-plugin-astro-server/plugin.ts | 2 +- .../test/fixtures/sessions/astro.config.mjs | 10 +- .../test/fixtures/sessions/src/pages/api.ts | 2 - packages/astro/test/sessions.test.js | 183 ++++++++++++++++-- packages/astro/test/test-utils.js | 1 + 12 files changed, 388 insertions(+), 107 deletions(-) create mode 100644 .changeset/tricky-insects-argue.md diff --git a/.changeset/tricky-insects-argue.md b/.changeset/tricky-insects-argue.md new file mode 100644 index 000000000000..0e51eba36709 --- /dev/null +++ b/.changeset/tricky-insects-argue.md @@ -0,0 +1,41 @@ +--- +'astro': minor +--- + +:warning: **BREAKING CHANGE FOR EXPERIMENTAL SESSIONS ONLY** :warning: + +Changes the `experimental.session` option to a boolean flag and moves session config to a top-level value. This change is to allow the new automatic session driver support. You now need to separately enable the `experimental.session` flag, and then configure the session driver using the top-level `session` key if providing manual configuration. + +```diff +defineConfig({ + // ... + experimental: { +- session: { +- driver: 'fs', +- }, ++ session: true, + }, ++ session: { ++ driver: 'fs', ++ }, +}); +``` + +You do not need to configure the session driver if you are using the Node or Netlify adapters and want to use the default session drivers for each adapter. The default session driver for the Node adapter is `fs`, and the default session driver for the Netlify adapter is `netlify-blobs`. + +For example, if you are using the Node adapter, you can just enable the flag: + +```js +defineConfig({ + // ... + adapter: node({ + mode: 'standalone', + }), + experimental: { + session: true, + }, +}); +``` +This will configure the session driver to use the default `fs` driver for the Node adapter. See the release notes for `@astrojs/node` and `@astrojs/netlify` for more information on the default session drivers for each adapter. + +If you enable the flag but are using an adapter that does not have a default session driver, you will need to configure the session driver manually or the build will fail. diff --git a/packages/astro/src/core/build/plugins/plugin-manifest.ts b/packages/astro/src/core/build/plugins/plugin-manifest.ts index de9645e0a2d0..d2e4d988e5be 100644 --- a/packages/astro/src/core/build/plugins/plugin-manifest.ts +++ b/packages/astro/src/core/build/plugins/plugin-manifest.ts @@ -55,7 +55,7 @@ function vitePluginManifest(options: StaticBuildOptions, internals: BuildInterna ]; const resolvedDriver = await resolveSessionDriver( - options.settings.config.experimental?.session?.driver, + options.settings.config.session?.driver, ); const contents = [ @@ -304,6 +304,6 @@ function buildManifest( (settings.config.security?.checkOrigin && settings.buildOutput === 'server') ?? false, serverIslandNameMap: Array.from(settings.serverIslandNameMap), key: encodedKey, - sessionConfig: settings.config.experimental.session, + sessionConfig: settings.config.session, }; } diff --git a/packages/astro/src/core/config/schema.ts b/packages/astro/src/core/config/schema.ts index 777e8df2665e..83546aeb9a9e 100644 --- a/packages/astro/src/core/config/schema.ts +++ b/packages/astro/src/core/config/schema.ts @@ -92,12 +92,14 @@ export const ASTRO_CONFIG_DEFAULTS = { schema: {}, validateSecrets: false, }, + session: undefined, experimental: { clientPrerender: false, contentIntellisense: false, responsiveImages: false, svg: false, serializeConfig: false, + session: false, }, } satisfies AstroUserConfig & { server: { open: boolean } }; @@ -522,6 +524,30 @@ export const AstroConfigSchema = z.object({ .strict() .optional() .default(ASTRO_CONFIG_DEFAULTS.env), + session: z + .object({ + driver: z.string(), + options: z.record(z.any()).optional(), + cookie: z + .object({ + name: z.string().optional(), + domain: z.string().optional(), + path: z.string().optional(), + maxAge: z.number().optional(), + sameSite: z.union([z.enum(['strict', 'lax', 'none']), z.boolean()]).optional(), + secure: z.boolean().optional(), + }) + .or(z.string()) + .transform((val) => { + if (typeof val === 'string') { + return { name: val }; + } + return val; + }) + .optional(), + ttl: z.number().optional(), + }) + .optional(), experimental: z .object({ clientPrerender: z @@ -536,32 +562,7 @@ export const AstroConfigSchema = z.object({ .boolean() .optional() .default(ASTRO_CONFIG_DEFAULTS.experimental.responsiveImages), - session: z - .object({ - driver: z.string(), - options: z.record(z.any()).optional(), - cookie: z - .union([ - z.object({ - name: z.string().optional(), - domain: z.string().optional(), - path: z.string().optional(), - maxAge: z.number().optional(), - sameSite: z.union([z.enum(['strict', 'lax', 'none']), z.boolean()]).optional(), - secure: z.boolean().optional(), - }), - z.string(), - ]) - .transform((val) => { - if (typeof val === 'string') { - return { name: val }; - } - return val; - }) - .optional(), - ttl: z.number().optional(), - }) - .optional(), + session: z.boolean().optional(), svg: z .union([ z.boolean(), diff --git a/packages/astro/src/core/errors/errors-data.ts b/packages/astro/src/core/errors/errors-data.ts index 0a79816343ce..09d2d51b3d74 100644 --- a/packages/astro/src/core/errors/errors-data.ts +++ b/packages/astro/src/core/errors/errors-data.ts @@ -881,38 +881,6 @@ export const AstroResponseHeadersReassigned = { hint: 'Consider using `Astro.response.headers.add()`, and `Astro.response.headers.delete()`.', } satisfies ErrorData; -/** - * @docs - * @message Error when initializing session storage with driver `DRIVER`. `ERROR` - * @see - * - [experimental.session](https://docs.astro.build/en/reference/experimental-flags/sessions/) - * @description - * Thrown when the session storage could not be initialized. - */ -export const SessionStorageInitError = { - name: 'SessionStorageInitError', - title: 'Session storage could not be initialized.', - message: (error: string, driver?: string) => - `Error when initializing session storage${driver ? ` with driver \`${driver}\`` : ''}. \`${error ?? ''}\``, - hint: 'For more information, see https://docs.astro.build/en/reference/experimental-flags/sessions/', -} satisfies ErrorData; - -/** - * @docs - * @message Error when saving session data with driver `DRIVER`. `ERROR` - * @see - * - [experimental.session](https://docs.astro.build/en/reference/experimental-flags/sessions/) - * @description - * Thrown when the session data could not be saved. - */ -export const SessionStorageSaveError = { - name: 'SessionStorageSaveError', - title: 'Session data could not be saved.', - message: (error: string, driver?: string) => - `Error when saving session data${driver ? ` with driver \`${driver}\`` : ''}. \`${error ?? ''}\``, - hint: 'For more information, see https://docs.astro.build/en/reference/experimental-flags/sessions/', -} satisfies ErrorData; - /** * @docs * @description @@ -1838,6 +1806,92 @@ export const ActionCalledFromServerError = { // Generic catch-all - Only use this in extreme cases, like if there was a cosmic ray bit flip. export const UnknownError = { name: 'UnknownError', title: 'Unknown Error.' } satisfies ErrorData; + +/** + * @docs + * @kind heading + * @name Session Errors + */ +// Session Errors +/** + * @docs + * @see + * - [On-demand rendering](https://docs.astro.build/en/guides/on-demand-rendering/) + * @description + * Your project must have a server output to use sessions. + */ +export const SessionWithoutServerOutputError = { + name: 'SessionWithoutServerOutputError', + title: 'Sessions must be used with server output.', + message: + 'A server is required to use sessions. To deploy routes to a server, add an adapter to your Astro config and configure your route for on-demand rendering', + hint: 'Add an adapter and enable on-demand rendering: https://docs.astro.build/en/guides/on-demand-rendering/', +} satisfies ErrorData; + +/** + * @docs + * @message Error when initializing session storage with driver `DRIVER`. `ERROR` + * @see + * - [experimental.session](https://docs.astro.build/en/reference/experimental-flags/sessions/) + * @description + * Thrown when the session storage could not be initialized. + */ +export const SessionStorageInitError = { + name: 'SessionStorageInitError', + title: 'Session storage could not be initialized.', + message: (error: string, driver?: string) => + `Error when initializing session storage${driver ? ` with driver \`${driver}\`` : ''}. \`${error ?? ''}\``, + hint: 'For more information, see https://docs.astro.build/en/reference/experimental-flags/sessions/', +} satisfies ErrorData; + +/** + * @docs + * @message Error when saving session data with driver `DRIVER`. `ERROR` + * @see + * - [experimental.session](https://docs.astro.build/en/reference/experimental-flags/sessions/) + * @description + * Thrown when the session data could not be saved. + */ +export const SessionStorageSaveError = { + name: 'SessionStorageSaveError', + title: 'Session data could not be saved.', + message: (error: string, driver?: string) => + `Error when saving session data${driver ? ` with driver \`${driver}\`` : ''}. \`${error ?? ''}\``, + hint: 'For more information, see https://docs.astro.build/en/reference/experimental-flags/sessions/', +} satisfies ErrorData; + +/** + * @docs + * @message The `experimental.session` flag was set to `true`, but no storage was configured. Either configure the storage manually or use an adapter that provides session storage + * @see + * - [experimental.session](https://docs.astro.build/en/reference/experimental-flags/sessions/) + * @description + * Thrown when session storage is enabled but not configured. + */ +export const SessionConfigMissingError = { + name: 'SessionConfigMissingError', + title: 'Session storage was enabled but not configured.', + message: 'The `experimental.session` flag was set to `true`, but no storage was configured. Either configure the storage manually or use an adapter that provides session storage', + hint: 'See https://docs.astro.build/en/reference/experimental-flags/sessions/', +} satisfies ErrorData; + +/** + * @docs + * @message Session config was provided without enabling the `experimental.session` flag + * @see + * - [experimental.session](https://docs.astro.build/en/reference/experimental-flags/sessions/) + * @description + * Thrown when session storage is configured but the `experimental.session` flag is not enabled. + */ +export const SessionConfigWithoutFlagError = { + name: 'SessionConfigWithoutFlagError', + title: 'Session flag not set', + message: 'Session config was provided without enabling the `experimental.session` flag', + hint: 'See https://docs.astro.build/en/reference/experimental-flags/sessions/', +} satisfies ErrorData; + + + /* * Adding an error? Follow these steps: * 1. Determine in which category it belongs (Astro, Vite, CSS, Content Collections etc.) diff --git a/packages/astro/src/core/session.ts b/packages/astro/src/core/session.ts index ccb01ef6117d..3be428934871 100644 --- a/packages/astro/src/core/session.ts +++ b/packages/astro/src/core/session.ts @@ -13,8 +13,15 @@ import type { } from '../types/public/config.js'; import type { AstroCookies } from './cookies/cookies.js'; import type { AstroCookieSetOptions } from './cookies/cookies.js'; -import { SessionStorageInitError, SessionStorageSaveError } from './errors/errors-data.js'; +import { + SessionConfigMissingError, + SessionConfigWithoutFlagError, + SessionStorageInitError, + SessionStorageSaveError, + SessionWithoutServerOutputError, +} from './errors/errors-data.js'; import { AstroError } from './errors/index.js'; +import type { AstroSettings } from '../types/astro.js'; export const PERSIST_SYMBOL = Symbol(); @@ -474,3 +481,18 @@ export function resolveSessionDriver(driver: string | undefined): Promise({ name, @@ -369,6 +370,7 @@ export async function runHookConfigDone({ }); } } + validateSessionConfig(settings); } export async function runHookServerSetup({ diff --git a/packages/astro/src/types/public/config.ts b/packages/astro/src/types/public/config.ts index a2b8ab8999e5..2cb0470ef712 100644 --- a/packages/astro/src/types/public/config.ts +++ b/packages/astro/src/types/public/config.ts @@ -1724,6 +1724,36 @@ export interface ViteUserConfig extends OriginalViteUserConfig { validateSecrets?: boolean; }; + /** + * @docs + * @name session + * @type {SessionConfig} + * @version 5.3.0 + * @description + * + * Configures experimental session support by specifying a storage `driver` as well as any associated `options`. + * You must enable the `experimental.session` flag to use this feature. + * Some adapters may provide a default session driver, but you can override it with your own configuration. + * + * You can specify [any driver from Unstorage](https://unstorage.unjs.io/drivers) or provide a custom config which will override your adapter's default. + * + * See [the experimental session guide](https://docs.astro.build/en/reference/experimental-flags/sessions/) for more information. + * + * ```js title="astro.config.mjs" + * { + * session: { + * // Required: the name of the Unstorage driver + * driver: "redis", + * // The required options depend on the driver + * options: { + * url: process.env.REDIS_URL, + * } + * }, + * } + * ``` + */ + session?: SessionConfig; + /** * * @kind heading @@ -1966,7 +1996,8 @@ export interface ViteUserConfig extends OriginalViteUserConfig { /** * * @name experimental.session - * @type {SessionConfig} + * @type {boolean} + * @default `false` * @version 5.0.0 * @description * @@ -1983,30 +2014,12 @@ export interface ViteUserConfig extends OriginalViteUserConfig { * 🛒 {cart?.length ?? 0} items * * ``` - * The object configures session management for your Astro site by specifying a `driver` as well as any `options` for your data storage. - * - * You can specify [any driver from Unstorage](https://unstorage.unjs.io/drivers) or provide a custom config which will override your adapter's default. - * - * ```js title="astro.config.mjs" - * { - * experimental: { - * session: { - * // Required: the name of the Unstorage driver - * driver: "redis", - * // The required options depend on the driver - * options: { - * url: process.env.REDIS_URL, - * } - * } - * }, - * } - * ``` * - * For more details, see [the Sessions RFC](https://github.com/withastro/roadmap/blob/sessions/proposals/0054-sessions.md). + * For more details, see [the experimental session guide](https://docs.astro.build/en/reference/experimental-flags/sessions/). * */ - session?: SessionConfig; + session?: boolean; /** * * @name experimental.svg diff --git a/packages/astro/src/vite-plugin-astro-server/plugin.ts b/packages/astro/src/vite-plugin-astro-server/plugin.ts index 113a85804352..cdbaefea11b8 100644 --- a/packages/astro/src/vite-plugin-astro-server/plugin.ts +++ b/packages/astro/src/vite-plugin-astro-server/plugin.ts @@ -203,6 +203,6 @@ export function createDevelopmentManifest(settings: AstroSettings): SSRManifest onRequest: NOOP_MIDDLEWARE_FN, }; }, - sessionConfig: settings.config.experimental.session, + sessionConfig: settings.config.experimental.session ? settings.config.session : undefined }; } diff --git a/packages/astro/test/fixtures/sessions/astro.config.mjs b/packages/astro/test/fixtures/sessions/astro.config.mjs index 7eb32d0cfb21..bcd1aed24e57 100644 --- a/packages/astro/test/fixtures/sessions/astro.config.mjs +++ b/packages/astro/test/fixtures/sessions/astro.config.mjs @@ -1,14 +1,6 @@ // @ts-check import { defineConfig } from 'astro/config'; -import testAdapter from '../../test-adapter.js'; export default defineConfig({ - adapter: testAdapter(), - output: 'server', - experimental: { - session: { - driver: 'fs', - ttl: 20, - }, - }, + }); diff --git a/packages/astro/test/fixtures/sessions/src/pages/api.ts b/packages/astro/test/fixtures/sessions/src/pages/api.ts index 77d50625aab1..21793c78a74f 100644 --- a/packages/astro/test/fixtures/sessions/src/pages/api.ts +++ b/packages/astro/test/fixtures/sessions/src/pages/api.ts @@ -1,7 +1,5 @@ import type { APIRoute } from 'astro'; -export const prerender = false; - export const GET: APIRoute = async (context) => { const url = new URL(context.url, 'http://localhost'); let value = url.searchParams.get('set'); diff --git a/packages/astro/test/sessions.test.js b/packages/astro/test/sessions.test.js index 1dbc304bd295..958930a698d5 100644 --- a/packages/astro/test/sessions.test.js +++ b/packages/astro/test/sessions.test.js @@ -1,25 +1,34 @@ import assert from 'node:assert/strict'; -import { before, describe, it } from 'node:test'; +import { before, after, describe, it } from 'node:test'; import * as devalue from 'devalue'; import testAdapter from './test-adapter.js'; import { loadFixture } from './test-utils.js'; +import { getSetCookiesFromResponse } from '../dist/core/cookies/index.js'; describe('Astro.session', () => { - /** @type {import('./test-utils').Fixture} */ - let fixture; - - before(async () => { - fixture = await loadFixture({ - root: './fixtures/sessions/', - output: 'server', - adapter: testAdapter(), + describe('Production', () => { + /** @type {import('./test-utils').Fixture} */ + let fixture; + + before(async () => { + fixture = await loadFixture({ + root: './fixtures/sessions/', + output: 'server', + adapter: testAdapter(), + session: { + driver: 'fs', + ttl: 20, + }, + experimental: { + session: true, + }, + }); }); - }); - describe('Production', () => { - let app; + /** @type {import('../src/core/app/index').App} response */ + let app before(async () => { - await fixture.build(); + await fixture.build({}); app = await fixture.loadTestAdapterApp(); }); @@ -92,4 +101,152 @@ describe('Astro.session', () => { ); }); }); + + describe('Development', () => { + /** @type {import('./test-utils').Fixture} */ + let fixture; + let devServer + before(async () => { + fixture = await loadFixture({ + root: './fixtures/sessions/', + output: 'server', + adapter: testAdapter(), + session: { + driver: 'fs', + ttl: 20, + }, + experimental: { + session: true, + }, + }); + devServer = await fixture.startDevServer(); + + }); + + after(async () => { + await devServer.stop(); + }); + + it('can regenerate session cookies upon request', async () => { + const firstResponse = await fixture.fetch('/regenerate'); + console.log(firstResponse.headers ) + // @ts-ignore + const firstHeaders = firstResponse.headers.get('set-cookie').split(','); + const firstSessionId = firstHeaders[0].split(';')[0].split('=')[1]; + + const secondResponse = await fixture.fetch('/regenerate', { + method: 'GET', + headers: { + cookie: `astro-session=${firstSessionId}`, + }, + }); + // @ts-ignore + const secondHeaders = secondResponse.headers.get('set-cookie').split(','); + const secondSessionId = secondHeaders[0].split(';')[0].split('=')[1]; + assert.notEqual(firstSessionId, secondSessionId); + }); + + it('can save session data by value', async () => { + const firstResponse = await fixture.fetch('/update'); + const firstValue = await firstResponse.json(); + assert.equal(firstValue.previousValue, 'none'); + + // @ts-ignore + const firstHeaders = firstResponse.headers.get('set-cookie').split(','); + const firstSessionId = firstHeaders[0].split(';')[0].split('=')[1]; + const secondResponse = await fixture.fetch('/update', { + method: 'GET', + headers: { + cookie: `astro-session=${firstSessionId}`, + }, + }); + const secondValue = await secondResponse.json(); + assert.equal(secondValue.previousValue, 'expected'); + }); + + it('can save and restore URLs in session data', async () => { + const firstResponse = await fixture.fetch('/_actions/addUrl', { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + }, + body: JSON.stringify({ favoriteUrl: 'https://domain.invalid' }), + }); + + assert.equal(firstResponse.ok, true); + // @ts-ignore + const firstHeaders = firstResponse.headers.get('set-cookie').split(','); + const firstSessionId = firstHeaders[0].split(';')[0].split('=')[1]; + + const data = devalue.parse(await firstResponse.text()); + assert.equal(data.message, 'Favorite URL set to https://domain.invalid/ from nothing'); + const secondResponse = await fixture.fetch('/_actions/addUrl', { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + cookie: `astro-session=${firstSessionId}`, + }, + body: JSON.stringify({ favoriteUrl: 'https://example.com' }), + }); + const secondData = devalue.parse(await secondResponse.text()); + assert.equal( + secondData.message, + 'Favorite URL set to https://example.com/ from https://domain.invalid/', + ); + }); + + }) + + describe('Configuration', () => { + it('throws if flag is enabled but driver is not set', async () => { + const fixture = await loadFixture({ + root: './fixtures/sessions/', + output: 'server', + adapter: testAdapter(), + experimental: { + session: true, + }, + }); + await assert.rejects( + fixture.build({}), + /Error: The `experimental.session` flag was set to `true`, but no storage was configured/, + ); + }); + + it('throws if session is configured but flag is not enabled', async () => { + const fixture = await loadFixture({ + root: './fixtures/sessions/', + output: 'server', + adapter: testAdapter(), + session: { + driver: 'fs', + }, + experimental: { + session: false, + }, + }); + await assert.rejects( + fixture.build({}), + /Error: Session config was provided without enabling the `experimental.session` flag/, + ); + }); + + it('throws if output is static', async () => { + const fixture = await loadFixture({ + root: './fixtures/sessions/', + output: 'static', + session: { + driver: 'fs', + ttl: 20, + }, + experimental: { + session: true, + }, + }); + // Disable actions so we can do a static build + await fixture.editFile('src/actions/index.ts', () => ''); + await assert.rejects(fixture.build({}), /Error: A server is required to use session/); + await fixture.resetAllFiles(); + }); + }); }); diff --git a/packages/astro/test/test-utils.js b/packages/astro/test/test-utils.js index c33e43ca36b0..5b540a78f575 100644 --- a/packages/astro/test/test-utils.js +++ b/packages/astro/test/test-utils.js @@ -49,6 +49,7 @@ process.env.ASTRO_TELEMETRY_DISABLED = true; * @property {typeof check} check * @property {typeof sync} sync * @property {AstroConfig} config + * @property {() => void} resetAllFiles * * This function returns an instance of the Check * From aa98169281e2b62504410556bcf794baf2f56a37 Mon Sep 17 00:00:00 2001 From: Matt Kane Date: Thu, 6 Feb 2025 12:21:45 +0000 Subject: [PATCH 02/22] chore: fix error logic --- packages/astro/src/core/session.ts | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/packages/astro/src/core/session.ts b/packages/astro/src/core/session.ts index 3be428934871..68b9b43f5912 100644 --- a/packages/astro/src/core/session.ts +++ b/packages/astro/src/core/session.ts @@ -483,13 +483,17 @@ export function resolveSessionDriver(driver: string | undefined): Promise Date: Thu, 6 Feb 2025 12:32:50 +0000 Subject: [PATCH 03/22] Lint test --- packages/astro/test/sessions.test.js | 2 -- 1 file changed, 2 deletions(-) diff --git a/packages/astro/test/sessions.test.js b/packages/astro/test/sessions.test.js index 958930a698d5..3be975fbd042 100644 --- a/packages/astro/test/sessions.test.js +++ b/packages/astro/test/sessions.test.js @@ -3,7 +3,6 @@ import { before, after, describe, it } from 'node:test'; import * as devalue from 'devalue'; import testAdapter from './test-adapter.js'; import { loadFixture } from './test-utils.js'; -import { getSetCookiesFromResponse } from '../dist/core/cookies/index.js'; describe('Astro.session', () => { describe('Production', () => { @@ -129,7 +128,6 @@ describe('Astro.session', () => { it('can regenerate session cookies upon request', async () => { const firstResponse = await fixture.fetch('/regenerate'); - console.log(firstResponse.headers ) // @ts-ignore const firstHeaders = firstResponse.headers.get('set-cookie').split(','); const firstSessionId = firstHeaders[0].split(';')[0].split('=')[1]; From bc4de01c368c8324920593bfc536e0d9a9cd724f Mon Sep 17 00:00:00 2001 From: Matt Kane Date: Thu, 6 Feb 2025 14:57:46 +0000 Subject: [PATCH 04/22] Add node support --- packages/integrations/node/src/index.ts | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/packages/integrations/node/src/index.ts b/packages/integrations/node/src/index.ts index e91ed171bc87..6660f446fb02 100644 --- a/packages/integrations/node/src/index.ts +++ b/packages/integrations/node/src/index.ts @@ -1,6 +1,7 @@ import type { AstroAdapter, AstroIntegration } from 'astro'; import { AstroError } from 'astro/errors'; import type { Options, UserOptions } from './types.js'; +import { fileURLToPath } from 'node:url'; export function getAdapter(options: Options): AstroAdapter { return { @@ -33,11 +34,25 @@ export default function createIntegration(userOptions: UserOptions): AstroIntegr return { name: '@astrojs/node', hooks: { - 'astro:config:setup': async ({ updateConfig, config }) => { + 'astro:config:setup': async ({ updateConfig, config, logger }) => { + let session = config.session; + + if (config.experimental.session && !session?.driver) { + logger.info('Configuring experimental session support using filesystem storage'); + session = { + ...session, + driver: 'fs-lite', + options: { + base: fileURLToPath(new URL('sessions', config.cacheDir)), + }, + }; + } + updateConfig({ image: { endpoint: config.image.endpoint ?? 'astro/assets/endpoint/node', }, + session, vite: { ssr: { noExternal: ['@astrojs/node'], From 4c3ded859c017f7358db9d42853be1815699f3c3 Mon Sep 17 00:00:00 2001 From: Matt Kane Date: Thu, 6 Feb 2025 15:09:50 +0000 Subject: [PATCH 05/22] Add node test fixture --- .../test/fixtures/session/astro.config.mjs | 11 ++++ .../node/test/fixtures/session/package.json | 9 ++++ .../fixtures/session/src/actions/index.ts | 27 ++++++++++ .../test/fixtures/session/src/middleware.ts | 50 +++++++++++++++++++ .../test/fixtures/session/src/pages/api.ts | 15 ++++++ .../fixtures/session/src/pages/cart.astro | 26 ++++++++++ .../fixtures/session/src/pages/destroy.ts | 6 +++ .../fixtures/session/src/pages/index.astro | 16 ++++++ .../fixtures/session/src/pages/regenerate.ts | 6 +++ pnpm-lock.yaml | 9 ++++ 10 files changed, 175 insertions(+) create mode 100644 packages/integrations/node/test/fixtures/session/astro.config.mjs create mode 100644 packages/integrations/node/test/fixtures/session/package.json create mode 100644 packages/integrations/node/test/fixtures/session/src/actions/index.ts create mode 100644 packages/integrations/node/test/fixtures/session/src/middleware.ts create mode 100644 packages/integrations/node/test/fixtures/session/src/pages/api.ts create mode 100644 packages/integrations/node/test/fixtures/session/src/pages/cart.astro create mode 100644 packages/integrations/node/test/fixtures/session/src/pages/destroy.ts create mode 100644 packages/integrations/node/test/fixtures/session/src/pages/index.astro create mode 100644 packages/integrations/node/test/fixtures/session/src/pages/regenerate.ts diff --git a/packages/integrations/node/test/fixtures/session/astro.config.mjs b/packages/integrations/node/test/fixtures/session/astro.config.mjs new file mode 100644 index 000000000000..51c6accb73e4 --- /dev/null +++ b/packages/integrations/node/test/fixtures/session/astro.config.mjs @@ -0,0 +1,11 @@ +// @ts-check +import { defineConfig } from "astro/config"; +import node from "@astrojs/node"; + +export default defineConfig({ + output: 'server', + adapter: node({ mode: 'standalone' }), + experimental: { + session: true + } +}); diff --git a/packages/integrations/node/test/fixtures/session/package.json b/packages/integrations/node/test/fixtures/session/package.json new file mode 100644 index 000000000000..423f348b87d7 --- /dev/null +++ b/packages/integrations/node/test/fixtures/session/package.json @@ -0,0 +1,9 @@ +{ + "name": "@test/session", + "version": "0.0.0", + "private": true, + "dependencies": { + "@astrojs/node": "workspace:*", + "astro": "^5.1.6" + } +} \ No newline at end of file diff --git a/packages/integrations/node/test/fixtures/session/src/actions/index.ts b/packages/integrations/node/test/fixtures/session/src/actions/index.ts new file mode 100644 index 000000000000..33ac1cb653fb --- /dev/null +++ b/packages/integrations/node/test/fixtures/session/src/actions/index.ts @@ -0,0 +1,27 @@ +import { defineAction } from 'astro:actions'; +import { z } from 'astro:schema'; + +export const server = { + addToCart: defineAction({ + accept: 'form', + input: z.object({ productId: z.string() }), + handler: async (input, context) => { + const cart: Array = (await context.session.get('cart')) || []; + cart.push(input.productId); + await context.session.set('cart', cart); + return { cart, message: 'Product added to cart at ' + new Date().toTimeString() }; + }, + }), + getCart: defineAction({ + handler: async (input, context) => { + return await context.session.get('cart'); + }, + }), + clearCart: defineAction({ + accept: 'json', + handler: async (input, context) => { + await context.session.set('cart', []); + return {cart: [], message: 'Cart cleared at ' + new Date().toTimeString() }; + }, + }), +}; diff --git a/packages/integrations/node/test/fixtures/session/src/middleware.ts b/packages/integrations/node/test/fixtures/session/src/middleware.ts new file mode 100644 index 000000000000..05a9f40b6788 --- /dev/null +++ b/packages/integrations/node/test/fixtures/session/src/middleware.ts @@ -0,0 +1,50 @@ +import { defineMiddleware } from 'astro:middleware'; +import { getActionContext } from 'astro:actions'; + +const ACTION_SESSION_KEY = 'actionResult' + +export const onRequest = defineMiddleware(async (context, next) => { + console.log("Deno" in globalThis ? "Deno" : "Node.js"); + // Skip requests for prerendered pages + if (context.isPrerendered) return next(); + + const { action, setActionResult, serializeActionResult } = + getActionContext(context); + + console.log(action?.name) + + const actionPayload = await context.session.get(ACTION_SESSION_KEY); + console.log({actionPayload}) + if (actionPayload) { + setActionResult(actionPayload.actionName, actionPayload.actionResult); + context.session.delete(ACTION_SESSION_KEY); + return next(); + } + + // If an action was called from an HTML form action, + // call the action handler and redirect to the destination page + if (action?.calledFrom === "form") { + const actionResult = await action.handler(); + + context.session.set(ACTION_SESSION_KEY, { + actionName: action.name, + actionResult: serializeActionResult(actionResult), + }); + + + // Redirect back to the previous page on error + if (actionResult.error) { + const referer = context.request.headers.get("Referer"); + if (!referer) { + throw new Error( + "Internal: Referer unexpectedly missing from Action POST request.", + ); + } + return context.redirect(referer); + } + // Redirect to the destination page on success + return context.redirect(context.originPathname); + } + + return next(); +}); diff --git a/packages/integrations/node/test/fixtures/session/src/pages/api.ts b/packages/integrations/node/test/fixtures/session/src/pages/api.ts new file mode 100644 index 000000000000..77d50625aab1 --- /dev/null +++ b/packages/integrations/node/test/fixtures/session/src/pages/api.ts @@ -0,0 +1,15 @@ +import type { APIRoute } from 'astro'; + +export const prerender = false; + +export const GET: APIRoute = async (context) => { + const url = new URL(context.url, 'http://localhost'); + let value = url.searchParams.get('set'); + if (value) { + context.session.set('value', value); + } else { + value = await context.session.get('value'); + } + const cart = await context.session.get('cart'); + return Response.json({ value, cart }); +}; diff --git a/packages/integrations/node/test/fixtures/session/src/pages/cart.astro b/packages/integrations/node/test/fixtures/session/src/pages/cart.astro new file mode 100644 index 000000000000..870ac0bcc214 --- /dev/null +++ b/packages/integrations/node/test/fixtures/session/src/pages/cart.astro @@ -0,0 +1,26 @@ +--- +import { actions } from "astro:actions"; + +const result = Astro.getActionResult(actions.addToCart); +const start = Date.now(); +const cart = result?.data?.cart ?? await Astro.session.get('cart'); +const end = Date.now(); +const message = result?.data?.message ?? 'Add something to your cart!'; +--- +

Cart: {JSON.stringify(cart)}

+

Time taken: {end - start}ms

+

{message}

+
+ + +
+ + diff --git a/packages/integrations/node/test/fixtures/session/src/pages/destroy.ts b/packages/integrations/node/test/fixtures/session/src/pages/destroy.ts new file mode 100644 index 000000000000..e83f6e4b6c31 --- /dev/null +++ b/packages/integrations/node/test/fixtures/session/src/pages/destroy.ts @@ -0,0 +1,6 @@ +import type { APIRoute } from 'astro'; + +export const GET: APIRoute = async (context) => { + await context.session.destroy(); + return Response.json({}); +}; diff --git a/packages/integrations/node/test/fixtures/session/src/pages/index.astro b/packages/integrations/node/test/fixtures/session/src/pages/index.astro new file mode 100644 index 000000000000..a85d55c39dac --- /dev/null +++ b/packages/integrations/node/test/fixtures/session/src/pages/index.astro @@ -0,0 +1,16 @@ +--- +const start = performance.now(); +const value = await Astro.session.get('value'); +const end = performance.now(); +--- + + + + Hi + + +

Hi

+

{value}

+

Time taken: {end - start}ms

+🛒 + diff --git a/packages/integrations/node/test/fixtures/session/src/pages/regenerate.ts b/packages/integrations/node/test/fixtures/session/src/pages/regenerate.ts new file mode 100644 index 000000000000..6f2240588e4f --- /dev/null +++ b/packages/integrations/node/test/fixtures/session/src/pages/regenerate.ts @@ -0,0 +1,6 @@ +import type { APIRoute } from 'astro'; + +export const GET: APIRoute = async (context) => { + await context.session.regenerate(); + return Response.json({}); +}; diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 86eda9d0207e..c561e02331f5 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -5130,6 +5130,15 @@ importers: specifier: ^5.1.6 version: link:../../../../../astro + packages/integrations/node/test/fixtures/session: + dependencies: + '@astrojs/node': + specifier: workspace:* + version: link:../../.. + astro: + specifier: ^5.1.6 + version: link:../../../../../astro + packages/integrations/node/test/fixtures/trailing-slash: dependencies: '@astrojs/node': From e1e232894bd4a292565c3870272f330899957ce5 Mon Sep 17 00:00:00 2001 From: Matt Kane Date: Thu, 6 Feb 2025 15:13:54 +0000 Subject: [PATCH 06/22] Lock --- pnpm-lock.yaml | 552 ++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 549 insertions(+), 3 deletions(-) diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index c561e02331f5..a2a39d44256b 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -4995,7 +4995,93 @@ importers: specifier: workspace:* version: link:../../../../../astro - packages/integrations/netlify: {} + packages/integrations/netlify: + dependencies: + '@astrojs/internal-helpers': + specifier: 0.5.1 + version: link:../../internal-helpers + '@astrojs/underscore-redirects': + specifier: ^0.6.0 + version: link:../../underscore-redirects + '@netlify/functions': + specifier: ^2.8.0 + version: 2.8.2 + '@vercel/nft': + specifier: ^0.29.0 + version: 0.29.1(rollup@4.34.2) + esbuild: + specifier: ^0.24.0 + version: 0.24.2 + vite: + specifier: ^6.0.7 + version: 6.0.11(@types/node@22.13.1)(jiti@2.4.2)(lightningcss@1.29.1)(sass@1.83.4)(yaml@2.5.1) + devDependencies: + '@netlify/edge-functions': + specifier: ^2.11.1 + version: 2.11.1 + '@netlify/edge-handler-types': + specifier: ^0.34.1 + version: 0.34.1 + '@types/node': + specifier: ^22.10.6 + version: 22.13.1 + astro: + specifier: ^5.1.6 + version: link:../../astro + astro-scripts: + specifier: workspace:* + version: link:../../../scripts + cheerio: + specifier: 1.0.0 + version: 1.0.0 + execa: + specifier: ^8.0.1 + version: 8.0.1 + fast-glob: + specifier: ^3.3.3 + version: 3.3.3 + strip-ansi: + specifier: ^7.1.0 + version: 7.1.0 + typescript: + specifier: ^5.7.3 + version: 5.7.3 + + packages/integrations/netlify/test/functions/fixtures/cookies: + dependencies: + '@astrojs/netlify': + specifier: 'workspace:' + version: link:../../../.. + + packages/integrations/netlify/test/functions/fixtures/middleware: + dependencies: + '@astrojs/netlify': + specifier: 'workspace:' + version: link:../../../.. + sharp: + specifier: ^0.33.5 + version: 0.33.5 + + packages/integrations/netlify/test/functions/fixtures/redirects: + dependencies: + '@astrojs/netlify': + specifier: 'workspace:' + version: link:../../../.. + + packages/integrations/netlify/test/hosted/hosted-astro-project: + dependencies: + '@astrojs/netlify': + specifier: workspace:* + version: link:../../.. + astro: + specifier: ^5.1.6 + version: link:../../../../../astro + + packages/integrations/netlify/test/static/fixtures/redirects: + dependencies: + '@astrojs/netlify': + specifier: 'workspace:' + version: link:../../../.. packages/integrations/node: dependencies: @@ -6441,6 +6527,9 @@ packages: '@emnapi/runtime@1.1.1': resolution: {integrity: sha512-3bfqkzuR1KLx57nZfjr2NLnFOobvyS0aTszaEGCGqmYMVDRaGvgIZbjGSV/MHSSmLgQ/b9JFHQ5xm5WRZYd+XQ==} + '@emnapi/runtime@1.3.1': + resolution: {integrity: sha512-kEBmG8KyqtxJZv+ygbEim+KCGtIq1fC22Ms3S4ziXmYKm8uyoLX0MHONVKwp+9opg390VaKRNt4a7A9NwmpNhw==} + '@esbuild/aix-ppc64@0.24.2': resolution: {integrity: sha512-thpVCb/rhxE/BnMLQ7GReQLLN8q9qbHmI55F4489/ByVg2aQaQ6kbcLb6FHkocZzQhxc4gx0sCk0tJkKBFzDhA==} engines: {node: '>=18'} @@ -6657,117 +6746,226 @@ packages: cpu: [arm64] os: [darwin] + '@img/sharp-darwin-arm64@0.33.5': + resolution: {integrity: sha512-UT4p+iz/2H4twwAoLCqfA9UH5pI6DggwKEGuaPy7nCVQ8ZsiY5PIcrRvD1DzuY3qYL07NtIQcWnBSY/heikIFQ==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [arm64] + os: [darwin] + '@img/sharp-darwin-x64@0.33.3': resolution: {integrity: sha512-2QeSl7QDK9ru//YBT4sQkoq7L0EAJZA3rtV+v9p8xTKl4U1bUqTIaCnoC7Ctx2kCjQgwFXDasOtPTCT8eCTXvw==} engines: {glibc: '>=2.26', node: ^18.17.0 || ^20.3.0 || >=21.0.0, npm: '>=9.6.5', pnpm: '>=7.1.0', yarn: '>=3.2.0'} cpu: [x64] os: [darwin] + '@img/sharp-darwin-x64@0.33.5': + resolution: {integrity: sha512-fyHac4jIc1ANYGRDxtiqelIbdWkIuQaI84Mv45KvGRRxSAa7o7d1ZKAOBaYbnepLC1WqxfpimdeWfvqqSGwR2Q==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [x64] + os: [darwin] + '@img/sharp-libvips-darwin-arm64@1.0.2': resolution: {integrity: sha512-tcK/41Rq8IKlSaKRCCAuuY3lDJjQnYIW1UXU1kxcEKrfL8WR7N6+rzNoOxoQRJWTAECuKwgAHnPvqXGN8XfkHA==} engines: {macos: '>=11', npm: '>=9.6.5', pnpm: '>=7.1.0', yarn: '>=3.2.0'} cpu: [arm64] os: [darwin] + '@img/sharp-libvips-darwin-arm64@1.0.4': + resolution: {integrity: sha512-XblONe153h0O2zuFfTAbQYAX2JhYmDHeWikp1LM9Hul9gVPjFY427k6dFEcOL72O01QxQsWi761svJ/ev9xEDg==} + cpu: [arm64] + os: [darwin] + '@img/sharp-libvips-darwin-x64@1.0.2': resolution: {integrity: sha512-Ofw+7oaWa0HiiMiKWqqaZbaYV3/UGL2wAPeLuJTx+9cXpCRdvQhCLG0IH8YGwM0yGWGLpsF4Su9vM1o6aer+Fw==} engines: {macos: '>=10.13', npm: '>=9.6.5', pnpm: '>=7.1.0', yarn: '>=3.2.0'} cpu: [x64] os: [darwin] + '@img/sharp-libvips-darwin-x64@1.0.4': + resolution: {integrity: sha512-xnGR8YuZYfJGmWPvmlunFaWJsb9T/AO2ykoP3Fz/0X5XV2aoYBPkX6xqCQvUTKKiLddarLaxpzNe+b1hjeWHAQ==} + cpu: [x64] + os: [darwin] + '@img/sharp-libvips-linux-arm64@1.0.2': resolution: {integrity: sha512-x7kCt3N00ofFmmkkdshwj3vGPCnmiDh7Gwnd4nUwZln2YjqPxV1NlTyZOvoDWdKQVDL911487HOueBvrpflagw==} engines: {glibc: '>=2.26', npm: '>=9.6.5', pnpm: '>=7.1.0', yarn: '>=3.2.0'} cpu: [arm64] os: [linux] + '@img/sharp-libvips-linux-arm64@1.0.4': + resolution: {integrity: sha512-9B+taZ8DlyyqzZQnoeIvDVR/2F4EbMepXMc/NdVbkzsJbzkUjhXv/70GQJ7tdLA4YJgNP25zukcxpX2/SueNrA==} + cpu: [arm64] + os: [linux] + '@img/sharp-libvips-linux-arm@1.0.2': resolution: {integrity: sha512-iLWCvrKgeFoglQxdEwzu1eQV04o8YeYGFXtfWU26Zr2wWT3q3MTzC+QTCO3ZQfWd3doKHT4Pm2kRmLbupT+sZw==} engines: {glibc: '>=2.28', npm: '>=9.6.5', pnpm: '>=7.1.0', yarn: '>=3.2.0'} cpu: [arm] os: [linux] + '@img/sharp-libvips-linux-arm@1.0.5': + resolution: {integrity: sha512-gvcC4ACAOPRNATg/ov8/MnbxFDJqf/pDePbBnuBDcjsI8PssmjoKMAz4LtLaVi+OnSb5FK/yIOamqDwGmXW32g==} + cpu: [arm] + os: [linux] + '@img/sharp-libvips-linux-s390x@1.0.2': resolution: {integrity: sha512-cmhQ1J4qVhfmS6szYW7RT+gLJq9dH2i4maq+qyXayUSn9/3iY2ZeWpbAgSpSVbV2E1JUL2Gg7pwnYQ1h8rQIog==} engines: {glibc: '>=2.28', npm: '>=9.6.5', pnpm: '>=7.1.0', yarn: '>=3.2.0'} cpu: [s390x] os: [linux] + '@img/sharp-libvips-linux-s390x@1.0.4': + resolution: {integrity: sha512-u7Wz6ntiSSgGSGcjZ55im6uvTrOxSIS8/dgoVMoiGE9I6JAfU50yH5BoDlYA1tcuGS7g/QNtetJnxA6QEsCVTA==} + cpu: [s390x] + os: [linux] + '@img/sharp-libvips-linux-x64@1.0.2': resolution: {integrity: sha512-E441q4Qdb+7yuyiADVi5J+44x8ctlrqn8XgkDTwr4qPJzWkaHwD489iZ4nGDgcuya4iMN3ULV6NwbhRZJ9Z7SQ==} engines: {glibc: '>=2.26', npm: '>=9.6.5', pnpm: '>=7.1.0', yarn: '>=3.2.0'} cpu: [x64] os: [linux] + '@img/sharp-libvips-linux-x64@1.0.4': + resolution: {integrity: sha512-MmWmQ3iPFZr0Iev+BAgVMb3ZyC4KeFc3jFxnNbEPas60e1cIfevbtuyf9nDGIzOaW9PdnDciJm+wFFaTlj5xYw==} + cpu: [x64] + os: [linux] + '@img/sharp-libvips-linuxmusl-arm64@1.0.2': resolution: {integrity: sha512-3CAkndNpYUrlDqkCM5qhksfE+qSIREVpyoeHIU6jd48SJZViAmznoQQLAv4hVXF7xyUB9zf+G++e2v1ABjCbEQ==} engines: {musl: '>=1.2.2', npm: '>=9.6.5', pnpm: '>=7.1.0', yarn: '>=3.2.0'} cpu: [arm64] os: [linux] + '@img/sharp-libvips-linuxmusl-arm64@1.0.4': + resolution: {integrity: sha512-9Ti+BbTYDcsbp4wfYib8Ctm1ilkugkA/uscUn6UXK1ldpC1JjiXbLfFZtRlBhjPZ5o1NCLiDbg8fhUPKStHoTA==} + cpu: [arm64] + os: [linux] + '@img/sharp-libvips-linuxmusl-x64@1.0.2': resolution: {integrity: sha512-VI94Q6khIHqHWNOh6LLdm9s2Ry4zdjWJwH56WoiJU7NTeDwyApdZZ8c+SADC8OH98KWNQXnE01UdJ9CSfZvwZw==} engines: {musl: '>=1.2.2', npm: '>=9.6.5', pnpm: '>=7.1.0', yarn: '>=3.2.0'} cpu: [x64] os: [linux] + '@img/sharp-libvips-linuxmusl-x64@1.0.4': + resolution: {integrity: sha512-viYN1KX9m+/hGkJtvYYp+CCLgnJXwiQB39damAO7WMdKWlIhmYTfHjwSbQeUK/20vY154mwezd9HflVFM1wVSw==} + cpu: [x64] + os: [linux] + '@img/sharp-linux-arm64@0.33.3': resolution: {integrity: sha512-Zf+sF1jHZJKA6Gor9hoYG2ljr4wo9cY4twaxgFDvlG0Xz9V7sinsPp8pFd1XtlhTzYo0IhDbl3rK7P6MzHpnYA==} engines: {glibc: '>=2.26', node: ^18.17.0 || ^20.3.0 || >=21.0.0, npm: '>=9.6.5', pnpm: '>=7.1.0', yarn: '>=3.2.0'} cpu: [arm64] os: [linux] + '@img/sharp-linux-arm64@0.33.5': + resolution: {integrity: sha512-JMVv+AMRyGOHtO1RFBiJy/MBsgz0x4AWrT6QoEVVTyh1E39TrCUpTRI7mx9VksGX4awWASxqCYLCV4wBZHAYxA==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [arm64] + os: [linux] + '@img/sharp-linux-arm@0.33.3': resolution: {integrity: sha512-Q7Ee3fFSC9P7vUSqVEF0zccJsZ8GiiCJYGWDdhEjdlOeS9/jdkyJ6sUSPj+bL8VuOYFSbofrW0t/86ceVhx32w==} engines: {glibc: '>=2.28', node: ^18.17.0 || ^20.3.0 || >=21.0.0, npm: '>=9.6.5', pnpm: '>=7.1.0', yarn: '>=3.2.0'} cpu: [arm] os: [linux] + '@img/sharp-linux-arm@0.33.5': + resolution: {integrity: sha512-JTS1eldqZbJxjvKaAkxhZmBqPRGmxgu+qFKSInv8moZ2AmT5Yib3EQ1c6gp493HvrvV8QgdOXdyaIBrhvFhBMQ==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [arm] + os: [linux] + '@img/sharp-linux-s390x@0.33.3': resolution: {integrity: sha512-vFk441DKRFepjhTEH20oBlFrHcLjPfI8B0pMIxGm3+yilKyYeHEVvrZhYFdqIseSclIqbQ3SnZMwEMWonY5XFA==} engines: {glibc: '>=2.28', node: ^18.17.0 || ^20.3.0 || >=21.0.0, npm: '>=9.6.5', pnpm: '>=7.1.0', yarn: '>=3.2.0'} cpu: [s390x] os: [linux] + '@img/sharp-linux-s390x@0.33.5': + resolution: {integrity: sha512-y/5PCd+mP4CA/sPDKl2961b+C9d+vPAveS33s6Z3zfASk2j5upL6fXVPZi7ztePZ5CuH+1kW8JtvxgbuXHRa4Q==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [s390x] + os: [linux] + '@img/sharp-linux-x64@0.33.3': resolution: {integrity: sha512-Q4I++herIJxJi+qmbySd072oDPRkCg/SClLEIDh5IL9h1zjhqjv82H0Seupd+q2m0yOfD+/fJnjSoDFtKiHu2g==} engines: {glibc: '>=2.26', node: ^18.17.0 || ^20.3.0 || >=21.0.0, npm: '>=9.6.5', pnpm: '>=7.1.0', yarn: '>=3.2.0'} cpu: [x64] os: [linux] + '@img/sharp-linux-x64@0.33.5': + resolution: {integrity: sha512-opC+Ok5pRNAzuvq1AG0ar+1owsu842/Ab+4qvU879ippJBHvyY5n2mxF1izXqkPYlGuP/M556uh53jRLJmzTWA==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [x64] + os: [linux] + '@img/sharp-linuxmusl-arm64@0.33.3': resolution: {integrity: sha512-qnDccehRDXadhM9PM5hLvcPRYqyFCBN31kq+ErBSZtZlsAc1U4Z85xf/RXv1qolkdu+ibw64fUDaRdktxTNP9A==} engines: {musl: '>=1.2.2', node: ^18.17.0 || ^20.3.0 || >=21.0.0, npm: '>=9.6.5', pnpm: '>=7.1.0', yarn: '>=3.2.0'} cpu: [arm64] os: [linux] + '@img/sharp-linuxmusl-arm64@0.33.5': + resolution: {integrity: sha512-XrHMZwGQGvJg2V/oRSUfSAfjfPxO+4DkiRh6p2AFjLQztWUuY/o8Mq0eMQVIY7HJ1CDQUJlxGGZRw1a5bqmd1g==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [arm64] + os: [linux] + '@img/sharp-linuxmusl-x64@0.33.3': resolution: {integrity: sha512-Jhchim8kHWIU/GZ+9poHMWRcefeaxFIs9EBqf9KtcC14Ojk6qua7ghKiPs0sbeLbLj/2IGBtDcxHyjCdYWkk2w==} engines: {musl: '>=1.2.2', node: ^18.17.0 || ^20.3.0 || >=21.0.0, npm: '>=9.6.5', pnpm: '>=7.1.0', yarn: '>=3.2.0'} cpu: [x64] os: [linux] + '@img/sharp-linuxmusl-x64@0.33.5': + resolution: {integrity: sha512-WT+d/cgqKkkKySYmqoZ8y3pxx7lx9vVejxW/W4DOFMYVSkErR+w7mf2u8m/y4+xHe7yY9DAXQMWQhpnMuFfScw==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [x64] + os: [linux] + '@img/sharp-wasm32@0.33.3': resolution: {integrity: sha512-68zivsdJ0koE96stdUfM+gmyaK/NcoSZK5dV5CAjES0FUXS9lchYt8LAB5rTbM7nlWtxaU/2GON0HVN6/ZYJAQ==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0, npm: '>=9.6.5', pnpm: '>=7.1.0', yarn: '>=3.2.0'} cpu: [wasm32] + '@img/sharp-wasm32@0.33.5': + resolution: {integrity: sha512-ykUW4LVGaMcU9lu9thv85CbRMAwfeadCJHRsg2GmeRa/cJxsVY9Rbd57JcMxBkKHag5U/x7TSBpScF4U8ElVzg==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [wasm32] + '@img/sharp-win32-ia32@0.33.3': resolution: {integrity: sha512-CyimAduT2whQD8ER4Ux7exKrtfoaUiVr7HG0zZvO0XTFn2idUWljjxv58GxNTkFb8/J9Ub9AqITGkJD6ZginxQ==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0, npm: '>=9.6.5', pnpm: '>=7.1.0', yarn: '>=3.2.0'} cpu: [ia32] os: [win32] + '@img/sharp-win32-ia32@0.33.5': + resolution: {integrity: sha512-T36PblLaTwuVJ/zw/LaH0PdZkRz5rd3SmMHX8GSmR7vtNSP5Z6bQkExdSK7xGWyxLw4sUknBuugTelgw2faBbQ==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [ia32] + os: [win32] + '@img/sharp-win32-x64@0.33.3': resolution: {integrity: sha512-viT4fUIDKnli3IfOephGnolMzhz5VaTvDRkYqtZxOMIoMQ4MrAziO7pT1nVnOt2FAm7qW5aa+CCc13aEY6Le0g==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0, npm: '>=9.6.5', pnpm: '>=7.1.0', yarn: '>=3.2.0'} cpu: [x64] os: [win32] + '@img/sharp-win32-x64@0.33.5': + resolution: {integrity: sha512-MpY/o8/8kj+EcnxwvrP4aTJSWw/aZ7JIGR4aBeZkZw5B7/Jn+tY9/VNwtcoGmdT7GfggGIU4kygOMSbYnOrAbg==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [x64] + os: [win32] + '@isaacs/cliui@8.0.2': resolution: {integrity: sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==} engines: {node: '>=12'} + '@isaacs/fs-minipass@4.0.1': + resolution: {integrity: sha512-wgm9Ehl2jpeqP3zw/7mo3kRHFp5MEDhqAdwy1fTGkHAwnkGOVsgpvQhL8B5n1qlb01jV3n/bI0ZfZp5lWA1k4w==} + engines: {node: '>=18.0.0'} + '@jridgewell/gen-mapping@0.3.5': resolution: {integrity: sha512-IzL8ZoEDIBRWEzlCcRhOaCupYyN5gdIK+Q6fbFdPDg6HqX6jpkItn7DFIpW9LQzXG6Df9sA7+OKnq0qlz/GaQg==} engines: {node: '>=6.0.0'} @@ -6853,6 +7051,11 @@ packages: '@manypkg/get-packages@1.1.3': resolution: {integrity: sha512-fo+QhuU3qE/2TQMQmbVMqaQ6EWbMhi4ABWP+O4AM1NqPBuy0OrApV5LO6BrrgnhtAHS2NH6RrVk9OL181tTi8A==} + '@mapbox/node-pre-gyp@2.0.0': + resolution: {integrity: sha512-llMXd39jtP0HpQLVI37Bf1m2ADlEb35GYSh1SDSLsBhR+5iCxiNGlT31yqbNtVHygHAtMy6dWFERpU2JgufhPg==} + engines: {node: '>=18'} + hasBin: true + '@markdoc/markdoc@0.4.0': resolution: {integrity: sha512-fSh4P3Y4E7oaKYc2oNzSIJVPDto7SMzAuQN1Iyx53UxzleA6QzRdNWRxmiPqtVDaDi5dELd2yICoG91csrGrAw==} engines: {node: '>=14.7.0'} @@ -6882,6 +7085,24 @@ packages: resolution: {integrity: sha512-9hIbusvAZjSGBJ42OyFC2AxsEph1LuKQahMWFcPGEIsOqIYHhMRkYA7wSUMhH7naydjNmllpcp3pJLOK4RhFaQ==} engines: {node: ^14.16.0 || >=16.0.0} + '@netlify/edge-functions@2.11.1': + resolution: {integrity: sha512-pyQOTZ8a+ge5lZlE+H/UAHyuqQqtL5gE0pXrHT9mOykr3YQqnkB2hZMtx12odatZ87gHg4EA+UPyMZUbLfnXvw==} + + '@netlify/edge-handler-types@0.34.1': + resolution: {integrity: sha512-YTwn8cw89M4lRTmoUhl9s8ljSGMDt7FOIsxsrx7YrRz/RZlbh4Yuh4RU13DDafDRBEVuRbjGo93cnN621ZfBjA==} + + '@netlify/functions@2.8.2': + resolution: {integrity: sha512-DeoAQh8LuNPvBE4qsKlezjKj0PyXDryOFJfJKo3Z1qZLKzQ21sT314KQKPVjfvw6knqijj+IO+0kHXy/TJiqNA==} + engines: {node: '>=14.0.0'} + + '@netlify/node-cookies@0.1.0': + resolution: {integrity: sha512-OAs1xG+FfLX0LoRASpqzVntVV/RpYkgpI0VrUnw2u0Q1qiZUzcPffxRK8HF3gc4GjuhG5ahOEMJ9bswBiZPq0g==} + engines: {node: ^14.16.0 || >=16.0.0} + + '@netlify/serverless-functions-api@1.26.1': + resolution: {integrity: sha512-q3L9i3HoNfz0SGpTIS4zTcKBbRkxzCRpd169eyiTuk3IwcPC3/85mzLHranlKo2b+HYT0gu37YxGB45aD8A3Tw==} + engines: {node: '>=18.0.0'} + '@nodelib/fs.scandir@2.1.5': resolution: {integrity: sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==} engines: {node: '>= 8'} @@ -7496,6 +7717,11 @@ packages: '@ungap/structured-clone@1.2.0': resolution: {integrity: sha512-zuVdFrMJiuCDQUMCzQaD6KL28MjnqqN8XnAqiEq9PNm/hCPTSGfrXCOfwj1ow4LFb/tNymJPwsNbVePc1xFqrQ==} + '@vercel/nft@0.29.1': + resolution: {integrity: sha512-6239JJM1V9b3OjvZIjbe+47/hGxMr44FEzlbTErrqzebCaoKAHK+yvahn3gdNacybDUbTxVF8Zuh0vqaeM8aKQ==} + engines: {node: '>=18'} + hasBin: true + '@vitejs/plugin-react@4.3.4': resolution: {integrity: sha512-SCCPBJtYLdE8PX/7ZQAs1QAZ8Jqwih+0VBLum1EGqmCCQal+MIUqLCzj3ZUy8ufbC0cAM4LRlSTm7IQJwWT4ug==} engines: {node: ^14.18.0 || >=16.0.0} @@ -7636,10 +7862,19 @@ packages: '@webcomponents/template-shadowroot@0.2.1': resolution: {integrity: sha512-fXL/vIUakyZL62hyvUh+EMwbVoTc0hksublmRz6ai6et8znHkJa6gtqMUZo1oc7dIz46exHSIImml9QTdknMHg==} + abbrev@3.0.0: + resolution: {integrity: sha512-+/kfrslGQ7TNV2ecmQwMJj/B65g5KVq1/L3SGVZ3tCYGqlzFuFCGBZJtMP99wH3NpEUyAjn0zPdPUg0D+DwrOA==} + engines: {node: ^18.17.0 || >=20.5.0} + accepts@1.3.8: resolution: {integrity: sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==} engines: {node: '>= 0.6'} + acorn-import-attributes@1.9.5: + resolution: {integrity: sha512-n02Vykv5uA3eHGM/Z2dQrcD56kL8TyDb2p1+0P83PClMnC/nc+anbQRhIOWnSq4Ke/KvDPrY3C9hDtC/A3eHnQ==} + peerDependencies: + acorn: ^8 + acorn-jsx@5.3.2: resolution: {integrity: sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==} peerDependencies: @@ -7659,6 +7894,10 @@ packages: resolution: {integrity: sha512-H0TSyFNDMomMNJQBn8wFV5YC/2eJ+VXECwOadZJT554xP6cODZHPX3H9QMQECxvrgiSOP1pHjy1sMWQVYJOUOA==} engines: {node: '>= 14'} + agent-base@7.1.3: + resolution: {integrity: sha512-jRR5wdylq8CkOe6hei19GGZnxM6rBGwFl3Bg0YItGDimvjGtAvdZk4Pu6Cl4u4Igsws4a1fd1Vq3ezrhn4KmFw==} + engines: {node: '>= 14'} + ajv@6.12.6: resolution: {integrity: sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==} @@ -7752,6 +7991,9 @@ packages: resolution: {integrity: sha512-cWMaNwUJnf37C/S5TfCkk/15MwbPRwVYALA2jtjkbHjCmAPiDXyNJy2q3p1KAZzDLHAWyarUWSujUoHR4pEgrA==} engines: {node: '>= 14'} + async-sema@3.1.1: + resolution: {integrity: sha512-tLRNUXati5MFePdAk8dw7Qt7DpxPB60ofAgn8WRhW6a2rcimZnYBP9oxHiv0OHy+Wz7kPMG+t4LGdt31+4EmGg==} + asynckit@0.4.0: resolution: {integrity: sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==} @@ -7814,6 +8056,9 @@ packages: resolution: {integrity: sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==} engines: {node: '>=8'} + bindings@1.5.0: + resolution: {integrity: sha512-p2q/t/mhvuOj/UeLlV6566GD/guowlr0hHxClI0W9m7MWYkL1F0hLo+0Aexs9HSPCtR1SXQ0TD3MMKrXZajbiQ==} + birpc@0.2.19: resolution: {integrity: sha512-5WeXXAvTmitV1RqJFppT5QtUiz2p1mRSYU000Jkft5ZUCLJIk4uQriYNO50HknxKwM6jd8utNc66K1qGIwwWBQ==} @@ -7940,6 +8185,10 @@ packages: resolution: {integrity: sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ==} engines: {node: '>=10'} + chownr@3.0.0: + resolution: {integrity: sha512-+IxzY9BZOQd/XuYPRmrvEVjF/nqj5kgT4kEq7VofrDoM1MxoRjEWkrCC3EtLi59TVawxTAn+orJwFQcrqEN1+g==} + engines: {node: '>=18'} + ci-info@3.9.0: resolution: {integrity: sha512-NIxF55hv4nSqQswkAeiOi1r83xy8JldOFDTWiug55KBu9Jnblncd2U6ViHmYgHf01TPZS77NJBhBMKdWj9HQMQ==} engines: {node: '>=8'} @@ -8640,6 +8889,9 @@ packages: resolution: {integrity: sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ==} engines: {node: '>=16.0.0'} + file-uri-to-path@1.0.0: + resolution: {integrity: sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw==} + fill-range@7.1.1: resolution: {integrity: sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==} engines: {node: '>=8'} @@ -8734,6 +8986,9 @@ packages: resolution: {integrity: sha512-V/JgOLFCS+R6Vcq0slCuaeWEdNC3ouDlJMNIsacH2VtALiu9mV4LPrHc5cDl8k5aw6J8jwgWWpiTo5RYhmIzvg==} engines: {node: '>= 8'} + fs.realpath@1.0.0: + resolution: {integrity: sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==} + fsevents@2.3.2: resolution: {integrity: sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==} engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0} @@ -8790,6 +9045,10 @@ packages: resolution: {integrity: sha512-7Bv8RF0k6xjo7d4A/PxYLbUCfb6c+Vpd2/mB2yRDlew7Jb5hEXiCD9ibfO7wpk8i4sevK6DFny9h7EYbM3/sHg==} hasBin: true + glob@7.2.3: + resolution: {integrity: sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==} + deprecated: Glob versions prior to v9 are no longer supported + globals@11.12.0: resolution: {integrity: sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==} engines: {node: '>=4'} @@ -8943,6 +9202,10 @@ packages: resolution: {integrity: sha512-wlwpilI7YdjSkWaQ/7omYBMTliDcmCN8OLihO6I9B86g06lMyAoqgoDpV0XqoaPOKj+0DIdAvnsWfyAAhmimcg==} engines: {node: '>= 14'} + https-proxy-agent@7.0.6: + resolution: {integrity: sha512-vK9P5/iUfdl95AI+JVyUuIcVtd4ofvtrOr3HNtM2yxC9bnMbEdp3x01OhQNnjb8IJYi38VlTE3mBXwcfvywuSw==} + engines: {node: '>= 14'} + human-id@1.0.2: resolution: {integrity: sha512-UNopramDEhHJD+VR+ehk8rOslwSfByxPIZyJRfV739NDhN5LF1fa1MqnzKm2lGTQRjNrjK19Q5fhkgIfjlVUKw==} @@ -8986,6 +9249,10 @@ packages: resolution: {integrity: sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==} engines: {node: '>=0.8.19'} + inflight@1.0.6: + resolution: {integrity: sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==} + deprecated: This module is not supported, and leaks memory. Do not use it. Check out lru-cache if you want a good and tested way to coalesce async requests by a key value, which is much more comprehensive and powerful. + inherits@2.0.4: resolution: {integrity: sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==} @@ -9640,6 +9907,10 @@ packages: resolution: {integrity: sha512-bAxsR8BVfj60DWXHE3u30oHzfl4G7khkSuPW+qvpd7jFRHm7dLxOjUk1EHACJ/hxLY8phGJ0YhYHZo7jil7Qdg==} engines: {node: '>= 8'} + minizlib@3.0.1: + resolution: {integrity: sha512-umcy022ILvb5/3Djuu8LWeqUa8D68JaBzlttKeMWen48SjabqS3iY5w/vzeMzMUNhLDifyhbOwKDSznB1vvrwg==} + engines: {node: '>= 18'} + mitt@3.0.1: resolution: {integrity: sha512-vKivATfr97l2/QBCYAkXYDbrIWPM2IIKEl7YPhjCvKlG3kE2gm+uBo6nEXK3M5/Ffh/FLpKExzOQ3JJoJGFKBw==} @@ -9651,6 +9922,11 @@ packages: engines: {node: '>=10'} hasBin: true + mkdirp@3.0.1: + resolution: {integrity: sha512-+NsyUUAZDmo6YVHzL/stxSu3t9YS1iljliy3BSDrXJ/dkn1KYdmtZODGGjLcc9XLgVVpH4KshHB8XmZgMhaBXg==} + engines: {node: '>=10'} + hasBin: true + mri@1.2.0: resolution: {integrity: sha512-tzzskb3bG8LvYGFF/mDTpq3jpI6Q9wc3LEmBaghu+DdCssd1FakN7Bc0hVNmEyGq1bq3RgfkCb3cmQLpNPOroA==} engines: {node: '>=4'} @@ -9747,6 +10023,11 @@ packages: node-releases@2.0.18: resolution: {integrity: sha512-d9VeXT4SJ7ZeOqGX6R5EM022wpL+eWPooLI+5UpWn2jCT1aosUQEhQP214x33Wkwx3JQMvIm+tIoVOdodFS40g==} + nopt@8.1.0: + resolution: {integrity: sha512-ieGu42u/Qsa4TFktmaKEwM6MQH0pOWnaB3htzh0JRtx84+Mebc0cbZYN5bC+6WTZ4+77xrL9Pn5m7CV6VIkV7A==} + engines: {node: ^18.17.0 || >=20.5.0} + hasBin: true + normalize-path@3.0.0: resolution: {integrity: sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==} engines: {node: '>=0.10.0'} @@ -9792,6 +10073,9 @@ packages: resolution: {integrity: sha512-y1HRYy8s/RlcBvDUwKXSmkODMdx4KSuIvloCnQYJ2LdBBC1asY4HtfhXwe3UWknLakATZDnbzht2Ijw3M1EqFg==} engines: {node: '>=9.4.0 || ^8.9.4'} + once@1.4.0: + resolution: {integrity: sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==} + onetime@5.1.2: resolution: {integrity: sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==} engines: {node: '>=6'} @@ -9929,6 +10213,10 @@ packages: resolution: {integrity: sha512-RjhtfwJOxzcFmNOi6ltcbcu4Iu+FL3zEj83dk4kAS+fVpTxXLO1b38RvJgT/0QwvV/L3aY9TAnyv0EOqW4GoMQ==} engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + path-is-absolute@1.0.1: + resolution: {integrity: sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==} + engines: {node: '>=0.10.0'} + path-key@3.1.1: resolution: {integrity: sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==} engines: {node: '>=8'} @@ -10512,6 +10800,10 @@ packages: rfdc@1.4.1: resolution: {integrity: sha512-q1b3N5QkRUWUl7iyylaaj3kOpIT0N2i9MqIEQXP73GVsN9cw3fdx8X63cEmWhJGi2PPCF23Ijp7ktmd39rawIA==} + rimraf@5.0.10: + resolution: {integrity: sha512-l0OE8wL34P4nJH/H2ffoaniAokM2qSmrtXHmlpvYr5AVVX8msAyW0l8NVJFDxlSK4u3Uh/f41cQheDVdnYijwQ==} + hasBin: true + rollup@4.34.2: resolution: {integrity: sha512-sBDUoxZEaqLu9QeNalL8v3jw6WjPku4wfZGyTU7l7m1oC+rpRihXc/n/H+4148ZkGz5Xli8CHMns//fFGKvpIQ==} engines: {node: '>=18.0.0', npm: '>=8.0.0'} @@ -10606,6 +10898,10 @@ packages: resolution: {integrity: sha512-vHUeXJU1UvlO/BNwTpT0x/r53WkLUVxrmb5JTgW92fdFCFk0ispLMAeu/jPO2vjkXM1fYUi3K7/qcLF47pwM1A==} engines: {libvips: '>=8.15.2', node: ^18.17.0 || ^20.3.0 || >=21.0.0} + sharp@0.33.5: + resolution: {integrity: sha512-haPVm1EkS9pgvHrQ/F3Xy+hgcuMV0Wm9vfIBSiwZ05k+xgb0PkBQpGsAA/oWdDobNaZTH5ppvHtzCFbnSEwHVw==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + shebang-command@2.0.0: resolution: {integrity: sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==} engines: {node: '>=8'} @@ -10862,6 +11158,10 @@ packages: resolution: {integrity: sha512-DZ4yORTwrbTj/7MZYq2w+/ZFdI6OZ/f9SFHR+71gIVUZhOQPHzVCLpvRnPgyaMpfWxxk/4ONva3GQSyNIKRv6A==} engines: {node: '>=10'} + tar@7.4.3: + resolution: {integrity: sha512-5S7Va8hKfV7W5U6g3aYxXmlPoZVAwUMy9AOKyF2fVuZa2UD3qZjg578OrLRt8PcNN1PleVaL/5/yYATNL0ICUw==} + engines: {node: '>=18'} + term-size@2.2.1: resolution: {integrity: sha512-wK0Ri4fOGjv/XPy8SBHZChl8CM7uMc5VML7SqiQ0zG7+J5Vr+RMQDoHa2CNT6KHUnTGIXH34UDMkPzAUyapBZg==} engines: {node: '>=8'} @@ -11212,6 +11512,9 @@ packages: url-parse@1.5.10: resolution: {integrity: sha512-WypcfiRhfeUP9vvF0j6rw0J3hrWrw6iZv3+22h6iRMJ/8z1Tj6XfLP4DsUix5MhMPnXpiHDoKyoZ/bdCkwBCiQ==} + urlpattern-polyfill@8.0.2: + resolution: {integrity: sha512-Qp95D4TPJl1kC9SKigDcqgyM2VDVO4RiJc2d4qe5GrYm+zbIQCWWKAFaJNQ4BhdFeDGwBmAxqJBwWSJDb9T3BQ==} + util-deprecate@1.0.2: resolution: {integrity: sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==} @@ -11567,6 +11870,9 @@ packages: resolution: {integrity: sha512-G8ura3S+3Z2G+mkgNRq8dqaFZAuxfsxpBB8OCTGRTCtp+l/v9nbFNmCUP1BZMts3G1142MsZfn6eeUKrr4PD1Q==} engines: {node: '>=18'} + wrappy@1.0.2: + resolution: {integrity: sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==} + ws@8.16.0: resolution: {integrity: sha512-HS0c//TP7Ina87TfiPUz1rQzMhHrl/SG2guqRcTOIUYD2q8uhUdNHZYJUaQ8aTGPzCh+c6oawMKW35nFl1dxyQ==} engines: {node: '>=10.0.0'} @@ -11611,6 +11917,10 @@ packages: yallist@4.0.0: resolution: {integrity: sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==} + yallist@5.0.0: + resolution: {integrity: sha512-YgvUTfwqyc7UXVMrB+SImsVYSmTS8X/tSrtdNZMImM+n7+QTriRXyXim0mBrTXNeqzVF0KWGgHPeiyViFFrNDw==} + engines: {node: '>=18'} + yaml-language-server@1.15.0: resolution: {integrity: sha512-N47AqBDCMQmh6mBLmI6oqxryHRzi33aPFPsJhYy3VTUGCdLHYjGh4FZzpUjRlphaADBBkDmnkM/++KNIOHi5Rw==} hasBin: true @@ -12515,6 +12825,11 @@ snapshots: tslib: 2.6.2 optional: true + '@emnapi/runtime@1.3.1': + dependencies: + tslib: 2.6.2 + optional: true + '@esbuild/aix-ppc64@0.24.2': optional: true @@ -12654,76 +12969,151 @@ snapshots: '@img/sharp-libvips-darwin-arm64': 1.0.2 optional: true + '@img/sharp-darwin-arm64@0.33.5': + optionalDependencies: + '@img/sharp-libvips-darwin-arm64': 1.0.4 + optional: true + '@img/sharp-darwin-x64@0.33.3': optionalDependencies: '@img/sharp-libvips-darwin-x64': 1.0.2 optional: true + '@img/sharp-darwin-x64@0.33.5': + optionalDependencies: + '@img/sharp-libvips-darwin-x64': 1.0.4 + optional: true + '@img/sharp-libvips-darwin-arm64@1.0.2': optional: true + '@img/sharp-libvips-darwin-arm64@1.0.4': + optional: true + '@img/sharp-libvips-darwin-x64@1.0.2': optional: true + '@img/sharp-libvips-darwin-x64@1.0.4': + optional: true + '@img/sharp-libvips-linux-arm64@1.0.2': optional: true + '@img/sharp-libvips-linux-arm64@1.0.4': + optional: true + '@img/sharp-libvips-linux-arm@1.0.2': optional: true + '@img/sharp-libvips-linux-arm@1.0.5': + optional: true + '@img/sharp-libvips-linux-s390x@1.0.2': optional: true + '@img/sharp-libvips-linux-s390x@1.0.4': + optional: true + '@img/sharp-libvips-linux-x64@1.0.2': optional: true + '@img/sharp-libvips-linux-x64@1.0.4': + optional: true + '@img/sharp-libvips-linuxmusl-arm64@1.0.2': optional: true + '@img/sharp-libvips-linuxmusl-arm64@1.0.4': + optional: true + '@img/sharp-libvips-linuxmusl-x64@1.0.2': optional: true + '@img/sharp-libvips-linuxmusl-x64@1.0.4': + optional: true + '@img/sharp-linux-arm64@0.33.3': optionalDependencies: '@img/sharp-libvips-linux-arm64': 1.0.2 optional: true + '@img/sharp-linux-arm64@0.33.5': + optionalDependencies: + '@img/sharp-libvips-linux-arm64': 1.0.4 + optional: true + '@img/sharp-linux-arm@0.33.3': optionalDependencies: '@img/sharp-libvips-linux-arm': 1.0.2 optional: true + '@img/sharp-linux-arm@0.33.5': + optionalDependencies: + '@img/sharp-libvips-linux-arm': 1.0.5 + optional: true + '@img/sharp-linux-s390x@0.33.3': optionalDependencies: '@img/sharp-libvips-linux-s390x': 1.0.2 optional: true + '@img/sharp-linux-s390x@0.33.5': + optionalDependencies: + '@img/sharp-libvips-linux-s390x': 1.0.4 + optional: true + '@img/sharp-linux-x64@0.33.3': optionalDependencies: '@img/sharp-libvips-linux-x64': 1.0.2 optional: true + '@img/sharp-linux-x64@0.33.5': + optionalDependencies: + '@img/sharp-libvips-linux-x64': 1.0.4 + optional: true + '@img/sharp-linuxmusl-arm64@0.33.3': optionalDependencies: '@img/sharp-libvips-linuxmusl-arm64': 1.0.2 optional: true + '@img/sharp-linuxmusl-arm64@0.33.5': + optionalDependencies: + '@img/sharp-libvips-linuxmusl-arm64': 1.0.4 + optional: true + '@img/sharp-linuxmusl-x64@0.33.3': optionalDependencies: '@img/sharp-libvips-linuxmusl-x64': 1.0.2 optional: true + '@img/sharp-linuxmusl-x64@0.33.5': + optionalDependencies: + '@img/sharp-libvips-linuxmusl-x64': 1.0.4 + optional: true + '@img/sharp-wasm32@0.33.3': dependencies: '@emnapi/runtime': 1.1.1 optional: true + '@img/sharp-wasm32@0.33.5': + dependencies: + '@emnapi/runtime': 1.3.1 + optional: true + '@img/sharp-win32-ia32@0.33.3': optional: true + '@img/sharp-win32-ia32@0.33.5': + optional: true + '@img/sharp-win32-x64@0.33.3': optional: true + '@img/sharp-win32-x64@0.33.5': + optional: true + '@isaacs/cliui@8.0.2': dependencies: string-width: 5.1.2 @@ -12733,6 +13123,10 @@ snapshots: wrap-ansi: 8.1.0 wrap-ansi-cjs: wrap-ansi@7.0.0 + '@isaacs/fs-minipass@4.0.1': + dependencies: + minipass: 7.1.2 + '@jridgewell/gen-mapping@0.3.5': dependencies: '@jridgewell/set-array': 1.2.1 @@ -12830,6 +13224,19 @@ snapshots: globby: 11.1.0 read-yaml-file: 1.1.0 + '@mapbox/node-pre-gyp@2.0.0': + dependencies: + consola: 3.2.3 + detect-libc: 2.0.3 + https-proxy-agent: 7.0.6 + node-fetch: 2.7.0 + nopt: 8.1.0 + semver: 7.7.1 + tar: 7.4.3 + transitivePeerDependencies: + - encoding + - supports-color + '@markdoc/markdoc@0.4.0(@types/react@18.3.18)(react@19.0.0)': optionalDependencies: '@types/markdown-it': 12.2.3 @@ -12875,6 +13282,23 @@ snapshots: '@netlify/blobs@8.1.0': {} + '@netlify/edge-functions@2.11.1': {} + + '@netlify/edge-handler-types@0.34.1': + dependencies: + web-streams-polyfill: 3.3.3 + + '@netlify/functions@2.8.2': + dependencies: + '@netlify/serverless-functions-api': 1.26.1 + + '@netlify/node-cookies@0.1.0': {} + + '@netlify/serverless-functions-api@1.26.1': + dependencies: + '@netlify/node-cookies': 0.1.0 + urlpattern-polyfill: 8.0.2 + '@nodelib/fs.scandir@2.1.5': dependencies: '@nodelib/fs.stat': 2.0.5 @@ -13340,7 +13764,7 @@ snapshots: '@types/sax@1.2.7': dependencies: - '@types/node': 18.19.50 + '@types/node': 22.13.1 '@types/semver@7.5.8': {} @@ -13365,7 +13789,7 @@ snapshots: '@types/ws@8.5.12': dependencies: - '@types/node': 18.19.50 + '@types/node': 22.13.1 '@types/xml2js@0.4.14': dependencies: @@ -13472,6 +13896,25 @@ snapshots: '@ungap/structured-clone@1.2.0': {} + '@vercel/nft@0.29.1(rollup@4.34.2)': + dependencies: + '@mapbox/node-pre-gyp': 2.0.0 + '@rollup/pluginutils': 5.1.4(rollup@4.34.2) + acorn: 8.14.0 + acorn-import-attributes: 1.9.5(acorn@8.14.0) + async-sema: 3.1.1 + bindings: 1.5.0 + estree-walker: 2.0.2 + glob: 7.2.3 + graceful-fs: 4.2.11 + node-gyp-build: 4.8.2 + picomatch: 4.0.2 + resolve-from: 5.0.0 + transitivePeerDependencies: + - encoding + - rollup + - supports-color + '@vitejs/plugin-react@4.3.4(vite@6.0.11(@types/node@22.13.1)(jiti@2.4.2)(lightningcss@1.29.1)(sass@1.83.4)(yaml@2.5.1))': dependencies: '@babel/core': 7.26.0 @@ -13706,11 +14149,17 @@ snapshots: '@webcomponents/template-shadowroot@0.2.1': {} + abbrev@3.0.0: {} + accepts@1.3.8: dependencies: mime-types: 2.1.35 negotiator: 0.6.3 + acorn-import-attributes@1.9.5(acorn@8.14.0): + dependencies: + acorn: 8.14.0 + acorn-jsx@5.3.2(acorn@8.14.0): dependencies: acorn: 8.14.0 @@ -13727,6 +14176,8 @@ snapshots: transitivePeerDependencies: - supports-color + agent-base@7.1.3: {} + ajv@6.12.6: dependencies: fast-deep-equal: 3.1.3 @@ -13818,6 +14269,8 @@ snapshots: async-listen@3.0.1: {} + async-sema@3.1.1: {} + asynckit@0.4.0: {} autocannon@7.15.0: @@ -13904,6 +14357,10 @@ snapshots: binary-extensions@2.3.0: {} + bindings@1.5.0: + dependencies: + file-uri-to-path: 1.0.0 + birpc@0.2.19: {} body-parser@1.20.3: @@ -14061,6 +14518,8 @@ snapshots: chownr@2.0.0: {} + chownr@3.0.0: {} + ci-info@3.9.0: {} ci-info@4.1.0: {} @@ -14693,6 +15152,8 @@ snapshots: dependencies: flat-cache: 4.0.1 + file-uri-to-path@1.0.0: {} + fill-range@7.1.1: dependencies: to-regex-range: 5.0.1 @@ -14793,6 +15254,8 @@ snapshots: dependencies: minipass: 3.3.6 + fs.realpath@1.0.0: {} + fsevents@2.3.2: optional: true @@ -14851,6 +15314,15 @@ snapshots: package-json-from-dist: 1.0.1 path-scurry: 1.11.1 + glob@7.2.3: + dependencies: + fs.realpath: 1.0.0 + inflight: 1.0.6 + inherits: 2.0.4 + minimatch: 3.1.2 + once: 1.4.0 + path-is-absolute: 1.0.1 + globals@11.12.0: {} globals@14.0.0: {} @@ -15137,6 +15609,13 @@ snapshots: transitivePeerDependencies: - supports-color + https-proxy-agent@7.0.6: + dependencies: + agent-base: 7.1.3 + debug: 4.4.0 + transitivePeerDependencies: + - supports-color + human-id@1.0.2: {} human-signals@5.0.0: {} @@ -15172,6 +15651,11 @@ snapshots: imurmurhash@0.1.4: {} + inflight@1.0.6: + dependencies: + once: 1.4.0 + wrappy: 1.0.2 + inherits@2.0.4: {} inline-style-parser@0.1.1: {} @@ -16070,12 +16554,19 @@ snapshots: minipass: 3.3.6 yallist: 4.0.0 + minizlib@3.0.1: + dependencies: + minipass: 7.1.2 + rimraf: 5.0.10 + mitt@3.0.1: {} mj-context-menu@0.6.1: {} mkdirp@1.0.4: {} + mkdirp@3.0.1: {} + mri@1.2.0: {} mrmime@2.0.0: {} @@ -16154,6 +16645,10 @@ snapshots: node-releases@2.0.18: {} + nopt@8.1.0: + dependencies: + abbrev: 3.0.0 + normalize-path@3.0.0: {} normalize-range@0.1.2: {} @@ -16191,6 +16686,10 @@ snapshots: on-net-listen@1.1.2: {} + once@1.4.0: + dependencies: + wrappy: 1.0.2 + onetime@5.1.2: dependencies: mimic-fn: 2.1.0 @@ -16336,6 +16835,8 @@ snapshots: path-exists@5.0.0: {} + path-is-absolute@1.0.1: {} + path-key@3.1.1: {} path-key@4.0.0: {} @@ -17037,6 +17538,10 @@ snapshots: rfdc@1.4.1: {} + rimraf@5.0.10: + dependencies: + glob: 10.4.5 + rollup@4.34.2: dependencies: '@types/estree': 1.0.6 @@ -17194,6 +17699,32 @@ snapshots: '@img/sharp-win32-ia32': 0.33.3 '@img/sharp-win32-x64': 0.33.3 + sharp@0.33.5: + dependencies: + color: 4.2.3 + detect-libc: 2.0.3 + semver: 7.7.1 + optionalDependencies: + '@img/sharp-darwin-arm64': 0.33.5 + '@img/sharp-darwin-x64': 0.33.5 + '@img/sharp-libvips-darwin-arm64': 1.0.4 + '@img/sharp-libvips-darwin-x64': 1.0.4 + '@img/sharp-libvips-linux-arm': 1.0.5 + '@img/sharp-libvips-linux-arm64': 1.0.4 + '@img/sharp-libvips-linux-s390x': 1.0.4 + '@img/sharp-libvips-linux-x64': 1.0.4 + '@img/sharp-libvips-linuxmusl-arm64': 1.0.4 + '@img/sharp-libvips-linuxmusl-x64': 1.0.4 + '@img/sharp-linux-arm': 0.33.5 + '@img/sharp-linux-arm64': 0.33.5 + '@img/sharp-linux-s390x': 0.33.5 + '@img/sharp-linux-x64': 0.33.5 + '@img/sharp-linuxmusl-arm64': 0.33.5 + '@img/sharp-linuxmusl-x64': 0.33.5 + '@img/sharp-wasm32': 0.33.5 + '@img/sharp-win32-ia32': 0.33.5 + '@img/sharp-win32-x64': 0.33.5 + shebang-command@2.0.0: dependencies: shebang-regex: 3.0.0 @@ -17514,6 +18045,15 @@ snapshots: mkdirp: 1.0.4 yallist: 4.0.0 + tar@7.4.3: + dependencies: + '@isaacs/fs-minipass': 4.0.1 + chownr: 3.0.0 + minipass: 7.1.2 + minizlib: 3.0.1 + mkdirp: 3.0.1 + yallist: 5.0.0 + term-size@2.2.1: {} terminal-link@3.0.0: @@ -17802,6 +18342,8 @@ snapshots: querystringify: 2.2.0 requires-port: 1.0.0 + urlpattern-polyfill@8.0.2: {} + util-deprecate@1.0.2: {} utils-merge@1.0.1: {} @@ -18181,6 +18723,8 @@ snapshots: string-width: 7.2.0 strip-ansi: 7.1.0 + wrappy@1.0.2: {} + ws@8.16.0: {} xml-name-validator@5.0.0: {} @@ -18204,6 +18748,8 @@ snapshots: yallist@4.0.0: {} + yallist@5.0.0: {} + yaml-language-server@1.15.0: dependencies: ajv: 8.17.1 From f0545d06a50f052d4f3f58445fbaa64537002fdf Mon Sep 17 00:00:00 2001 From: Matt Kane Date: Thu, 6 Feb 2025 15:42:49 +0000 Subject: [PATCH 07/22] Add Netlify support --- packages/integrations/netlify/src/index.ts | 29 ++++++++++- .../fixtures/session/astro.config.mjs | 12 +++++ .../functions/fixtures/session/netlify.toml | 6 +++ .../functions/fixtures/session/package.json | 15 ++++++ .../fixtures/session/src/actions/index.ts | 27 ++++++++++ .../fixtures/session/src/middleware.ts | 50 +++++++++++++++++++ .../fixtures/session/src/pages/api.ts | 15 ++++++ .../fixtures/session/src/pages/cart.astro | 26 ++++++++++ .../fixtures/session/src/pages/destroy.ts | 6 +++ .../fixtures/session/src/pages/index.astro | 16 ++++++ .../fixtures/session/src/pages/regenerate.ts | 6 +++ pnpm-lock.yaml | 46 ++++++++++------- 12 files changed, 235 insertions(+), 19 deletions(-) create mode 100644 packages/integrations/netlify/test/functions/fixtures/session/astro.config.mjs create mode 100644 packages/integrations/netlify/test/functions/fixtures/session/netlify.toml create mode 100644 packages/integrations/netlify/test/functions/fixtures/session/package.json create mode 100644 packages/integrations/netlify/test/functions/fixtures/session/src/actions/index.ts create mode 100644 packages/integrations/netlify/test/functions/fixtures/session/src/middleware.ts create mode 100644 packages/integrations/netlify/test/functions/fixtures/session/src/pages/api.ts create mode 100644 packages/integrations/netlify/test/functions/fixtures/session/src/pages/cart.astro create mode 100644 packages/integrations/netlify/test/functions/fixtures/session/src/pages/destroy.ts create mode 100644 packages/integrations/netlify/test/functions/fixtures/session/src/pages/index.astro create mode 100644 packages/integrations/netlify/test/functions/fixtures/session/src/pages/regenerate.ts diff --git a/packages/integrations/netlify/src/index.ts b/packages/integrations/netlify/src/index.ts index a43325cd1133..aae5f5511882 100644 --- a/packages/integrations/netlify/src/index.ts +++ b/packages/integrations/netlify/src/index.ts @@ -443,7 +443,7 @@ export default function netlifyIntegration( return { name: '@astrojs/netlify', hooks: { - 'astro:config:setup': async ({ config, updateConfig }) => { + 'astro:config:setup': async ({ config, updateConfig, logger }) => { rootDir = config.root; await cleanFunctions(); @@ -451,6 +451,32 @@ export default function netlifyIntegration( const enableImageCDN = isRunningInNetlify && (integrationConfig?.imageCDN ?? true); + let session = config.session; + + if (config.experimental.session && !session?.driver) { + logger.info( + `Configuring experimental session support using ${isRunningInNetlify ? 'Netlify Blobs' : 'filesystem storage'}`, + ); + session = isRunningInNetlify + ? { + ...session, + driver: 'netlify-blobs', + options: { + name: 'astro-sessions', + consistency: 'strong', + ...session?.options, + }, + } + : { + ...session, + driver: 'fs-lite', + options: { + base: fileURLToPath(new URL('sessions', config.cacheDir)), + ...session?.options, + }, + }; + } + updateConfig({ outDir, build: { @@ -458,6 +484,7 @@ export default function netlifyIntegration( client: outDir, server: ssrBuildDir(), }, + session, vite: { server: { watch: { diff --git a/packages/integrations/netlify/test/functions/fixtures/session/astro.config.mjs b/packages/integrations/netlify/test/functions/fixtures/session/astro.config.mjs new file mode 100644 index 000000000000..eb9b478b261f --- /dev/null +++ b/packages/integrations/netlify/test/functions/fixtures/session/astro.config.mjs @@ -0,0 +1,12 @@ +// @ts-check +import netlify from '@astrojs/netlify'; +import { defineConfig } from 'astro/config'; + +export default defineConfig({ + output: 'server', + adapter: netlify(), + site: 'http://example.com', + experimental: { + session: true + } +}); diff --git a/packages/integrations/netlify/test/functions/fixtures/session/netlify.toml b/packages/integrations/netlify/test/functions/fixtures/session/netlify.toml new file mode 100644 index 000000000000..6a29ab05d38e --- /dev/null +++ b/packages/integrations/netlify/test/functions/fixtures/session/netlify.toml @@ -0,0 +1,6 @@ +[build] +command = "pnpm run --filter @test/netlify-session... build" +publish = "dist" +[dev] +framework = "astro" +targetPort = 4321 diff --git a/packages/integrations/netlify/test/functions/fixtures/session/package.json b/packages/integrations/netlify/test/functions/fixtures/session/package.json new file mode 100644 index 000000000000..ed3de61f73ac --- /dev/null +++ b/packages/integrations/netlify/test/functions/fixtures/session/package.json @@ -0,0 +1,15 @@ +{ + "name": "@test/netlify-session", + "version": "0.0.0", + "private": true, + "dependencies": { + "@astrojs/netlify": "workspace:*" + }, + "devDependencies": { + "astro": "workspace:*" + }, + "scripts": { + "build": "astro build", + "start": "astro dev" + } +} diff --git a/packages/integrations/netlify/test/functions/fixtures/session/src/actions/index.ts b/packages/integrations/netlify/test/functions/fixtures/session/src/actions/index.ts new file mode 100644 index 000000000000..33ac1cb653fb --- /dev/null +++ b/packages/integrations/netlify/test/functions/fixtures/session/src/actions/index.ts @@ -0,0 +1,27 @@ +import { defineAction } from 'astro:actions'; +import { z } from 'astro:schema'; + +export const server = { + addToCart: defineAction({ + accept: 'form', + input: z.object({ productId: z.string() }), + handler: async (input, context) => { + const cart: Array = (await context.session.get('cart')) || []; + cart.push(input.productId); + await context.session.set('cart', cart); + return { cart, message: 'Product added to cart at ' + new Date().toTimeString() }; + }, + }), + getCart: defineAction({ + handler: async (input, context) => { + return await context.session.get('cart'); + }, + }), + clearCart: defineAction({ + accept: 'json', + handler: async (input, context) => { + await context.session.set('cart', []); + return {cart: [], message: 'Cart cleared at ' + new Date().toTimeString() }; + }, + }), +}; diff --git a/packages/integrations/netlify/test/functions/fixtures/session/src/middleware.ts b/packages/integrations/netlify/test/functions/fixtures/session/src/middleware.ts new file mode 100644 index 000000000000..05a9f40b6788 --- /dev/null +++ b/packages/integrations/netlify/test/functions/fixtures/session/src/middleware.ts @@ -0,0 +1,50 @@ +import { defineMiddleware } from 'astro:middleware'; +import { getActionContext } from 'astro:actions'; + +const ACTION_SESSION_KEY = 'actionResult' + +export const onRequest = defineMiddleware(async (context, next) => { + console.log("Deno" in globalThis ? "Deno" : "Node.js"); + // Skip requests for prerendered pages + if (context.isPrerendered) return next(); + + const { action, setActionResult, serializeActionResult } = + getActionContext(context); + + console.log(action?.name) + + const actionPayload = await context.session.get(ACTION_SESSION_KEY); + console.log({actionPayload}) + if (actionPayload) { + setActionResult(actionPayload.actionName, actionPayload.actionResult); + context.session.delete(ACTION_SESSION_KEY); + return next(); + } + + // If an action was called from an HTML form action, + // call the action handler and redirect to the destination page + if (action?.calledFrom === "form") { + const actionResult = await action.handler(); + + context.session.set(ACTION_SESSION_KEY, { + actionName: action.name, + actionResult: serializeActionResult(actionResult), + }); + + + // Redirect back to the previous page on error + if (actionResult.error) { + const referer = context.request.headers.get("Referer"); + if (!referer) { + throw new Error( + "Internal: Referer unexpectedly missing from Action POST request.", + ); + } + return context.redirect(referer); + } + // Redirect to the destination page on success + return context.redirect(context.originPathname); + } + + return next(); +}); diff --git a/packages/integrations/netlify/test/functions/fixtures/session/src/pages/api.ts b/packages/integrations/netlify/test/functions/fixtures/session/src/pages/api.ts new file mode 100644 index 000000000000..77d50625aab1 --- /dev/null +++ b/packages/integrations/netlify/test/functions/fixtures/session/src/pages/api.ts @@ -0,0 +1,15 @@ +import type { APIRoute } from 'astro'; + +export const prerender = false; + +export const GET: APIRoute = async (context) => { + const url = new URL(context.url, 'http://localhost'); + let value = url.searchParams.get('set'); + if (value) { + context.session.set('value', value); + } else { + value = await context.session.get('value'); + } + const cart = await context.session.get('cart'); + return Response.json({ value, cart }); +}; diff --git a/packages/integrations/netlify/test/functions/fixtures/session/src/pages/cart.astro b/packages/integrations/netlify/test/functions/fixtures/session/src/pages/cart.astro new file mode 100644 index 000000000000..aebd27c42ae6 --- /dev/null +++ b/packages/integrations/netlify/test/functions/fixtures/session/src/pages/cart.astro @@ -0,0 +1,26 @@ +--- +import { actions } from "astro:actions"; + +const result = Astro.getActionResult(actions.addToCart); +const start = Date.now(); +const cart = result?.data?.cart ?? await Astro.session.get('cart'); +const end = Date.now(); +const message = result?.data?.message ?? 'Add something to your cart!'; +--- +

Cart: {JSON.stringify(cart)}

+

Time taken: {end - start}ms

+

{message}

+
+ + +
+ + diff --git a/packages/integrations/netlify/test/functions/fixtures/session/src/pages/destroy.ts b/packages/integrations/netlify/test/functions/fixtures/session/src/pages/destroy.ts new file mode 100644 index 000000000000..e83f6e4b6c31 --- /dev/null +++ b/packages/integrations/netlify/test/functions/fixtures/session/src/pages/destroy.ts @@ -0,0 +1,6 @@ +import type { APIRoute } from 'astro'; + +export const GET: APIRoute = async (context) => { + await context.session.destroy(); + return Response.json({}); +}; diff --git a/packages/integrations/netlify/test/functions/fixtures/session/src/pages/index.astro b/packages/integrations/netlify/test/functions/fixtures/session/src/pages/index.astro new file mode 100644 index 000000000000..a85d55c39dac --- /dev/null +++ b/packages/integrations/netlify/test/functions/fixtures/session/src/pages/index.astro @@ -0,0 +1,16 @@ +--- +const start = performance.now(); +const value = await Astro.session.get('value'); +const end = performance.now(); +--- + + + + Hi + + +

Hi

+

{value}

+

Time taken: {end - start}ms

+🛒 + diff --git a/packages/integrations/netlify/test/functions/fixtures/session/src/pages/regenerate.ts b/packages/integrations/netlify/test/functions/fixtures/session/src/pages/regenerate.ts new file mode 100644 index 000000000000..6f2240588e4f --- /dev/null +++ b/packages/integrations/netlify/test/functions/fixtures/session/src/pages/regenerate.ts @@ -0,0 +1,6 @@ +import type { APIRoute } from 'astro'; + +export const GET: APIRoute = async (context) => { + await context.session.regenerate(); + return Response.json({}); +}; diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index a2a39d44256b..8de9bece1123 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -5026,7 +5026,7 @@ importers: specifier: ^22.10.6 version: 22.13.1 astro: - specifier: ^5.1.6 + specifier: workspace:* version: link:../../astro astro-scripts: specifier: workspace:* @@ -5068,13 +5068,23 @@ importers: specifier: 'workspace:' version: link:../../../.. + packages/integrations/netlify/test/functions/fixtures/session: + dependencies: + '@astrojs/netlify': + specifier: workspace:* + version: link:../../../.. + devDependencies: + astro: + specifier: workspace:* + version: link:../../../../../../astro + packages/integrations/netlify/test/hosted/hosted-astro-project: dependencies: '@astrojs/netlify': specifier: workspace:* version: link:../../.. astro: - specifier: ^5.1.6 + specifier: workspace:* version: link:../../../../../astro packages/integrations/netlify/test/static/fixtures/redirects: @@ -5102,7 +5112,7 @@ importers: specifier: ^1.0.4 version: 1.0.4 astro: - specifier: ^5.1.6 + specifier: workspace:* version: link:../../astro astro-scripts: specifier: workspace:* @@ -5123,7 +5133,7 @@ importers: specifier: workspace:* version: link:../../.. astro: - specifier: ^5.1.6 + specifier: workspace:* version: link:../../../../../astro packages/integrations/node/test/fixtures/bad-urls: @@ -5132,7 +5142,7 @@ importers: specifier: workspace:* version: link:../../.. astro: - specifier: ^5.1.6 + specifier: workspace:* version: link:../../../../../astro packages/integrations/node/test/fixtures/encoded: @@ -5141,7 +5151,7 @@ importers: specifier: workspace:* version: link:../../.. astro: - specifier: ^5.1.6 + specifier: workspace:* version: link:../../../../../astro packages/integrations/node/test/fixtures/errors: @@ -5150,7 +5160,7 @@ importers: specifier: workspace:* version: link:../../.. astro: - specifier: ^5.1.6 + specifier: workspace:* version: link:../../../../../astro packages/integrations/node/test/fixtures/headers: @@ -5159,7 +5169,7 @@ importers: specifier: workspace:* version: link:../../.. astro: - specifier: ^5.1.6 + specifier: workspace:* version: link:../../../../../astro packages/integrations/node/test/fixtures/image: @@ -5168,7 +5178,7 @@ importers: specifier: workspace:* version: link:../../.. astro: - specifier: ^5.1.6 + specifier: workspace:* version: link:../../../../../astro packages/integrations/node/test/fixtures/locals: @@ -5177,7 +5187,7 @@ importers: specifier: workspace:* version: link:../../.. astro: - specifier: ^5.1.6 + specifier: workspace:* version: link:../../../../../astro packages/integrations/node/test/fixtures/node-middleware: @@ -5186,7 +5196,7 @@ importers: specifier: workspace:* version: link:../../.. astro: - specifier: ^5.1.6 + specifier: workspace:* version: link:../../../../../astro packages/integrations/node/test/fixtures/prerender: @@ -5195,7 +5205,7 @@ importers: specifier: workspace:* version: link:../../.. astro: - specifier: ^5.1.6 + specifier: workspace:* version: link:../../../../../astro packages/integrations/node/test/fixtures/prerender-404-500: @@ -5204,7 +5214,7 @@ importers: specifier: workspace:* version: link:../../.. astro: - specifier: ^5.1.6 + specifier: workspace:* version: link:../../../../../astro packages/integrations/node/test/fixtures/preview-headers: @@ -5213,7 +5223,7 @@ importers: specifier: workspace:* version: link:../../.. astro: - specifier: ^5.1.6 + specifier: workspace:* version: link:../../../../../astro packages/integrations/node/test/fixtures/session: @@ -5222,7 +5232,7 @@ importers: specifier: workspace:* version: link:../../.. astro: - specifier: ^5.1.6 + specifier: workspace:* version: link:../../../../../astro packages/integrations/node/test/fixtures/trailing-slash: @@ -5231,7 +5241,7 @@ importers: specifier: workspace:* version: link:../../.. astro: - specifier: ^5.1.6 + specifier: workspace:* version: link:../../../../../astro packages/integrations/node/test/fixtures/url: @@ -5240,7 +5250,7 @@ importers: specifier: workspace:* version: link:../../.. astro: - specifier: ^5.1.6 + specifier: workspace:* version: link:../../../../../astro packages/integrations/node/test/fixtures/well-known-locations: @@ -5249,7 +5259,7 @@ importers: specifier: workspace:* version: link:../../.. astro: - specifier: ^5.1.6 + specifier: workspace:* version: link:../../../../../astro packages/integrations/partytown: From 680f9288759e6553b780b6453ac311cb7173e791 Mon Sep 17 00:00:00 2001 From: Matt Kane Date: Thu, 6 Feb 2025 15:44:40 +0000 Subject: [PATCH 08/22] Use workspace Astro version --- packages/integrations/netlify/package.json | 6 +++--- .../netlify/test/hosted/hosted-astro-project/package.json | 2 +- packages/integrations/node/package.json | 2 +- .../integrations/node/test/fixtures/api-route/package.json | 2 +- .../integrations/node/test/fixtures/bad-urls/package.json | 2 +- .../integrations/node/test/fixtures/encoded/package.json | 2 +- .../integrations/node/test/fixtures/errors/package.json | 2 +- .../integrations/node/test/fixtures/headers/package.json | 2 +- packages/integrations/node/test/fixtures/image/package.json | 4 ++-- .../integrations/node/test/fixtures/locals/package.json | 2 +- .../node/test/fixtures/node-middleware/package.json | 2 +- .../node/test/fixtures/prerender-404-500/package.json | 2 +- .../integrations/node/test/fixtures/prerender/package.json | 2 +- .../node/test/fixtures/preview-headers/package.json | 2 +- .../integrations/node/test/fixtures/session/package.json | 4 ++-- .../node/test/fixtures/trailing-slash/package.json | 2 +- packages/integrations/node/test/fixtures/url/package.json | 2 +- .../node/test/fixtures/well-known-locations/package.json | 2 +- pnpm-lock.yaml | 4 ++-- 19 files changed, 24 insertions(+), 24 deletions(-) diff --git a/packages/integrations/netlify/package.json b/packages/integrations/netlify/package.json index 4fdd0fa90a49..562c24e9d5fd 100644 --- a/packages/integrations/netlify/package.json +++ b/packages/integrations/netlify/package.json @@ -36,8 +36,8 @@ "test:hosted": "astro-scripts test \"test/hosted/*.test.js\"" }, "dependencies": { - "@astrojs/internal-helpers": "0.5.1", - "@astrojs/underscore-redirects": "^0.6.0", + "@astrojs/internal-helpers": "workspace:*", + "@astrojs/underscore-redirects": "workspace:*", "@netlify/functions": "^2.8.0", "@vercel/nft": "^0.29.0", "esbuild": "^0.24.0", @@ -50,7 +50,7 @@ "@netlify/edge-functions": "^2.11.1", "@netlify/edge-handler-types": "^0.34.1", "@types/node": "^22.10.6", - "astro": "^5.1.6", + "astro": "workspace:*", "astro-scripts": "workspace:*", "cheerio": "1.0.0", "execa": "^8.0.1", diff --git a/packages/integrations/netlify/test/hosted/hosted-astro-project/package.json b/packages/integrations/netlify/test/hosted/hosted-astro-project/package.json index 69914a8dbe00..0624ca789481 100644 --- a/packages/integrations/netlify/test/hosted/hosted-astro-project/package.json +++ b/packages/integrations/netlify/test/hosted/hosted-astro-project/package.json @@ -7,6 +7,6 @@ }, "dependencies": { "@astrojs/netlify": "workspace:*", - "astro": "^5.1.6" + "astro": "workspace:*" } } diff --git a/packages/integrations/node/package.json b/packages/integrations/node/package.json index 874945614064..0aa7aa791c0b 100644 --- a/packages/integrations/node/package.json +++ b/packages/integrations/node/package.json @@ -41,7 +41,7 @@ "@types/node": "^22.10.6", "@types/send": "^0.17.4", "@types/server-destroy": "^1.0.4", - "astro": "^5.1.6", + "astro": "workspace:*", "astro-scripts": "workspace:*", "cheerio": "1.0.0", "express": "^4.21.2", diff --git a/packages/integrations/node/test/fixtures/api-route/package.json b/packages/integrations/node/test/fixtures/api-route/package.json index d2a97c8c7e4d..3fdb79cfea50 100644 --- a/packages/integrations/node/test/fixtures/api-route/package.json +++ b/packages/integrations/node/test/fixtures/api-route/package.json @@ -4,6 +4,6 @@ "private": true, "dependencies": { "@astrojs/node": "workspace:*", - "astro": "^5.1.6" + "astro": "workspace:*" } } diff --git a/packages/integrations/node/test/fixtures/bad-urls/package.json b/packages/integrations/node/test/fixtures/bad-urls/package.json index 14525a047955..8769aab8f8a0 100644 --- a/packages/integrations/node/test/fixtures/bad-urls/package.json +++ b/packages/integrations/node/test/fixtures/bad-urls/package.json @@ -4,6 +4,6 @@ "private": true, "dependencies": { "@astrojs/node": "workspace:*", - "astro": "^5.1.6" + "astro": "workspace:*" } } diff --git a/packages/integrations/node/test/fixtures/encoded/package.json b/packages/integrations/node/test/fixtures/encoded/package.json index 53dc0855f91d..53eb38989b70 100644 --- a/packages/integrations/node/test/fixtures/encoded/package.json +++ b/packages/integrations/node/test/fixtures/encoded/package.json @@ -4,6 +4,6 @@ "private": true, "dependencies": { "@astrojs/node": "workspace:*", - "astro": "^5.1.6" + "astro": "workspace:*" } } diff --git a/packages/integrations/node/test/fixtures/errors/package.json b/packages/integrations/node/test/fixtures/errors/package.json index 9ba94b5af8ce..427e6f723540 100644 --- a/packages/integrations/node/test/fixtures/errors/package.json +++ b/packages/integrations/node/test/fixtures/errors/package.json @@ -4,6 +4,6 @@ "private": true, "dependencies": { "@astrojs/node": "workspace:*", - "astro": "^5.1.6" + "astro": "workspace:*" } } diff --git a/packages/integrations/node/test/fixtures/headers/package.json b/packages/integrations/node/test/fixtures/headers/package.json index 8746f772b312..3a663d06267b 100644 --- a/packages/integrations/node/test/fixtures/headers/package.json +++ b/packages/integrations/node/test/fixtures/headers/package.json @@ -4,6 +4,6 @@ "private": true, "dependencies": { "@astrojs/node": "workspace:*", - "astro": "^5.1.6" + "astro": "workspace:*" } } diff --git a/packages/integrations/node/test/fixtures/image/package.json b/packages/integrations/node/test/fixtures/image/package.json index 8e4407688167..e21388c8a88a 100644 --- a/packages/integrations/node/test/fixtures/image/package.json +++ b/packages/integrations/node/test/fixtures/image/package.json @@ -4,7 +4,7 @@ "private": true, "dependencies": { "@astrojs/node": "workspace:*", - "astro": "^5.1.6" + "astro": "workspace:*" }, "peerDependencies": { "sharp": "^0.33.5" @@ -13,4 +13,4 @@ "build": "astro build", "preview": "astro preview" } -} \ No newline at end of file +} diff --git a/packages/integrations/node/test/fixtures/locals/package.json b/packages/integrations/node/test/fixtures/locals/package.json index db854caac6ee..1591b3f30e43 100644 --- a/packages/integrations/node/test/fixtures/locals/package.json +++ b/packages/integrations/node/test/fixtures/locals/package.json @@ -4,6 +4,6 @@ "private": true, "dependencies": { "@astrojs/node": "workspace:*", - "astro": "^5.1.6" + "astro": "workspace:*" } } diff --git a/packages/integrations/node/test/fixtures/node-middleware/package.json b/packages/integrations/node/test/fixtures/node-middleware/package.json index 336e69fefe32..22ea418698ba 100644 --- a/packages/integrations/node/test/fixtures/node-middleware/package.json +++ b/packages/integrations/node/test/fixtures/node-middleware/package.json @@ -4,6 +4,6 @@ "private": true, "dependencies": { "@astrojs/node": "workspace:*", - "astro": "^5.1.6" + "astro": "workspace:*" } } diff --git a/packages/integrations/node/test/fixtures/prerender-404-500/package.json b/packages/integrations/node/test/fixtures/prerender-404-500/package.json index 61d70fbb9316..6b8433d59ed1 100644 --- a/packages/integrations/node/test/fixtures/prerender-404-500/package.json +++ b/packages/integrations/node/test/fixtures/prerender-404-500/package.json @@ -5,6 +5,6 @@ "type": "module", "dependencies": { "@astrojs/node": "workspace:*", - "astro": "^5.1.6" + "astro": "workspace:*" } } diff --git a/packages/integrations/node/test/fixtures/prerender/package.json b/packages/integrations/node/test/fixtures/prerender/package.json index f0e873151ac6..0c1fa7d3e8d4 100644 --- a/packages/integrations/node/test/fixtures/prerender/package.json +++ b/packages/integrations/node/test/fixtures/prerender/package.json @@ -4,6 +4,6 @@ "private": true, "dependencies": { "@astrojs/node": "workspace:*", - "astro": "^5.1.6" + "astro": "workspace:*" } } diff --git a/packages/integrations/node/test/fixtures/preview-headers/package.json b/packages/integrations/node/test/fixtures/preview-headers/package.json index 0764f2581a52..cee2f790fb50 100644 --- a/packages/integrations/node/test/fixtures/preview-headers/package.json +++ b/packages/integrations/node/test/fixtures/preview-headers/package.json @@ -4,6 +4,6 @@ "private": true, "dependencies": { "@astrojs/node": "workspace:*", - "astro": "^5.1.6" + "astro": "workspace:*" } } diff --git a/packages/integrations/node/test/fixtures/session/package.json b/packages/integrations/node/test/fixtures/session/package.json index 423f348b87d7..e796bf33a2b4 100644 --- a/packages/integrations/node/test/fixtures/session/package.json +++ b/packages/integrations/node/test/fixtures/session/package.json @@ -4,6 +4,6 @@ "private": true, "dependencies": { "@astrojs/node": "workspace:*", - "astro": "^5.1.6" + "astro": "workspace:*" } -} \ No newline at end of file +} diff --git a/packages/integrations/node/test/fixtures/trailing-slash/package.json b/packages/integrations/node/test/fixtures/trailing-slash/package.json index 69a1b92c4d44..e8e15f58e1d3 100644 --- a/packages/integrations/node/test/fixtures/trailing-slash/package.json +++ b/packages/integrations/node/test/fixtures/trailing-slash/package.json @@ -4,6 +4,6 @@ "private": true, "dependencies": { "@astrojs/node": "workspace:*", - "astro": "^5.1.6" + "astro": "workspace:*" } } diff --git a/packages/integrations/node/test/fixtures/url/package.json b/packages/integrations/node/test/fixtures/url/package.json index 07145a8cb28f..e9bc15a3e66d 100644 --- a/packages/integrations/node/test/fixtures/url/package.json +++ b/packages/integrations/node/test/fixtures/url/package.json @@ -4,6 +4,6 @@ "private": true, "dependencies": { "@astrojs/node": "workspace:*", - "astro": "^5.1.6" + "astro": "workspace:*" } } diff --git a/packages/integrations/node/test/fixtures/well-known-locations/package.json b/packages/integrations/node/test/fixtures/well-known-locations/package.json index 3a8a66de78d0..9182445aa7ba 100644 --- a/packages/integrations/node/test/fixtures/well-known-locations/package.json +++ b/packages/integrations/node/test/fixtures/well-known-locations/package.json @@ -4,6 +4,6 @@ "private": true, "dependencies": { "@astrojs/node": "workspace:*", - "astro": "^5.1.6" + "astro": "workspace:*" } } diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 8de9bece1123..902e002983c9 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -4998,10 +4998,10 @@ importers: packages/integrations/netlify: dependencies: '@astrojs/internal-helpers': - specifier: 0.5.1 + specifier: workspace:* version: link:../../internal-helpers '@astrojs/underscore-redirects': - specifier: ^0.6.0 + specifier: workspace:* version: link:../../underscore-redirects '@netlify/functions': specifier: ^2.8.0 From bb76d36e171ccbd1cf32fd324fa9c804e740db7a Mon Sep 17 00:00:00 2001 From: Matt Kane Date: Thu, 6 Feb 2025 15:46:55 +0000 Subject: [PATCH 09/22] Format --- .../astro/src/core/build/plugins/plugin-manifest.ts | 4 +--- packages/astro/src/core/errors/errors-data.ts | 6 ++---- packages/astro/src/core/session.ts | 2 +- packages/astro/src/integrations/hooks.ts | 2 +- packages/astro/src/types/public/config.ts | 2 +- packages/astro/src/vite-plugin-astro-server/plugin.ts | 2 +- packages/astro/test/sessions.test.js | 10 ++++------ packages/integrations/node/src/index.ts | 2 +- packages/integrations/node/test/errors.test.js | 3 --- 9 files changed, 12 insertions(+), 21 deletions(-) diff --git a/packages/astro/src/core/build/plugins/plugin-manifest.ts b/packages/astro/src/core/build/plugins/plugin-manifest.ts index d2e4d988e5be..f051b128771d 100644 --- a/packages/astro/src/core/build/plugins/plugin-manifest.ts +++ b/packages/astro/src/core/build/plugins/plugin-manifest.ts @@ -54,9 +54,7 @@ function vitePluginManifest(options: StaticBuildOptions, internals: BuildInterna `import { _privateSetManifestDontUseThis } from 'astro:ssr-manifest'`, ]; - const resolvedDriver = await resolveSessionDriver( - options.settings.config.session?.driver, - ); + const resolvedDriver = await resolveSessionDriver(options.settings.config.session?.driver); const contents = [ `const manifest = _deserializeManifest('${manifestReplace}');`, diff --git a/packages/astro/src/core/errors/errors-data.ts b/packages/astro/src/core/errors/errors-data.ts index 09d2d51b3d74..56d36bc4cde7 100644 --- a/packages/astro/src/core/errors/errors-data.ts +++ b/packages/astro/src/core/errors/errors-data.ts @@ -1806,7 +1806,6 @@ export const ActionCalledFromServerError = { // Generic catch-all - Only use this in extreme cases, like if there was a cosmic ray bit flip. export const UnknownError = { name: 'UnknownError', title: 'Unknown Error.' } satisfies ErrorData; - /** * @docs * @kind heading @@ -1871,7 +1870,8 @@ export const SessionStorageSaveError = { export const SessionConfigMissingError = { name: 'SessionConfigMissingError', title: 'Session storage was enabled but not configured.', - message: 'The `experimental.session` flag was set to `true`, but no storage was configured. Either configure the storage manually or use an adapter that provides session storage', + message: + 'The `experimental.session` flag was set to `true`, but no storage was configured. Either configure the storage manually or use an adapter that provides session storage', hint: 'See https://docs.astro.build/en/reference/experimental-flags/sessions/', } satisfies ErrorData; @@ -1890,8 +1890,6 @@ export const SessionConfigWithoutFlagError = { hint: 'See https://docs.astro.build/en/reference/experimental-flags/sessions/', } satisfies ErrorData; - - /* * Adding an error? Follow these steps: * 1. Determine in which category it belongs (Astro, Vite, CSS, Content Collections etc.) diff --git a/packages/astro/src/core/session.ts b/packages/astro/src/core/session.ts index 68b9b43f5912..57e653bcd3cb 100644 --- a/packages/astro/src/core/session.ts +++ b/packages/astro/src/core/session.ts @@ -6,6 +6,7 @@ import { builtinDrivers, createStorage, } from 'unstorage'; +import type { AstroSettings } from '../types/astro.js'; import type { ResolvedSessionConfig, SessionConfig, @@ -21,7 +22,6 @@ import { SessionWithoutServerOutputError, } from './errors/errors-data.js'; import { AstroError } from './errors/index.js'; -import type { AstroSettings } from '../types/astro.js'; export const PERSIST_SYMBOL = Symbol(); diff --git a/packages/astro/src/integrations/hooks.ts b/packages/astro/src/integrations/hooks.ts index affc84685703..4e391e247fbb 100644 --- a/packages/astro/src/integrations/hooks.ts +++ b/packages/astro/src/integrations/hooks.ts @@ -14,6 +14,7 @@ import { buildClientDirectiveEntrypoint } from '../core/client-directive/index.j import { mergeConfig } from '../core/config/index.js'; import { validateSetAdapter } from '../core/dev/adapter-validation.js'; import type { AstroIntegrationLogger, Logger } from '../core/logger/core.js'; +import { validateSessionConfig } from '../core/session.js'; import type { AstroSettings } from '../types/astro.js'; import type { AstroConfig } from '../types/public/config.js'; import type { @@ -32,7 +33,6 @@ import type { } from '../types/public/integrations.js'; import type { RouteData } from '../types/public/internal.js'; import { validateSupportedFeatures } from './features-validation.js'; -import { validateSessionConfig } from '../core/session.js'; async function withTakingALongTimeMsg({ name, diff --git a/packages/astro/src/types/public/config.ts b/packages/astro/src/types/public/config.ts index 2cb0470ef712..3b4711e48d64 100644 --- a/packages/astro/src/types/public/config.ts +++ b/packages/astro/src/types/public/config.ts @@ -1736,7 +1736,7 @@ export interface ViteUserConfig extends OriginalViteUserConfig { * Some adapters may provide a default session driver, but you can override it with your own configuration. * * You can specify [any driver from Unstorage](https://unstorage.unjs.io/drivers) or provide a custom config which will override your adapter's default. - * + * * See [the experimental session guide](https://docs.astro.build/en/reference/experimental-flags/sessions/) for more information. * * ```js title="astro.config.mjs" diff --git a/packages/astro/src/vite-plugin-astro-server/plugin.ts b/packages/astro/src/vite-plugin-astro-server/plugin.ts index cdbaefea11b8..42146d856a5c 100644 --- a/packages/astro/src/vite-plugin-astro-server/plugin.ts +++ b/packages/astro/src/vite-plugin-astro-server/plugin.ts @@ -203,6 +203,6 @@ export function createDevelopmentManifest(settings: AstroSettings): SSRManifest onRequest: NOOP_MIDDLEWARE_FN, }; }, - sessionConfig: settings.config.experimental.session ? settings.config.session : undefined + sessionConfig: settings.config.experimental.session ? settings.config.session : undefined, }; } diff --git a/packages/astro/test/sessions.test.js b/packages/astro/test/sessions.test.js index 3be975fbd042..1cbfae6e84e3 100644 --- a/packages/astro/test/sessions.test.js +++ b/packages/astro/test/sessions.test.js @@ -1,5 +1,5 @@ import assert from 'node:assert/strict'; -import { before, after, describe, it } from 'node:test'; +import { after, before, describe, it } from 'node:test'; import * as devalue from 'devalue'; import testAdapter from './test-adapter.js'; import { loadFixture } from './test-utils.js'; @@ -25,7 +25,7 @@ describe('Astro.session', () => { }); /** @type {import('../src/core/app/index').App} response */ - let app + let app; before(async () => { await fixture.build({}); app = await fixture.loadTestAdapterApp(); @@ -104,7 +104,7 @@ describe('Astro.session', () => { describe('Development', () => { /** @type {import('./test-utils').Fixture} */ let fixture; - let devServer + let devServer; before(async () => { fixture = await loadFixture({ root: './fixtures/sessions/', @@ -119,7 +119,6 @@ describe('Astro.session', () => { }, }); devServer = await fixture.startDevServer(); - }); after(async () => { @@ -192,8 +191,7 @@ describe('Astro.session', () => { 'Favorite URL set to https://example.com/ from https://domain.invalid/', ); }); - - }) + }); describe('Configuration', () => { it('throws if flag is enabled but driver is not set', async () => { diff --git a/packages/integrations/node/src/index.ts b/packages/integrations/node/src/index.ts index 6660f446fb02..a5dccc0c3ced 100644 --- a/packages/integrations/node/src/index.ts +++ b/packages/integrations/node/src/index.ts @@ -1,7 +1,7 @@ +import { fileURLToPath } from 'node:url'; import type { AstroAdapter, AstroIntegration } from 'astro'; import { AstroError } from 'astro/errors'; import type { Options, UserOptions } from './types.js'; -import { fileURLToPath } from 'node:url'; export function getAdapter(options: Options): AstroAdapter { return { diff --git a/packages/integrations/node/test/errors.test.js b/packages/integrations/node/test/errors.test.js index 69ae1ec5c78d..feec4ed9e8c0 100644 --- a/packages/integrations/node/test/errors.test.js +++ b/packages/integrations/node/test/errors.test.js @@ -76,9 +76,6 @@ describe('Errors', () => { const chunk2 = await reader.read(); const chunk3 = await reader.read(); assert.equal(chunk1.done, false); - console.log(chunk1); - console.log(chunk2); - console.log(chunk3); if (chunk2.done) { assert.equal(decoder.decode(chunk1.value), result.join('')); } else if (chunk3.done) { From be1e2374682eb8d724bca674f562ed58373fcdc7 Mon Sep 17 00:00:00 2001 From: Matt Kane Date: Thu, 6 Feb 2025 15:48:40 +0000 Subject: [PATCH 10/22] Changeset --- .changeset/cool-deers-join.md | 6 ++++++ 1 file changed, 6 insertions(+) create mode 100644 .changeset/cool-deers-join.md diff --git a/.changeset/cool-deers-join.md b/.changeset/cool-deers-join.md new file mode 100644 index 000000000000..74d7f33dbe82 --- /dev/null +++ b/.changeset/cool-deers-join.md @@ -0,0 +1,6 @@ +--- +'@astrojs/netlify': patch +'@astrojs/node': patch +--- + +Automatically configures experimental sessions when enabled From e422b63a39617ce0ec396d128f53eeee01635913 Mon Sep 17 00:00:00 2001 From: Matt Kane Date: Fri, 7 Feb 2025 11:54:57 +0000 Subject: [PATCH 11/22] Add tests --- .../astro/test/fixtures/sessions/package.json | 1 - .../test/fixtures/sessions/tsconfig.json | 11 - packages/integrations/netlify/package.json | 1 + .../functions/fixtures/session/netlify.toml | 6 - .../{session => sessions}/astro.config.mjs | 5 +- .../{session => sessions}/package.json | 0 .../fixtures/sessions}/src/actions/index.ts | 13 +- .../{session => sessions}/src/middleware.ts | 3 +- .../{session => sessions}/src/pages/api.ts | 2 - .../src/pages/cart.astro | 4 +- .../src/pages/destroy.ts | 0 .../fixtures/sessions}/src/pages/index.astro | 3 - .../src/pages/regenerate.ts | 0 .../fixtures/sessions/src/pages/update.ts | 10 + .../netlify/test/functions/sessions.test.js | 129 +++++++ .../test/fixtures/session/astro.config.mjs | 11 - .../test/fixtures/sessions/astro.config.mjs | 6 + .../{session => sessions}/package.json | 2 +- .../fixtures/sessions}/src/actions/index.ts | 13 +- .../{session => sessions}/src/middleware.ts | 3 +- .../{session => sessions}/src/pages/api.ts | 2 - .../src/pages/cart.astro | 10 +- .../src/pages/destroy.ts | 0 .../fixtures/sessions}/src/pages/index.astro | 3 - .../src/pages/regenerate.ts | 0 .../fixtures/sessions/src/pages/update.ts | 10 + .../integrations/node/test/sessions.test.js | 191 +++++++++++ pnpm-lock.yaml | 320 ++++++++++++++++-- 28 files changed, 664 insertions(+), 95 deletions(-) delete mode 100644 packages/astro/test/fixtures/sessions/tsconfig.json delete mode 100644 packages/integrations/netlify/test/functions/fixtures/session/netlify.toml rename packages/integrations/netlify/test/functions/fixtures/{session => sessions}/astro.config.mjs (75%) rename packages/integrations/netlify/test/functions/fixtures/{session => sessions}/package.json (100%) rename packages/integrations/{node/test/fixtures/session => netlify/test/functions/fixtures/sessions}/src/actions/index.ts (60%) rename packages/integrations/netlify/test/functions/fixtures/{session => sessions}/src/middleware.ts (94%) rename packages/integrations/netlify/test/functions/fixtures/{session => sessions}/src/pages/api.ts (92%) rename packages/integrations/netlify/test/functions/fixtures/{session => sessions}/src/pages/cart.astro (91%) rename packages/integrations/netlify/test/functions/fixtures/{session => sessions}/src/pages/destroy.ts (100%) rename packages/integrations/{node/test/fixtures/session => netlify/test/functions/fixtures/sessions}/src/pages/index.astro (68%) rename packages/integrations/netlify/test/functions/fixtures/{session => sessions}/src/pages/regenerate.ts (100%) create mode 100644 packages/integrations/netlify/test/functions/fixtures/sessions/src/pages/update.ts create mode 100644 packages/integrations/netlify/test/functions/sessions.test.js delete mode 100644 packages/integrations/node/test/fixtures/session/astro.config.mjs create mode 100644 packages/integrations/node/test/fixtures/sessions/astro.config.mjs rename packages/integrations/node/test/fixtures/{session => sessions}/package.json (80%) rename packages/integrations/{netlify/test/functions/fixtures/session => node/test/fixtures/sessions}/src/actions/index.ts (60%) rename packages/integrations/node/test/fixtures/{session => sessions}/src/middleware.ts (94%) rename packages/integrations/node/test/fixtures/{session => sessions}/src/pages/api.ts (92%) rename packages/integrations/node/test/fixtures/{session => sessions}/src/pages/cart.astro (68%) rename packages/integrations/node/test/fixtures/{session => sessions}/src/pages/destroy.ts (100%) rename packages/integrations/{netlify/test/functions/fixtures/session => node/test/fixtures/sessions}/src/pages/index.astro (68%) rename packages/integrations/node/test/fixtures/{session => sessions}/src/pages/regenerate.ts (100%) create mode 100644 packages/integrations/node/test/fixtures/sessions/src/pages/update.ts create mode 100644 packages/integrations/node/test/sessions.test.js diff --git a/packages/astro/test/fixtures/sessions/package.json b/packages/astro/test/fixtures/sessions/package.json index 9e73d9e21f58..453f09a96d4b 100644 --- a/packages/astro/test/fixtures/sessions/package.json +++ b/packages/astro/test/fixtures/sessions/package.json @@ -3,7 +3,6 @@ "version": "0.0.0", "private": true, "dependencies": { - "@netlify/blobs": "^8.1.0", "astro": "workspace:*" } } diff --git a/packages/astro/test/fixtures/sessions/tsconfig.json b/packages/astro/test/fixtures/sessions/tsconfig.json deleted file mode 100644 index c193287fccd6..000000000000 --- a/packages/astro/test/fixtures/sessions/tsconfig.json +++ /dev/null @@ -1,11 +0,0 @@ -{ - "extends": "astro/tsconfigs/base", - "compilerOptions": { - "baseUrl": ".", - "paths": { - "~/assets/*": ["src/assets/*"] - }, - }, - "include": [".astro/types.d.ts", "**/*"], - "exclude": ["dist"] -} diff --git a/packages/integrations/netlify/package.json b/packages/integrations/netlify/package.json index 562c24e9d5fd..6ed5a8a46733 100644 --- a/packages/integrations/netlify/package.json +++ b/packages/integrations/netlify/package.json @@ -38,6 +38,7 @@ "dependencies": { "@astrojs/internal-helpers": "workspace:*", "@astrojs/underscore-redirects": "workspace:*", + "@netlify/blobs": "^8.1.0", "@netlify/functions": "^2.8.0", "@vercel/nft": "^0.29.0", "esbuild": "^0.24.0", diff --git a/packages/integrations/netlify/test/functions/fixtures/session/netlify.toml b/packages/integrations/netlify/test/functions/fixtures/session/netlify.toml deleted file mode 100644 index 6a29ab05d38e..000000000000 --- a/packages/integrations/netlify/test/functions/fixtures/session/netlify.toml +++ /dev/null @@ -1,6 +0,0 @@ -[build] -command = "pnpm run --filter @test/netlify-session... build" -publish = "dist" -[dev] -framework = "astro" -targetPort = 4321 diff --git a/packages/integrations/netlify/test/functions/fixtures/session/astro.config.mjs b/packages/integrations/netlify/test/functions/fixtures/sessions/astro.config.mjs similarity index 75% rename from packages/integrations/netlify/test/functions/fixtures/session/astro.config.mjs rename to packages/integrations/netlify/test/functions/fixtures/sessions/astro.config.mjs index eb9b478b261f..23d03b44fab3 100644 --- a/packages/integrations/netlify/test/functions/fixtures/session/astro.config.mjs +++ b/packages/integrations/netlify/test/functions/fixtures/sessions/astro.config.mjs @@ -1,12 +1,11 @@ -// @ts-check import netlify from '@astrojs/netlify'; import { defineConfig } from 'astro/config'; export default defineConfig({ output: 'server', adapter: netlify(), - site: 'http://example.com', + site: `http://example.com`, experimental: { - session: true + session: true, } }); diff --git a/packages/integrations/netlify/test/functions/fixtures/session/package.json b/packages/integrations/netlify/test/functions/fixtures/sessions/package.json similarity index 100% rename from packages/integrations/netlify/test/functions/fixtures/session/package.json rename to packages/integrations/netlify/test/functions/fixtures/sessions/package.json diff --git a/packages/integrations/node/test/fixtures/session/src/actions/index.ts b/packages/integrations/netlify/test/functions/fixtures/sessions/src/actions/index.ts similarity index 60% rename from packages/integrations/node/test/fixtures/session/src/actions/index.ts rename to packages/integrations/netlify/test/functions/fixtures/sessions/src/actions/index.ts index 33ac1cb653fb..856f68ba8fb1 100644 --- a/packages/integrations/node/test/fixtures/session/src/actions/index.ts +++ b/packages/integrations/netlify/test/functions/fixtures/sessions/src/actions/index.ts @@ -21,7 +21,16 @@ export const server = { accept: 'json', handler: async (input, context) => { await context.session.set('cart', []); - return {cart: [], message: 'Cart cleared at ' + new Date().toTimeString() }; + return { cart: [], message: 'Cart cleared at ' + new Date().toTimeString() }; }, }), -}; + addUrl: defineAction({ + input: z.object({ favoriteUrl: z.string().url() }), + handler: async (input, context) => { + const previousFavoriteUrl = await context.session.get('favoriteUrl'); + const url = new URL(input.favoriteUrl); + context.session.set('favoriteUrl', url); + return { message: 'Favorite URL set to ' + url.href + ' from ' + (previousFavoriteUrl?.href ?? "nothing") }; + } + }) +} diff --git a/packages/integrations/netlify/test/functions/fixtures/session/src/middleware.ts b/packages/integrations/netlify/test/functions/fixtures/sessions/src/middleware.ts similarity index 94% rename from packages/integrations/netlify/test/functions/fixtures/session/src/middleware.ts rename to packages/integrations/netlify/test/functions/fixtures/sessions/src/middleware.ts index 05a9f40b6788..7f56f11f364f 100644 --- a/packages/integrations/netlify/test/functions/fixtures/session/src/middleware.ts +++ b/packages/integrations/netlify/test/functions/fixtures/sessions/src/middleware.ts @@ -4,7 +4,6 @@ import { getActionContext } from 'astro:actions'; const ACTION_SESSION_KEY = 'actionResult' export const onRequest = defineMiddleware(async (context, next) => { - console.log("Deno" in globalThis ? "Deno" : "Node.js"); // Skip requests for prerendered pages if (context.isPrerendered) return next(); @@ -14,7 +13,7 @@ export const onRequest = defineMiddleware(async (context, next) => { console.log(action?.name) const actionPayload = await context.session.get(ACTION_SESSION_KEY); - console.log({actionPayload}) + if (actionPayload) { setActionResult(actionPayload.actionName, actionPayload.actionResult); context.session.delete(ACTION_SESSION_KEY); diff --git a/packages/integrations/netlify/test/functions/fixtures/session/src/pages/api.ts b/packages/integrations/netlify/test/functions/fixtures/sessions/src/pages/api.ts similarity index 92% rename from packages/integrations/netlify/test/functions/fixtures/session/src/pages/api.ts rename to packages/integrations/netlify/test/functions/fixtures/sessions/src/pages/api.ts index 77d50625aab1..21793c78a74f 100644 --- a/packages/integrations/netlify/test/functions/fixtures/session/src/pages/api.ts +++ b/packages/integrations/netlify/test/functions/fixtures/sessions/src/pages/api.ts @@ -1,7 +1,5 @@ import type { APIRoute } from 'astro'; -export const prerender = false; - export const GET: APIRoute = async (context) => { const url = new URL(context.url, 'http://localhost'); let value = url.searchParams.get('set'); diff --git a/packages/integrations/netlify/test/functions/fixtures/session/src/pages/cart.astro b/packages/integrations/netlify/test/functions/fixtures/sessions/src/pages/cart.astro similarity index 91% rename from packages/integrations/netlify/test/functions/fixtures/session/src/pages/cart.astro rename to packages/integrations/netlify/test/functions/fixtures/sessions/src/pages/cart.astro index aebd27c42ae6..e69a9e5e15b1 100644 --- a/packages/integrations/netlify/test/functions/fixtures/session/src/pages/cart.astro +++ b/packages/integrations/netlify/test/functions/fixtures/sessions/src/pages/cart.astro @@ -2,13 +2,11 @@ import { actions } from "astro:actions"; const result = Astro.getActionResult(actions.addToCart); -const start = Date.now(); + const cart = result?.data?.cart ?? await Astro.session.get('cart'); -const end = Date.now(); const message = result?.data?.message ?? 'Add something to your cart!'; ---

Cart: {JSON.stringify(cart)}

-

Time taken: {end - start}ms

{message}

diff --git a/packages/integrations/netlify/test/functions/fixtures/session/src/pages/destroy.ts b/packages/integrations/netlify/test/functions/fixtures/sessions/src/pages/destroy.ts similarity index 100% rename from packages/integrations/netlify/test/functions/fixtures/session/src/pages/destroy.ts rename to packages/integrations/netlify/test/functions/fixtures/sessions/src/pages/destroy.ts diff --git a/packages/integrations/node/test/fixtures/session/src/pages/index.astro b/packages/integrations/netlify/test/functions/fixtures/sessions/src/pages/index.astro similarity index 68% rename from packages/integrations/node/test/fixtures/session/src/pages/index.astro rename to packages/integrations/netlify/test/functions/fixtures/sessions/src/pages/index.astro index a85d55c39dac..30d6a1618796 100644 --- a/packages/integrations/node/test/fixtures/session/src/pages/index.astro +++ b/packages/integrations/netlify/test/functions/fixtures/sessions/src/pages/index.astro @@ -1,7 +1,5 @@ --- -const start = performance.now(); const value = await Astro.session.get('value'); -const end = performance.now(); --- @@ -11,6 +9,5 @@ const end = performance.now();

Hi

{value}

-

Time taken: {end - start}ms

🛒 diff --git a/packages/integrations/netlify/test/functions/fixtures/session/src/pages/regenerate.ts b/packages/integrations/netlify/test/functions/fixtures/sessions/src/pages/regenerate.ts similarity index 100% rename from packages/integrations/netlify/test/functions/fixtures/session/src/pages/regenerate.ts rename to packages/integrations/netlify/test/functions/fixtures/sessions/src/pages/regenerate.ts diff --git a/packages/integrations/netlify/test/functions/fixtures/sessions/src/pages/update.ts b/packages/integrations/netlify/test/functions/fixtures/sessions/src/pages/update.ts new file mode 100644 index 000000000000..71b058e75321 --- /dev/null +++ b/packages/integrations/netlify/test/functions/fixtures/sessions/src/pages/update.ts @@ -0,0 +1,10 @@ +import type { APIRoute } from 'astro'; + +export const GET: APIRoute = async (context) => { + const previousObject = await context.session.get("key") ?? { value: "none" }; + const previousValue = previousObject.value; + const sessionData = { value: "expected" }; + context.session.set("key", sessionData); + sessionData.value = "unexpected"; + return Response.json({previousValue}); +}; diff --git a/packages/integrations/netlify/test/functions/sessions.test.js b/packages/integrations/netlify/test/functions/sessions.test.js new file mode 100644 index 000000000000..6c6be8cb8691 --- /dev/null +++ b/packages/integrations/netlify/test/functions/sessions.test.js @@ -0,0 +1,129 @@ +// @ts-check +import assert from 'node:assert/strict'; +import { after, before, describe, it } from 'node:test'; +import * as devalue from 'devalue'; +import netlify from '../../dist/index.js'; +import { loadFixture } from '../../../../astro/test/test-utils.js'; +import { BlobsServer } from '@netlify/blobs/server'; +import { rm, mkdir } from 'node:fs/promises'; +const token = 'mock'; +const siteID = '1'; +const dataDir = '.netlify/sessions'; +const options = { + name: 'test', + uncachedEdgeURL: `http://localhost:8971`, + edgeURL: `http://localhost:8971`, + token, + siteID, + region: 'us-east-1', +}; + +describe('Astro.session', () => { + describe('Production', () => { + /** @type {import('../../../../astro/test/test-utils.js').Fixture} */ + let fixture; + + /** @type {BlobsServer} */ + let blobServer; + before(async () => { + process.env.NETLIFY = '1'; + await rm(dataDir, { recursive: true, force: true }).catch(() => {}); + await mkdir(dataDir, { recursive: true }); + blobServer = new BlobsServer({ + directory: dataDir, + token, + port: 8971, + }); + await blobServer.start(); + fixture = await loadFixture({ + // @ts-ignore + root: new URL('./fixtures/sessions/', import.meta.url), + output: 'server', + adapter: netlify(), + experimental: { + session: true, + }, + // @ts-ignore + session: { driver: '', options }, + }); + await fixture.build({}); + const entryURL = new URL( + './fixtures/sessions/.netlify/v1/functions/ssr/ssr.mjs', + import.meta.url, + ); + const mod = await import(entryURL.href); + handler = mod.default; + }); + let handler; + after(async () => { + await blobServer.stop(); + delete process.env.NETLIFY; + }); + async function fetchResponse(path, requestInit) { + return handler(new Request(new URL(path, 'http://example.com'), requestInit), {}); + } + + it('can regenerate session cookies upon request', async () => { + const firstResponse = await fetchResponse('/regenerate', { method: 'GET' }); + const firstHeaders = firstResponse.headers.get('set-cookie').split(','); + const firstSessionId = firstHeaders[0].split(';')[0].split('=')[1]; + + const secondResponse = await fetchResponse('/regenerate', { + method: 'GET', + headers: { + cookie: `astro-session=${firstSessionId}`, + }, + }); + const secondHeaders = secondResponse.headers.get('set-cookie').split(','); + const secondSessionId = secondHeaders[0].split(';')[0].split('=')[1]; + assert.notEqual(firstSessionId, secondSessionId); + }); + + it('can save session data by value', async () => { + const firstResponse = await fetchResponse('/update', { method: 'GET' }); + const firstValue = await firstResponse.json(); + assert.equal(firstValue.previousValue, 'none'); + + const firstHeaders = firstResponse.headers.get('set-cookie').split(','); + const firstSessionId = firstHeaders[0].split(';')[0].split('=')[1]; + const secondResponse = await fetchResponse('/update', { + method: 'GET', + headers: { + cookie: `astro-session=${firstSessionId}`, + }, + }); + const secondValue = await secondResponse.json(); + assert.equal(secondValue.previousValue, 'expected'); + }); + + it('can save and restore URLs in session data', async () => { + const firstResponse = await fetchResponse('/_actions/addUrl', { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + }, + body: JSON.stringify({ favoriteUrl: 'https://domain.invalid' }), + }); + + assert.equal(firstResponse.ok, true); + const firstHeaders = firstResponse.headers.get('set-cookie').split(','); + const firstSessionId = firstHeaders[0].split(';')[0].split('=')[1]; + + const data = devalue.parse(await firstResponse.text()); + assert.equal(data.message, 'Favorite URL set to https://domain.invalid/ from nothing'); + const secondResponse = await fetchResponse('/_actions/addUrl', { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + cookie: `astro-session=${firstSessionId}`, + }, + body: JSON.stringify({ favoriteUrl: 'https://example.com' }), + }); + const secondData = devalue.parse(await secondResponse.text()); + assert.equal( + secondData.message, + 'Favorite URL set to https://example.com/ from https://domain.invalid/', + ); + }); + }); +}); diff --git a/packages/integrations/node/test/fixtures/session/astro.config.mjs b/packages/integrations/node/test/fixtures/session/astro.config.mjs deleted file mode 100644 index 51c6accb73e4..000000000000 --- a/packages/integrations/node/test/fixtures/session/astro.config.mjs +++ /dev/null @@ -1,11 +0,0 @@ -// @ts-check -import { defineConfig } from "astro/config"; -import node from "@astrojs/node"; - -export default defineConfig({ - output: 'server', - adapter: node({ mode: 'standalone' }), - experimental: { - session: true - } -}); diff --git a/packages/integrations/node/test/fixtures/sessions/astro.config.mjs b/packages/integrations/node/test/fixtures/sessions/astro.config.mjs new file mode 100644 index 000000000000..bcd1aed24e57 --- /dev/null +++ b/packages/integrations/node/test/fixtures/sessions/astro.config.mjs @@ -0,0 +1,6 @@ +// @ts-check +import { defineConfig } from 'astro/config'; + +export default defineConfig({ + +}); diff --git a/packages/integrations/node/test/fixtures/session/package.json b/packages/integrations/node/test/fixtures/sessions/package.json similarity index 80% rename from packages/integrations/node/test/fixtures/session/package.json rename to packages/integrations/node/test/fixtures/sessions/package.json index e796bf33a2b4..e6fc29588431 100644 --- a/packages/integrations/node/test/fixtures/session/package.json +++ b/packages/integrations/node/test/fixtures/sessions/package.json @@ -1,5 +1,5 @@ { - "name": "@test/session", + "name": "@test/node-sessions", "version": "0.0.0", "private": true, "dependencies": { diff --git a/packages/integrations/netlify/test/functions/fixtures/session/src/actions/index.ts b/packages/integrations/node/test/fixtures/sessions/src/actions/index.ts similarity index 60% rename from packages/integrations/netlify/test/functions/fixtures/session/src/actions/index.ts rename to packages/integrations/node/test/fixtures/sessions/src/actions/index.ts index 33ac1cb653fb..856f68ba8fb1 100644 --- a/packages/integrations/netlify/test/functions/fixtures/session/src/actions/index.ts +++ b/packages/integrations/node/test/fixtures/sessions/src/actions/index.ts @@ -21,7 +21,16 @@ export const server = { accept: 'json', handler: async (input, context) => { await context.session.set('cart', []); - return {cart: [], message: 'Cart cleared at ' + new Date().toTimeString() }; + return { cart: [], message: 'Cart cleared at ' + new Date().toTimeString() }; }, }), -}; + addUrl: defineAction({ + input: z.object({ favoriteUrl: z.string().url() }), + handler: async (input, context) => { + const previousFavoriteUrl = await context.session.get('favoriteUrl'); + const url = new URL(input.favoriteUrl); + context.session.set('favoriteUrl', url); + return { message: 'Favorite URL set to ' + url.href + ' from ' + (previousFavoriteUrl?.href ?? "nothing") }; + } + }) +} diff --git a/packages/integrations/node/test/fixtures/session/src/middleware.ts b/packages/integrations/node/test/fixtures/sessions/src/middleware.ts similarity index 94% rename from packages/integrations/node/test/fixtures/session/src/middleware.ts rename to packages/integrations/node/test/fixtures/sessions/src/middleware.ts index 05a9f40b6788..7f56f11f364f 100644 --- a/packages/integrations/node/test/fixtures/session/src/middleware.ts +++ b/packages/integrations/node/test/fixtures/sessions/src/middleware.ts @@ -4,7 +4,6 @@ import { getActionContext } from 'astro:actions'; const ACTION_SESSION_KEY = 'actionResult' export const onRequest = defineMiddleware(async (context, next) => { - console.log("Deno" in globalThis ? "Deno" : "Node.js"); // Skip requests for prerendered pages if (context.isPrerendered) return next(); @@ -14,7 +13,7 @@ export const onRequest = defineMiddleware(async (context, next) => { console.log(action?.name) const actionPayload = await context.session.get(ACTION_SESSION_KEY); - console.log({actionPayload}) + if (actionPayload) { setActionResult(actionPayload.actionName, actionPayload.actionResult); context.session.delete(ACTION_SESSION_KEY); diff --git a/packages/integrations/node/test/fixtures/session/src/pages/api.ts b/packages/integrations/node/test/fixtures/sessions/src/pages/api.ts similarity index 92% rename from packages/integrations/node/test/fixtures/session/src/pages/api.ts rename to packages/integrations/node/test/fixtures/sessions/src/pages/api.ts index 77d50625aab1..21793c78a74f 100644 --- a/packages/integrations/node/test/fixtures/session/src/pages/api.ts +++ b/packages/integrations/node/test/fixtures/sessions/src/pages/api.ts @@ -1,7 +1,5 @@ import type { APIRoute } from 'astro'; -export const prerender = false; - export const GET: APIRoute = async (context) => { const url = new URL(context.url, 'http://localhost'); let value = url.searchParams.get('set'); diff --git a/packages/integrations/node/test/fixtures/session/src/pages/cart.astro b/packages/integrations/node/test/fixtures/sessions/src/pages/cart.astro similarity index 68% rename from packages/integrations/node/test/fixtures/session/src/pages/cart.astro rename to packages/integrations/node/test/fixtures/sessions/src/pages/cart.astro index 870ac0bcc214..e69a9e5e15b1 100644 --- a/packages/integrations/node/test/fixtures/session/src/pages/cart.astro +++ b/packages/integrations/node/test/fixtures/sessions/src/pages/cart.astro @@ -2,13 +2,11 @@ import { actions } from "astro:actions"; const result = Astro.getActionResult(actions.addToCart); -const start = Date.now(); + const cart = result?.data?.cart ?? await Astro.session.get('cart'); -const end = Date.now(); const message = result?.data?.message ?? 'Add something to your cart!'; ---

Cart: {JSON.stringify(cart)}

-

Time taken: {end - start}ms

{message}

@@ -19,8 +17,8 @@ const message = result?.data?.message ?? 'Add something to your cart!'; import { actions } from "astro:actions"; async function clearCart() { const result = await actions.clearCart({}); - document.getElementById('cart')!.textContent = JSON.stringify(result.data.cart); - document.getElementById('message')!.textContent = result.data.message; + document.getElementById('cart').textContent = JSON.stringify(result.data.cart); + document.getElementById('message').textContent = result.data.message; } - document.getElementById('clearCart')!.addEventListener('click', clearCart); + document.getElementById('clearCart').addEventListener('click', clearCart); diff --git a/packages/integrations/node/test/fixtures/session/src/pages/destroy.ts b/packages/integrations/node/test/fixtures/sessions/src/pages/destroy.ts similarity index 100% rename from packages/integrations/node/test/fixtures/session/src/pages/destroy.ts rename to packages/integrations/node/test/fixtures/sessions/src/pages/destroy.ts diff --git a/packages/integrations/netlify/test/functions/fixtures/session/src/pages/index.astro b/packages/integrations/node/test/fixtures/sessions/src/pages/index.astro similarity index 68% rename from packages/integrations/netlify/test/functions/fixtures/session/src/pages/index.astro rename to packages/integrations/node/test/fixtures/sessions/src/pages/index.astro index a85d55c39dac..30d6a1618796 100644 --- a/packages/integrations/netlify/test/functions/fixtures/session/src/pages/index.astro +++ b/packages/integrations/node/test/fixtures/sessions/src/pages/index.astro @@ -1,7 +1,5 @@ --- -const start = performance.now(); const value = await Astro.session.get('value'); -const end = performance.now(); --- @@ -11,6 +9,5 @@ const end = performance.now();

Hi

{value}

-

Time taken: {end - start}ms

🛒 diff --git a/packages/integrations/node/test/fixtures/session/src/pages/regenerate.ts b/packages/integrations/node/test/fixtures/sessions/src/pages/regenerate.ts similarity index 100% rename from packages/integrations/node/test/fixtures/session/src/pages/regenerate.ts rename to packages/integrations/node/test/fixtures/sessions/src/pages/regenerate.ts diff --git a/packages/integrations/node/test/fixtures/sessions/src/pages/update.ts b/packages/integrations/node/test/fixtures/sessions/src/pages/update.ts new file mode 100644 index 000000000000..71b058e75321 --- /dev/null +++ b/packages/integrations/node/test/fixtures/sessions/src/pages/update.ts @@ -0,0 +1,10 @@ +import type { APIRoute } from 'astro'; + +export const GET: APIRoute = async (context) => { + const previousObject = await context.session.get("key") ?? { value: "none" }; + const previousValue = previousObject.value; + const sessionData = { value: "expected" }; + context.session.set("key", sessionData); + sessionData.value = "unexpected"; + return Response.json({previousValue}); +}; diff --git a/packages/integrations/node/test/sessions.test.js b/packages/integrations/node/test/sessions.test.js new file mode 100644 index 000000000000..8d82f63b6554 --- /dev/null +++ b/packages/integrations/node/test/sessions.test.js @@ -0,0 +1,191 @@ +// @ts-check +import assert from 'node:assert/strict'; +import { after, before, describe, it } from 'node:test'; +import * as devalue from 'devalue'; +import nodejs from '../dist/index.js'; +import { loadFixture } from './test-utils.js'; + +describe('Astro.session', () => { + describe('Production', () => { + /** @type {import('./test-utils').Fixture} */ + let fixture; + + before(async () => { + fixture = await loadFixture({ + root: './fixtures/sessions/', + output: 'server', + adapter: nodejs({ mode: 'middleware' }), + experimental: { + session: true, + }, + }); + }); + + /** @type {import('../../../astro/src/types/public/preview.js').PreviewServer} */ + let app; + before(async () => { + await fixture.build({}); + app = await fixture.preview({}); + }); + + after(async () => { + await app.stop(); + }); + + it('can regenerate session cookies upon request', async () => { + const firstResponse = await fixture.fetch('/regenerate'); + // @ts-ignore + const firstHeaders = firstResponse.headers.get('set-cookie').split(','); + const firstSessionId = firstHeaders[0].split(';')[0].split('=')[1]; + + const secondResponse = await fixture.fetch('/regenerate', { + method: 'GET', + headers: { + cookie: `astro-session=${firstSessionId}`, + }, + }); + // @ts-ignore + const secondHeaders = secondResponse.headers.get('set-cookie').split(','); + const secondSessionId = secondHeaders[0].split(';')[0].split('=')[1]; + assert.notEqual(firstSessionId, secondSessionId); + }); + + it('can save session data by value', async () => { + const firstResponse = await fixture.fetch('/update'); + const firstValue = await firstResponse.json(); + assert.equal(firstValue.previousValue, 'none'); + + // @ts-ignore + const firstHeaders = firstResponse.headers.get('set-cookie').split(','); + const firstSessionId = firstHeaders[0].split(';')[0].split('=')[1]; + const secondResponse = await fixture.fetch('/update', { + method: 'GET', + headers: { + cookie: `astro-session=${firstSessionId}`, + }, + }); + const secondValue = await secondResponse.json(); + assert.equal(secondValue.previousValue, 'expected'); + }); + + it('can save and restore URLs in session data', async () => { + const firstResponse = await fixture.fetch('/_actions/addUrl', { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + }, + body: JSON.stringify({ favoriteUrl: 'https://domain.invalid' }), + }); + + assert.equal(firstResponse.ok, true); + // @ts-ignore + const firstHeaders = firstResponse.headers.get('set-cookie').split(','); + const firstSessionId = firstHeaders[0].split(';')[0].split('=')[1]; + + const data = devalue.parse(await firstResponse.text()); + assert.equal(data.message, 'Favorite URL set to https://domain.invalid/ from nothing'); + const secondResponse = await fixture.fetch('/_actions/addUrl', { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + cookie: `astro-session=${firstSessionId}`, + }, + body: JSON.stringify({ favoriteUrl: 'https://example.com' }), + }); + const secondData = devalue.parse(await secondResponse.text()); + assert.equal( + secondData.message, + 'Favorite URL set to https://example.com/ from https://domain.invalid/', + ); + }); + }); + + describe('Development', () => { + /** @type {import('./test-utils').Fixture} */ + let fixture; + let devServer; + before(async () => { + fixture = await loadFixture({ + root: './fixtures/sessions/', + output: 'server', + adapter: nodejs({ mode: 'middleware' }), + experimental: { + session: true, + }, + + }); + devServer = await fixture.startDevServer(); + }); + + after(async () => { + await devServer.stop(); + }); + + it('can regenerate session cookies upon request', async () => { + const firstResponse = await fixture.fetch('/regenerate'); + // @ts-ignore + const firstHeaders = firstResponse.headers.get('set-cookie').split(','); + const firstSessionId = firstHeaders[0].split(';')[0].split('=')[1]; + + const secondResponse = await fixture.fetch('/regenerate', { + method: 'GET', + headers: { + cookie: `astro-session=${firstSessionId}`, + }, + }); + // @ts-ignore + const secondHeaders = secondResponse.headers.get('set-cookie').split(','); + const secondSessionId = secondHeaders[0].split(';')[0].split('=')[1]; + assert.notEqual(firstSessionId, secondSessionId); + }); + + it('can save session data by value', async () => { + const firstResponse = await fixture.fetch('/update'); + const firstValue = await firstResponse.json(); + assert.equal(firstValue.previousValue, 'none'); + + // @ts-ignore + const firstHeaders = firstResponse.headers.get('set-cookie').split(','); + const firstSessionId = firstHeaders[0].split(';')[0].split('=')[1]; + const secondResponse = await fixture.fetch('/update', { + method: 'GET', + headers: { + cookie: `astro-session=${firstSessionId}`, + }, + }); + const secondValue = await secondResponse.json(); + assert.equal(secondValue.previousValue, 'expected'); + }); + + it('can save and restore URLs in session data', async () => { + const firstResponse = await fixture.fetch('/_actions/addUrl', { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + }, + body: JSON.stringify({ favoriteUrl: 'https://domain.invalid' }), + }); + + assert.equal(firstResponse.ok, true); + // @ts-ignore + const firstHeaders = firstResponse.headers.get('set-cookie').split(','); + const firstSessionId = firstHeaders[0].split(';')[0].split('=')[1]; + + const data = devalue.parse(await firstResponse.text()); + assert.equal(data.message, 'Favorite URL set to https://domain.invalid/ from nothing'); + const secondResponse = await fixture.fetch('/_actions/addUrl', { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + cookie: `astro-session=${firstSessionId}`, + }, + body: JSON.stringify({ favoriteUrl: 'https://example.com' }), + }); + const secondData = devalue.parse(await secondResponse.text()); + assert.equal( + secondData.message, + 'Favorite URL set to https://example.com/ from https://domain.invalid/', + ); + }); + }); +}); diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 902e002983c9..2c900ef6771c 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -68,7 +68,7 @@ importers: version: link:../packages/integrations/mdx '@astrojs/node': specifier: ^9.0.2 - version: 9.0.2(astro@packages+astro) + version: link:../packages/integrations/node '@benchmark/adapter': specifier: workspace:* version: link:packages/adapter @@ -327,7 +327,7 @@ importers: dependencies: '@astrojs/node': specifier: ^9.0.2 - version: 9.0.2(astro@packages+astro) + version: link:../../packages/integrations/node astro: specifier: ^5.2.5 version: link:../../packages/astro @@ -354,7 +354,7 @@ importers: dependencies: '@astrojs/node': specifier: ^9.0.2 - version: 9.0.2(astro@packages+astro) + version: link:../../packages/integrations/node '@astrojs/svelte': specifier: ^7.0.4 version: link:../../packages/integrations/svelte @@ -799,7 +799,7 @@ importers: version: link:../../../../db '@astrojs/node': specifier: ^9.0.2 - version: 9.0.2(astro@packages+astro) + version: link:../../../../integrations/node '@astrojs/react': specifier: workspace:* version: link:../../../../integrations/react @@ -832,7 +832,7 @@ importers: version: link:../../../../db '@astrojs/node': specifier: ^9.0.2 - version: 9.0.2(astro@packages+astro) + version: link:../../../../integrations/node '@astrojs/react': specifier: workspace:* version: link:../../../../integrations/react @@ -1068,7 +1068,7 @@ importers: dependencies: '@astrojs/node': specifier: ^9.0.2 - version: 9.0.2(astro@packages+astro) + version: link:../../../../integrations/node astro: specifier: workspace:* version: link:../../.. @@ -1470,7 +1470,7 @@ importers: version: link:../../../../integrations/mdx '@astrojs/node': specifier: ^9.0.2 - version: 9.0.2(astro@packages+astro) + version: link:../../../../integrations/node '@astrojs/react': specifier: workspace:* version: link:../../../../integrations/react @@ -1488,7 +1488,7 @@ importers: dependencies: '@astrojs/node': specifier: ^9.0.2 - version: 9.0.2(astro@packages+astro) + version: link:../../../../integrations/node astro: specifier: workspace:* version: link:../../.. @@ -1583,7 +1583,7 @@ importers: dependencies: '@astrojs/node': specifier: ^9.0.2 - version: 9.0.2(astro@packages+astro) + version: link:../../../../integrations/node '@astrojs/react': specifier: workspace:* version: link:../../../../integrations/react @@ -2439,7 +2439,7 @@ importers: dependencies: '@astrojs/node': specifier: ^9.0.2 - version: 9.0.2(astro@packages+astro) + version: link:../../../../integrations/node astro: specifier: workspace:* version: link:../../.. @@ -2970,7 +2970,7 @@ importers: dependencies: '@astrojs/node': specifier: ^9.0.2 - version: 9.0.2(astro@packages+astro) + version: link:../../../../integrations/node astro: specifier: workspace:* version: link:../../.. @@ -3707,9 +3707,6 @@ importers: packages/astro/test/fixtures/sessions: dependencies: - '@netlify/blobs': - specifier: ^8.1.0 - version: 8.1.0 astro: specifier: workspace:* version: link:../../.. @@ -3865,7 +3862,7 @@ importers: dependencies: '@astrojs/node': specifier: ^9.0.2 - version: 9.0.2(astro@packages+astro) + version: link:../../../../integrations/node astro: specifier: workspace:* version: link:../../.. @@ -4077,7 +4074,7 @@ importers: dependencies: '@astrojs/node': specifier: ^9.0.2 - version: 9.0.2(astro@packages+astro) + version: link:../../../../integrations/node '@test/static-build-pkg': specifier: workspace:* version: link:../static-build/pkg @@ -4452,7 +4449,7 @@ importers: version: link:../../.. '@astrojs/node': specifier: ^9.0.2 - version: 9.0.2(astro@packages+astro) + version: link:../../../../integrations/node '@astrojs/react': specifier: workspace:* version: link:../../../../integrations/react @@ -5003,6 +5000,9 @@ importers: '@astrojs/underscore-redirects': specifier: workspace:* version: link:../../underscore-redirects + '@netlify/blobs': + specifier: ^8.1.0 + version: 8.1.0 '@netlify/functions': specifier: ^2.8.0 version: 2.8.2 @@ -5068,7 +5068,7 @@ importers: specifier: 'workspace:' version: link:../../../.. - packages/integrations/netlify/test/functions/fixtures/session: + packages/integrations/netlify/test/functions/fixtures/sessions: dependencies: '@astrojs/netlify': specifier: workspace:* @@ -5226,7 +5226,7 @@ importers: specifier: workspace:* version: link:../../../../../astro - packages/integrations/node/test/fixtures/session: + packages/integrations/node/test/fixtures/sessions: dependencies: '@astrojs/node': specifier: workspace:* @@ -5381,7 +5381,7 @@ importers: devDependencies: '@astrojs/node': specifier: ^9.0.0 - version: 9.0.2(astro@packages+astro) + version: link:../node astro: specifier: workspace:* version: link:../../astro @@ -5503,7 +5503,213 @@ importers: specifier: workspace:* version: link:../../../../../astro - packages/integrations/vercel: {} + packages/integrations/vercel: + dependencies: + '@astrojs/internal-helpers': + specifier: ^0.5.1 + version: link:../../internal-helpers + '@vercel/analytics': + specifier: ^1.4.1 + version: 1.4.1(react@19.0.0)(svelte@5.19.7)(vue@3.5.13(typescript@5.7.3)) + '@vercel/edge': + specifier: ^1.2.1 + version: 1.2.1 + '@vercel/nft': + specifier: ^0.29.0 + version: 0.29.1(rollup@4.34.2) + '@vercel/routing-utils': + specifier: 5.0.2 + version: 5.0.2 + esbuild: + specifier: ^0.24.0 + version: 0.24.2 + fast-glob: + specifier: ^3.3.3 + version: 3.3.3 + devDependencies: + astro: + specifier: workspace:* + version: link:../../astro + astro-scripts: + specifier: workspace:* + version: link:../../../scripts + cheerio: + specifier: 1.0.0 + version: 1.0.0 + + packages/integrations/vercel/test/fixtures/basic: + dependencies: + '@astrojs/vercel': + specifier: workspace:* + version: link:../../.. + astro: + specifier: workspace:* + version: link:../../../../../astro + + packages/integrations/vercel/test/fixtures/image: + dependencies: + '@astrojs/vercel': + specifier: workspace:* + version: link:../../.. + astro: + specifier: workspace:* + version: link:../../../../../astro + + packages/integrations/vercel/test/fixtures/integration-assets: + dependencies: + '@astrojs/sitemap': + specifier: ^3.2.1 + version: link:../../../../sitemap + '@astrojs/vercel': + specifier: workspace:* + version: link:../../.. + astro: + specifier: workspace:* + version: link:../../../../../astro + + packages/integrations/vercel/test/fixtures/isr: + dependencies: + '@astrojs/vercel': + specifier: workspace:* + version: link:../../.. + astro: + specifier: workspace:* + version: link:../../../../../astro + + packages/integrations/vercel/test/fixtures/max-duration: + dependencies: + '@astrojs/vercel': + specifier: workspace:* + version: link:../../.. + astro: + specifier: workspace:* + version: link:../../../../../astro + + packages/integrations/vercel/test/fixtures/middleware-with-edge-file: + dependencies: + '@astrojs/vercel': + specifier: workspace:* + version: link:../../.. + astro: + specifier: workspace:* + version: link:../../../../../astro + + packages/integrations/vercel/test/fixtures/middleware-without-edge-file: + dependencies: + '@astrojs/vercel': + specifier: workspace:* + version: link:../../.. + astro: + specifier: workspace:* + version: link:../../../../../astro + + packages/integrations/vercel/test/fixtures/no-output: + dependencies: + '@astrojs/vercel': + specifier: workspace:* + version: link:../../.. + astro: + specifier: workspace:* + version: link:../../../../../astro + + packages/integrations/vercel/test/fixtures/prerendered-error-pages: + dependencies: + '@astrojs/vercel': + specifier: workspace:* + version: link:../../.. + astro: + specifier: workspace:* + version: link:../../../../../astro + + packages/integrations/vercel/test/fixtures/redirects: + dependencies: + '@astrojs/vercel': + specifier: workspace:* + version: link:../../.. + astro: + specifier: workspace:* + version: link:../../../../../astro + + packages/integrations/vercel/test/fixtures/redirects-serverless: + dependencies: + '@astrojs/vercel': + specifier: workspace:* + version: link:../../.. + astro: + specifier: workspace:* + version: link:../../../../../astro + + packages/integrations/vercel/test/fixtures/server-islands: + dependencies: + '@astrojs/vercel': + specifier: workspace:* + version: link:../../.. + astro: + specifier: workspace:* + version: link:../../../../../astro + + packages/integrations/vercel/test/fixtures/serverless-prerender: + dependencies: + '@astrojs/vercel': + specifier: workspace:* + version: link:../../.. + astro: + specifier: workspace:* + version: link:../../../../../astro + + packages/integrations/vercel/test/fixtures/serverless-with-dynamic-routes: + dependencies: + '@astrojs/vercel': + specifier: workspace:* + version: link:../../.. + astro: + specifier: workspace:* + version: link:../../../../../astro + + packages/integrations/vercel/test/fixtures/static: + dependencies: + '@astrojs/vercel': + specifier: workspace:* + version: link:../../.. + astro: + specifier: workspace:* + version: link:../../../../../astro + + packages/integrations/vercel/test/fixtures/static-assets: + dependencies: + '@astrojs/vercel': + specifier: workspace:* + version: link:../../.. + astro: + specifier: workspace:* + version: link:../../../../../astro + + packages/integrations/vercel/test/fixtures/streaming: + dependencies: + '@astrojs/vercel': + specifier: workspace:* + version: link:../../.. + astro: + specifier: workspace:* + version: link:../../../../../astro + + packages/integrations/vercel/test/fixtures/with-web-analytics-enabled/output-as-static: + dependencies: + '@astrojs/vercel': + specifier: workspace:* + version: link:../../../.. + astro: + specifier: workspace:* + version: link:../../../../../../astro + + packages/integrations/vercel/test/hosted/hosted-astro-project: + dependencies: + '@astrojs/vercel': + specifier: workspace:* + version: link:../../.. + astro: + specifier: ^5.1.6 + version: link:../../../../../astro packages/integrations/vue: dependencies: @@ -5646,7 +5852,7 @@ importers: version: link:../../../../../db '@astrojs/node': specifier: ^9.0.2 - version: 9.0.2(astro@packages+astro) + version: link:../../../../node '@astrojs/web-vitals': specifier: workspace:* version: link:../../.. @@ -5946,11 +6152,6 @@ packages: prettier-plugin-astro: optional: true - '@astrojs/node@9.0.2': - resolution: {integrity: sha512-MFFYRa5yQEBegKrSUPMeKnjDMB4okTrkVRA40/mU3ADKrKY5VV3af0LS+NYkH9pFOvj/OsPbdeQVxQ0jI3f6aQ==} - peerDependencies: - astro: ^5.0.0 - '@astrojs/yaml2ts@0.2.1': resolution: {integrity: sha512-CBaNwDQJz20E5WxzQh4thLVfhB3JEEGz72wRA+oJp6fQR37QLAqXZJU0mHC+yqMOQ6oj0GfRPJrz6hjf+zm6zA==} @@ -7727,11 +7928,43 @@ packages: '@ungap/structured-clone@1.2.0': resolution: {integrity: sha512-zuVdFrMJiuCDQUMCzQaD6KL28MjnqqN8XnAqiEq9PNm/hCPTSGfrXCOfwj1ow4LFb/tNymJPwsNbVePc1xFqrQ==} + '@vercel/analytics@1.4.1': + resolution: {integrity: sha512-ekpL4ReX2TH3LnrRZTUKjHHNpNy9S1I7QmS+g/RQXoSUQ8ienzosuX7T9djZ/s8zPhBx1mpHP/Rw5875N+zQIQ==} + peerDependencies: + '@remix-run/react': ^2 + '@sveltejs/kit': ^1 || ^2 + next: '>= 13' + react: ^18 || ^19 || ^19.0.0-rc + svelte: '>= 4' + vue: ^3 + vue-router: ^4 + peerDependenciesMeta: + '@remix-run/react': + optional: true + '@sveltejs/kit': + optional: true + next: + optional: true + react: + optional: true + svelte: + optional: true + vue: + optional: true + vue-router: + optional: true + + '@vercel/edge@1.2.1': + resolution: {integrity: sha512-1++yncEyIAi68D3UEOlytYb1IUcIulMWdoSzX2h9LuSeeyR7JtaIgR8DcTQ6+DmYOQn+5MCh6LY+UmK6QBByNA==} + '@vercel/nft@0.29.1': resolution: {integrity: sha512-6239JJM1V9b3OjvZIjbe+47/hGxMr44FEzlbTErrqzebCaoKAHK+yvahn3gdNacybDUbTxVF8Zuh0vqaeM8aKQ==} engines: {node: '>=18'} hasBin: true + '@vercel/routing-utils@5.0.2': + resolution: {integrity: sha512-uJViB3+HEo+kzHYELs7cQWX5k0kCNvq9G/8nJQX8mP5Ta0fG68CBRmOaaG8A+2xbtTp/QuGORIwV8CsI9ebcNg==} + '@vitejs/plugin-react@4.3.4': resolution: {integrity: sha512-SCCPBJtYLdE8PX/7ZQAs1QAZ8Jqwih+0VBLum1EGqmCCQal+MIUqLCzj3ZUy8ufbC0cAM4LRlSTm7IQJwWT4ug==} engines: {node: ^14.18.0 || >=16.0.0} @@ -10245,6 +10478,12 @@ packages: path-to-regexp@0.1.12: resolution: {integrity: sha512-RA1GjUVMnvYFxuqovrEqZoxxW5NUZqbwKtYz/Tt7nXerk0LbLblQmrsgdeOxV5SFHf0UDggjS/bSeOZwt1pmEQ==} + path-to-regexp@6.1.0: + resolution: {integrity: sha512-h9DqehX3zZZDCEm+xbfU0ZmwCGFCAAraPJWMXJ4+v32NjZJilVg3k1TcKsRgIb8IQ/izZSaydDc1OhJCZvs2Dw==} + + path-to-regexp@6.3.0: + resolution: {integrity: sha512-Yhpw4T9C6hPpgPeA28us07OJeqZ5EzQTkbfwuhsUg0c237RomFoETJgmp2sa3F/41gfLE6G5cqcYwznmeEeOlQ==} + path-type@4.0.0: resolution: {integrity: sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==} engines: {node: '>=8'} @@ -12091,14 +12330,6 @@ snapshots: transitivePeerDependencies: - typescript - '@astrojs/node@9.0.2(astro@packages+astro)': - dependencies: - astro: link:packages/astro - send: 1.1.0 - server-destroy: 1.0.1 - transitivePeerDependencies: - - supports-color - '@astrojs/yaml2ts@0.2.1': dependencies: yaml: 2.5.1 @@ -13906,6 +14137,14 @@ snapshots: '@ungap/structured-clone@1.2.0': {} + '@vercel/analytics@1.4.1(react@19.0.0)(svelte@5.19.7)(vue@3.5.13(typescript@5.7.3))': + optionalDependencies: + react: 19.0.0 + svelte: 5.19.7 + vue: 3.5.13(typescript@5.7.3) + + '@vercel/edge@1.2.1': {} + '@vercel/nft@0.29.1(rollup@4.34.2)': dependencies: '@mapbox/node-pre-gyp': 2.0.0 @@ -13925,6 +14164,13 @@ snapshots: - rollup - supports-color + '@vercel/routing-utils@5.0.2': + dependencies: + path-to-regexp: 6.1.0 + path-to-regexp-updated: path-to-regexp@6.3.0 + optionalDependencies: + ajv: 6.12.6 + '@vitejs/plugin-react@4.3.4(vite@6.0.11(@types/node@22.13.1)(jiti@2.4.2)(lightningcss@1.29.1)(sass@1.83.4)(yaml@2.5.1))': dependencies: '@babel/core': 7.26.0 @@ -16860,6 +17106,10 @@ snapshots: path-to-regexp@0.1.12: {} + path-to-regexp@6.1.0: {} + + path-to-regexp@6.3.0: {} + path-type@4.0.0: {} path-type@5.0.0: {} From 41e0474ae5aecd64f8a4784c3e2b585a860a7ace Mon Sep 17 00:00:00 2001 From: Matt Kane Date: Fri, 7 Feb 2025 12:11:40 +0000 Subject: [PATCH 12/22] Add dep for tests --- packages/integrations/netlify/package.json | 1 + packages/integrations/node/package.json | 1 + pnpm-lock.yaml | 11 +++++++++++ 3 files changed, 13 insertions(+) diff --git a/packages/integrations/netlify/package.json b/packages/integrations/netlify/package.json index 6ed5a8a46733..311cf3ec4187 100644 --- a/packages/integrations/netlify/package.json +++ b/packages/integrations/netlify/package.json @@ -54,6 +54,7 @@ "astro": "workspace:*", "astro-scripts": "workspace:*", "cheerio": "1.0.0", + "devalue": "^5.1.1", "execa": "^8.0.1", "fast-glob": "^3.3.3", "strip-ansi": "^7.1.0", diff --git a/packages/integrations/node/package.json b/packages/integrations/node/package.json index 0aa7aa791c0b..fa3df4b0b7bd 100644 --- a/packages/integrations/node/package.json +++ b/packages/integrations/node/package.json @@ -44,6 +44,7 @@ "astro": "workspace:*", "astro-scripts": "workspace:*", "cheerio": "1.0.0", + "devalue": "^5.1.1", "express": "^4.21.2", "node-mocks-http": "^1.16.2" }, diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 2c900ef6771c..669d9a6df9e5 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -5034,6 +5034,9 @@ importers: cheerio: specifier: 1.0.0 version: 1.0.0 + devalue: + specifier: ^5.1.1 + version: 5.1.1 execa: specifier: ^8.0.1 version: 8.0.1 @@ -5120,6 +5123,9 @@ importers: cheerio: specifier: 1.0.0 version: 1.0.0 + devalue: + specifier: ^5.1.1 + version: 5.1.1 express: specifier: ^4.21.2 version: 4.21.2 @@ -9705,6 +9711,7 @@ packages: libsql@0.4.5: resolution: {integrity: sha512-sorTJV6PNt94Wap27Sai5gtVLIea4Otb2LUiAUyr3p6BPOScGMKGt5F1b5X/XgkNtcsDKeX5qfeBDj+PdShclQ==} + cpu: [x64, arm64, wasm32] os: [darwin, linux, win32] lightningcss-darwin-arm64@1.29.1: @@ -11842,6 +11849,9 @@ packages: resolution: {integrity: sha512-M/wqwtOEjgb956/+m5ZrYT/Iq6Hax0OakWbokj8+9PXOnB7b/4AxESHieEtnNEy7ZpjsjYW1/5nK8fATQMmRxw==} peerDependencies: vue: '>=3.2.13' + peerDependenciesMeta: + vue: + optional: true vite@6.0.11: resolution: {integrity: sha512-4VL9mQPKoHy4+FE0NnRE/kbY51TOfaknxAjt3fJbGJxhIpBZiqVzlZDEesWWsuREXHwNdAoOFZ9MkPEVXczHwg==} @@ -18727,6 +18737,7 @@ snapshots: vite-svg-loader@5.1.0(vue@3.5.13(typescript@5.7.3)): dependencies: svgo: 3.3.2 + optionalDependencies: vue: 3.5.13(typescript@5.7.3) vite@6.0.11(@types/node@22.13.1)(jiti@2.4.2)(lightningcss@1.29.1)(sass@1.83.4)(yaml@2.5.1): From 304303e535053b3fc46097cf7bf5cf3b897a5136 Mon Sep 17 00:00:00 2001 From: Matt Kane Date: Fri, 7 Feb 2025 12:46:25 +0000 Subject: [PATCH 13/22] chore: fix repo URL --- packages/integrations/cloudflare/package.json | 4 ++-- packages/integrations/netlify/package.json | 4 ++-- packages/integrations/node/package.json | 4 ++-- packages/integrations/vercel/package.json | 4 ++-- 4 files changed, 8 insertions(+), 8 deletions(-) diff --git a/packages/integrations/cloudflare/package.json b/packages/integrations/cloudflare/package.json index 4888946cbdd3..6b9ee1a71139 100644 --- a/packages/integrations/cloudflare/package.json +++ b/packages/integrations/cloudflare/package.json @@ -8,14 +8,14 @@ "license": "MIT", "repository": { "type": "git", - "url": "https://github.com/withastro/adapters.git", + "url": "https://github.com/withastro/astro.git", "directory": "packages/cloudflare" }, "keywords": [ "withastro", "astro-adapter" ], - "bugs": "https://github.com/withastro/adapters/issues", + "bugs": "https://github.com/withastro/astro/issues", "homepage": "https://docs.astro.build/en/guides/integrations-guide/cloudflare/", "exports": { ".": "./dist/index.js", diff --git a/packages/integrations/netlify/package.json b/packages/integrations/netlify/package.json index 311cf3ec4187..f928823bf9f7 100644 --- a/packages/integrations/netlify/package.json +++ b/packages/integrations/netlify/package.json @@ -8,14 +8,14 @@ "license": "MIT", "repository": { "type": "git", - "url": "https://github.com/withastro/adapters.git", + "url": "https://github.com/withastro/astro.git", "directory": "packages/netlify" }, "keywords": [ "withastro", "astro-adapter" ], - "bugs": "https://github.com/withastro/adapters/issues", + "bugs": "https://github.com/withastro/astro/issues", "homepage": "https://docs.astro.build/en/guides/integrations-guide/netlify/", "exports": { ".": "./dist/index.js", diff --git a/packages/integrations/node/package.json b/packages/integrations/node/package.json index fa3df4b0b7bd..945a503eaeb7 100644 --- a/packages/integrations/node/package.json +++ b/packages/integrations/node/package.json @@ -8,14 +8,14 @@ "license": "MIT", "repository": { "type": "git", - "url": "https://github.com/withastro/adapters.git", + "url": "https://github.com/withastro/astro.git", "directory": "packages/node" }, "keywords": [ "withastro", "astro-adapter" ], - "bugs": "https://github.com/withastro/adapters/issues", + "bugs": "https://github.com/withastro/astro/issues", "homepage": "https://docs.astro.build/en/guides/integrations-guide/node/", "exports": { ".": "./dist/index.js", diff --git a/packages/integrations/vercel/package.json b/packages/integrations/vercel/package.json index f64350839713..4ae3120adafb 100644 --- a/packages/integrations/vercel/package.json +++ b/packages/integrations/vercel/package.json @@ -7,14 +7,14 @@ "license": "MIT", "repository": { "type": "git", - "url": "https://github.com/withastro/adapters.git", + "url": "https://github.com/withastro/astro.git", "directory": "packages/vercel" }, "keywords": [ "withastro", "astro-adapter" ], - "bugs": "https://github.com/withastro/adapters/issues", + "bugs": "https://github.com/withastro/astro/issues", "homepage": "https://docs.astro.build/en/guides/integrations-guide/vercel/", "exports": { ".": "./dist/index.js", From db142f0cb71d43a4dae753037c78d14676779b80 Mon Sep 17 00:00:00 2001 From: Matt Kane Date: Fri, 7 Feb 2025 14:25:59 +0000 Subject: [PATCH 14/22] temp log --- packages/astro/src/core/session.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/packages/astro/src/core/session.ts b/packages/astro/src/core/session.ts index 57e653bcd3cb..6c2bb0ffe41f 100644 --- a/packages/astro/src/core/session.ts +++ b/packages/astro/src/core/session.ts @@ -424,6 +424,7 @@ export class AstroSession { driver = (await import(driverPackage)).default; } } catch (err: any) { + console.error(err); // If the driver failed to load, throw an error. if (err.code === 'ERR_MODULE_NOT_FOUND') { throw new AstroError( @@ -473,6 +474,7 @@ export function resolveSessionDriver(driver: string | undefined): Promise Date: Fri, 7 Feb 2025 15:43:10 +0000 Subject: [PATCH 15/22] Fix module resoltuion --- packages/astro/src/core/session.ts | 19 +++++++++++-------- pnpm-lock.yaml | 5 ----- 2 files changed, 11 insertions(+), 13 deletions(-) diff --git a/packages/astro/src/core/session.ts b/packages/astro/src/core/session.ts index 6c2bb0ffe41f..f05d2914c2ac 100644 --- a/packages/astro/src/core/session.ts +++ b/packages/astro/src/core/session.ts @@ -424,7 +424,6 @@ export class AstroSession { driver = (await import(driverPackage)).default; } } catch (err: any) { - console.error(err); // If the driver failed to load, throw an error. if (err.code === 'ERR_MODULE_NOT_FOUND') { throw new AstroError( @@ -470,17 +469,21 @@ export class AstroSession { } } // TODO: make this sync when we drop support for Node < 18.19.0 -export function resolveSessionDriver(driver: string | undefined): Promise | string | null { +export async function resolveSessionDriver(driver: string | undefined): Promise { if (!driver) { return null; } - console.log({driver, id: builtinDrivers[driver as keyof typeof builtinDrivers]}); - if (driver === 'fs') { - return import.meta.resolve(builtinDrivers.fsLite); - } - if (driver in builtinDrivers) { - return import.meta.resolve(builtinDrivers[driver as keyof typeof builtinDrivers]); + try { + if (driver === 'fs') { + return await import.meta.resolve(builtinDrivers.fsLite); + } + if (driver in builtinDrivers) { + return await import.meta.resolve(builtinDrivers[driver as keyof typeof builtinDrivers]); + } + } catch { + return null; } + return driver; } diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 4e153db0e050..8706953dd982 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -10122,7 +10122,6 @@ packages: libsql@0.4.5: resolution: {integrity: sha512-sorTJV6PNt94Wap27Sai5gtVLIea4Otb2LUiAUyr3p6BPOScGMKGt5F1b5X/XgkNtcsDKeX5qfeBDj+PdShclQ==} - cpu: [x64, arm64, wasm32] os: [darwin, linux, win32] lightningcss-darwin-arm64@1.29.1: @@ -12316,9 +12315,6 @@ packages: resolution: {integrity: sha512-M/wqwtOEjgb956/+m5ZrYT/Iq6Hax0OakWbokj8+9PXOnB7b/4AxESHieEtnNEy7ZpjsjYW1/5nK8fATQMmRxw==} peerDependencies: vue: '>=3.2.13' - peerDependenciesMeta: - vue: - optional: true vite@6.0.11: resolution: {integrity: sha512-4VL9mQPKoHy4+FE0NnRE/kbY51TOfaknxAjt3fJbGJxhIpBZiqVzlZDEesWWsuREXHwNdAoOFZ9MkPEVXczHwg==} @@ -19479,7 +19475,6 @@ snapshots: vite-svg-loader@5.1.0(vue@3.5.13(typescript@5.7.3)): dependencies: svgo: 3.3.2 - optionalDependencies: vue: 3.5.13(typescript@5.7.3) vite@6.0.11(@types/node@22.13.1)(jiti@2.4.2)(lightningcss@1.29.1)(sass@1.83.4)(yaml@2.5.1): From 3ddeaf0d3d7feeb59705f82e978981f1e7726356 Mon Sep 17 00:00:00 2001 From: Matt Kane Date: Fri, 7 Feb 2025 16:52:52 +0000 Subject: [PATCH 16/22] [skip ci] Update changeset --- .changeset/cool-deers-join.md | 9 ++++++--- .changeset/thin-cobras-glow.md | 9 +++++++++ 2 files changed, 15 insertions(+), 3 deletions(-) create mode 100644 .changeset/thin-cobras-glow.md diff --git a/.changeset/cool-deers-join.md b/.changeset/cool-deers-join.md index 74d7f33dbe82..113efe5565b8 100644 --- a/.changeset/cool-deers-join.md +++ b/.changeset/cool-deers-join.md @@ -1,6 +1,9 @@ --- -'@astrojs/netlify': patch -'@astrojs/node': patch +'@astrojs/node': minor --- -Automatically configures experimental sessions when enabled +Automatically configures filesystem storage when experimental session enabled + +If the `experimental.session` flag is enabled when using the Node adapter, Astro will automatically configure session storage using the filesystem driver. You can still manually configure session storage if you need to use a different driver or want to customize the session storage configuration. + +See [the experimental session docs](https://docs.astro.build/en/reference/experimental-flags/sessions/) for more information on configuring session storage. diff --git a/.changeset/thin-cobras-glow.md b/.changeset/thin-cobras-glow.md new file mode 100644 index 000000000000..af633a0695ac --- /dev/null +++ b/.changeset/thin-cobras-glow.md @@ -0,0 +1,9 @@ +--- +'@astrojs/netlify': minor +--- + +Automatically configures Netlify Blobs storage when experimental session enabled + +If the `experimental.session` flag is enabled when using the Netlify adapter, Astro will automatically configure the session storage using the Netlify Blobs driver. You can still manually configure the session storage if you need to use a different driver or want to customize the session storage configuration. + +See [the experimental session docs](https://docs.astro.build/en/reference/experimental-flags/sessions/) for more information on configuring session storage. From d0fac272af0d5b7155078494df1ab7bd0a5614ec Mon Sep 17 00:00:00 2001 From: Matt Kane Date: Mon, 10 Feb 2025 12:16:04 +0000 Subject: [PATCH 17/22] chore: bump peer dependencies --- packages/integrations/netlify/package.json | 2 +- packages/integrations/node/package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/integrations/netlify/package.json b/packages/integrations/netlify/package.json index ffde4b547948..1c0bd6a2e3ae 100644 --- a/packages/integrations/netlify/package.json +++ b/packages/integrations/netlify/package.json @@ -45,7 +45,7 @@ "vite": "^6.0.7" }, "peerDependencies": { - "astro": "^5.0.0" + "astro": "^5.3.0" }, "devDependencies": { "@netlify/edge-functions": "^2.11.1", diff --git a/packages/integrations/node/package.json b/packages/integrations/node/package.json index 1789b1ed9881..205eb56fb228 100644 --- a/packages/integrations/node/package.json +++ b/packages/integrations/node/package.json @@ -35,7 +35,7 @@ "server-destroy": "^1.0.1" }, "peerDependencies": { - "astro": "^5.0.0" + "astro": "^5.3.0" }, "devDependencies": { "@types/node": "^22.10.6", From 704fe3e480aa2c3fc08f41477c06361fa7c9b92d Mon Sep 17 00:00:00 2001 From: Matt Kane Date: Mon, 10 Feb 2025 16:10:18 +0000 Subject: [PATCH 18/22] Changes from review --- packages/astro/src/integrations/hooks.ts | 4 ++++ packages/astro/src/types/public/config.ts | 20 ++++++++++---------- 2 files changed, 14 insertions(+), 10 deletions(-) diff --git a/packages/astro/src/integrations/hooks.ts b/packages/astro/src/integrations/hooks.ts index 4e391e247fbb..17a5a7dbda31 100644 --- a/packages/astro/src/integrations/hooks.ts +++ b/packages/astro/src/integrations/hooks.ts @@ -370,6 +370,10 @@ export async function runHookConfigDone({ }); } } + // Session config is validated after all integrations have had a chance to + // register a default session driver, and we know the output type. + // This can't happen in the Zod schema because it that happens before adapters run + // and also doesn't know whether it's a server build or static build. validateSessionConfig(settings); } diff --git a/packages/astro/src/types/public/config.ts b/packages/astro/src/types/public/config.ts index 3b4711e48d64..7f5920f85ab5 100644 --- a/packages/astro/src/types/public/config.ts +++ b/packages/astro/src/types/public/config.ts @@ -1740,16 +1740,16 @@ export interface ViteUserConfig extends OriginalViteUserConfig { * See [the experimental session guide](https://docs.astro.build/en/reference/experimental-flags/sessions/) for more information. * * ```js title="astro.config.mjs" - * { - * session: { - * // Required: the name of the Unstorage driver - * driver: "redis", - * // The required options depend on the driver - * options: { - * url: process.env.REDIS_URL, - * } - * }, - * } + * { + * session: { + * // Required: the name of the Unstorage driver + * driver: 'redis', + * // The required options depend on the driver + * options: { + * url: process.env.REDIS_URL, + * }, + * } + * } * ``` */ session?: SessionConfig; From db89093d9037bcd9a63ab73fafd9d4dbda53c14e Mon Sep 17 00:00:00 2001 From: Matt Kane Date: Mon, 10 Feb 2025 16:17:08 +0000 Subject: [PATCH 19/22] Changeset changes from review --- .changeset/tame-games-enjoy.md | 7 +++++++ .changeset/tricky-insects-argue.md | 21 ++------------------- 2 files changed, 9 insertions(+), 19 deletions(-) create mode 100644 .changeset/tame-games-enjoy.md diff --git a/.changeset/tame-games-enjoy.md b/.changeset/tame-games-enjoy.md new file mode 100644 index 000000000000..c041923e7889 --- /dev/null +++ b/.changeset/tame-games-enjoy.md @@ -0,0 +1,7 @@ +--- +'astro': minor +--- + +Adds support for adapters auto-configuring experimental session storage drivers. + +Adapters can now configure a default session storage driver when the `experimental.session` flag is enabled. If a hosting platform has a storage primitive that can be used for session storage, the adapter can automatically configure the session storage using that driver. This allows Astro to provide a more seamless experience for users who want to use sessions without needing to manually configure the session storage. diff --git a/.changeset/tricky-insects-argue.md b/.changeset/tricky-insects-argue.md index 0e51eba36709..769d5a4dc82b 100644 --- a/.changeset/tricky-insects-argue.md +++ b/.changeset/tricky-insects-argue.md @@ -1,5 +1,5 @@ --- -'astro': minor +'astro': patch --- :warning: **BREAKING CHANGE FOR EXPERIMENTAL SESSIONS ONLY** :warning: @@ -21,21 +21,4 @@ defineConfig({ }); ``` -You do not need to configure the session driver if you are using the Node or Netlify adapters and want to use the default session drivers for each adapter. The default session driver for the Node adapter is `fs`, and the default session driver for the Netlify adapter is `netlify-blobs`. - -For example, if you are using the Node adapter, you can just enable the flag: - -```js -defineConfig({ - // ... - adapter: node({ - mode: 'standalone', - }), - experimental: { - session: true, - }, -}); -``` -This will configure the session driver to use the default `fs` driver for the Node adapter. See the release notes for `@astrojs/node` and `@astrojs/netlify` for more information on the default session drivers for each adapter. - -If you enable the flag but are using an adapter that does not have a default session driver, you will need to configure the session driver manually or the build will fail. +You do not need to configure the session driver if you are using an adapter that supports automatic session driver configuration. For more information, see the [experimental session docs](https://docs.astro.build/en/reference/experimental-flags/sessions/). From 7d4f1da8bb9287d8979e6c1170f9e71f331226ee Mon Sep 17 00:00:00 2001 From: Matt Kane Date: Wed, 12 Feb 2025 10:14:31 +0000 Subject: [PATCH 20/22] Apply suggestions from code review Co-authored-by: Sarah Rainsberger <5098874+sarah11918@users.noreply.github.com> --- .changeset/tricky-insects-argue.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/.changeset/tricky-insects-argue.md b/.changeset/tricky-insects-argue.md index 769d5a4dc82b..1ada96cd3a1f 100644 --- a/.changeset/tricky-insects-argue.md +++ b/.changeset/tricky-insects-argue.md @@ -21,4 +21,6 @@ defineConfig({ }); ``` -You do not need to configure the session driver if you are using an adapter that supports automatic session driver configuration. For more information, see the [experimental session docs](https://docs.astro.build/en/reference/experimental-flags/sessions/). +You no longer need to configure a session driver if you are using an adapter that supports automatic session driver configuration and wish to use its default settings. + +However, you can still manually configure additional driver options or choose a non-default driver to use with your adapter with the new top-level `session` config option. For more information, see the [experimental session docs](https://docs.astro.build/en/reference/experimental-flags/sessions/). From 1801e550b26405ed5db41cf2cabc355c35ee5c02 Mon Sep 17 00:00:00 2001 From: Matt Kane Date: Wed, 12 Feb 2025 10:18:40 +0000 Subject: [PATCH 21/22] More changeset detail --- .changeset/tricky-insects-argue.md | 24 +++++++++++++++++++++--- 1 file changed, 21 insertions(+), 3 deletions(-) diff --git a/.changeset/tricky-insects-argue.md b/.changeset/tricky-insects-argue.md index 1ada96cd3a1f..6b72528177dc 100644 --- a/.changeset/tricky-insects-argue.md +++ b/.changeset/tricky-insects-argue.md @@ -11,16 +11,34 @@ defineConfig({ // ... experimental: { - session: { -- driver: 'fs', +- driver: 'upstash', - }, + session: true, }, + session: { -+ driver: 'fs', -+ }, ++ driver: 'upstash', ++ }, }); ``` You no longer need to configure a session driver if you are using an adapter that supports automatic session driver configuration and wish to use its default settings. +```diff +defineConfig({ + adapter: node({ + mode: "standalone", + }), + experimental: { +- session: { +- driver: 'fs', +- cookie: 'astro-cookie', +- }, ++ session: true, + }, ++ session: { ++ cookie: 'astro-cookie', ++ }, +}); +``` + However, you can still manually configure additional driver options or choose a non-default driver to use with your adapter with the new top-level `session` config option. For more information, see the [experimental session docs](https://docs.astro.build/en/reference/experimental-flags/sessions/). From f673dee8a9a0058aca66a5689b7cb19e8a85877a Mon Sep 17 00:00:00 2001 From: Matt Kane Date: Wed, 12 Feb 2025 14:22:28 +0000 Subject: [PATCH 22/22] Lock --- pnpm-lock.yaml | 205 +++++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 174 insertions(+), 31 deletions(-) diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 3ba60adbd56e..afc02e0b359f 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -142,7 +142,7 @@ importers: examples/basics: dependencies: astro: - specifier: ^5.2.5 + specifier: ^5.2.6 version: link:../../packages/astro examples/blog: @@ -157,13 +157,13 @@ importers: specifier: ^3.2.1 version: link:../../packages/integrations/sitemap astro: - specifier: ^5.2.5 + specifier: ^5.2.6 version: link:../../packages/astro examples/component: devDependencies: astro: - specifier: ^5.2.5 + specifier: ^5.2.6 version: link:../../packages/astro examples/container-with-vitest: @@ -172,7 +172,7 @@ importers: specifier: ^4.2.0 version: link:../../packages/integrations/react astro: - specifier: ^5.2.5 + specifier: ^5.2.6 version: link:../../packages/astro react: specifier: ^18.3.1 @@ -203,7 +203,7 @@ importers: specifier: ^3.14.8 version: 3.14.8 astro: - specifier: ^5.2.5 + specifier: ^5.2.6 version: link:../../packages/astro examples/framework-multiple: @@ -230,7 +230,7 @@ importers: specifier: ^18.3.5 version: 18.3.5(@types/react@18.3.18) astro: - specifier: ^5.2.5 + specifier: ^5.2.6 version: link:../../packages/astro preact: specifier: ^10.25.4 @@ -260,7 +260,7 @@ importers: specifier: ^2.0.1 version: 2.0.1(preact@10.25.4) astro: - specifier: ^5.2.5 + specifier: ^5.2.6 version: link:../../packages/astro preact: specifier: ^10.25.4 @@ -278,7 +278,7 @@ importers: specifier: ^18.3.5 version: 18.3.5(@types/react@18.3.18) astro: - specifier: ^5.2.5 + specifier: ^5.2.6 version: link:../../packages/astro react: specifier: ^18.3.1 @@ -293,7 +293,7 @@ importers: specifier: ^5.0.4 version: link:../../packages/integrations/solid astro: - specifier: ^5.2.5 + specifier: ^5.2.6 version: link:../../packages/astro solid-js: specifier: ^1.9.4 @@ -305,7 +305,7 @@ importers: specifier: ^7.0.4 version: link:../../packages/integrations/svelte astro: - specifier: ^5.2.5 + specifier: ^5.2.6 version: link:../../packages/astro svelte: specifier: ^5.19.7 @@ -317,7 +317,7 @@ importers: specifier: ^5.0.6 version: link:../../packages/integrations/vue astro: - specifier: ^5.2.5 + specifier: ^5.2.6 version: link:../../packages/astro vue: specifier: ^3.5.13 @@ -326,40 +326,40 @@ importers: examples/hackernews: dependencies: '@astrojs/node': - specifier: ^9.0.2 + specifier: ^9.0.3 version: link:../../packages/integrations/node astro: - specifier: ^5.2.5 + specifier: ^5.2.6 version: link:../../packages/astro examples/integration: devDependencies: astro: - specifier: ^5.2.5 + specifier: ^5.2.6 version: link:../../packages/astro examples/minimal: dependencies: astro: - specifier: ^5.2.5 + specifier: ^5.2.6 version: link:../../packages/astro examples/portfolio: dependencies: astro: - specifier: ^5.2.5 + specifier: ^5.2.6 version: link:../../packages/astro examples/ssr: dependencies: '@astrojs/node': - specifier: ^9.0.2 + specifier: ^9.0.3 version: link:../../packages/integrations/node '@astrojs/svelte': specifier: ^7.0.4 version: link:../../packages/integrations/svelte astro: - specifier: ^5.2.5 + specifier: ^5.2.6 version: link:../../packages/astro svelte: specifier: ^5.19.7 @@ -368,7 +368,7 @@ importers: examples/starlog: dependencies: astro: - specifier: ^5.2.5 + specifier: ^5.2.6 version: link:../../packages/astro sass: specifier: ^1.83.4 @@ -383,7 +383,7 @@ importers: specifier: ^18.17.8 version: 18.19.50 astro: - specifier: ^5.2.5 + specifier: ^5.2.6 version: link:../../packages/astro examples/with-markdoc: @@ -392,7 +392,7 @@ importers: specifier: ^0.12.9 version: link:../../packages/integrations/markdoc astro: - specifier: ^5.2.5 + specifier: ^5.2.6 version: link:../../packages/astro examples/with-mdx: @@ -404,7 +404,7 @@ importers: specifier: ^4.0.4 version: link:../../packages/integrations/preact astro: - specifier: ^5.2.5 + specifier: ^5.2.6 version: link:../../packages/astro preact: specifier: ^10.25.4 @@ -419,7 +419,7 @@ importers: specifier: ^0.5.2 version: 0.5.2(nanostores@0.11.3)(preact@10.25.4) astro: - specifier: ^5.2.5 + specifier: ^5.2.6 version: link:../../packages/astro nanostores: specifier: ^0.11.3 @@ -440,7 +440,7 @@ importers: specifier: ^1.9.0 version: 1.9.0 astro: - specifier: ^5.2.5 + specifier: ^5.2.6 version: link:../../packages/astro canvas-confetti: specifier: ^1.9.3 @@ -452,7 +452,7 @@ importers: examples/with-vitest: dependencies: astro: - specifier: ^5.2.5 + specifier: ^5.2.6 version: link:../../packages/astro vitest: specifier: ^3.0.5 @@ -5234,6 +5234,15 @@ importers: specifier: 'workspace:' version: link:../../../.. + packages/integrations/netlify/test/functions/fixtures/includes: + dependencies: + '@astrojs/netlify': + specifier: 'workspace:' + version: link:../../../.. + cowsay: + specifier: 1.6.0 + version: 1.6.0 + packages/integrations/netlify/test/functions/fixtures/middleware: dependencies: '@astrojs/netlify': @@ -5276,6 +5285,9 @@ importers: packages/integrations/node: dependencies: + '@astrojs/internal-helpers': + specifier: workspace:* + version: link:../../internal-helpers send: specifier: ^1.1.0 version: 1.1.0 @@ -5564,7 +5576,7 @@ importers: version: 3.24.1 devDependencies: '@astrojs/node': - specifier: ^9.0.0 + specifier: ^9.0.3 version: link:../node astro: specifier: workspace:* @@ -5702,8 +5714,8 @@ importers: specifier: ^0.29.0 version: 0.29.1(rollup@4.34.2) '@vercel/routing-utils': - specifier: 5.0.2 - version: 5.0.2 + specifier: ^5.0.4 + version: 5.0.4 esbuild: specifier: ^0.24.0 version: 0.24.2 @@ -8339,8 +8351,8 @@ packages: engines: {node: '>=18'} hasBin: true - '@vercel/routing-utils@5.0.2': - resolution: {integrity: sha512-uJViB3+HEo+kzHYELs7cQWX5k0kCNvq9G/8nJQX8mP5Ta0fG68CBRmOaaG8A+2xbtTp/QuGORIwV8CsI9ebcNg==} + '@vercel/routing-utils@5.0.4': + resolution: {integrity: sha512-4ke67zkXVi2fRZdoYckABcsSkRC9CnrdadOGxoS/Bk22+ObHjGQWvUHExRSXh339anwu9YY7ZacNSGH4gUnTQA==} '@vitejs/plugin-react@4.3.4': resolution: {integrity: sha512-SCCPBJtYLdE8PX/7ZQAs1QAZ8Jqwih+0VBLum1EGqmCCQal+MIUqLCzj3ZUy8ufbC0cAM4LRlSTm7IQJwWT4ug==} @@ -8542,6 +8554,10 @@ packages: resolution: {integrity: sha512-5GFMVX8HqE/TB+FuBJGuO5XG0WrsA6ptUqoODaT/n9mmUaZFkqnBueB4leqGBCmrUHnCnC4PCZTCd0E7QQ83bA==} engines: {node: '>=12'} + ansi-regex@3.0.1: + resolution: {integrity: sha512-+O9Jct8wf++lXxxFc4hc8LsjaSq0HFzzL7cVsw8pRDIPdjKD2mT4ytDZlLuSBZ4cLKZFXIrMGO7DbQCtMJJMKw==} + engines: {node: '>=4'} + ansi-regex@5.0.1: resolution: {integrity: sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==} engines: {node: '>=8'} @@ -8749,6 +8765,10 @@ packages: resolution: {integrity: sha512-QOSvevhslijgYwRx6Rv7zKdMF8lbRmx+uQGx2+vDc+KI/eBnsy9kit5aj23AgGu3pa4t9AgwbnXWqS+iOY+2aA==} engines: {node: '>= 6'} + camelcase@5.3.1: + resolution: {integrity: sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==} + engines: {node: '>=6'} + camelcase@8.0.0: resolution: {integrity: sha512-8WB3Jcas3swSvjIeA2yvCJ+Miyz5l1ZmB6HFb9R1317dt9LCQoswg/BGrmAmkWVEszSrrg4RwmO46qIm2OEnSA==} engines: {node: '>=16'} @@ -8839,6 +8859,9 @@ packages: resolution: {integrity: sha512-+W/5efTR7y5HRD7gACw9yQjqMVvEMLBHmboM/kPWam+H+Hmyrgjh6YncVKK122YZkXrLudzTuAukUw9FnMf7IQ==} engines: {node: 10.* || >= 12.*} + cliui@6.0.0: + resolution: {integrity: sha512-t6wbgtoCXvAzst7QgXxJYqPt0usEfbgQdftEPbLL/cvv6HPE5VgvqCuAIDR0NgU52ds6rFwqrgakNLrHEjCbrQ==} + cliui@8.0.1: resolution: {integrity: sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==} engines: {node: '>=12'} @@ -8937,6 +8960,11 @@ packages: resolution: {integrity: sha512-yCEafptTtb4bk7GLEQoM8KVJpxAfdBJYaXyzQEgQQQgYrZiDp8SJmGKlYza6CYjEDNstAdNdKA3UuoULlEbS6w==} engines: {node: '>=12.13'} + cowsay@1.6.0: + resolution: {integrity: sha512-8C4H1jdrgNusTQr3Yu4SCm+ZKsAlDFbpa0KS0Z3im8ueag+9pGOf3CrioruvmeaW/A5oqg9L0ar6qeftAh03jw==} + engines: {node: '>= 4'} + hasBin: true + cross-argv@2.0.0: resolution: {integrity: sha512-YIaY9TR5Nxeb8SMdtrU8asWVM4jqJDNDYlKV21LxtYcfNJhp1kEsgSa6qXwXgzN0WQWGODps0+TlGp2xQSHwOg==} @@ -9039,6 +9067,10 @@ packages: supports-color: optional: true + decamelize@1.2.0: + resolution: {integrity: sha512-z2S+W9X73hAUUki+N+9Za2lBlun89zigOyGrsax+KUQ6wKW4ZoWpEYBkGhQjwAjjDCkWxhY0VKEhk8wzY7F5cA==} + engines: {node: '>=0.10.0'} + decimal.js@10.4.3: resolution: {integrity: sha512-VBBaLc1MgL5XpzgIP7ny5Z6Nx3UrRkIViUkPUdtl9aya5amy3De1gsUUSB1g3+3sExYNjCAsAznmukyxCb1GRA==} @@ -9673,6 +9705,10 @@ packages: get-source@2.0.12: resolution: {integrity: sha512-X5+4+iD+HoSeEED+uwrQ07BOQr0kEDFMVqqpBuI+RaZBpBpHCuXxo70bjar6f0b0u/DQJsJ7ssurpP0V60Az+w==} + get-stdin@8.0.0: + resolution: {integrity: sha512-sY22aA6xchAzprjyqmSEQv4UbAAzRN0L2dQB0NlN5acTTK9Don6nhoc3eAbUnpZiCANAMfd/+40kVdKfFygohg==} + engines: {node: '>=10'} + get-stream@8.0.1: resolution: {integrity: sha512-VaUJspBffn/LMCJVoMvSAdmscJyS1auj5Zulnn5UoYcY531UWmdwhRWkcGKnGU93m5HSXP9LP2usOryrBtQowA==} engines: {node: '>=16'} @@ -9958,6 +9994,10 @@ packages: resolution: {integrity: sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==} engines: {node: '>=0.10.0'} + is-fullwidth-code-point@2.0.0: + resolution: {integrity: sha512-VHskAKYM8RfSFXwee5t5cbN5PZeq1Wrh6qd5bkyiXIf6UQcN6w/A0eXM9r6t8d+GYOh+o6ZhiEnb88LN/Y8m2w==} + engines: {node: '>=4'} + is-fullwidth-code-point@3.0.0: resolution: {integrity: sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==} engines: {node: '>=8'} @@ -11445,6 +11485,9 @@ packages: resolution: {integrity: sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==} engines: {node: '>=0.10.0'} + require-main-filename@2.0.0: + resolution: {integrity: sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==} + requires-port@1.0.0: resolution: {integrity: sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ==} @@ -11588,6 +11631,9 @@ packages: server-destroy@1.0.1: resolution: {integrity: sha512-rb+9B5YBIEzYcD6x2VKidaa+cqYBJQKnU4oe4E3ANwRRN56yk/ua1YCJT1n21NTS8w6CcOclAKNP3PhdCXKYtQ==} + set-blocking@2.0.0: + resolution: {integrity: sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw==} + setprototypeof@1.2.0: resolution: {integrity: sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==} @@ -11754,6 +11800,10 @@ packages: stream-replace-string@2.0.0: resolution: {integrity: sha512-TlnjJ1C0QrmxRNrON00JvaFFlNh5TTG00APw23j74ET7gkQpTASi6/L2fuiav8pzK715HXtUeClpBTw2NPSn6w==} + string-width@2.1.1: + resolution: {integrity: sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==} + engines: {node: '>=4'} + string-width@4.2.3: resolution: {integrity: sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==} engines: {node: '>=8'} @@ -11769,6 +11819,10 @@ packages: stringify-entities@4.0.4: resolution: {integrity: sha512-IwfBptatlO+QCJUo19AqvrPNqlVMpW9YEL2LIVY+Rpv2qsjCGxaDLNRgeGsQWJhfItebuJhsGSLjaBbNSQ+ieg==} + strip-ansi@4.0.0: + resolution: {integrity: sha512-4XaJ2zQdCzROZDivEVIDPkcQn8LMFSa8kj8Gxb/Lnwzv9A8VctNZ+lfivC/sV3ivW8ElJTERXZoPBRrZKkNKow==} + engines: {node: '>=4'} + strip-ansi@6.0.1: resolution: {integrity: sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==} engines: {node: '>=8'} @@ -11781,6 +11835,10 @@ packages: resolution: {integrity: sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==} engines: {node: '>=4'} + strip-final-newline@2.0.0: + resolution: {integrity: sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==} + engines: {node: '>=6'} + strip-final-newline@3.0.0: resolution: {integrity: sha512-dOESqjYr96iWYylGObzd39EuNTa5VJxyvVAEm5Jnh7KGo75V43Hk1odPQkNDyXNmUR6k+gEiDVXnjB8HJ3crXw==} engines: {node: '>=12'} @@ -12551,6 +12609,9 @@ packages: whatwg-url@5.0.0: resolution: {integrity: sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==} + which-module@2.0.1: + resolution: {integrity: sha512-iBdZ57RDvnOR9AGBhML2vFZf7h8vmBjhoaZqODJBFWHVtKkDmKuHai3cx5PgVMrX5YDNp27AofYbAwctSS+vhQ==} + which-pm-runs@1.1.0: resolution: {integrity: sha512-n1brCuqClxfFfq/Rb0ICg9giSZqCS+pLtccdag6C2HyufBrh3fBOiy9nb6ggRMvWOVH5GrdJskj5iGTZNxd7SA==} engines: {node: '>=4'} @@ -12595,6 +12656,10 @@ packages: '@cloudflare/workers-types': optional: true + wrap-ansi@6.2.0: + resolution: {integrity: sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==} + engines: {node: '>=8'} + wrap-ansi@7.0.0: resolution: {integrity: sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==} engines: {node: '>=10'} @@ -12656,6 +12721,9 @@ packages: xxhash-wasm@1.1.0: resolution: {integrity: sha512-147y/6YNh+tlp6nd/2pWq38i9h6mz/EuQ6njIrmW8D1BS5nCqs0P6DG+m6zTGnNz5I+uhZ0SHxBs9BsPrwcKDA==} + y18n@4.0.3: + resolution: {integrity: sha512-JKhqTOwSrqNA1NY5lSztJ1GrBiUodLMmIZuLiDaMRJ+itFd+ABVE8XBjOvIWL+rSqNDC74LCSFmlb/U4UZ4hJQ==} + y18n@5.0.8: resolution: {integrity: sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==} engines: {node: '>=10'} @@ -12683,10 +12751,18 @@ packages: engines: {node: '>= 14'} hasBin: true + yargs-parser@18.1.3: + resolution: {integrity: sha512-o50j0JeToy/4K6OZcaQmW6lyXXKhq7csREXcDwk2omFPJEwUNOVtJKvmDr9EI1fAJZUyZcRF7kxGBWmRXudrCQ==} + engines: {node: '>=6'} + yargs-parser@21.1.1: resolution: {integrity: sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==} engines: {node: '>=12'} + yargs@15.4.1: + resolution: {integrity: sha512-aePbxDmcYW++PaqBsJ+HYUFwCdv4LVvdnhBy78E57PIor8/OVvhMrADFFEDh8DHDFRv/O9i3lPhsENjO7QX0+A==} + engines: {node: '>=8'} + yargs@17.7.2: resolution: {integrity: sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==} engines: {node: '>=12'} @@ -14777,7 +14853,7 @@ snapshots: - rollup - supports-color - '@vercel/routing-utils@5.0.2': + '@vercel/routing-utils@5.0.4': dependencies: path-to-regexp: 6.1.0 path-to-regexp-updated: path-to-regexp@6.3.0 @@ -15079,6 +15155,8 @@ snapshots: dependencies: type-fest: 1.4.0 + ansi-regex@3.0.1: {} + ansi-regex@5.0.1: {} ansi-regex@6.1.0: {} @@ -15319,6 +15397,8 @@ snapshots: camelcase-css@2.0.1: {} + camelcase@5.3.1: {} + camelcase@8.0.0: {} caniuse-lite@1.0.30001667: {} @@ -15415,6 +15495,12 @@ snapshots: optionalDependencies: '@colors/colors': 1.5.0 + cliui@6.0.0: + dependencies: + string-width: 4.2.3 + strip-ansi: 6.0.1 + wrap-ansi: 6.2.0 + cliui@8.0.1: dependencies: string-width: 4.2.3 @@ -15487,6 +15573,13 @@ snapshots: dependencies: is-what: 4.1.16 + cowsay@1.6.0: + dependencies: + get-stdin: 8.0.0 + string-width: 2.1.1 + strip-final-newline: 2.0.0 + yargs: 15.4.1 + cross-argv@2.0.0: {} cross-spawn@7.0.6: @@ -15574,6 +15667,8 @@ snapshots: dependencies: ms: 2.1.3 + decamelize@1.2.0: {} + decimal.js@10.4.3: {} decode-named-character-reference@1.0.2: @@ -16206,6 +16301,8 @@ snapshots: data-uri-to-buffer: 2.0.2 source-map: 0.6.1 + get-stdin@8.0.0: {} + get-stream@8.0.1: {} get-stream@9.0.1: @@ -16613,6 +16710,8 @@ snapshots: is-extglob@2.1.1: {} + is-fullwidth-code-point@2.0.0: {} + is-fullwidth-code-point@3.0.0: {} is-fullwidth-code-point@4.0.0: {} @@ -18456,6 +18555,8 @@ snapshots: require-from-string@2.0.2: {} + require-main-filename@2.0.0: {} + requires-port@1.0.0: {} resolve-from@4.0.0: {} @@ -18651,6 +18752,8 @@ snapshots: server-destroy@1.0.1: {} + set-blocking@2.0.0: {} + setprototypeof@1.2.0: {} sharp@0.33.3: @@ -18874,6 +18977,11 @@ snapshots: stream-replace-string@2.0.0: {} + string-width@2.1.1: + dependencies: + is-fullwidth-code-point: 2.0.0 + strip-ansi: 4.0.0 + string-width@4.2.3: dependencies: emoji-regex: 8.0.0 @@ -18897,6 +19005,10 @@ snapshots: character-entities-html4: 2.1.0 character-entities-legacy: 3.0.0 + strip-ansi@4.0.0: + dependencies: + ansi-regex: 3.0.1 + strip-ansi@6.0.1: dependencies: ansi-regex: 5.0.1 @@ -18907,6 +19019,8 @@ snapshots: strip-bom@3.0.0: {} + strip-final-newline@2.0.0: {} + strip-final-newline@3.0.0: {} strip-final-newline@4.0.0: {} @@ -19690,6 +19804,8 @@ snapshots: tr46: 0.0.3 webidl-conversions: 3.0.1 + which-module@2.0.1: {} + which-pm-runs@1.1.0: {} which-pm@3.0.1: @@ -19739,6 +19855,12 @@ snapshots: - bufferutil - utf-8-validate + wrap-ansi@6.2.0: + dependencies: + ansi-styles: 4.3.0 + string-width: 4.2.3 + strip-ansi: 6.0.1 + wrap-ansi@7.0.0: dependencies: ansi-styles: 4.3.0 @@ -19778,6 +19900,8 @@ snapshots: xxhash-wasm@1.1.0: {} + y18n@4.0.3: {} + y18n@5.0.8: {} yallist@3.1.1: {} @@ -19805,8 +19929,27 @@ snapshots: yaml@2.5.1: {} + yargs-parser@18.1.3: + dependencies: + camelcase: 5.3.1 + decamelize: 1.2.0 + yargs-parser@21.1.1: {} + yargs@15.4.1: + dependencies: + cliui: 6.0.0 + decamelize: 1.2.0 + find-up: 4.1.0 + get-caller-file: 2.0.5 + require-directory: 2.1.1 + require-main-filename: 2.0.0 + set-blocking: 2.0.0 + string-width: 4.2.3 + which-module: 2.0.1 + y18n: 4.0.3 + yargs-parser: 18.1.3 + yargs@17.7.2: dependencies: cliui: 8.0.1