astro 4.9.3 → 4.10.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (68) hide show
  1. package/client.d.ts +8 -0
  2. package/config.d.ts +6 -0
  3. package/config.mjs +1 -0
  4. package/dist/@types/astro.d.ts +124 -0
  5. package/dist/config/index.js +2 -2
  6. package/dist/container/index.d.ts +11 -15
  7. package/dist/container/index.js +29 -27
  8. package/dist/container/pipeline.d.ts +1 -0
  9. package/dist/container/pipeline.js +8 -1
  10. package/dist/content/types-generator.js +5 -5
  11. package/dist/content/utils.d.ts +2 -3
  12. package/dist/content/utils.js +3 -4
  13. package/dist/content/vite-plugin-content-virtual-mod.d.ts +1 -1
  14. package/dist/core/app/pipeline.d.ts +2 -1
  15. package/dist/core/app/pipeline.js +44 -19
  16. package/dist/core/app/types.d.ts +1 -0
  17. package/dist/core/base-pipeline.d.ts +15 -3
  18. package/dist/core/base-pipeline.js +10 -1
  19. package/dist/core/build/generate.js +14 -4
  20. package/dist/core/build/pipeline.d.ts +2 -1
  21. package/dist/core/build/pipeline.js +31 -19
  22. package/dist/core/build/plugins/plugin-manifest.js +2 -1
  23. package/dist/core/config/config.js +1 -1
  24. package/dist/core/config/schema.d.ts +644 -0
  25. package/dist/core/config/schema.js +5 -1
  26. package/dist/core/config/settings.js +1 -0
  27. package/dist/core/constants.d.ts +1 -1
  28. package/dist/core/constants.js +2 -2
  29. package/dist/core/create-vite.js +2 -0
  30. package/dist/core/dev/dev.js +1 -1
  31. package/dist/core/errors/errors-data.d.ts +61 -1
  32. package/dist/core/errors/errors-data.js +39 -0
  33. package/dist/core/logger/core.d.ts +1 -1
  34. package/dist/core/messages.js +2 -2
  35. package/dist/core/render-context.d.ts +1 -0
  36. package/dist/core/render-context.js +74 -57
  37. package/dist/core/routing/astro-designed-error-pages.d.ts +8 -1
  38. package/dist/core/routing/astro-designed-error-pages.js +29 -12
  39. package/dist/env/config.d.ts +9 -0
  40. package/dist/env/config.js +17 -0
  41. package/dist/env/constants.d.ts +11 -0
  42. package/dist/env/constants.js +21 -0
  43. package/dist/env/runtime.d.ts +6 -0
  44. package/dist/env/runtime.js +21 -0
  45. package/dist/env/schema.d.ts +387 -0
  46. package/dist/env/schema.js +113 -0
  47. package/dist/env/validators.d.ts +13 -0
  48. package/dist/env/validators.js +57 -0
  49. package/dist/env/vite-plugin-env.d.ts +11 -0
  50. package/dist/env/vite-plugin-env.js +174 -0
  51. package/dist/integrations/features-validation.js +9 -1
  52. package/dist/jsx/server.js +2 -1
  53. package/dist/virtual-modules/container.d.ts +16 -0
  54. package/dist/virtual-modules/container.js +18 -0
  55. package/dist/virtual-modules/env-setup.d.ts +1 -0
  56. package/dist/virtual-modules/env-setup.js +4 -0
  57. package/dist/vite-plugin-astro-server/pipeline.d.ts +3 -2
  58. package/dist/vite-plugin-astro-server/pipeline.js +34 -20
  59. package/dist/vite-plugin-astro-server/plugin.js +1 -0
  60. package/dist/vite-plugin-astro-server/response.d.ts +0 -6
  61. package/dist/vite-plugin-astro-server/response.js +0 -13
  62. package/dist/vite-plugin-astro-server/route.js +2 -1
  63. package/dist/vite-plugin-inject-env-ts/index.js +46 -38
  64. package/package.json +4 -5
  65. package/templates/env/module.mjs +18 -0
  66. package/templates/env/types.d.ts +20 -0
  67. /package/{content-module.template.mjs → templates/content/module.mjs} +0 -0
  68. /package/{content-types.template.d.ts → templates/content/types.d.ts} +0 -0
@@ -0,0 +1,174 @@
1
+ import { fileURLToPath } from "node:url";
2
+ import { loadEnv } from "vite";
3
+ import { AstroError, AstroErrorData } from "../core/errors/index.js";
4
+ import {
5
+ ENV_TYPES_FILE,
6
+ MODULE_TEMPLATE_URL,
7
+ TYPES_TEMPLATE_URL,
8
+ VIRTUAL_MODULES_IDS,
9
+ VIRTUAL_MODULES_IDS_VALUES,
10
+ VIRTUAL_MODULE_SETUP_ID
11
+ } from "./constants.js";
12
+ import { getEnvFieldType, validateEnvVariable } from "./validators.js";
13
+ function astroEnv({
14
+ settings,
15
+ mode,
16
+ fs
17
+ }) {
18
+ if (!settings.config.experimental.env) {
19
+ return;
20
+ }
21
+ const schema = settings.config.experimental.env.schema ?? {};
22
+ let templates = null;
23
+ return {
24
+ name: "astro-env-plugin",
25
+ enforce: "pre",
26
+ buildStart() {
27
+ const loadedEnv = loadEnv(
28
+ mode === "dev" ? "development" : "production",
29
+ fileURLToPath(settings.config.root),
30
+ ""
31
+ );
32
+ const validatedVariables = validatePublicVariables({ schema, loadedEnv });
33
+ const clientTemplates = getClientTemplates({ validatedVariables });
34
+ const serverTemplates = getServerTemplates({ validatedVariables, schema, fs });
35
+ templates = {
36
+ client: clientTemplates.module,
37
+ server: serverTemplates.module,
38
+ internal: `export const schema = ${JSON.stringify(schema)};`
39
+ };
40
+ generateDts({
41
+ settings,
42
+ fs,
43
+ content: getDts({
44
+ fs,
45
+ clientPublic: clientTemplates.types,
46
+ serverPublic: serverTemplates.types.public,
47
+ serverSecret: serverTemplates.types.secret
48
+ })
49
+ });
50
+ },
51
+ buildEnd() {
52
+ templates = null;
53
+ },
54
+ resolveId(id) {
55
+ if (VIRTUAL_MODULES_IDS_VALUES.has(id)) {
56
+ return resolveVirtualModuleId(id);
57
+ }
58
+ if (id === VIRTUAL_MODULE_SETUP_ID) {
59
+ return this.resolve("astro/virtual-modules/env-setup.js");
60
+ }
61
+ },
62
+ load(id, options) {
63
+ if (id === resolveVirtualModuleId(VIRTUAL_MODULES_IDS.client)) {
64
+ return templates.client;
65
+ }
66
+ if (id === resolveVirtualModuleId(VIRTUAL_MODULES_IDS.server)) {
67
+ if (options?.ssr) {
68
+ return templates.server;
69
+ }
70
+ throw new AstroError({
71
+ ...AstroErrorData.ServerOnlyModule,
72
+ message: AstroErrorData.ServerOnlyModule.message(VIRTUAL_MODULES_IDS.server)
73
+ });
74
+ }
75
+ if (id === resolveVirtualModuleId(VIRTUAL_MODULES_IDS.internal)) {
76
+ return templates.internal;
77
+ }
78
+ }
79
+ };
80
+ }
81
+ function resolveVirtualModuleId(id) {
82
+ return `\0${id}`;
83
+ }
84
+ function generateDts({
85
+ content,
86
+ settings,
87
+ fs
88
+ }) {
89
+ fs.mkdirSync(settings.dotAstroDir, { recursive: true });
90
+ fs.writeFileSync(new URL(ENV_TYPES_FILE, settings.dotAstroDir), content, "utf-8");
91
+ }
92
+ function validatePublicVariables({
93
+ schema,
94
+ loadedEnv
95
+ }) {
96
+ const valid = [];
97
+ const invalid = [];
98
+ for (const [key, options] of Object.entries(schema)) {
99
+ if (options.access !== "public") {
100
+ continue;
101
+ }
102
+ const variable = loadedEnv[key];
103
+ const result = validateEnvVariable(variable === "" ? void 0 : variable, options);
104
+ if (result.ok) {
105
+ valid.push({ key, value: result.value, type: result.type, context: options.context });
106
+ } else {
107
+ invalid.push({ key, type: result.type });
108
+ }
109
+ }
110
+ if (invalid.length > 0) {
111
+ throw new AstroError({
112
+ ...AstroErrorData.EnvInvalidVariables,
113
+ message: AstroErrorData.EnvInvalidVariables.message(
114
+ invalid.map(({ key, type }) => `Variable ${key} is not of type: ${type}.`).join("\n")
115
+ )
116
+ });
117
+ }
118
+ return valid;
119
+ }
120
+ function getDts({
121
+ clientPublic,
122
+ serverPublic,
123
+ serverSecret,
124
+ fs
125
+ }) {
126
+ const template = fs.readFileSync(TYPES_TEMPLATE_URL, "utf-8");
127
+ return template.replace("// @@CLIENT@@", clientPublic).replace("// @@SERVER@@", serverPublic).replace("// @@SECRET_VALUES@@", serverSecret);
128
+ }
129
+ function getClientTemplates({
130
+ validatedVariables
131
+ }) {
132
+ let module = "";
133
+ let types = "";
134
+ for (const { key, type, value } of validatedVariables.filter((e) => e.context === "client")) {
135
+ module += `export const ${key} = ${JSON.stringify(value)};`;
136
+ types += `export const ${key}: ${type};
137
+ `;
138
+ }
139
+ return {
140
+ module,
141
+ types
142
+ };
143
+ }
144
+ function getServerTemplates({
145
+ validatedVariables,
146
+ schema,
147
+ fs
148
+ }) {
149
+ let module = fs.readFileSync(MODULE_TEMPLATE_URL, "utf-8");
150
+ let publicTypes = "";
151
+ let secretTypes = "";
152
+ for (const { key, type, value } of validatedVariables.filter((e) => e.context === "server")) {
153
+ module += `export const ${key} = ${JSON.stringify(value)};`;
154
+ publicTypes += `export const ${key}: ${type};
155
+ `;
156
+ }
157
+ for (const [key, options] of Object.entries(schema)) {
158
+ if (!(options.context === "server" && options.access === "secret")) {
159
+ continue;
160
+ }
161
+ secretTypes += `${key}: ${getEnvFieldType(options)};
162
+ `;
163
+ }
164
+ return {
165
+ module,
166
+ types: {
167
+ public: publicTypes,
168
+ secret: secretTypes
169
+ }
170
+ };
171
+ }
172
+ export {
173
+ astroEnv
174
+ };
@@ -13,7 +13,8 @@ function validateSupportedFeatures(adapterName, featureMap, config, adapterFeatu
13
13
  serverOutput = UNSUPPORTED,
14
14
  staticOutput = UNSUPPORTED,
15
15
  hybridOutput = UNSUPPORTED,
16
- i18nDomains = UNSUPPORTED
16
+ i18nDomains = UNSUPPORTED,
17
+ envGetSecret = UNSUPPORTED
17
18
  } = featureMap;
18
19
  const validationResult = {};
19
20
  validationResult.staticOutput = validateSupportKind(
@@ -55,6 +56,13 @@ function validateSupportedFeatures(adapterName, featureMap, config, adapterFeatu
55
56
  );
56
57
  }
57
58
  }
59
+ validationResult.envGetSecret = validateSupportKind(
60
+ envGetSecret,
61
+ adapterName,
62
+ logger,
63
+ "astro:env getSecret",
64
+ () => config?.experimental?.env !== void 0
65
+ );
58
66
  return validationResult;
59
67
  }
60
68
  function validateSupportKind(supportKind, adapterName, logger, featureName, hasCorrectConfig) {
@@ -1,4 +1,4 @@
1
- import { AstroError } from "../core/errors/errors.js";
1
+ import { AstroError, AstroUserError } from "../core/errors/errors.js";
2
2
  import { AstroJSX, jsx } from "../jsx-runtime/index.js";
3
3
  import { renderJSX } from "../runtime/server/jsx.js";
4
4
  const slotName = (str) => str.trim().replace(/[-_]([a-z])/g, (_, w) => w.toUpperCase());
@@ -34,6 +34,7 @@ async function renderToStaticMarkup(Component, props = {}, { default: children =
34
34
  }
35
35
  function throwEnhancedErrorIfMdxComponent(error, Component) {
36
36
  if (Component[Symbol.for("mdx-component")]) {
37
+ if (AstroUserError.is(error)) return;
37
38
  throw new AstroError({
38
39
  message: error.message,
39
40
  title: error.name,
@@ -0,0 +1,16 @@
1
+ import type { AstroRenderer, SSRLoadedRenderer } from '../@types/astro.js';
2
+ /**
3
+ * Use this function to provide renderers to the `AstroContainer`:
4
+ *
5
+ * ```js
6
+ * import { getContainerRenderer } from "@astrojs/react";
7
+ * import { experimental_AstroContainer as AstroContainer } from "astro/container";
8
+ * import { loadRenderers } from "astro:container"; // use this only when using vite/vitest
9
+ *
10
+ * const renderers = await loadRenderers([ getContainerRenderer ]);
11
+ * const container = await AstroContainer.create({ renderers });
12
+ *
13
+ * ```
14
+ * @param renderers
15
+ */
16
+ export declare function loadRenderers(renderers: AstroRenderer[]): Promise<SSRLoadedRenderer[]>;
@@ -0,0 +1,18 @@
1
+ async function loadRenderers(renderers) {
2
+ const loadedRenderers = await Promise.all(
3
+ renderers.map(async (renderer) => {
4
+ const mod = await import(renderer.serverEntrypoint);
5
+ if (typeof mod.default !== "undefined") {
6
+ return {
7
+ ...renderer,
8
+ ssr: mod.default
9
+ };
10
+ }
11
+ return void 0;
12
+ })
13
+ );
14
+ return loadedRenderers.filter((r) => Boolean(r));
15
+ }
16
+ export {
17
+ loadRenderers
18
+ };
@@ -0,0 +1 @@
1
+ export { setGetEnv, type GetEnv } from '../env/runtime.js';
@@ -0,0 +1,4 @@
1
+ import { setGetEnv } from "../env/runtime.js";
2
+ export {
3
+ setGetEnv
4
+ };
@@ -1,5 +1,5 @@
1
1
  import type { AstroSettings, ComponentInstance, ManifestData, RewritePayload, RouteData, SSRLoadedRenderer, SSRManifest } from '../@types/astro.js';
2
- import type { HeadElements } from '../core/base-pipeline.js';
2
+ import { type HeadElements } from '../core/base-pipeline.js';
3
3
  import type { Logger } from '../core/logger/core.js';
4
4
  import type { ModuleLoader } from '../core/module-loader/index.js';
5
5
  import { Pipeline } from '../core/render/index.js';
@@ -19,6 +19,7 @@ export declare class DevPipeline extends Pipeline {
19
19
  preload(routeData: RouteData, filePath: URL): Promise<ComponentInstance>;
20
20
  clearRouteCache(): void;
21
21
  getComponentByRoute(routeData: RouteData): Promise<ComponentInstance>;
22
- tryRewrite(payload: RewritePayload, request: Request): Promise<[RouteData, ComponentInstance]>;
22
+ tryRewrite(payload: RewritePayload, request: Request, sourceRoute: RouteData): Promise<[RouteData, ComponentInstance]>;
23
23
  setManifestData(manifestData: ManifestData): void;
24
+ rewriteKnownRoute(route: string, sourceRoute: RouteData): ComponentInstance;
24
25
  }
@@ -1,16 +1,17 @@
1
1
  import { fileURLToPath } from "node:url";
2
2
  import { getInfoOutput } from "../cli/info/index.js";
3
+ import {} from "../core/base-pipeline.js";
3
4
  import { ASTRO_VERSION, DEFAULT_404_COMPONENT } from "../core/constants.js";
4
5
  import { enhanceViteSSRError } from "../core/errors/dev/index.js";
5
- import { RouteNotFound } from "../core/errors/errors-data.js";
6
+ import { InvalidRewrite404, RewriteEncounteredAnError } from "../core/errors/errors-data.js";
6
7
  import { AggregateError, AstroError, CSSError, MarkdownError } from "../core/errors/index.js";
7
8
  import { Pipeline, loadRenderer } from "../core/render/index.js";
9
+ import { DEFAULT_404_ROUTE, default404Page } from "../core/routing/astro-designed-error-pages.js";
8
10
  import { isPage, isServerLikeOutput, resolveIdToUrl, viteID } from "../core/util.js";
9
11
  import { PAGE_SCRIPT_ID } from "../vite-plugin-scripts/index.js";
10
12
  import { getStylesForURL } from "./css.js";
11
13
  import { getComponentMetadata } from "./metadata.js";
12
14
  import { createResolve } from "./resolve.js";
13
- import { default404Page } from "./response.js";
14
15
  import { getScriptsForURL } from "./scripts.js";
15
16
  class DevPipeline extends Pipeline {
16
17
  constructor(loader, logger, manifest, settings, config = settings.config) {
@@ -132,41 +133,54 @@ class DevPipeline extends Pipeline {
132
133
  return await this.preload(routeData, filePath);
133
134
  }
134
135
  }
135
- async tryRewrite(payload, request) {
136
+ async tryRewrite(payload, request, sourceRoute) {
136
137
  let foundRoute;
137
138
  if (!this.manifestData) {
138
139
  throw new Error("Missing manifest data. This is an internal error, please file an issue.");
139
140
  }
140
141
  for (const route of this.manifestData.routes) {
142
+ let finalUrl = void 0;
141
143
  if (payload instanceof URL) {
142
- if (route.pattern.test(payload.pathname)) {
143
- foundRoute = route;
144
- break;
145
- }
144
+ finalUrl = payload;
146
145
  } else if (payload instanceof Request) {
147
- const url = new URL(payload.url);
148
- if (route.pattern.test(url.pathname)) {
149
- foundRoute = route;
150
- break;
151
- }
146
+ finalUrl = new URL(payload.url);
152
147
  } else {
153
- const newUrl = new URL(payload, new URL(request.url).origin);
154
- if (route.pattern.test(decodeURI(newUrl.pathname))) {
155
- foundRoute = route;
156
- break;
157
- }
148
+ finalUrl = new URL(payload, new URL(request.url).origin);
149
+ }
150
+ if (route.pattern.test(decodeURI(finalUrl.pathname))) {
151
+ foundRoute = route;
152
+ break;
153
+ } else if (finalUrl.pathname === "/404") {
154
+ foundRoute = DEFAULT_404_ROUTE;
155
+ break;
158
156
  }
159
157
  }
160
158
  if (foundRoute) {
161
- const componentInstance = await this.getComponentByRoute(foundRoute);
162
- return [foundRoute, componentInstance];
159
+ if (foundRoute.pathname === "/404") {
160
+ const componentInstance = this.rewriteKnownRoute(foundRoute.pathname, sourceRoute);
161
+ return [foundRoute, componentInstance];
162
+ } else {
163
+ const componentInstance = await this.getComponentByRoute(foundRoute);
164
+ return [foundRoute, componentInstance];
165
+ }
163
166
  } else {
164
- throw new AstroError(RouteNotFound);
167
+ throw new AstroError({
168
+ ...RewriteEncounteredAnError,
169
+ message: RewriteEncounteredAnError.message(payload.toString())
170
+ });
165
171
  }
166
172
  }
167
173
  setManifestData(manifestData) {
168
174
  this.manifestData = manifestData;
169
175
  }
176
+ rewriteKnownRoute(route, sourceRoute) {
177
+ if (isServerLikeOutput(this.config) && sourceRoute.prerender) {
178
+ if (route === "/404") {
179
+ return { default: default404Page };
180
+ }
181
+ }
182
+ throw new AstroError(InvalidRewrite404);
183
+ }
170
184
  }
171
185
  export {
172
186
  DevPipeline
@@ -115,6 +115,7 @@ function createDevelopmentManifest(settings) {
115
115
  i18n: i18nManifest,
116
116
  checkOrigin: settings.config.security?.checkOrigin ?? false,
117
117
  rewritingEnabled: settings.config.experimental.rewriting,
118
+ experimentalEnvGetSecretEnabled: false,
118
119
  middleware(_, next) {
119
120
  return next();
120
121
  }
@@ -3,12 +3,6 @@ import type http from 'node:http';
3
3
  import type { ErrorWithMetadata } from '../core/errors/index.js';
4
4
  import type { ModuleLoader } from '../core/module-loader/index.js';
5
5
  export declare function handle404Response(origin: string, req: http.IncomingMessage, res: http.ServerResponse): Promise<void>;
6
- export declare function default404Page({ pathname }: {
7
- pathname: string;
8
- }): Promise<Response>;
9
- export declare namespace default404Page {
10
- var isAstroComponentFactory: boolean;
11
- }
12
6
  export declare function handle500Response(loader: ModuleLoader, res: http.ServerResponse, err: ErrorWithMetadata): Promise<void>;
13
7
  export declare function writeHtmlResponse(res: http.ServerResponse, statusCode: number, html: string): void;
14
8
  export declare function writeWebResponse(res: http.ServerResponse, webResponse: Response): Promise<void>;
@@ -12,18 +12,6 @@ async function handle404Response(origin, req, res) {
12
12
  });
13
13
  writeHtmlResponse(res, 404, html);
14
14
  }
15
- async function default404Page({ pathname }) {
16
- return new Response(
17
- notFoundTemplate({
18
- statusCode: 404,
19
- title: "Not found",
20
- tabTitle: "404: Not Found",
21
- pathname
22
- }),
23
- { status: 404, headers: { "Content-Type": "text/html; charset=utf-8" } }
24
- );
25
- }
26
- default404Page.isAstroComponentFactory = true;
27
15
  async function handle500Response(loader, res, err) {
28
16
  res.on(
29
17
  "close",
@@ -92,7 +80,6 @@ async function writeSSRResult(webRequest, webResponse, res) {
92
80
  return writeWebResponse(res, webResponse);
93
81
  }
94
82
  export {
95
- default404Page,
96
83
  handle404Response,
97
84
  handle500Response,
98
85
  writeHtmlResponse,
@@ -9,10 +9,11 @@ import { loadMiddleware } from "../core/middleware/loadMiddleware.js";
9
9
  import { RenderContext } from "../core/render-context.js";
10
10
  import { getProps } from "../core/render/index.js";
11
11
  import { createRequest } from "../core/request.js";
12
+ import { default404Page } from "../core/routing/astro-designed-error-pages.js";
12
13
  import { matchAllRoutes } from "../core/routing/index.js";
13
14
  import { normalizeTheLocale } from "../i18n/index.js";
14
15
  import { getSortedPreloadedMatches } from "../prerender/routing.js";
15
- import { default404Page, handle404Response, writeSSRResult, writeWebResponse } from "./response.js";
16
+ import { handle404Response, writeSSRResult, writeWebResponse } from "./response.js";
16
17
  function isLoggedRequest(url) {
17
18
  return url !== "/favicon.ico";
18
19
  }
@@ -4,8 +4,8 @@ import { bold } from "kleur/colors";
4
4
  import { normalizePath } from "vite";
5
5
  import { ACTIONS_TYPES_FILE } from "../actions/consts.js";
6
6
  import { CONTENT_TYPES_FILE } from "../content/consts.js";
7
- import { getContentPaths } from "../content/index.js";
8
7
  import {} from "../core/logger/core.js";
8
+ import { ENV_TYPES_FILE } from "../env/constants.js";
9
9
  function getEnvTsPath({ srcDir }) {
10
10
  return new URL("env.d.ts", srcDir);
11
11
  }
@@ -24,62 +24,70 @@ function astroInjectEnvTsPlugin({
24
24
  }
25
25
  };
26
26
  }
27
+ function getDotAstroTypeReference({
28
+ settings,
29
+ filename
30
+ }) {
31
+ const relativePath = normalizePath(
32
+ path.relative(
33
+ fileURLToPath(settings.config.srcDir),
34
+ fileURLToPath(new URL(filename, settings.dotAstroDir))
35
+ )
36
+ );
37
+ return `/// <reference path=${JSON.stringify(relativePath)} />`;
38
+ }
27
39
  async function setUpEnvTs({
28
40
  settings,
29
41
  logger,
30
42
  fs
31
43
  }) {
32
44
  const envTsPath = getEnvTsPath(settings.config);
33
- const dotAstroDir = getContentPaths(settings.config).cacheDir;
34
- const dotAstroTypeReferences = getDotAstroTypeReferences({
35
- root: settings.config.root,
36
- srcDir: settings.config.srcDir,
37
- fs
38
- });
39
- const envTsPathRelativeToRoot = normalizePath(
45
+ const envTsPathRelativetoRoot = normalizePath(
40
46
  path.relative(fileURLToPath(settings.config.root), fileURLToPath(envTsPath))
41
47
  );
48
+ const injectedTypes = [
49
+ {
50
+ filename: CONTENT_TYPES_FILE,
51
+ meetsCondition: () => fs.existsSync(new URL(CONTENT_TYPES_FILE, settings.dotAstroDir))
52
+ },
53
+ {
54
+ filename: ACTIONS_TYPES_FILE,
55
+ meetsCondition: () => fs.existsSync(new URL(ACTIONS_TYPES_FILE, settings.dotAstroDir))
56
+ }
57
+ ];
58
+ if (settings.config.experimental.env) {
59
+ injectedTypes.push({
60
+ filename: ENV_TYPES_FILE
61
+ });
62
+ }
42
63
  if (fs.existsSync(envTsPath)) {
43
64
  let typesEnvContents = await fs.promises.readFile(envTsPath, "utf-8");
44
- let addedTypes = false;
45
- for (const typeReference of dotAstroTypeReferences) {
46
- if (typesEnvContents.includes(typeReference)) continue;
47
- typesEnvContents = `${typeReference}
65
+ for (const injectedType of injectedTypes) {
66
+ if (!injectedType.meetsCondition || await injectedType.meetsCondition?.()) {
67
+ const expectedTypeReference = getDotAstroTypeReference({
68
+ settings,
69
+ filename: injectedType.filename
70
+ });
71
+ if (!typesEnvContents.includes(expectedTypeReference)) {
72
+ typesEnvContents = `${expectedTypeReference}
48
73
  ${typesEnvContents}`;
49
- await fs.promises.writeFile(envTsPath, typesEnvContents, "utf-8");
50
- addedTypes = true;
51
- }
52
- if (addedTypes) {
53
- logger.info("types", `Added ${bold(envTsPathRelativeToRoot)} type declarations`);
74
+ }
75
+ }
54
76
  }
77
+ logger.info("types", `Added ${bold(envTsPathRelativetoRoot)} type declarations.`);
78
+ await fs.promises.writeFile(envTsPath, typesEnvContents, "utf-8");
55
79
  } else {
56
80
  let referenceDefs = [];
57
81
  referenceDefs.push('/// <reference types="astro/client" />');
58
- if (fs.existsSync(dotAstroDir)) {
59
- referenceDefs.push(...dotAstroTypeReferences);
82
+ for (const injectedType of injectedTypes) {
83
+ if (!injectedType.meetsCondition || await injectedType.meetsCondition?.()) {
84
+ referenceDefs.push(getDotAstroTypeReference({ settings, filename: injectedType.filename }));
85
+ }
60
86
  }
61
87
  await fs.promises.mkdir(settings.config.srcDir, { recursive: true });
62
88
  await fs.promises.writeFile(envTsPath, referenceDefs.join("\n"), "utf-8");
63
- logger.info("types", `Added ${bold(envTsPathRelativeToRoot)} type declarations`);
64
- }
65
- }
66
- function getDotAstroTypeReferences({
67
- fs,
68
- root,
69
- srcDir
70
- }) {
71
- const { cacheDir } = getContentPaths({ root, srcDir });
72
- let referenceDefs = [];
73
- const typesFiles = [CONTENT_TYPES_FILE, ACTIONS_TYPES_FILE];
74
- for (const typesFile of typesFiles) {
75
- const url = new URL(typesFile, cacheDir);
76
- if (!fs.existsSync(url)) continue;
77
- const typesRelativeToSrcDir = normalizePath(
78
- path.relative(fileURLToPath(srcDir), fileURLToPath(url))
79
- );
80
- referenceDefs.push(`/// <reference path=${JSON.stringify(typesRelativeToSrcDir)} />`);
89
+ logger.info("types", `Added ${bold(envTsPathRelativetoRoot)} type declarations`);
81
90
  }
82
- return referenceDefs;
83
91
  }
84
92
  export {
85
93
  astroInjectEnvTsPlugin,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "astro",
3
- "version": "4.9.3",
3
+ "version": "4.10.0",
4
4
  "description": "Astro is a modern site builder with web best practices, performance, and DX front-of-mind.",
5
5
  "type": "module",
6
6
  "author": "withastro",
@@ -32,6 +32,7 @@
32
32
  "default": "./dist/core/index.js"
33
33
  },
34
34
  "./env": "./env.d.ts",
35
+ "./env/runtime": "./dist/env/runtime.js",
35
36
  "./types": "./types.d.ts",
36
37
  "./client": "./client.d.ts",
37
38
  "./astro-jsx": "./astro-jsx.d.ts",
@@ -100,8 +101,6 @@
100
101
  "env.d.ts",
101
102
  "client.d.ts",
102
103
  "jsx-runtime.d.ts",
103
- "content-types.template.d.ts",
104
- "content-module.template.mjs",
105
104
  "templates",
106
105
  "astro-jsx.d.ts",
107
106
  "types.d.ts",
@@ -170,8 +169,8 @@
170
169
  "zod": "^3.23.8",
171
170
  "zod-to-json-schema": "^3.23.0",
172
171
  "@astrojs/internal-helpers": "0.4.0",
173
- "@astrojs/telemetry": "3.1.0",
174
- "@astrojs/markdown-remark": "5.1.0"
172
+ "@astrojs/markdown-remark": "5.1.0",
173
+ "@astrojs/telemetry": "3.1.0"
175
174
  },
176
175
  "optionalDependencies": {
177
176
  "sharp": "^0.33.3"
@@ -0,0 +1,18 @@
1
+ import { schema } from 'virtual:astro:env/internal';
2
+ import { createInvalidVariableError, getEnv, validateEnvVariable } from 'astro/env/runtime';
3
+
4
+ export const getSecret = (key) => {
5
+ const rawVariable = getEnv(key);
6
+ const variable = rawVariable === '' ? undefined : rawVariable;
7
+ const options = schema[key];
8
+
9
+ if (!options) {
10
+ return variable;
11
+ }
12
+
13
+ const result = validateEnvVariable(variable, options);
14
+ if (result.ok) {
15
+ return result.value;
16
+ }
17
+ throw createInvalidVariableError(key, result.type);
18
+ };
@@ -0,0 +1,20 @@
1
+ declare module 'astro:env/client' {
2
+ // @@CLIENT@@
3
+ }
4
+
5
+ declare module 'astro:env/server' {
6
+ // @@SERVER@@
7
+
8
+ type SecretValues = {
9
+ // @@SECRET_VALUES@@
10
+ };
11
+
12
+ type SecretValue = keyof SecretValues;
13
+
14
+ type Loose<T> = T | (string & {});
15
+ type Strictify<T extends string> = T extends `${infer _}` ? T : never;
16
+
17
+ export const getSecret: <TKey extends Loose<SecretValue>>(
18
+ key: TKey
19
+ ) => TKey extends Strictify<SecretValue> ? SecretValues[TKey] : string | undefined;
20
+ }