diff options
32 files changed, 210 insertions, 282 deletions
diff --git a/.changeset/eighty-boxes-applaud.md b/.changeset/eighty-boxes-applaud.md new file mode 100644 index 000000000..a732758cb --- /dev/null +++ b/.changeset/eighty-boxes-applaud.md @@ -0,0 +1,48 @@ +--- +'astro': major +--- + +The `astro:env` feature introduced behind a flag in [v4.10.0](https://github.com/withastro/astro/blob/main/packages/astro/CHANGELOG.md#x4100) is no longer experimental and is available for general use. If you have been waiting for stabilization before using `astro:env`, you can now do so. + +This feature lets you configure a type-safe schema for your environment variables, and indicate whether they should be available on the server or the client. + +To configure a schema, add the `env` option to your Astro config and define your client and server variables. If you were previously using this feature, please remove the experimental flag from your Astro config and move your entire `env` configuration unchanged to a top-level option. + +```js +import { defineConfig, envField } from 'astro/config' + +export default defineConfig({ + env: { + schema: { + API_URL: envField.string({ context: "client", access: "public", optional: true }), + PORT: envField.number({ context: "server", access: "public", default: 4321 }), + API_SECRET: envField.string({ context: "server", access: "secret" }), + } + } +}) +``` + +You can import and use your defined variables from the appropriate `/client` or `/server` module: + +```astro +--- +import { API_URL } from "astro:env/client" +import { API_SECRET_TOKEN } from "astro:env/server" + +const data = await fetch(`${API_URL}/users`, { + method: "GET", + headers: { + "Content-Type": "application/json", + "Authorization": `Bearer ${API_SECRET_TOKEN}` + }, +}) +--- + +<script> +import { API_URL } from "astro:env/client" + +fetch(`${API_URL}/ping`) +</script> +``` + +Please see our [guide to using environment variables](https://docs.astro.build/en/guides/environment-variables/#astroenv) for more about this feature. diff --git a/.changeset/selfish-impalas-grin.md b/.changeset/selfish-impalas-grin.md new file mode 100644 index 000000000..d2319c3d8 --- /dev/null +++ b/.changeset/selfish-impalas-grin.md @@ -0,0 +1,6 @@ +--- +'@astrojs/vercel': major +'@astrojs/node': major +--- + +Adds stable support for `astro:env` diff --git a/packages/astro/client.d.ts b/packages/astro/client.d.ts index 796bf3f33..8a61150c7 100644 --- a/packages/astro/client.d.ts +++ b/packages/astro/client.d.ts @@ -1,6 +1,7 @@ /// <reference types="vite/types/import-meta.d.ts" /> /// <reference path="./types/content.d.ts" /> /// <reference path="./types/actions.d.ts" /> +/// <reference path="./types/env.d.ts" /> interface ImportMetaEnv { /** diff --git a/packages/astro/src/container/index.ts b/packages/astro/src/container/index.ts index 8a8c83e07..e4365ecf5 100644 --- a/packages/astro/src/container/index.ts +++ b/packages/astro/src/container/index.ts @@ -143,7 +143,7 @@ function createManifest( i18n: manifest?.i18n, checkOrigin: false, middleware: manifest?.middleware ?? middleware ?? defaultMiddleware, - experimentalEnvGetSecretEnabled: false, + envGetSecretEnabled: false, key: createKey(), }; } diff --git a/packages/astro/src/core/app/types.ts b/packages/astro/src/core/app/types.ts index 29cb00ed4..66140e778 100644 --- a/packages/astro/src/core/app/types.ts +++ b/packages/astro/src/core/app/types.ts @@ -69,8 +69,7 @@ export type SSRManifest = { i18n: SSRManifestI18n | undefined; middleware: MiddlewareHandler; checkOrigin: boolean; - // TODO: remove experimental prefix - experimentalEnvGetSecretEnabled: boolean; + envGetSecretEnabled: boolean; }; export type SSRManifestI18n = { diff --git a/packages/astro/src/core/base-pipeline.ts b/packages/astro/src/core/base-pipeline.ts index 562b65174..9d772de9d 100644 --- a/packages/astro/src/core/base-pipeline.ts +++ b/packages/astro/src/core/base-pipeline.ts @@ -68,7 +68,7 @@ export abstract class Pipeline { } // In SSR, getSecret should fail by default. Setting it here will run before the // adapter override. - if (callSetGetEnv && manifest.experimentalEnvGetSecretEnabled) { + if (callSetGetEnv && manifest.envGetSecretEnabled) { setGetEnv(() => { throw new AstroError(AstroErrorData.EnvUnsupportedGetSecret); }, true); diff --git a/packages/astro/src/core/build/generate.ts b/packages/astro/src/core/build/generate.ts index e58f56100..5c9ee20b6 100644 --- a/packages/astro/src/core/build/generate.ts +++ b/packages/astro/src/core/build/generate.ts @@ -530,6 +530,6 @@ function createBuildManifest( middleware, checkOrigin: settings.config.security?.checkOrigin ?? false, key, - experimentalEnvGetSecretEnabled: false, + envGetSecretEnabled: false, }; } diff --git a/packages/astro/src/core/build/plugins/plugin-chunks.ts b/packages/astro/src/core/build/plugins/plugin-chunks.ts index bcd1d15bf..3348e126c 100644 --- a/packages/astro/src/core/build/plugins/plugin-chunks.ts +++ b/packages/astro/src/core/build/plugins/plugin-chunks.ts @@ -16,11 +16,6 @@ export function vitePluginChunks(): VitePlugin { if (id.includes('astro/dist/runtime')) { return 'astro'; } - // Place `astro/env/setup` import in its own chunk to prevent Rollup's TLA bug - // https://github.com/rollup/rollup/issues/4708 - if (id.includes('astro/dist/env/setup')) { - return 'astro/env-setup'; - } }, }); }, diff --git a/packages/astro/src/core/build/plugins/plugin-manifest.ts b/packages/astro/src/core/build/plugins/plugin-manifest.ts index 6b38758c3..5aee33337 100644 --- a/packages/astro/src/core/build/plugins/plugin-manifest.ts +++ b/packages/astro/src/core/build/plugins/plugin-manifest.ts @@ -281,8 +281,7 @@ function buildManifest( checkOrigin: settings.config.security?.checkOrigin ?? false, serverIslandNameMap: Array.from(settings.serverIslandNameMap), key: encodedKey, - experimentalEnvGetSecretEnabled: - settings.config.experimental.env !== undefined && + envGetSecretEnabled: (settings.adapter?.supportedAstroFeatures.envGetSecret ?? 'unsupported') !== 'unsupported', }; } diff --git a/packages/astro/src/core/config/schema.ts b/packages/astro/src/core/config/schema.ts index 05b1cc3cc..7940e4eb6 100644 --- a/packages/astro/src/core/config/schema.ts +++ b/packages/astro/src/core/config/schema.ts @@ -82,6 +82,10 @@ export const ASTRO_CONFIG_DEFAULTS = { legacy: {}, redirects: {}, security: {}, + env: { + schema: {}, + validateSecrets: false, + }, experimental: { actions: false, directRenderScript: false, @@ -90,9 +94,6 @@ export const ASTRO_CONFIG_DEFAULTS = { globalRoutePriority: false, serverIslands: false, contentIntellisense: false, - env: { - validateSecrets: false, - }, contentLayer: false, }, } satisfies AstroUserConfig & { server: { open: boolean } }; @@ -503,6 +504,14 @@ export const AstroConfigSchema = z.object({ }) .optional() .default(ASTRO_CONFIG_DEFAULTS.security), + env: z + .object({ + schema: EnvSchema.optional().default(ASTRO_CONFIG_DEFAULTS.env.schema), + validateSecrets: z.boolean().optional().default(ASTRO_CONFIG_DEFAULTS.env.validateSecrets), + }) + .strict() + .optional() + .default(ASTRO_CONFIG_DEFAULTS.env), experimental: z .object({ actions: z.boolean().optional().default(ASTRO_CONFIG_DEFAULTS.experimental.actions), @@ -522,16 +531,6 @@ export const AstroConfigSchema = z.object({ .boolean() .optional() .default(ASTRO_CONFIG_DEFAULTS.experimental.globalRoutePriority), - env: z - .object({ - schema: EnvSchema.optional(), - validateSecrets: z - .boolean() - .optional() - .default(ASTRO_CONFIG_DEFAULTS.experimental.env.validateSecrets), - }) - .strict() - .optional(), serverIslands: z .boolean() .optional() diff --git a/packages/astro/src/core/create-vite.ts b/packages/astro/src/core/create-vite.ts index d01eedb0d..6a5995e3f 100644 --- a/packages/astro/src/core/create-vite.ts +++ b/packages/astro/src/core/create-vite.ts @@ -132,7 +132,7 @@ export async function createVite( // the build to run very slow as the filewatcher is triggered often. mode !== 'build' && vitePluginAstroServer({ settings, logger, fs }), envVitePlugin({ settings, logger }), - astroEnv({ settings, mode, fs, sync }), + astroEnv({ settings, mode, sync }), markdownVitePlugin({ settings, logger }), htmlVitePlugin(), astroPostprocessVitePlugin(), diff --git a/packages/astro/src/core/errors/errors-data.ts b/packages/astro/src/core/errors/errors-data.ts index e083ba2f5..475acdbbf 100644 --- a/packages/astro/src/core/errors/errors-data.ts +++ b/packages/astro/src/core/errors/errors-data.ts @@ -1235,15 +1235,15 @@ export const RouteNotFound = { /** * @docs * @description - * Some environment variables do not match the data type and/or properties defined in `experimental.env.schema`. + * Some environment variables do not match the data type and/or properties defined in `env.schema`. * @message - * The following environment variables defined in `experimental.env.schema` are invalid. + * The following environment variables defined in `env.schema` are invalid. */ export const EnvInvalidVariables = { name: 'EnvInvalidVariables', title: 'Invalid Environment Variables', message: (errors: Array<string>) => - `The following environment variables defined in \`experimental.env.schema\` are invalid:\n\n${errors.map((err) => `- ${err}`).join('\n')}\n`, + `The following environment variables defined in \`env.schema\` are invalid:\n\n${errors.map((err) => `- ${err}`).join('\n')}\n`, } satisfies ErrorData; /** diff --git a/packages/astro/src/core/sync/index.ts b/packages/astro/src/core/sync/index.ts index 805a955bb..c9769443e 100644 --- a/packages/astro/src/core/sync/index.ts +++ b/packages/astro/src/core/sync/index.ts @@ -133,7 +133,7 @@ export async function syncInternal({ content: '', }); } - syncAstroEnv(settings, fs); + syncAstroEnv(settings); await writeFiles(settings, fs, logger); logger.info('types', `Generated ${dim(getTimeStat(timerStart, performance.now()))}`); diff --git a/packages/astro/src/env/constants.ts b/packages/astro/src/env/constants.ts index de5f06233..ac2c2c297 100644 --- a/packages/astro/src/env/constants.ts +++ b/packages/astro/src/env/constants.ts @@ -5,8 +5,7 @@ export const VIRTUAL_MODULES_IDS = { }; export const VIRTUAL_MODULES_IDS_VALUES = new Set(Object.values(VIRTUAL_MODULES_IDS)); -export const ENV_TYPES_FILE = 'env.d.ts'; +export const ENV_TYPES_FILE = 'astro/env.d.ts'; const PKG_BASE = new URL('../../', import.meta.url); -export const MODULE_TEMPLATE_URL = new URL('templates/env/module.mjs', PKG_BASE); -export const TYPES_TEMPLATE_URL = new URL('templates/env/types.d.ts', PKG_BASE); +export const MODULE_TEMPLATE_URL = new URL('templates/env.mjs', PKG_BASE); diff --git a/packages/astro/src/env/sync.ts b/packages/astro/src/env/sync.ts index 90a29685d..5949a4766 100644 --- a/packages/astro/src/env/sync.ts +++ b/packages/astro/src/env/sync.ts @@ -1,20 +1,13 @@ -import fsMod from 'node:fs'; import type { AstroSettings } from '../types/astro.js'; -import { TYPES_TEMPLATE_URL } from './constants.js'; +import { ENV_TYPES_FILE } from './constants.js'; import { getEnvFieldType } from './validators.js'; -export function syncAstroEnv(settings: AstroSettings, fs = fsMod): void { - if (!settings.config.experimental.env) { - return; - } - - const schema = settings.config.experimental.env.schema ?? {}; - +export function syncAstroEnv(settings: AstroSettings): void { let client = ''; let server = ''; - for (const [key, options] of Object.entries(schema)) { - const str = `export const ${key}: ${getEnvFieldType(options)}; \n`; + for (const [key, options] of Object.entries(settings.config.env.schema)) { + const str = ` export const ${key}: ${getEnvFieldType(options)}; \n`; if (options.context === 'client') { client += str; } else { @@ -22,11 +15,20 @@ export function syncAstroEnv(settings: AstroSettings, fs = fsMod): void { } } - const template = fs.readFileSync(TYPES_TEMPLATE_URL, 'utf-8'); - const content = template.replace('// @@CLIENT@@', client).replace('// @@SERVER@@', server); + let content = ''; + if (client !== '') { + content = `declare module 'astro:env/client' { +${client}}`; + } + if (server !== '') { + content += `declare module 'astro:env/server' { +${server}}`; + } - settings.injectedTypes.push({ - filename: 'astro/env.d.ts', - content, - }); + if (content !== '') { + settings.injectedTypes.push({ + filename: ENV_TYPES_FILE, + content, + }); + } } diff --git a/packages/astro/src/env/vite-plugin-env.ts b/packages/astro/src/env/vite-plugin-env.ts index b6d3194a6..fffc37c5e 100644 --- a/packages/astro/src/env/vite-plugin-env.ts +++ b/packages/astro/src/env/vite-plugin-env.ts @@ -1,4 +1,4 @@ -import type fsMod from 'node:fs'; +import { readFileSync } from 'node:fs'; import { fileURLToPath } from 'node:url'; import { type Plugin, loadEnv } from 'vite'; import { AstroError, AstroErrorData } from '../core/errors/index.js'; @@ -12,29 +12,14 @@ import { type InvalidVariable, invalidVariablesToError } from './errors.js'; import type { EnvSchema } from './schema.js'; import { getEnvFieldType, validateEnvVariable } from './validators.js'; -// TODO: reminders for when astro:env comes out of experimental -// Types should always be generated (like in types/content.d.ts). That means the client module will be empty -// and server will only contain getSecret for unknown variables. Then, specifying a schema should only add -// variables as needed. For secret variables, it will only require specifying SecretValues and it should get -// merged with the static types/content.d.ts - -interface AstroEnvVirtualModPluginParams { +interface AstroEnvPluginParams { settings: AstroSettings; mode: 'dev' | 'build' | string; - fs: typeof fsMod; sync: boolean; } -export function astroEnv({ - settings, - mode, - fs, - sync, -}: AstroEnvVirtualModPluginParams): Plugin | undefined { - if (!settings.config.experimental.env) { - return; - } - const schema = settings.config.experimental.env.schema ?? {}; +export function astroEnv({ settings, mode, sync }: AstroEnvPluginParams): Plugin { + const { schema, validateSecrets } = settings.config.env; let templates: { client: string; server: string; internal: string } | null = null; @@ -56,12 +41,12 @@ export function astroEnv({ const validatedVariables = validatePublicVariables({ schema, loadedEnv, - validateSecrets: settings.config.experimental.env?.validateSecrets ?? false, + validateSecrets, sync, }); templates = { - ...getTemplates(schema, fs, validatedVariables), + ...getTemplates(schema, validatedVariables), internal: `export const schema = ${JSON.stringify(schema)};`, }; }, @@ -140,11 +125,10 @@ function validatePublicVariables({ function getTemplates( schema: EnvSchema, - fs: typeof fsMod, validatedVariables: ReturnType<typeof validatePublicVariables>, ) { let client = ''; - let server = fs.readFileSync(MODULE_TEMPLATE_URL, 'utf-8'); + let server = readFileSync(MODULE_TEMPLATE_URL, 'utf-8'); let onSetGetEnv = ''; for (const { key, value, context } of validatedVariables) { diff --git a/packages/astro/src/integrations/features-validation.ts b/packages/astro/src/integrations/features-validation.ts index 9d8ecdcf4..a9386090d 100644 --- a/packages/astro/src/integrations/features-validation.ts +++ b/packages/astro/src/integrations/features-validation.ts @@ -87,7 +87,7 @@ export function validateSupportedFeatures( adapterName, logger, 'astro:env getSecret', - () => config?.experimental?.env !== undefined, + () => Object.keys(config?.env?.schema ?? {}).length !== 0, ); return validationResult; diff --git a/packages/astro/src/types/public/config.ts b/packages/astro/src/types/public/config.ts index 5dfe40f39..a2f8e61cc 100644 --- a/packages/astro/src/types/public/config.ts +++ b/packages/astro/src/types/public/config.ts @@ -1381,6 +1381,73 @@ export interface AstroUserConfig { /** * @docs + * @name env + * @type {object} + * @default `{}` + * @version 5.0.0 + * @description + * + * Holds `astro:env` options. + */ + env?: { + /** + * @docs + * @name env.schema + * @type {EnvSchema} + * @default `{}` + * @version 5.0.0 + * @description + * + * An object that uses `envField` to define the data type (`string`, `number`, or `boolean`) and properties of your environment variables: `context` (client or server), `access` (public or secret), a `default` value to use, and whether or not this environment variable is `optional` (defaults to `false`). + * ```js + * // astro.config.mjs + * import { defineConfig, envField } from "astro/config" + * + * export default defineConfig({ + * env: { + * schema: { + * API_URL: envField.string({ context: "client", access: "public", optional: true }), + * PORT: envField.number({ context: "server", access: "public", default: 4321 }), + * API_SECRET: envField.string({ context: "server", access: "secret" }), + * } + * } + * }) + * ``` + */ + schema?: EnvSchema; + + /** + * @docs + * @name env.validateSecrets + * @type {boolean} + * @default `false` + * @version 5.0.0 + * @description + * + * Whether or not to validate secrets on the server when starting the dev server or running a build. + * + * By default, only public variables are validated on the server when starting the dev server or a build, and private variables are validated at runtime only. If enabled, private variables will also be checked on start. This is useful in some continuous integration (CI) pipelines to make sure all your secrets are correctly set before deploying. + * + * ```js + * // astro.config.mjs + * import { defineConfig, envField } from "astro/config" + * + * export default defineConfig({ + * env: { + * schema: { + * // ... + * }, + * validateSecrets: true + * } + * }) + * ``` + */ + validateSecrets?: boolean; + }; + + + /** + * @docs * @kind heading * @name Legacy Flags * @description @@ -1614,148 +1681,6 @@ export interface AstroUserConfig { /** * @docs - * @name experimental.env - * @type {object} - * @default `undefined` - * @version 4.10.0 - * @description - * - * Enables experimental `astro:env` features. - * - * The `astro:env` API lets you configure a type-safe schema for your environment variables, and indicate whether they should be available on the server or the client. Import and use your defined variables from the appropriate `/client` or `/server` module: - * - * ```astro - * --- - * import { API_URL } from "astro:env/client" - * import { API_SECRET_TOKEN } from "astro:env/server" - * - * const data = await fetch(`${API_URL}/users`, { - * method: "GET", - * headers: { - * "Content-Type": "application/json", - * "Authorization": `Bearer ${API_SECRET_TOKEN}` - * }, - * }) - * --- - * - * <script> - * import { API_URL } from "astro:env/client" - * - * fetch(`${API_URL}/ping`) - * </script> - * ``` - * - * To define the data type and properties of your environment variables, declare a schema in your Astro config in `experimental.env.schema`. The `envField` helper allows you define your variable as a string, number, or boolean and pass properties in an object: - * - * ```js - * // astro.config.mjs - * import { defineConfig, envField } from "astro/config" - * - * export default defineConfig({ - * experimental: { - * env: { - * schema: { - * API_URL: envField.string({ context: "client", access: "public", optional: true }), - * PORT: envField.number({ context: "server", access: "public", default: 4321 }), - * API_SECRET: envField.string({ context: "server", access: "secret" }), - * } - * } - * } - * }) - * ``` - * - * There are currently four data types supported: strings, numbers, booleans and enums. - * - * There are three kinds of environment variables, determined by the combination of `context` (client or server) and `access` (secret or public) settings defined in your [`env.schema`](#experimentalenvschema): - * - * - **Public client variables**: These variables end up in both your final client and server bundles, and can be accessed from both client and server through the `astro:env/client` module: - * - * ```js - * import { API_URL } from "astro:env/client" - * ``` - * - * - **Public server variables**: These variables end up in your final server bundle and can be accessed on the server through the `astro:env/server` module: - * - * ```js - * import { PORT } from "astro:env/server" - * ``` - * - * - **Secret server variables**: These variables are not part of your final bundle and can be accessed on the server through the `astro:env/server` module. The `getSecret()` helper function can be used to retrieve secrets not specified in the schema. Its implementation is provided by your adapter and defaults to `process.env`: - * - * ```js - * import { API_SECRET, getSecret } from "astro:env/server" - * - * const SECRET_NOT_IN_SCHEMA = getSecret("SECRET_NOT_IN_SCHEMA") // string | undefined - * ``` - * - * **Note:** Secret client variables are not supported because there is no safe way to send this data to the client. Therefore, it is not possible to configure both `context: "client"` and `access: "secret"` in your schema. - * - * For a complete overview, and to give feedback on this experimental API, see the [Astro Env RFC](https://github.com/withastro/roadmap/blob/feat/astro-env-rfc/proposals/0046-astro-env.md). - */ - env?: { - /** - * @docs - * @name experimental.env.schema - * @kind h4 - * @type {EnvSchema} - * @default `undefined` - * @version 4.10.0 - * @description - * - * An object that uses `envField` to define the data type (`string`, `number`, or `boolean`) and properties of your environment variables: `context` (client or server), `access` (public or secret), a `default` value to use, and whether or not this environment variable is `optional` (defaults to `false`). - * ```js - * // astro.config.mjs - * import { defineConfig, envField } from "astro/config" - * - * export default defineConfig({ - * experimental: { - * env: { - * schema: { - * API_URL: envField.string({ context: "client", access: "public", optional: true }), - * PORT: envField.number({ context: "server", access: "public", default: 4321 }), - * API_SECRET: envField.string({ context: "server", access: "secret" }), - * } - * } - * } - * }) - * ``` - */ - schema?: EnvSchema; - - /** - * @docs - * @name experimental.env.validateSecrets - * @kind h4 - * @type {boolean} - * @default `false` - * @version 4.11.6 - * @description - * - * Whether or not to validate secrets on the server when starting the dev server or running a build. - * - * By default, only public variables are validated on the server when starting the dev server or a build, and private variables are validated at runtime only. If enabled, private variables will also be checked on start. This is useful in some continuous integration (CI) pipelines to make sure all your secrets are correctly set before deploying. - * - * ```js - * // astro.config.mjs - * import { defineConfig, envField } from "astro/config" - * - * export default defineConfig({ - * experimental: { - * env: { - * schema: { - * // ... - * }, - * validateSecrets: true - * } - * } - * }) - * ``` - */ - validateSecrets?: boolean; - }; - - /** - * @docs * @name experimental.serverIslands * @type {boolean} * @default `false` diff --git a/packages/astro/src/vite-plugin-astro-server/plugin.ts b/packages/astro/src/vite-plugin-astro-server/plugin.ts index 3015f1003..414034561 100644 --- a/packages/astro/src/vite-plugin-astro-server/plugin.ts +++ b/packages/astro/src/vite-plugin-astro-server/plugin.ts @@ -149,7 +149,7 @@ export function createDevelopmentManifest(settings: AstroSettings): SSRManifest inlinedScripts: new Map(), i18n: i18nManifest, checkOrigin: settings.config.security?.checkOrigin ?? false, - experimentalEnvGetSecretEnabled: false, + envGetSecretEnabled: false, key: createKey(), middleware(_, next) { return next(); diff --git a/packages/astro/templates/env/module.mjs b/packages/astro/templates/env.mjs index d7637af15..d7637af15 100644 --- a/packages/astro/templates/env/module.mjs +++ b/packages/astro/templates/env.mjs diff --git a/packages/astro/test/env-secret.test.js b/packages/astro/test/env-secret.test.js index 7a569e35a..cad86dcda 100644 --- a/packages/astro/test/env-secret.test.js +++ b/packages/astro/test/env-secret.test.js @@ -71,10 +71,8 @@ describe('astro:env secret variables', () => { it('fails if validateSecrets is enabled and secret is not set', async () => { fixture = await loadFixture({ root: './fixtures/astro-env-server-secret/', - experimental: { - env: { - validateSecrets: true, - }, + env: { + validateSecrets: true, }, }); diff --git a/packages/astro/test/fixtures/astro-env-content-collections/astro.config.mjs b/packages/astro/test/fixtures/astro-env-content-collections/astro.config.mjs index 310a5ebab..ad36aa9c7 100644 --- a/packages/astro/test/fixtures/astro-env-content-collections/astro.config.mjs +++ b/packages/astro/test/fixtures/astro-env-content-collections/astro.config.mjs @@ -2,11 +2,9 @@ import { defineConfig, envField } from 'astro/config'; // https://astro.build/config export default defineConfig({ - experimental: { - env: { - schema: { - FOO: envField.string({ context: "client", access: "public", optional: true, default: "ABC" }), - } + env: { + schema: { + FOO: envField.string({ context: "client", access: "public", optional: true, default: "ABC" }), } } }); diff --git a/packages/astro/test/fixtures/astro-env-required-public/astro.config.mjs b/packages/astro/test/fixtures/astro-env-required-public/astro.config.mjs index c668e1e21..57cca3cec 100644 --- a/packages/astro/test/fixtures/astro-env-required-public/astro.config.mjs +++ b/packages/astro/test/fixtures/astro-env-required-public/astro.config.mjs @@ -2,12 +2,10 @@ import { defineConfig, envField } from 'astro/config'; // https://astro.build/config export default defineConfig({ - experimental: { - env: { - schema: { - FOO: envField.string({ context: "client", access: "public" }), - BAR: envField.number({ context: "server", access: "public" }), - } + env: { + schema: { + FOO: envField.string({ context: "client", access: "public" }), + BAR: envField.number({ context: "server", access: "public" }), } } }); diff --git a/packages/astro/test/fixtures/astro-env-server-fail/astro.config.mjs b/packages/astro/test/fixtures/astro-env-server-fail/astro.config.mjs index a5b69ee5f..b4ca20243 100644 --- a/packages/astro/test/fixtures/astro-env-server-fail/astro.config.mjs +++ b/packages/astro/test/fixtures/astro-env-server-fail/astro.config.mjs @@ -2,11 +2,9 @@ import { defineConfig, envField } from 'astro/config'; // https://astro.build/config export default defineConfig({ - experimental: { - env: { - schema: { - FOO: envField.string({ context: "server", access: "public", optional: true, default: "ABC" }), - } + env: { + schema: { + FOO: envField.string({ context: "server", access: "public", optional: true, default: "ABC" }), } } }); diff --git a/packages/astro/test/fixtures/astro-env-server-secret/astro.config.mjs b/packages/astro/test/fixtures/astro-env-server-secret/astro.config.mjs index 1737fa64a..3f5fea3c7 100644 --- a/packages/astro/test/fixtures/astro-env-server-secret/astro.config.mjs +++ b/packages/astro/test/fixtures/astro-env-server-secret/astro.config.mjs @@ -2,11 +2,9 @@ import { defineConfig, envField } from 'astro/config'; // https://astro.build/config export default defineConfig({ - experimental: { - env: { - schema: { - KNOWN_SECRET: envField.number({ context: "server", access: "secret" }) - } + env: { + schema: { + KNOWN_SECRET: envField.number({ context: "server", access: "secret" }) } } }); diff --git a/packages/astro/test/fixtures/astro-env/astro.config.mjs b/packages/astro/test/fixtures/astro-env/astro.config.mjs index 6b6276e89..fbd76c522 100644 --- a/packages/astro/test/fixtures/astro-env/astro.config.mjs +++ b/packages/astro/test/fixtures/astro-env/astro.config.mjs @@ -2,13 +2,11 @@ import { defineConfig, envField } from 'astro/config'; // https://astro.build/config export default defineConfig({ - experimental: { - env: { - schema: { - FOO: envField.string({ context: "client", access: "public", optional: true, default: "ABC" }), - BAR: envField.string({ context: "client", access: "public", optional: true, default: "DEF" }), - BAZ: envField.string({ context: "server", access: "public", optional: true, default: "GHI" }), - } + env: { + schema: { + FOO: envField.string({ context: "client", access: "public", optional: true, default: "ABC" }), + BAR: envField.string({ context: "client", access: "public", optional: true, default: "DEF" }), + BAZ: envField.string({ context: "server", access: "public", optional: true, default: "GHI" }), } } }); diff --git a/packages/astro/test/units/config/config-validate.test.js b/packages/astro/test/units/config/config-validate.test.js index fc69b595f..87e437813 100644 --- a/packages/astro/test/units/config/config-validate.test.js +++ b/packages/astro/test/units/config/config-validate.test.js @@ -358,10 +358,8 @@ describe('Config Validation', () => { assert.doesNotThrow(() => validateConfig( { - experimental: { - env: { - schema: undefined, - }, + env: { + schema: undefined, }, }, process.cwd(), @@ -373,11 +371,9 @@ describe('Config Validation', () => { assert.doesNotThrow(() => validateConfig( { - experimental: { - env: { - schema: { - ABC123: envField.string({ access: 'public', context: 'server' }), - }, + env: { + schema: { + ABC123: envField.string({ access: 'public', context: 'server' }), }, }, }, @@ -389,11 +385,9 @@ describe('Config Validation', () => { it('Should not allow schema variables starting with a number', async () => { const configError = await validateConfig( { - experimental: { - env: { - schema: { - '123ABC': envField.string({ access: 'public', context: 'server' }), - }, + env: { + schema: { + '123ABC': envField.string({ access: 'public', context: 'server' }), }, }, }, diff --git a/packages/astro/templates/env/types.d.ts b/packages/astro/types/env.d.ts index 5af1ac6a1..6dc51a221 100644 --- a/packages/astro/templates/env/types.d.ts +++ b/packages/astro/types/env.d.ts @@ -1,9 +1,5 @@ -declare module 'astro:env/client' { - // @@CLIENT@@ -} +declare module 'astro:env/client' {} declare module 'astro:env/server' { - // @@SERVER@@ - export const getSecret: (key: string) => string | undefined; } diff --git a/packages/integrations/node/src/index.ts b/packages/integrations/node/src/index.ts index 60f489c79..42a2ed91f 100644 --- a/packages/integrations/node/src/index.ts +++ b/packages/integrations/node/src/index.ts @@ -18,7 +18,7 @@ export function getAdapter(options: Options): AstroAdapter { isSharpCompatible: true, }, i18nDomains: 'experimental', - envGetSecret: 'experimental', + envGetSecret: 'stable', }, }; } diff --git a/packages/integrations/node/src/server.ts b/packages/integrations/node/src/server.ts index 1bb27e002..93d75d360 100644 --- a/packages/integrations/node/src/server.ts +++ b/packages/integrations/node/src/server.ts @@ -1,17 +1,14 @@ import type { SSRManifest } from 'astro'; import { NodeApp, applyPolyfills } from 'astro/app/node'; +import { setGetEnv } from 'astro/env/setup'; import createMiddleware from './middleware.js'; import { createStandaloneHandler } from './standalone.js'; import startServer from './standalone.js'; import type { Options } from './types.js'; + // This needs to run first because some internals depend on `crypto` applyPolyfills(); - -// Won't throw if the virtual module is not available because it's not supported in -// the users's astro version or if astro:env is not enabled in the project -await import('astro/env/setup') - .then((mod) => mod.setGetEnv((key) => process.env[key])) - .catch(() => {}); +setGetEnv((key) => process.env[key]); export function createExports(manifest: SSRManifest, options: Options) { const app = new NodeApp(manifest); diff --git a/packages/integrations/vercel/src/serverless/adapter.ts b/packages/integrations/vercel/src/serverless/adapter.ts index bbc624e97..3b86cec0e 100644 --- a/packages/integrations/vercel/src/serverless/adapter.ts +++ b/packages/integrations/vercel/src/serverless/adapter.ts @@ -94,7 +94,7 @@ function getAdapter({ isSharpCompatible: true, }, i18nDomains: 'experimental', - envGetSecret: 'experimental', + envGetSecret: 'stable', }, }; } diff --git a/packages/integrations/vercel/src/serverless/entrypoint.ts b/packages/integrations/vercel/src/serverless/entrypoint.ts index a881d701a..222722dd8 100644 --- a/packages/integrations/vercel/src/serverless/entrypoint.ts +++ b/packages/integrations/vercel/src/serverless/entrypoint.ts @@ -1,6 +1,7 @@ import type { IncomingMessage, ServerResponse } from 'node:http'; import type { SSRManifest } from 'astro'; import { NodeApp, applyPolyfills } from 'astro/app/node'; +import { setGetEnv } from 'astro/env/setup'; import { ASTRO_LOCALS_HEADER, ASTRO_MIDDLEWARE_SECRET_HEADER, @@ -10,12 +11,7 @@ import { // Run polyfills immediately so any dependent code can use the globals applyPolyfills(); - -// Won't throw if the virtual module is not available because it's not supported in -// the users's astro version or if astro:env is not enabled in the project -await import('astro/env/setup') - .then((mod) => mod.setGetEnv((key) => process.env[key])) - .catch(() => {}); +setGetEnv((key) => process.env[key]); export const createExports = ( manifest: SSRManifest, |