mirror of
https://github.com/withastro/astro.git
synced 2024-12-30 22:03:56 -05:00
fix: incorrect astro:env runtime error (#11479)
* fix: incorrect astro:env runtime error * fix: import * feat: type check template
This commit is contained in:
parent
4779b8ef15
commit
6059b4234b
8 changed files with 63 additions and 43 deletions
5
.changeset/chilly-jokes-fold.md
Normal file
5
.changeset/chilly-jokes-fold.md
Normal file
|
@ -0,0 +1,5 @@
|
|||
---
|
||||
'astro': patch
|
||||
---
|
||||
|
||||
Fixes a case where invalid `astro:env` variables at runtime would not throw correctly
|
5
packages/astro/dev-only.d.ts
vendored
Normal file
5
packages/astro/dev-only.d.ts
vendored
Normal file
|
@ -0,0 +1,5 @@
|
|||
// IMPORTANT: do not publish this file! It's only intended for development within the monorepo
|
||||
|
||||
declare module 'virtual:astro:env/internal' {
|
||||
export const schema: import('./src/env/schema.js').EnvSchema;
|
||||
}
|
|
@ -1235,6 +1235,8 @@ export const RouteNotFound = {
|
|||
* @docs
|
||||
* @description
|
||||
* Some environment variables do not match the data type and/or properties defined in `experimental.env.schema`.
|
||||
* @message
|
||||
* The following environment variables defined in `experimental.env.schema` are invalid.
|
||||
*/
|
||||
export const EnvInvalidVariables = {
|
||||
name: 'EnvInvalidVariables',
|
||||
|
@ -1243,18 +1245,6 @@ export const EnvInvalidVariables = {
|
|||
`The following environment variables defined in \`experimental.env.schema\` are invalid:\n\n${errors.map((err) => `- ${err}`).join('\n')}\n`,
|
||||
} satisfies ErrorData;
|
||||
|
||||
/**
|
||||
* @docs
|
||||
* @description
|
||||
* An environment variable does not match the data type and/or properties defined in `experimental.env.schema`.
|
||||
*/
|
||||
export const EnvInvalidVariable = {
|
||||
name: 'EnvInvalidVariable',
|
||||
title: 'Invalid Environment Variable',
|
||||
message: (key: string, type: string) =>
|
||||
`The following environment variable does not match the data type and/or properties defined in \`experimental.env.schema\`: ${key} is not of type ${type}`,
|
||||
} satisfies ErrorData;
|
||||
|
||||
/**
|
||||
* @docs
|
||||
* @description
|
||||
|
|
22
packages/astro/src/env/errors.ts
vendored
Normal file
22
packages/astro/src/env/errors.ts
vendored
Normal file
|
@ -0,0 +1,22 @@
|
|||
import type { ValidationResultErrors } from './validators.js';
|
||||
|
||||
export interface InvalidVariable {
|
||||
key: string;
|
||||
type: string;
|
||||
errors: ValidationResultErrors;
|
||||
}
|
||||
|
||||
export function invalidVariablesToError(invalid: Array<InvalidVariable>) {
|
||||
const _errors: Array<string> = [];
|
||||
for (const { key, type, errors } of invalid) {
|
||||
if (errors[0] === 'missing') {
|
||||
_errors.push(`${key} is missing`);
|
||||
} else if (errors[0] === 'type') {
|
||||
_errors.push(`${key}'s type is invalid, expected: ${type}`);
|
||||
} else {
|
||||
// constraints
|
||||
_errors.push(`The following constraints for ${key} are not met: ${errors.join(', ')}`);
|
||||
}
|
||||
}
|
||||
return _errors;
|
||||
}
|
16
packages/astro/src/env/runtime.ts
vendored
16
packages/astro/src/env/runtime.ts
vendored
|
@ -1,5 +1,7 @@
|
|||
import { AstroError, AstroErrorData } from '../core/errors/index.js';
|
||||
export { validateEnvVariable } from './validators.js';
|
||||
import { invalidVariablesToError } from './errors.js';
|
||||
import type { ValidationResultInvalid } from './validators.js';
|
||||
export { validateEnvVariable, getEnvFieldType } from './validators.js';
|
||||
|
||||
export type GetEnv = (key: string) => string | undefined;
|
||||
|
||||
|
@ -21,11 +23,15 @@ export function getEnv(...args: Parameters<GetEnv>) {
|
|||
return _getEnv(...args);
|
||||
}
|
||||
|
||||
export function createInvalidVariableError(
|
||||
...args: Parameters<typeof AstroErrorData.EnvInvalidVariable.message>
|
||||
export function createInvalidVariablesError(
|
||||
key: string,
|
||||
type: string,
|
||||
result: ValidationResultInvalid
|
||||
) {
|
||||
return new AstroError({
|
||||
...AstroErrorData.EnvInvalidVariable,
|
||||
message: AstroErrorData.EnvInvalidVariable.message(...args),
|
||||
...AstroErrorData.EnvInvalidVariables,
|
||||
message: AstroErrorData.EnvInvalidVariables.message(
|
||||
invalidVariablesToError([{ key, type, errors: result.errors }])
|
||||
),
|
||||
});
|
||||
}
|
||||
|
|
19
packages/astro/src/env/validators.ts
vendored
19
packages/astro/src/env/validators.ts
vendored
|
@ -2,16 +2,15 @@ import type { EnumSchema, EnvFieldType, NumberSchema, StringSchema } from './sch
|
|||
|
||||
export type ValidationResultValue = EnvFieldType['default'];
|
||||
export type ValidationResultErrors = ['missing'] | ['type'] | Array<string>;
|
||||
|
||||
type ValidationResult =
|
||||
| {
|
||||
ok: true;
|
||||
value: ValidationResultValue;
|
||||
}
|
||||
| {
|
||||
ok: false;
|
||||
errors: ValidationResultErrors;
|
||||
};
|
||||
interface ValidationResultValid {
|
||||
ok: true;
|
||||
value: ValidationResultValue;
|
||||
}
|
||||
export interface ValidationResultInvalid {
|
||||
ok: false;
|
||||
errors: ValidationResultErrors;
|
||||
}
|
||||
type ValidationResult = ValidationResultValid | ValidationResultInvalid;
|
||||
|
||||
export function getEnvFieldType(options: EnvFieldType) {
|
||||
const optional = options.optional ? (options.default !== undefined ? false : true) : false;
|
||||
|
|
18
packages/astro/src/env/vite-plugin-env.ts
vendored
18
packages/astro/src/env/vite-plugin-env.ts
vendored
|
@ -9,7 +9,8 @@ import {
|
|||
VIRTUAL_MODULES_IDS_VALUES,
|
||||
} from './constants.js';
|
||||
import type { EnvSchema } from './schema.js';
|
||||
import { type ValidationResultErrors, getEnvFieldType, validateEnvVariable } from './validators.js';
|
||||
import { getEnvFieldType, validateEnvVariable } from './validators.js';
|
||||
import { invalidVariablesToError, type InvalidVariable } from './errors.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
|
||||
|
@ -105,7 +106,7 @@ function validatePublicVariables({
|
|||
validateSecrets: boolean;
|
||||
}) {
|
||||
const valid: Array<{ key: string; value: any; type: string; context: 'server' | 'client' }> = [];
|
||||
const invalid: Array<{ key: string; type: string; errors: ValidationResultErrors }> = [];
|
||||
const invalid: Array<InvalidVariable> = [];
|
||||
|
||||
for (const [key, options] of Object.entries(schema)) {
|
||||
const variable = loadedEnv[key] === '' ? undefined : loadedEnv[key];
|
||||
|
@ -125,20 +126,9 @@ function validatePublicVariables({
|
|||
}
|
||||
|
||||
if (invalid.length > 0) {
|
||||
const _errors: Array<string> = [];
|
||||
for (const { key, type, errors } of invalid) {
|
||||
if (errors[0] === 'missing') {
|
||||
_errors.push(`${key} is missing`);
|
||||
} else if (errors[0] === 'type') {
|
||||
_errors.push(`${key}'s type is invalid, expected: ${type}`);
|
||||
} else {
|
||||
// constraints
|
||||
_errors.push(`The following constraints for ${key} are not met: ${errors.join(', ')}`);
|
||||
}
|
||||
}
|
||||
throw new AstroError({
|
||||
...AstroErrorData.EnvInvalidVariables,
|
||||
message: AstroErrorData.EnvInvalidVariables.message(_errors),
|
||||
message: AstroErrorData.EnvInvalidVariables.message(invalidVariablesToError(invalid)),
|
||||
});
|
||||
}
|
||||
|
||||
|
|
7
packages/astro/templates/env/module.mjs
vendored
7
packages/astro/templates/env/module.mjs
vendored
|
@ -1,9 +1,11 @@
|
|||
// @ts-check
|
||||
import { schema } from 'virtual:astro:env/internal';
|
||||
import {
|
||||
createInvalidVariableError,
|
||||
createInvalidVariablesError,
|
||||
getEnv,
|
||||
setOnSetGetEnv,
|
||||
validateEnvVariable,
|
||||
getEnvFieldType,
|
||||
} from 'astro/env/runtime';
|
||||
|
||||
export const getSecret = (key) => {
|
||||
|
@ -19,7 +21,8 @@ const _internalGetSecret = (key) => {
|
|||
if (result.ok) {
|
||||
return result.value;
|
||||
}
|
||||
throw createInvalidVariableError(key, result.type);
|
||||
const type = getEnvFieldType(options);
|
||||
throw createInvalidVariablesError(key, type, result);
|
||||
};
|
||||
|
||||
setOnSetGetEnv((reset) => {
|
||||
|
|
Loading…
Reference in a new issue