diff options
| author | 2025-04-02 11:30:54 +0100 | |
|---|---|---|
| committer | 2025-04-02 11:30:54 +0100 | |
| commit | c43bf8cd0513c2260d4ba32b5beffe97306e2e09 (patch) | |
| tree | 15de99ad7cd7f91f9db558a569e4ece40621c7e8 | |
| parent | 0edd79fb54906e40dfc423534e387d1fe1855f7e (diff) | |
| download | astro-c43bf8cd0513c2260d4ba32b5beffe97306e2e09.tar.gz astro-c43bf8cd0513c2260d4ba32b5beffe97306e2e09.tar.zst astro-c43bf8cd0513c2260d4ba32b5beffe97306e2e09.zip | |
feat: add `session.load(id)` method (#13539)
| -rw-r--r-- | .changeset/famous-areas-peel.md | 7 | ||||
| -rw-r--r-- | packages/astro/src/core/session.ts | 14 | ||||
| -rw-r--r-- | packages/astro/test/fixtures/sessions/src/actions/index.ts | 8 | ||||
| -rw-r--r-- | packages/astro/test/sessions.test.js | 28 |
4 files changed, 57 insertions, 0 deletions
diff --git a/.changeset/famous-areas-peel.md b/.changeset/famous-areas-peel.md new file mode 100644 index 000000000..958f1c0be --- /dev/null +++ b/.changeset/famous-areas-peel.md @@ -0,0 +1,7 @@ +--- +'astro': patch +--- + +Adds support for loading a session by ID + +Adds a new `session.load()` method to the experimental session API that allows you to load a session by ID. In normal use a session is loaded automatically from the session cookie. This method allows a session to be loaded manually instead. This is useful for cases where the session ID has been persisted somewhere other than the browser cookie. For example, a session ID might be stored in a user database. This would allow that user's session to be loaded when logging-in on another device or in a different browser. It would also allow a session to be loaded in an API when cookies can't be set, such as when loading across domains. diff --git a/packages/astro/src/core/session.ts b/packages/astro/src/core/session.ts index 89bffd348..f86fa536b 100644 --- a/packages/astro/src/core/session.ts +++ b/packages/astro/src/core/session.ts @@ -293,6 +293,20 @@ export class AstroSession<TDriver extends SessionDriverName = any> { } /** + * Loads a session from storage with the given ID, and replaces the current session. + * Any changes made to the current session will be lost. + * This is not normally needed, as the session is automatically loaded using the cookie. + * However it can be used to restore a session where the ID has been recorded somewhere + * else (e.g. in a database). + */ + async load(sessionID: string) { + this.#sessionID = sessionID; + this.#data = undefined; + await this.#setCookie(); + await this.#ensureData(); + } + + /** * Sets the session cookie. */ async #setCookie() { diff --git a/packages/astro/test/fixtures/sessions/src/actions/index.ts b/packages/astro/test/fixtures/sessions/src/actions/index.ts index 856f68ba8..5935e9ea0 100644 --- a/packages/astro/test/fixtures/sessions/src/actions/index.ts +++ b/packages/astro/test/fixtures/sessions/src/actions/index.ts @@ -17,6 +17,14 @@ export const server = { return await context.session.get('cart'); }, }), + loadCart: defineAction({ + input: z.object({ id: z.string() }), + handler: async (input, context) => { + context.session.load(input.id); + const cart = await context.session.get('cart'); + return { cart }; + } + }), clearCart: defineAction({ accept: 'json', handler: async (input, context) => { diff --git a/packages/astro/test/sessions.test.js b/packages/astro/test/sessions.test.js index 738a0c0a3..212ed4657 100644 --- a/packages/astro/test/sessions.test.js +++ b/packages/astro/test/sessions.test.js @@ -99,6 +99,34 @@ describe('Astro.session', () => { 'Favorite URL set to https://example.com/ from https://domain.invalid/', ); }); + + it('can load a session by ID', async () => { + const firstResponse = await fetchResponse('/_actions/addToCart', { + method: 'POST', + headers: { + 'Content-Type': 'application/x-www-form-urlencoded', + 'Origin': 'http://example.com', + }, + body: new URLSearchParams({ productId: 'item1' }), + }); + const firstResponseData = devalue.parse(await firstResponse.text()); + assert.equal(firstResponseData.cart.includes('item1'), true); + + const firstHeaders = Array.from(app.setCookieHeaders(firstResponse)); + const firstSessionId = firstHeaders[0].split(';')[0].split('=')[1]; + + // Load without a cookie, but with the session ID for the action to load + const secondResponse = await fetchResponse('/_actions/loadCart', { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + }, + body: JSON.stringify({ id: firstSessionId }), + }); + const cartData = devalue.parse(await secondResponse.text()); + assert.deepEqual(cartData.cart, firstResponseData.cart); + }); + }); describe('Development', () => { |
