From b11acc6156a7c62eb2fadd706d4ee8d509424696 Mon Sep 17 00:00:00 2001 From: bluwy Date: Wed, 5 Oct 2022 17:43:59 +0800 Subject: [PATCH 01/14] Add new fields to API route context --- .changeset/fifty-ads-march.md | 5 ++ packages/astro/src/@types/astro.ts | 52 ++++++++++++++----- packages/astro/src/core/endpoint/dev/index.ts | 2 + packages/astro/src/core/endpoint/index.ts | 41 ++++++++++++++- packages/astro/src/core/render/core.ts | 2 +- .../fixtures/ssr-api-route/astro.config.mjs | 8 +++ .../test/fixtures/ssr-api-route/package.json | 1 + .../src/pages/context/[param].js | 16 ++++++ packages/astro/test/ssr-api-route.test.js | 27 ++++++++++ pnpm-lock.yaml | 2 + 10 files changed, 141 insertions(+), 15 deletions(-) create mode 100644 .changeset/fifty-ads-march.md create mode 100644 packages/astro/test/fixtures/ssr-api-route/astro.config.mjs create mode 100644 packages/astro/test/fixtures/ssr-api-route/src/pages/context/[param].js diff --git a/.changeset/fifty-ads-march.md b/.changeset/fifty-ads-march.md new file mode 100644 index 000000000000..dc826f7c0b73 --- /dev/null +++ b/.changeset/fifty-ads-march.md @@ -0,0 +1,5 @@ +--- +'astro': minor +--- + +Add `site`, `generator`, `url`, and `clientAddress` fields to API route context diff --git a/packages/astro/src/@types/astro.ts b/packages/astro/src/@types/astro.ts index 12782752c1aa..362ad193ada6 100644 --- a/packages/astro/src/@types/astro.ts +++ b/packages/astro/src/@types/astro.ts @@ -93,7 +93,7 @@ export interface BuildConfig { * * [Astro reference](https://docs.astro.build/reference/api-reference/#astro-global) */ -export interface AstroGlobal extends AstroGlobalPartial { +export interface AstroGlobal extends AstroGlobalPartial, AstroSharedContext { /** * Canonical URL of the current page. * @deprecated Use `Astro.url` instead. @@ -106,21 +106,13 @@ export interface AstroGlobal extends AstroGlobalPartial { * ``` */ canonicalURL: URL; - /** The address (usually IP address) of the user. Used with SSR only. - * - */ - clientAddress: string; /** * A full URL object of the request URL. * Equivalent to: `new URL(Astro.request.url)` * * [Astro reference](https://docs.astro.build/en/reference/api-reference/#url) */ - /** - * Utility for getting and setting cookies values. - */ - cookies: AstroCookies; - url: URL; + url: AstroSharedContext['url']; /** Parameters passed to a dynamic page generated using [getStaticPaths](https://docs.astro.build/en/reference/api-reference/#getstaticpaths) * * Example usage: @@ -139,7 +131,7 @@ export interface AstroGlobal extends AstroGlobalPartial { * * [Astro reference](https://docs.astro.build/en/reference/api-reference/#params) */ - params: Params; + params: AstroSharedContext['params']; /** List of props passed to this component * * A common way to get specific props is through [destructuring](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Destructuring_assignment), ex: @@ -1095,10 +1087,46 @@ export interface AstroAdapter { type Body = string; -export interface APIContext { +// Shared types between `Astro` global and API context object +interface AstroSharedContext { + /** + * The address (usually IP address) of the user. Used with SSR only. + */ + clientAddress: string; + /** + * Utility for getting and setting cookies values. + */ cookies: AstroCookies; + /** + * Information about the current request. This is a standard [Request](https://developer.mozilla.org/en-US/docs/Web/API/Request) object + */ + request: Request; + /** + * A full URL object of the request URL. + */ + url: URL; + /** + * Parameters passed to a dynamic page generated. + */ params: Params; +} + +export interface APIContext extends AstroSharedContext { + site: URL | undefined; + generator: string; + /** + * A full URL object of the request URL. + * Equivalent to: `new URL(request.url)` + */ + url: AstroSharedContext['url']; +} + +interface AstroSharedContext { + cookies: AstroCookies; request: Request; + clientAddress: string; + url: URL; + params: Params; } export interface EndpointOutput { diff --git a/packages/astro/src/core/endpoint/dev/index.ts b/packages/astro/src/core/endpoint/dev/index.ts index b2f16225b2b3..b27127119d69 100644 --- a/packages/astro/src/core/endpoint/dev/index.ts +++ b/packages/astro/src/core/endpoint/dev/index.ts @@ -8,5 +8,7 @@ export async function call(ssrOpts: SSROptions) { return await callEndpoint(mod as unknown as EndpointHandler, { ...ssrOpts, ssr: ssrOpts.settings.config.output === 'server', + site: ssrOpts.settings.config.site, + adapterName: ssrOpts.settings.config.adapter?.name, }); } diff --git a/packages/astro/src/core/endpoint/index.ts b/packages/astro/src/core/endpoint/index.ts index 9f1adb6555b5..7191e2115a0d 100644 --- a/packages/astro/src/core/endpoint/index.ts +++ b/packages/astro/src/core/endpoint/index.ts @@ -4,6 +4,9 @@ import type { RenderOptions } from '../render/core'; import { renderEndpoint } from '../../runtime/server/index.js'; import { AstroCookies, attachToResponse } from '../cookies/index.js'; import { getParamsAndProps, GetParamsAndPropsError } from '../render/core.js'; +import { ASTRO_VERSION } from '../util.js'; + +const clientAddressSymbol = Symbol.for('astro.clientAddress'); export type EndpointOptions = Pick< RenderOptions, @@ -17,6 +20,7 @@ export type EndpointOptions = Pick< | 'site' | 'ssr' | 'status' + | 'adapterName' >; type EndpointCallResult = @@ -30,11 +34,39 @@ type EndpointCallResult = response: Response; }; -function createAPIContext(request: Request, params: Params): APIContext { +function createAPIContext({ + request, + params, + site, + adapterName, +}: { + request: Request; + params: Params; + site?: string; + adapterName?: string; +}): APIContext { return { cookies: new AstroCookies(request), request, params, + site: site ? new URL(site) : undefined, + generator: `Astro v${ASTRO_VERSION}`, + url: new URL(request.url), + get clientAddress() { + if (!(clientAddressSymbol in request)) { + if (adapterName) { + throw new Error( + `Astro.clientAddress is not available in the ${args.adapterName} adapter. File an issue with the adapter to add support.` + ); + } else { + throw new Error( + `Astro.clientAddress is not available in your environment. Ensure that you are using an SSR adapter that supports this feature.` + ); + } + } + + return Reflect.get(request, clientAddressSymbol); + }, }; } @@ -51,7 +83,12 @@ export async function call( } const [params] = paramsAndPropsResp; - const context = createAPIContext(opts.request, params); + const context = createAPIContext({ + request: opts.request, + params, + site: opts.site, + adapterName: opts.adapterName, + }); const response = await renderEndpoint(mod, context, opts.ssr); if (response instanceof Response) { diff --git a/packages/astro/src/core/render/core.ts b/packages/astro/src/core/render/core.ts index bbbb6c53fd8c..5b7a3122a373 100644 --- a/packages/astro/src/core/render/core.ts +++ b/packages/astro/src/core/render/core.ts @@ -68,7 +68,7 @@ export async function getParamsAndProps( } export interface RenderOptions { - adapterName: string | undefined; + adapterName?: string; logging: LogOptions; links: Set; styles?: Set; diff --git a/packages/astro/test/fixtures/ssr-api-route/astro.config.mjs b/packages/astro/test/fixtures/ssr-api-route/astro.config.mjs new file mode 100644 index 000000000000..ef9763e01e72 --- /dev/null +++ b/packages/astro/test/fixtures/ssr-api-route/astro.config.mjs @@ -0,0 +1,8 @@ +import { defineConfig } from 'astro/config'; +import node from '@astrojs/node'; + +// https://astro.build/config +export default defineConfig({ + output: 'server', + adapter: node(), +}); diff --git a/packages/astro/test/fixtures/ssr-api-route/package.json b/packages/astro/test/fixtures/ssr-api-route/package.json index f31c4aeee69d..942034f45246 100644 --- a/packages/astro/test/fixtures/ssr-api-route/package.json +++ b/packages/astro/test/fixtures/ssr-api-route/package.json @@ -3,6 +3,7 @@ "version": "0.0.0", "private": true, "dependencies": { + "@astrojs/node": "^1.1.0", "astro": "workspace:*" } } diff --git a/packages/astro/test/fixtures/ssr-api-route/src/pages/context/[param].js b/packages/astro/test/fixtures/ssr-api-route/src/pages/context/[param].js new file mode 100644 index 000000000000..275c6497615f --- /dev/null +++ b/packages/astro/test/fixtures/ssr-api-route/src/pages/context/[param].js @@ -0,0 +1,16 @@ +/** + * @param {import('astro').APIContext} api + */ +export function get(ctx) { + return { + body: JSON.stringify({ + cookiesExist: !!ctx.cookies, + requestExist: !!ctx.request, + params: ctx.params, + site: ctx.site?.toString(), + generator: ctx.generator, + url: ctx.url.toString(), + clientAddress: ctx.clientAddress, + }) + }; +} diff --git a/packages/astro/test/ssr-api-route.test.js b/packages/astro/test/ssr-api-route.test.js index 1409657c318c..fc419638c61c 100644 --- a/packages/astro/test/ssr-api-route.test.js +++ b/packages/astro/test/ssr-api-route.test.js @@ -35,6 +35,20 @@ describe('API routes in SSR', () => { expect(body.length).to.equal(3); }); + it('Has valid api context', async () => { + const app = await fixture.loadTestAdapterApp(); + const request = new Request('http://example.com/context/any'); + const response = await app.render(request); + expect(response.status).to.equal(200); + const data = await response.json(); + expect(data.cookiesExist).to.equal(true); + expect(data.requestExist).to.equal(true); + expect(data.params).to.deep.equal({ param: 'any' }); + expect(data.generator).to.match(/^Astro v/); + expect(data.url).to.equal('http://example.com/context/any'); + expect(data.clientAddress).to.equal('0.0.0.0'); + }); + describe('API Routes - Dev', () => { let devServer; before(async () => { @@ -87,3 +101,16 @@ describe('API routes in SSR', () => { }); }); }); + +describe('API context in SSR', () => { + /** @type {import('./test-utils').Fixture} */ + let fixture; + + before(async () => { + fixture = await loadFixture({ + root: './fixtures/ssr-api-route/', + output: 'server', + }); + await fixture.build(); + }); +}); diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 6d9bde609018..ba673878bcba 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -2128,8 +2128,10 @@ importers: packages/astro/test/fixtures/ssr-api-route: specifiers: + '@astrojs/node': ^1.1.0 astro: workspace:* dependencies: + '@astrojs/node': link:../../../../integrations/node astro: link:../../.. packages/astro/test/fixtures/ssr-api-route-custom-404: From 200f4b7d714b9d8626aedd14c8313ad0a87faffa Mon Sep 17 00:00:00 2001 From: bluwy Date: Wed, 5 Oct 2022 22:09:01 +0800 Subject: [PATCH 02/14] Add props and redirect --- .changeset/fifty-ads-march.md | 4 +++- packages/astro/src/@types/astro.ts | 12 ++++++++++-- packages/astro/src/core/endpoint/index.ts | 9 +++++++++ 3 files changed, 22 insertions(+), 3 deletions(-) diff --git a/.changeset/fifty-ads-march.md b/.changeset/fifty-ads-march.md index dc826f7c0b73..571910ebb17e 100644 --- a/.changeset/fifty-ads-march.md +++ b/.changeset/fifty-ads-march.md @@ -2,4 +2,6 @@ 'astro': minor --- -Add `site`, `generator`, `url`, and `clientAddress` fields to API route context +Add `site`, `generator`, `url`, `clientAddress`, `props`, and `redirect` fields to API route context. + +Check out the docs for more information: https://docs.astro.build/en/core-concepts/endpoints/#server-endpoints-api-routes diff --git a/packages/astro/src/@types/astro.ts b/packages/astro/src/@types/astro.ts index 362ad193ada6..f12eb57a29bb 100644 --- a/packages/astro/src/@types/astro.ts +++ b/packages/astro/src/@types/astro.ts @@ -141,7 +141,7 @@ export interface AstroGlobal extends AstroGlobalPartial, AstroSharedContext { * * [Astro reference](https://docs.astro.build/en/core-concepts/astro-components/#component-props) */ - props: Record; + props: AstroSharedContext['props']; /** Information about the current request. This is a standard [Request](https://developer.mozilla.org/en-US/docs/Web/API/Request) object * * For example, to get a URL object of the current URL, you can use: @@ -175,7 +175,7 @@ export interface AstroGlobal extends AstroGlobalPartial, AstroSharedContext { * * [Astro reference](https://docs.astro.build/en/guides/server-side-rendering/#astroredirect) */ - redirect(path: string): Response; + redirect: AstroSharedContext['redirect']; /** * The element allows a component to reference itself recursively. * @@ -1109,6 +1109,14 @@ interface AstroSharedContext { * Parameters passed to a dynamic page generated. */ params: Params; + /** + * List of props passed. + */ + props: Record; + /** + * Redirect to another page + */ + redirect(path: string): Response; } export interface APIContext extends AstroSharedContext { diff --git a/packages/astro/src/core/endpoint/index.ts b/packages/astro/src/core/endpoint/index.ts index 7191e2115a0d..38545c45a2f8 100644 --- a/packages/astro/src/core/endpoint/index.ts +++ b/packages/astro/src/core/endpoint/index.ts @@ -51,6 +51,15 @@ function createAPIContext({ params, site: site ? new URL(site) : undefined, generator: `Astro v${ASTRO_VERSION}`, + props: {}, + redirect(path) { + return new Response(null, { + status: 302, + headers: { + Location: path, + }, + }); + }, url: new URL(request.url), get clientAddress() { if (!(clientAddressSymbol in request)) { From 5bd72f58f789b512d336955313109a8f798f642e Mon Sep 17 00:00:00 2001 From: bluwy Date: Wed, 5 Oct 2022 22:11:50 +0800 Subject: [PATCH 03/14] Pass custom redirect status code --- .changeset/selfish-foxes-bake.md | 5 +++++ packages/astro/src/@types/astro.ts | 2 +- packages/astro/src/core/endpoint/index.ts | 4 ++-- packages/astro/src/core/render/result.ts | 4 ++-- 4 files changed, 10 insertions(+), 5 deletions(-) create mode 100644 .changeset/selfish-foxes-bake.md diff --git a/.changeset/selfish-foxes-bake.md b/.changeset/selfish-foxes-bake.md new file mode 100644 index 000000000000..c81d3e83b533 --- /dev/null +++ b/.changeset/selfish-foxes-bake.md @@ -0,0 +1,5 @@ +--- +'astro': minor +--- + +Support passing a custom status code for Astro.redirect diff --git a/packages/astro/src/@types/astro.ts b/packages/astro/src/@types/astro.ts index f12eb57a29bb..50355b565eb6 100644 --- a/packages/astro/src/@types/astro.ts +++ b/packages/astro/src/@types/astro.ts @@ -1116,7 +1116,7 @@ interface AstroSharedContext { /** * Redirect to another page */ - redirect(path: string): Response; + redirect(path: string, status?: number): Response; } export interface APIContext extends AstroSharedContext { diff --git a/packages/astro/src/core/endpoint/index.ts b/packages/astro/src/core/endpoint/index.ts index 38545c45a2f8..e955f3372e61 100644 --- a/packages/astro/src/core/endpoint/index.ts +++ b/packages/astro/src/core/endpoint/index.ts @@ -52,9 +52,9 @@ function createAPIContext({ site: site ? new URL(site) : undefined, generator: `Astro v${ASTRO_VERSION}`, props: {}, - redirect(path) { + redirect(path, status) { return new Response(null, { - status: 302, + status: status || 302, headers: { Location: path, }, diff --git a/packages/astro/src/core/render/result.ts b/packages/astro/src/core/render/result.ts index f0cd02c54dbf..f0a6c747e54c 100644 --- a/packages/astro/src/core/render/result.ts +++ b/packages/astro/src/core/render/result.ts @@ -196,9 +196,9 @@ export function createResult(args: CreateResultArgs): SSRResult { request, url, redirect: args.ssr - ? (path: string) => { + ? (path: string, status?: number) => { return new Response(null, { - status: 302, + status: status || 302, headers: { Location: path, }, From 497c70d1c0f7ee9cfc1ed6c8864e4cb79cb0dfc8 Mon Sep 17 00:00:00 2001 From: bluwy Date: Wed, 5 Oct 2022 22:15:33 +0800 Subject: [PATCH 04/14] Correctly pass props in api routes --- packages/astro/src/core/endpoint/index.ts | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/packages/astro/src/core/endpoint/index.ts b/packages/astro/src/core/endpoint/index.ts index e955f3372e61..861a1ab8601b 100644 --- a/packages/astro/src/core/endpoint/index.ts +++ b/packages/astro/src/core/endpoint/index.ts @@ -38,11 +38,13 @@ function createAPIContext({ request, params, site, + props, adapterName, }: { request: Request; params: Params; site?: string; + props: Record; adapterName?: string; }): APIContext { return { @@ -51,7 +53,7 @@ function createAPIContext({ params, site: site ? new URL(site) : undefined, generator: `Astro v${ASTRO_VERSION}`, - props: {}, + props, redirect(path, status) { return new Response(null, { status: status || 302, @@ -90,11 +92,12 @@ export async function call( `[getStaticPath] route pattern matched, but no matching static path found. (${opts.pathname})` ); } - const [params] = paramsAndPropsResp; + const [params, props] = paramsAndPropsResp; const context = createAPIContext({ request: opts.request, params, + props, site: opts.site, adapterName: opts.adapterName, }); From e46dab9227660c28b1deca57e5632a63d3906a67 Mon Sep 17 00:00:00 2001 From: bluwy Date: Wed, 5 Oct 2022 22:30:10 +0800 Subject: [PATCH 05/14] Add better docs --- packages/astro/src/@types/astro.ts | 54 ++++++++++++++++++++++++++++++ 1 file changed, 54 insertions(+) diff --git a/packages/astro/src/@types/astro.ts b/packages/astro/src/@types/astro.ts index 50355b565eb6..e5d2e3e2237a 100644 --- a/packages/astro/src/@types/astro.ts +++ b/packages/astro/src/@types/astro.ts @@ -1127,6 +1127,60 @@ export interface APIContext extends AstroSharedContext { * Equivalent to: `new URL(request.url)` */ url: AstroSharedContext['url']; + /** + * Parameters passed to a dynamic page generated using `getStaticPaths`. + * + * Example usage: + * ```ts + * export function getStaticPaths() { + * return [ + * { params: { id: '0' }, props: { name: 'Sarah' } }, + * { params: { id: '1' }, props: { name: 'Chris' } }, + * { params: { id: '2' }, props: { name: 'Fuzzy' } }, + * ]; + * } + * + * export async function getStaticProps({ params }) { + * return { + * body: `Hello user ${params.id}!`, + * } + * } + * ``` + */ + params: AstroSharedContext['params']; + /** + * List of props passed from `getStaticPaths`. + * + * Example usage: + * ```ts + * export function getStaticPaths() { + * return [ + * { params: { id: '0' }, props: { name: 'Sarah' } }, + * { params: { id: '1' }, props: { name: 'Chris' } }, + * { params: { id: '2' }, props: { name: 'Fuzzy' } }, + * ]; + * } + * + * export function get({ props }) { + * return { + * body: `Hello ${props.name}!`, + * } + * } + * ``` + */ + props: AstroSharedContext['props']; + /** + * Redirect to another page. + * + * Example usage: + * ```ts + * // src/pages/secret.ts + * export function get({ redirect }) { + * return redirect('/login'); + * } + * ``` + */ + redirect: AstroSharedContext['redirect']; } interface AstroSharedContext { From d9091c3fe1f3a0c82c9ae6c3c520349a25e621e4 Mon Sep 17 00:00:00 2001 From: bluwy Date: Wed, 5 Oct 2022 22:35:48 +0800 Subject: [PATCH 06/14] Add test --- .../ssr-api-route/src/pages/context/[param].js | 2 ++ packages/astro/test/ssr-api-route.test.js | 15 ++------------- 2 files changed, 4 insertions(+), 13 deletions(-) diff --git a/packages/astro/test/fixtures/ssr-api-route/src/pages/context/[param].js b/packages/astro/test/fixtures/ssr-api-route/src/pages/context/[param].js index 275c6497615f..0ff1f625aaf8 100644 --- a/packages/astro/test/fixtures/ssr-api-route/src/pages/context/[param].js +++ b/packages/astro/test/fixtures/ssr-api-route/src/pages/context/[param].js @@ -6,6 +6,8 @@ export function get(ctx) { body: JSON.stringify({ cookiesExist: !!ctx.cookies, requestExist: !!ctx.request, + redirectExist: !!ctx.redirect, + propsExist: !!ctx.props, params: ctx.params, site: ctx.site?.toString(), generator: ctx.generator, diff --git a/packages/astro/test/ssr-api-route.test.js b/packages/astro/test/ssr-api-route.test.js index fc419638c61c..33b1ffdabcf7 100644 --- a/packages/astro/test/ssr-api-route.test.js +++ b/packages/astro/test/ssr-api-route.test.js @@ -43,6 +43,8 @@ describe('API routes in SSR', () => { const data = await response.json(); expect(data.cookiesExist).to.equal(true); expect(data.requestExist).to.equal(true); + expect(data.redirectExist).to.equal(true); + expect(data.propsExist).to.equal(true); expect(data.params).to.deep.equal({ param: 'any' }); expect(data.generator).to.match(/^Astro v/); expect(data.url).to.equal('http://example.com/context/any'); @@ -101,16 +103,3 @@ describe('API routes in SSR', () => { }); }); }); - -describe('API context in SSR', () => { - /** @type {import('./test-utils').Fixture} */ - let fixture; - - before(async () => { - fixture = await loadFixture({ - root: './fixtures/ssr-api-route/', - output: 'server', - }); - await fixture.build(); - }); -}); From 653eb37bec68a36d3953c50d5e33e1ccb8788790 Mon Sep 17 00:00:00 2001 From: bluwy Date: Wed, 5 Oct 2022 22:43:32 +0800 Subject: [PATCH 07/14] Fix build --- packages/astro/src/core/endpoint/index.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/astro/src/core/endpoint/index.ts b/packages/astro/src/core/endpoint/index.ts index 861a1ab8601b..fc44860ef5b0 100644 --- a/packages/astro/src/core/endpoint/index.ts +++ b/packages/astro/src/core/endpoint/index.ts @@ -67,11 +67,11 @@ function createAPIContext({ if (!(clientAddressSymbol in request)) { if (adapterName) { throw new Error( - `Astro.clientAddress is not available in the ${args.adapterName} adapter. File an issue with the adapter to add support.` + `clientAddress is not available in the ${adapterName} adapter. File an issue with the adapter to add support.` ); } else { throw new Error( - `Astro.clientAddress is not available in your environment. Ensure that you are using an SSR adapter that supports this feature.` + `clientAddress is not available in your environment. Ensure that you are using an SSR adapter that supports this feature.` ); } } From 1b89e0d103765bd108ece497f328c036c88eac26 Mon Sep 17 00:00:00 2001 From: bluwy Date: Thu, 6 Oct 2022 16:47:34 +0800 Subject: [PATCH 08/14] Add constants file --- packages/astro/src/@types/astro.ts | 2 +- packages/astro/src/cli/index.ts | 3 ++- packages/astro/src/core/constants.ts | 2 ++ packages/astro/src/core/endpoint/index.ts | 2 +- packages/astro/src/core/util.ts | 3 --- packages/astro/src/events/index.ts | 2 +- packages/astro/src/runtime/server/astro-global.ts | 4 +--- 7 files changed, 8 insertions(+), 10 deletions(-) create mode 100644 packages/astro/src/core/constants.ts diff --git a/packages/astro/src/@types/astro.ts b/packages/astro/src/@types/astro.ts index e5d2e3e2237a..cc2935bd1266 100644 --- a/packages/astro/src/@types/astro.ts +++ b/packages/astro/src/@types/astro.ts @@ -179,7 +179,7 @@ export interface AstroGlobal extends AstroGlobalPartial, AstroSharedContext { /** * The element allows a component to reference itself recursively. * - * [Astro reference](https://docs.astro.build/en/guides/server-side-rendering/#astroself) + * [Astro reference](https://docs.astro.build/en/guides/api-reference/#astroself) */ self: AstroComponentFactory; /** Utility functions for modifying an Astro component’s slotted children diff --git a/packages/astro/src/cli/index.ts b/packages/astro/src/cli/index.ts index 93e589396fd9..70d49b18d400 100644 --- a/packages/astro/src/cli/index.ts +++ b/packages/astro/src/cli/index.ts @@ -22,7 +22,8 @@ import { enableVerboseLogging, nodeLogDestination } from '../core/logger/node.js import { formatConfigErrorMessage, formatErrorMessage, printHelp } from '../core/messages.js'; import { appendForwardSlash } from '../core/path.js'; import preview from '../core/preview/index.js'; -import { ASTRO_VERSION, createSafeError } from '../core/util.js'; +import { ASTRO_VERSION } from '../core/constants.js'; +import { createSafeError } from '../core/util.js'; import * as event from '../events/index.js'; import { eventConfigError, eventError, telemetry } from '../events/index.js'; import { check } from './check/index.js'; diff --git a/packages/astro/src/core/constants.ts b/packages/astro/src/core/constants.ts new file mode 100644 index 000000000000..15c5d34e4add --- /dev/null +++ b/packages/astro/src/core/constants.ts @@ -0,0 +1,2 @@ +// process.env.PACKAGE_VERSION is injected when we build and publish the astro package. +export const ASTRO_VERSION = process.env.PACKAGE_VERSION ?? 'development'; diff --git a/packages/astro/src/core/endpoint/index.ts b/packages/astro/src/core/endpoint/index.ts index fc44860ef5b0..3df01af256f5 100644 --- a/packages/astro/src/core/endpoint/index.ts +++ b/packages/astro/src/core/endpoint/index.ts @@ -4,7 +4,7 @@ import type { RenderOptions } from '../render/core'; import { renderEndpoint } from '../../runtime/server/index.js'; import { AstroCookies, attachToResponse } from '../cookies/index.js'; import { getParamsAndProps, GetParamsAndPropsError } from '../render/core.js'; -import { ASTRO_VERSION } from '../util.js'; +import { ASTRO_VERSION } from '../constants.js'; const clientAddressSymbol = Symbol.for('astro.clientAddress'); diff --git a/packages/astro/src/core/util.ts b/packages/astro/src/core/util.ts index 780918bd0976..73dcb650077b 100644 --- a/packages/astro/src/core/util.ts +++ b/packages/astro/src/core/util.ts @@ -8,9 +8,6 @@ import type { ErrorPayload, ViteDevServer } from 'vite'; import type { AstroConfig, AstroSettings, RouteType } from '../@types/astro'; import { prependForwardSlash, removeTrailingForwardSlash } from './path.js'; -// process.env.PACKAGE_VERSION is injected when we build and publish the astro package. -export const ASTRO_VERSION = process.env.PACKAGE_VERSION ?? 'development'; - /** Returns true if argument is an object of any prototype/class (but not null). */ export function isObject(value: unknown): value is Record { return typeof value === 'object' && value != null; diff --git a/packages/astro/src/events/index.ts b/packages/astro/src/events/index.ts index 784e7723f884..31e549ad7bdd 100644 --- a/packages/astro/src/events/index.ts +++ b/packages/astro/src/events/index.ts @@ -1,6 +1,6 @@ import { AstroTelemetry } from '@astrojs/telemetry'; import { createRequire } from 'module'; -import { ASTRO_VERSION } from '../core/util.js'; +import { ASTRO_VERSION } from '../core/constants.js'; const require = createRequire(import.meta.url); function getViteVersion() { diff --git a/packages/astro/src/runtime/server/astro-global.ts b/packages/astro/src/runtime/server/astro-global.ts index 5ffca377ada3..101ec53ac598 100644 --- a/packages/astro/src/runtime/server/astro-global.ts +++ b/packages/astro/src/runtime/server/astro-global.ts @@ -1,7 +1,5 @@ import type { AstroGlobalPartial } from '../../@types/astro'; - -// process.env.PACKAGE_VERSION is injected when we build and publish the astro package. -const ASTRO_VERSION = process.env.PACKAGE_VERSION ?? 'development'; +import { ASTRO_VERSION } from '../../core/constants.js'; /** Create the Astro.fetchContent() runtime function. */ function createDeprecatedFetchContentFn() { From 396aa8d620c906071ce4efadfcc27db0390d1dd1 Mon Sep 17 00:00:00 2001 From: bluwy Date: Fri, 7 Oct 2022 17:16:49 +0800 Subject: [PATCH 09/14] Add links to jsdoc --- packages/astro/src/@types/astro.ts | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/packages/astro/src/@types/astro.ts b/packages/astro/src/@types/astro.ts index f494757129ff..49feb2f43340 100644 --- a/packages/astro/src/@types/astro.ts +++ b/packages/astro/src/@types/astro.ts @@ -131,7 +131,7 @@ export interface AstroGlobal = Record{id} * ``` * - * [Astro reference](https://docs.astro.build/en/reference/api-reference/#params) + * [Astro reference](https://docs.astro.build/en/reference/api-reference/#astroparams) */ params: AstroSharedContext['params']; /** List of props passed to this component @@ -1116,12 +1116,13 @@ interface AstroSharedContext = Record = Record> extends AstroSharedContext { +export interface APIContext = Record> + extends AstroSharedContext { site: URL | undefined; generator: string; /** @@ -1148,6 +1149,8 @@ export interface APIContext = Record = Record['props']; /** @@ -1181,6 +1186,8 @@ export interface APIContext = Record Date: Fri, 7 Oct 2022 17:25:30 +0800 Subject: [PATCH 10/14] Workaround lint issue --- packages/astro/src/@types/astro.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/astro/src/@types/astro.ts b/packages/astro/src/@types/astro.ts index 49feb2f43340..cac1e7b15fed 100644 --- a/packages/astro/src/@types/astro.ts +++ b/packages/astro/src/@types/astro.ts @@ -1078,8 +1078,6 @@ export type PaginateFunction = (data: any[], args?: PaginateOptions) => GetStati export type Params = Record; -export type Props = Record; - export interface AstroAdapter { name: string; serverEntrypoint?: string; @@ -1192,6 +1190,8 @@ export interface APIContext = Record; + export interface EndpointOutput { body: Body; encoding?: BufferEncoding; From c38d9c2080d2c6972c676bf83d9627c188a9dd32 Mon Sep 17 00:00:00 2001 From: Bjorn Lu Date: Fri, 7 Oct 2022 23:26:18 +0800 Subject: [PATCH 11/14] Thanks Chris Co-authored-by: Chris Swithinbank --- packages/astro/src/@types/astro.ts | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/packages/astro/src/@types/astro.ts b/packages/astro/src/@types/astro.ts index cac1e7b15fed..10eed3345f1e 100644 --- a/packages/astro/src/@types/astro.ts +++ b/packages/astro/src/@types/astro.ts @@ -1106,15 +1106,15 @@ interface AstroSharedContext = Record = Record = Record = Record = Record['props']; /** - * Redirect to another page. + * Redirect to another page. Only available in SSR builds. * * Example usage: * ```ts From 7b40b86dc51fba17c32fc9c552b9414ed8a8d977 Mon Sep 17 00:00:00 2001 From: Bjorn Lu Date: Fri, 7 Oct 2022 23:26:39 +0800 Subject: [PATCH 12/14] Missed one doc change Co-authored-by: Chris Swithinbank --- packages/astro/src/@types/astro.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/astro/src/@types/astro.ts b/packages/astro/src/@types/astro.ts index 10eed3345f1e..080b70449532 100644 --- a/packages/astro/src/@types/astro.ts +++ b/packages/astro/src/@types/astro.ts @@ -1094,7 +1094,7 @@ interface AstroSharedContext = Record Date: Mon, 10 Oct 2022 14:22:56 -0400 Subject: [PATCH 13/14] Add more detail to the changesets --- .changeset/fifty-ads-march.md | 16 ++++++++++++++-- .changeset/selfish-foxes-bake.md | 11 ++++++++++- 2 files changed, 24 insertions(+), 3 deletions(-) diff --git a/.changeset/fifty-ads-march.md b/.changeset/fifty-ads-march.md index 571910ebb17e..d06e8fc36cc2 100644 --- a/.changeset/fifty-ads-march.md +++ b/.changeset/fifty-ads-march.md @@ -2,6 +2,18 @@ 'astro': minor --- -Add `site`, `generator`, `url`, `clientAddress`, `props`, and `redirect` fields to API route context. +## New properties for API routes -Check out the docs for more information: https://docs.astro.build/en/core-concepts/endpoints/#server-endpoints-api-routes +In API routes, you can now get the `site`, `generator`, `url`, `clientAddress`, `props`, and `redirect` fields on the APIContext, which is the first parameter passed to an API route. This was done to make the APIContext more closely align with the `Astro` global in .astro pages. + +For example, here's how you might use the `clientAddress`, which is the user's IP address, to selectively allow users. + +```js +export function post({ clientAddress, request, redirect }) { + if(!allowList.has(clientAddress)) { + return redirect('/not-allowed'); + } +} +``` + +Check out the docs for more information on the newly available fields: https://docs.astro.build/en/core-concepts/endpoints/#server-endpoints-api-routes diff --git a/.changeset/selfish-foxes-bake.md b/.changeset/selfish-foxes-bake.md index c81d3e83b533..9e253388ac91 100644 --- a/.changeset/selfish-foxes-bake.md +++ b/.changeset/selfish-foxes-bake.md @@ -2,4 +2,13 @@ 'astro': minor --- -Support passing a custom status code for Astro.redirect +## Support passing a custom status code for Astro.redirect + +New in this minor is the ability to pass a status code to `Astro.redirect`. By default it uses `302` but now you can pass another code as the second argument: + +```astro +--- +// This page was moved +return Astro.redirect('/posts/new-post-name', 301); +--- +``` From 8a1a2f316088dd0fc755b2cb302d60284289ae4e Mon Sep 17 00:00:00 2001 From: bluwy Date: Tue, 11 Oct 2022 15:45:28 +0800 Subject: [PATCH 14/14] Strict redirect status type --- packages/astro/src/@types/astro.ts | 2 +- packages/astro/src/core/render/result.ts | 11 ++++++----- 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/packages/astro/src/@types/astro.ts b/packages/astro/src/@types/astro.ts index 9fb1492dceb9..60453291880d 100644 --- a/packages/astro/src/@types/astro.ts +++ b/packages/astro/src/@types/astro.ts @@ -1107,7 +1107,7 @@ interface AstroSharedContext = Record = Record> diff --git a/packages/astro/src/core/render/result.ts b/packages/astro/src/core/render/result.ts index f0a6c747e54c..a87ea54c72f1 100644 --- a/packages/astro/src/core/render/result.ts +++ b/packages/astro/src/core/render/result.ts @@ -166,7 +166,8 @@ export function createResult(args: CreateResultArgs): SSRResult { ) { const astroSlots = new Slots(result, slots, args.logging); - const Astro = { + const Astro: AstroGlobal = { + // @ts-expect-error set prototype __proto__: astroGlobal, get clientAddress() { if (!(clientAddressSymbol in request)) { @@ -196,7 +197,7 @@ export function createResult(args: CreateResultArgs): SSRResult { request, url, redirect: args.ssr - ? (path: string, status?: number) => { + ? (path, status) => { return new Response(null, { status: status || 302, headers: { @@ -237,9 +238,9 @@ ${extra}` // Intentionally return an empty string so that it is not relied upon. return ''; }, - response, - slots: astroSlots, - } as unknown as AstroGlobal; + response: response as AstroGlobal['response'], + slots: astroSlots as unknown as AstroGlobal['slots'], + }; Object.defineProperty(Astro, 'canonicalURL', { get: function () {