Skip to content

Commit

Permalink
Merge branch 'content-layer' into content-layer-rendering
Browse files Browse the repository at this point in the history
  • Loading branch information
ascorbic authored Jul 18, 2024
2 parents a2d6288 + 4149aaf commit ef5d0d2
Show file tree
Hide file tree
Showing 8 changed files with 63 additions and 43 deletions.
5 changes: 5 additions & 0 deletions .changeset/chilly-jokes-fold.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'astro': patch
---

Fixes a case where invalid `astro:env` variables at runtime would not throw correctly
5 changes: 5 additions & 0 deletions packages/astro/dev-only.d.ts
Original file line number Diff line number Diff line change
@@ -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;
}
14 changes: 2 additions & 12 deletions packages/astro/src/core/errors/errors-data.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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',
Expand All @@ -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
Expand Down
22 changes: 22 additions & 0 deletions packages/astro/src/env/errors.ts
Original file line number Diff line number Diff line change
@@ -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 changes: 11 additions & 5 deletions packages/astro/src/env/runtime.ts
Original file line number Diff line number Diff line change
@@ -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;

Expand All @@ -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 changes: 9 additions & 10 deletions packages/astro/src/env/validators.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
18 changes: 4 additions & 14 deletions packages/astro/src/env/vite-plugin-env.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,9 @@ import {
VIRTUAL_MODULES_IDS,
VIRTUAL_MODULES_IDS_VALUES,
} from './constants.js';
import { type InvalidVariable, invalidVariablesToError } from './errors.js';
import type { EnvSchema } from './schema.js';
import { type ValidationResultErrors, getEnvFieldType, validateEnvVariable } from './validators.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
Expand Down Expand Up @@ -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];
Expand All @@ -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)),
});
}

Expand Down
7 changes: 5 additions & 2 deletions packages/astro/templates/env/module.mjs
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
// @ts-check
import { schema } from 'virtual:astro:env/internal';
import {
createInvalidVariableError,
createInvalidVariablesError,
getEnv,
getEnvFieldType,
setOnSetGetEnv,
validateEnvVariable,
} from 'astro/env/runtime';
Expand All @@ -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) => {
Expand Down

0 comments on commit ef5d0d2

Please sign in to comment.