astro 1.3.0 → 1.4.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 (46) hide show
  1. package/dist/@types/astro.d.ts +8 -0
  2. package/dist/cli/index.js +1 -1
  3. package/dist/core/app/index.d.ts +1 -0
  4. package/dist/core/app/index.js +4 -0
  5. package/dist/core/build/index.js +9 -0
  6. package/dist/core/build/static-build.js +31 -11
  7. package/dist/core/config/config.js +4 -1
  8. package/dist/core/cookies/cookies.d.ts +75 -0
  9. package/dist/core/cookies/cookies.js +154 -0
  10. package/dist/core/cookies/index.d.ts +2 -0
  11. package/dist/core/cookies/index.js +7 -0
  12. package/dist/core/cookies/response.d.ts +3 -0
  13. package/dist/core/cookies/response.js +25 -0
  14. package/dist/core/create-vite.js +2 -1
  15. package/dist/core/dev/index.js +1 -1
  16. package/dist/core/endpoint/index.js +11 -1
  17. package/dist/core/messages.js +6 -6
  18. package/dist/core/path.d.ts +1 -0
  19. package/dist/core/path.js +4 -0
  20. package/dist/core/render/core.js +6 -1
  21. package/dist/core/render/result.js +12 -0
  22. package/dist/core/render/route-cache.js +1 -4
  23. package/dist/core/routing/params.js +1 -1
  24. package/dist/core/util.js +2 -2
  25. package/dist/runtime/server/astro-global.js +1 -1
  26. package/dist/runtime/server/endpoint.d.ts +2 -2
  27. package/dist/runtime/server/endpoint.js +6 -5
  28. package/dist/runtime/server/escape.d.ts +0 -1
  29. package/dist/runtime/server/escape.js +4 -2
  30. package/dist/runtime/server/hydration.js +3 -1
  31. package/dist/runtime/server/render/any.d.ts +0 -1
  32. package/dist/runtime/server/render/any.js +8 -19
  33. package/dist/runtime/server/render/component.js +10 -24
  34. package/dist/runtime/server/render/dom.js +1 -1
  35. package/dist/runtime/server/render/head.js +2 -3
  36. package/dist/runtime/server/render/index.d.ts +1 -1
  37. package/dist/runtime/server/render/index.js +1 -1
  38. package/dist/runtime/server/render/page.js +4 -2
  39. package/dist/runtime/server/render/slot.d.ts +14 -0
  40. package/dist/runtime/server/render/slot.js +52 -0
  41. package/dist/runtime/server/render/util.js +2 -2
  42. package/dist/vite-plugin-astro/hmr.js +3 -2
  43. package/dist/vite-plugin-astro-server/index.js +5 -0
  44. package/dist/vite-plugin-markdown/index.js +6 -1
  45. package/dist/vite-plugin-utils/index.js +4 -1
  46. package/package.json +17 -7
@@ -9,6 +9,7 @@ import type { z } from 'zod';
9
9
  import type { SerializedSSRManifest } from '../core/app/types';
10
10
  import type { PageBuildData } from '../core/build/types';
11
11
  import type { AstroConfigSchema } from '../core/config';
12
+ import type { AstroCookies } from '../core/cookies';
12
13
  import type { ViteConfigWithSSR } from '../core/create-vite';
13
14
  import type { AstroComponentFactory, Metadata } from '../runtime/server';
14
15
  export type { MarkdownHeading, MarkdownMetadata, MarkdownRenderingResult, RehypePlugins, RemarkPlugins, ShikiConfig, } from '@astrojs/markdown-remark';
@@ -92,6 +93,10 @@ export interface AstroGlobal extends AstroGlobalPartial {
92
93
  *
93
94
  * [Astro reference](https://docs.astro.build/en/reference/api-reference/#url)
94
95
  */
96
+ /**
97
+ * Utility for getting and setting cookies values.
98
+ */
99
+ cookies: AstroCookies;
95
100
  url: URL;
96
101
  /** Parameters passed to a dynamic page generated using [getStaticPaths](https://docs.astro.build/en/reference/api-reference/#getstaticpaths)
97
102
  *
@@ -974,6 +979,7 @@ export interface AstroAdapter {
974
979
  }
975
980
  declare type Body = string;
976
981
  export interface APIContext {
982
+ cookies: AstroCookies;
977
983
  params: Params;
978
984
  request: Request;
979
985
  }
@@ -1090,11 +1096,13 @@ export interface SSRMetadata {
1090
1096
  pathname: string;
1091
1097
  hasHydrationScript: boolean;
1092
1098
  hasDirectives: Set<string>;
1099
+ hasRenderedHead: boolean;
1093
1100
  }
1094
1101
  export interface SSRResult {
1095
1102
  styles: Set<SSRElement>;
1096
1103
  scripts: Set<SSRElement>;
1097
1104
  links: Set<SSRElement>;
1105
+ cookies: AstroCookies | undefined;
1098
1106
  createAstro(Astro: AstroGlobalPartial, props: Record<string, any>, slots: Record<string, any> | null): AstroGlobal;
1099
1107
  resolve: (s: string) => Promise<string>;
1100
1108
  response: ResponseInit;
package/dist/cli/index.js CHANGED
@@ -187,7 +187,7 @@ async function runCommand(cmd, flags) {
187
187
  });
188
188
  }
189
189
  case "build": {
190
- return await build(settings, { logging, telemetry });
190
+ return await build(settings, { ...flags, logging, telemetry });
191
191
  }
192
192
  case "check": {
193
193
  const ret = await check(settings);
@@ -11,4 +11,5 @@ export declare class App {
11
11
  constructor(manifest: Manifest, streaming?: boolean);
12
12
  match(request: Request, { matchNotFound }?: MatchOptions): RouteData | undefined;
13
13
  render(request: Request, routeData?: RouteData): Promise<Response>;
14
+ setCookieHeaders(response: Response): Generator<string, void, unknown>;
14
15
  }
@@ -22,6 +22,7 @@ var __privateMethod = (obj, member, method) => {
22
22
  };
23
23
  var _manifest, _manifestData, _routeDataToRouteInfo, _routeCache, _encoder, _logging, _streaming, _renderPage, renderPage_fn, _callEndpoint, callEndpoint_fn;
24
24
  import mime from "mime";
25
+ import { getSetCookiesFromResponse } from "../cookies/index.js";
25
26
  import { call as callEndpoint } from "../endpoint/index.js";
26
27
  import { consoleLogDestination } from "../logger/console.js";
27
28
  import { error } from "../logger/core.js";
@@ -111,6 +112,9 @@ class App {
111
112
  throw new Error(`Unsupported route type [${routeData.type}].`);
112
113
  }
113
114
  }
115
+ setCookieHeaders(response) {
116
+ return getSetCookiesFromResponse(response);
117
+ }
114
118
  }
115
119
  _manifest = new WeakMap();
116
120
  _manifestData = new WeakMap();
@@ -64,6 +64,7 @@ class AstroBuilder {
64
64
  serverEntry: "entry.mjs"
65
65
  };
66
66
  await runHookBuildStart({ config: this.settings.config, buildConfig, logging: this.logging });
67
+ this.validateConfig();
67
68
  info(this.logging, "build", `output target: ${colors.green(this.settings.config.output)}`);
68
69
  if (this.settings.adapter) {
69
70
  info(this.logging, "build", `deploy adapter: ${colors.green(this.settings.adapter.name)}`);
@@ -129,6 +130,14 @@ class AstroBuilder {
129
130
  throw fixViteErrorMessage(_err);
130
131
  }
131
132
  }
133
+ validateConfig() {
134
+ const { config } = this.settings;
135
+ if (config.outDir.toString() === config.root.toString()) {
136
+ throw new Error(
137
+ `the outDir cannot be the root folder. Please build to a folder such as dist.`
138
+ );
139
+ }
140
+ }
132
141
  async printStats({
133
142
  logging,
134
143
  timeStart,
@@ -1,6 +1,7 @@
1
1
  import glob from "fast-glob";
2
2
  import fs from "fs";
3
3
  import { bgGreen, bgMagenta, black, dim } from "kleur/colors";
4
+ import path from "path";
4
5
  import { fileURLToPath } from "url";
5
6
  import * as vite from "vite";
6
7
  import { createBuildInternals } from "../../core/build/internal.js";
@@ -82,8 +83,8 @@ async function ssrBuild(opts, internals, input) {
82
83
  const out = ssr ? opts.buildConfig.server : getOutDirWithinCwd(settings.config.outDir);
83
84
  const viteBuildConfig = {
84
85
  ...viteConfig,
86
+ mode: viteConfig.mode || "production",
85
87
  logLevel: opts.viteConfig.logLevel ?? "error",
86
- mode: "production",
87
88
  build: {
88
89
  target: "esnext",
89
90
  ...viteConfig.build,
@@ -147,8 +148,8 @@ async function clientBuild(opts, internals, input) {
147
148
  ${bgGreen(black(" building client "))}`);
148
149
  const viteBuildConfig = {
149
150
  ...viteConfig,
151
+ mode: viteConfig.mode || "production",
150
152
  logLevel: "info",
151
- mode: "production",
152
153
  build: {
153
154
  target: "esnext",
154
155
  ...viteConfig.build,
@@ -194,19 +195,38 @@ ${bgGreen(black(" building client "))}`);
194
195
  }
195
196
  async function cleanSsrOutput(opts) {
196
197
  const out = getOutDirWithinCwd(opts.settings.config.outDir);
198
+ const files = await glob("**/*.mjs", {
199
+ cwd: fileURLToPath(out)
200
+ });
201
+ if (files.length) {
202
+ await Promise.all(
203
+ files.map(async (filename) => {
204
+ const url = new URL(filename, out);
205
+ await fs.promises.rm(url);
206
+ })
207
+ );
208
+ const directories = /* @__PURE__ */ new Set();
209
+ files.forEach((i) => {
210
+ const splitFilePath = i.split(path.sep);
211
+ if (splitFilePath.length > 1) {
212
+ directories.add(splitFilePath[0]);
213
+ }
214
+ });
215
+ await Promise.all(
216
+ Array.from(directories).map(async (filename) => {
217
+ const url = new URL(filename, out);
218
+ const folder = await fs.promises.readdir(url);
219
+ if (!folder.length) {
220
+ await fs.promises.rmdir(url, { recursive: true });
221
+ }
222
+ })
223
+ );
224
+ }
197
225
  if (out.toString() !== opts.settings.config.outDir.toString()) {
226
+ copyFiles(out, opts.settings.config.outDir);
198
227
  await fs.promises.rm(out, { recursive: true });
199
228
  return;
200
229
  }
201
- const files = await glob("**/*.mjs", {
202
- cwd: fileURLToPath(out)
203
- });
204
- await Promise.all(
205
- files.map(async (filename) => {
206
- const url = new URL(filename, out);
207
- await fs.promises.rm(url);
208
- })
209
- );
210
230
  }
211
231
  async function copyFiles(fromFolder, toFolder) {
212
232
  const files = await glob("**/*", {
@@ -182,7 +182,10 @@ async function tryLoadConfig(configOptions, flags, root) {
182
182
  server: { middlewareMode: true, hmr: false },
183
183
  optimizeDeps: { entries: [] },
184
184
  clearScreen: false,
185
- appType: "custom"
185
+ appType: "custom",
186
+ ssr: {
187
+ external: ["@astrojs/mdx", "@astrojs/react"]
188
+ }
186
189
  });
187
190
  try {
188
191
  const mod = await viteServer.ssrLoadModule(configPath);
@@ -0,0 +1,75 @@
1
+ interface AstroCookieSetOptions {
2
+ domain?: string;
3
+ expires?: Date;
4
+ httpOnly?: boolean;
5
+ maxAge?: number;
6
+ path?: string;
7
+ sameSite?: boolean | 'lax' | 'none' | 'strict';
8
+ secure?: boolean;
9
+ }
10
+ interface AstroCookieDeleteOptions {
11
+ path?: string;
12
+ }
13
+ interface AstroCookieInterface {
14
+ value: string | undefined;
15
+ json(): Record<string, any>;
16
+ number(): number;
17
+ boolean(): boolean;
18
+ }
19
+ interface AstroCookiesInterface {
20
+ get(key: string): AstroCookieInterface;
21
+ has(key: string): boolean;
22
+ set(key: string, value: string | Record<string, any>, options?: AstroCookieSetOptions): void;
23
+ delete(key: string, options?: AstroCookieDeleteOptions): void;
24
+ }
25
+ declare class AstroCookie implements AstroCookieInterface {
26
+ value: string | undefined;
27
+ constructor(value: string | undefined);
28
+ json(): any;
29
+ number(): number;
30
+ boolean(): boolean;
31
+ }
32
+ declare class AstroCookies implements AstroCookiesInterface {
33
+ #private;
34
+ constructor(request: Request);
35
+ /**
36
+ * Astro.cookies.delete(key) is used to delete a cookie. Using this method will result
37
+ * in a Set-Cookie header added to the response.
38
+ * @param key The cookie to delete
39
+ * @param options Options related to this deletion, such as the path of the cookie.
40
+ */
41
+ delete(key: string, options?: AstroCookieDeleteOptions): void;
42
+ /**
43
+ * Astro.cookies.get(key) is used to get a cookie value. The cookie value is read from the
44
+ * request. If you have set a cookie via Astro.cookies.set(key, value), the value will be taken
45
+ * from that set call, overriding any values already part of the request.
46
+ * @param key The cookie to get.
47
+ * @returns An object containing the cookie value as well as convenience methods for converting its value.
48
+ */
49
+ get(key: string): AstroCookie;
50
+ /**
51
+ * Astro.cookies.has(key) returns a boolean indicating whether this cookie is either
52
+ * part of the initial request or set via Astro.cookies.set(key)
53
+ * @param key The cookie to check for.
54
+ * @returns
55
+ */
56
+ has(key: string): boolean;
57
+ /**
58
+ * Astro.cookies.set(key, value) is used to set a cookie's value. If provided
59
+ * an object it will be stringified via JSON.stringify(value). Additionally you
60
+ * can provide options customizing how this cookie will be set, such as setting httpOnly
61
+ * in order to prevent the cookie from being read in client-side JavaScript.
62
+ * @param key The name of the cookie to set.
63
+ * @param value A value, either a string or other primitive or an object.
64
+ * @param options Options for the cookie, such as the path and security settings.
65
+ */
66
+ set(key: string, value: string | Record<string, any>, options?: AstroCookieSetOptions): void;
67
+ /**
68
+ * Astro.cookies.header() returns an iterator for the cookies that have previously
69
+ * been set by either Astro.cookies.set() or Astro.cookies.delete().
70
+ * This method is primarily used by adapters to set the header on outgoing responses.
71
+ * @returns
72
+ */
73
+ headers(): Generator<string, void, unknown>;
74
+ }
75
+ export { AstroCookies };
@@ -0,0 +1,154 @@
1
+ var __accessCheck = (obj, member, msg) => {
2
+ if (!member.has(obj))
3
+ throw TypeError("Cannot " + msg);
4
+ };
5
+ var __privateGet = (obj, member, getter) => {
6
+ __accessCheck(obj, member, "read from private field");
7
+ return getter ? getter.call(obj) : member.get(obj);
8
+ };
9
+ var __privateAdd = (obj, member, value) => {
10
+ if (member.has(obj))
11
+ throw TypeError("Cannot add the same private member more than once");
12
+ member instanceof WeakSet ? member.add(obj) : member.set(obj, value);
13
+ };
14
+ var __privateSet = (obj, member, value, setter) => {
15
+ __accessCheck(obj, member, "write to private field");
16
+ setter ? setter.call(obj, value) : member.set(obj, value);
17
+ return value;
18
+ };
19
+ var __privateMethod = (obj, member, method) => {
20
+ __accessCheck(obj, member, "access private method");
21
+ return method;
22
+ };
23
+ var _request, _requestValues, _outgoing, _ensureParsed, ensureParsed_fn, _ensureOutgoingMap, ensureOutgoingMap_fn, _parse, parse_fn;
24
+ import { parse, serialize } from "cookie";
25
+ const DELETED_EXPIRATION = new Date(0);
26
+ const DELETED_VALUE = "deleted";
27
+ class AstroCookie {
28
+ constructor(value) {
29
+ this.value = value;
30
+ }
31
+ json() {
32
+ if (this.value === void 0) {
33
+ throw new Error(`Cannot convert undefined to an object.`);
34
+ }
35
+ return JSON.parse(this.value);
36
+ }
37
+ number() {
38
+ return Number(this.value);
39
+ }
40
+ boolean() {
41
+ if (this.value === "false")
42
+ return false;
43
+ if (this.value === "0")
44
+ return false;
45
+ return Boolean(this.value);
46
+ }
47
+ }
48
+ class AstroCookies {
49
+ constructor(request) {
50
+ __privateAdd(this, _ensureParsed);
51
+ __privateAdd(this, _ensureOutgoingMap);
52
+ __privateAdd(this, _parse);
53
+ __privateAdd(this, _request, void 0);
54
+ __privateAdd(this, _requestValues, void 0);
55
+ __privateAdd(this, _outgoing, void 0);
56
+ __privateSet(this, _request, request);
57
+ __privateSet(this, _requestValues, null);
58
+ __privateSet(this, _outgoing, null);
59
+ }
60
+ delete(key, options) {
61
+ const serializeOptions = {
62
+ expires: DELETED_EXPIRATION
63
+ };
64
+ if (options == null ? void 0 : options.path) {
65
+ serializeOptions.path = options.path;
66
+ }
67
+ __privateMethod(this, _ensureOutgoingMap, ensureOutgoingMap_fn).call(this).set(key, [
68
+ DELETED_VALUE,
69
+ serialize(key, DELETED_VALUE, serializeOptions),
70
+ false
71
+ ]);
72
+ }
73
+ get(key) {
74
+ if (__privateGet(this, _outgoing) !== null && __privateGet(this, _outgoing).has(key)) {
75
+ let [serializedValue, , isSetValue] = __privateGet(this, _outgoing).get(key);
76
+ if (isSetValue) {
77
+ return new AstroCookie(serializedValue);
78
+ } else {
79
+ return new AstroCookie(void 0);
80
+ }
81
+ }
82
+ const values = __privateMethod(this, _ensureParsed, ensureParsed_fn).call(this);
83
+ const value = values[key];
84
+ return new AstroCookie(value);
85
+ }
86
+ has(key) {
87
+ if (__privateGet(this, _outgoing) !== null && __privateGet(this, _outgoing).has(key)) {
88
+ let [, , isSetValue] = __privateGet(this, _outgoing).get(key);
89
+ return isSetValue;
90
+ }
91
+ const values = __privateMethod(this, _ensureParsed, ensureParsed_fn).call(this);
92
+ return !!values[key];
93
+ }
94
+ set(key, value, options) {
95
+ let serializedValue;
96
+ if (typeof value === "string") {
97
+ serializedValue = value;
98
+ } else {
99
+ let toStringValue = value.toString();
100
+ if (toStringValue === Object.prototype.toString.call(value)) {
101
+ serializedValue = JSON.stringify(value);
102
+ } else {
103
+ serializedValue = toStringValue;
104
+ }
105
+ }
106
+ const serializeOptions = {};
107
+ if (options) {
108
+ Object.assign(serializeOptions, options);
109
+ }
110
+ __privateMethod(this, _ensureOutgoingMap, ensureOutgoingMap_fn).call(this).set(key, [
111
+ serializedValue,
112
+ serialize(key, serializedValue, serializeOptions),
113
+ true
114
+ ]);
115
+ }
116
+ *headers() {
117
+ if (__privateGet(this, _outgoing) == null)
118
+ return;
119
+ for (const [, value] of __privateGet(this, _outgoing)) {
120
+ yield value[1];
121
+ }
122
+ }
123
+ }
124
+ _request = new WeakMap();
125
+ _requestValues = new WeakMap();
126
+ _outgoing = new WeakMap();
127
+ _ensureParsed = new WeakSet();
128
+ ensureParsed_fn = function() {
129
+ if (!__privateGet(this, _requestValues)) {
130
+ __privateMethod(this, _parse, parse_fn).call(this);
131
+ }
132
+ if (!__privateGet(this, _requestValues)) {
133
+ __privateSet(this, _requestValues, {});
134
+ }
135
+ return __privateGet(this, _requestValues);
136
+ };
137
+ _ensureOutgoingMap = new WeakSet();
138
+ ensureOutgoingMap_fn = function() {
139
+ if (!__privateGet(this, _outgoing)) {
140
+ __privateSet(this, _outgoing, /* @__PURE__ */ new Map());
141
+ }
142
+ return __privateGet(this, _outgoing);
143
+ };
144
+ _parse = new WeakSet();
145
+ parse_fn = function() {
146
+ const raw = __privateGet(this, _request).headers.get("cookie");
147
+ if (!raw) {
148
+ return;
149
+ }
150
+ __privateSet(this, _requestValues, parse(raw));
151
+ };
152
+ export {
153
+ AstroCookies
154
+ };
@@ -0,0 +1,2 @@
1
+ export { AstroCookies } from './cookies.js';
2
+ export { attachToResponse, getSetCookiesFromResponse } from './response.js';
@@ -0,0 +1,7 @@
1
+ import { AstroCookies } from "./cookies.js";
2
+ import { attachToResponse, getSetCookiesFromResponse } from "./response.js";
3
+ export {
4
+ AstroCookies,
5
+ attachToResponse,
6
+ getSetCookiesFromResponse
7
+ };
@@ -0,0 +1,3 @@
1
+ import type { AstroCookies } from './cookies';
2
+ export declare function attachToResponse(response: Response, cookies: AstroCookies): void;
3
+ export declare function getSetCookiesFromResponse(response: Response): Generator<string, void, unknown>;
@@ -0,0 +1,25 @@
1
+ const astroCookiesSymbol = Symbol.for("astro.cookies");
2
+ function attachToResponse(response, cookies) {
3
+ Reflect.set(response, astroCookiesSymbol, cookies);
4
+ }
5
+ function getFromResponse(response) {
6
+ let cookies = Reflect.get(response, astroCookiesSymbol);
7
+ if (cookies != null) {
8
+ return cookies;
9
+ } else {
10
+ return void 0;
11
+ }
12
+ }
13
+ function* getSetCookiesFromResponse(response) {
14
+ const cookies = getFromResponse(response);
15
+ if (!cookies) {
16
+ return;
17
+ }
18
+ for (const headerValue of cookies.headers()) {
19
+ yield headerValue;
20
+ }
21
+ }
22
+ export {
23
+ attachToResponse,
24
+ getSetCookiesFromResponse
25
+ };
@@ -88,7 +88,8 @@ async function createVite(commandConfig, { settings, logging, mode }) {
88
88
  conditions: ["astro"]
89
89
  },
90
90
  ssr: {
91
- noExternal: [...getSsrNoExternalDeps(settings.config.root), ...thirdPartyAstroPackages]
91
+ noExternal: [...getSsrNoExternalDeps(settings.config.root), ...thirdPartyAstroPackages],
92
+ external: mode === "dev" ? ["shiki"] : []
92
93
  }
93
94
  };
94
95
  let result = commonConfig;
@@ -46,7 +46,7 @@ async function dev(settings, options) {
46
46
  isRestart
47
47
  })
48
48
  );
49
- const currentVersion = "1.3.0";
49
+ const currentVersion = "1.4.0";
50
50
  if (currentVersion.includes("-")) {
51
51
  warn(options.logging, null, msg.prerelease({ currentVersion }));
52
52
  }
@@ -1,5 +1,13 @@
1
1
  import { renderEndpoint } from "../../runtime/server/index.js";
2
+ import { AstroCookies, attachToResponse } from "../cookies/index.js";
2
3
  import { getParamsAndProps, GetParamsAndPropsError } from "../render/core.js";
4
+ function createAPIContext(request, params) {
5
+ return {
6
+ cookies: new AstroCookies(request),
7
+ request,
8
+ params
9
+ };
10
+ }
3
11
  async function call(mod, opts) {
4
12
  const paramsAndPropsResp = await getParamsAndProps({ ...opts, mod });
5
13
  if (paramsAndPropsResp === GetParamsAndPropsError.NoMatchingStaticPath) {
@@ -8,8 +16,10 @@ async function call(mod, opts) {
8
16
  );
9
17
  }
10
18
  const [params] = paramsAndPropsResp;
11
- const response = await renderEndpoint(mod, opts.request, params);
19
+ const context = createAPIContext(opts.request, params);
20
+ const response = await renderEndpoint(mod, context, opts.ssr);
12
21
  if (response instanceof Response) {
22
+ attachToResponse(response, context.cookies);
13
23
  return {
14
24
  type: "response",
15
25
  response
@@ -47,7 +47,7 @@ function serverStart({
47
47
  site,
48
48
  isRestart = false
49
49
  }) {
50
- const version = "1.3.0";
50
+ const version = "1.4.0";
51
51
  const rootPath = site ? site.pathname : "/";
52
52
  const localPrefix = `${dim("\u2503")} Local `;
53
53
  const networkPrefix = `${dim("\u2503")} Network `;
@@ -97,12 +97,12 @@ function resolveServerUrls({
97
97
  const ipv4Networks = Object.values(os.networkInterfaces()).flatMap((networkInterface) => networkInterface ?? []).filter(
98
98
  (networkInterface) => (networkInterface == null ? void 0 : networkInterface.address) && (networkInterface == null ? void 0 : networkInterface.family) === (nodeVersion < 18 || nodeVersion >= 18.4 ? "IPv4" : 4)
99
99
  );
100
- for (let { address: address2 } of ipv4Networks) {
101
- if (address2.includes("127.0.0.1")) {
102
- const displayAddress = address2.replace("127.0.0.1", localAddress);
100
+ for (let { address: ipv4Address } of ipv4Networks) {
101
+ if (ipv4Address.includes("127.0.0.1")) {
102
+ const displayAddress = ipv4Address.replace("127.0.0.1", localAddress);
103
103
  local = toDisplayUrl(displayAddress);
104
104
  } else {
105
- network = toDisplayUrl(address2);
105
+ network = toDisplayUrl(ipv4Address);
106
106
  }
107
107
  }
108
108
  }
@@ -250,7 +250,7 @@ function printHelp({
250
250
  message.push(
251
251
  linebreak(),
252
252
  ` ${bgGreen(black(` ${commandName} `))} ${green(
253
- `v${"1.3.0"}`
253
+ `v${"1.4.0"}`
254
254
  )} ${headline}`
255
255
  );
256
256
  }
@@ -1,3 +1,4 @@
1
+ export declare function appendExtension(path: string, extension: string): string;
1
2
  export declare function appendForwardSlash(path: string): string;
2
3
  export declare function prependForwardSlash(path: string): string;
3
4
  export declare function removeTrailingForwardSlash(path: string): string;
package/dist/core/path.js CHANGED
@@ -1,3 +1,6 @@
1
+ function appendExtension(path, extension) {
2
+ return path + "." + extension;
3
+ }
1
4
  function appendForwardSlash(path) {
2
5
  return path.endsWith("/") ? path : path + "/";
3
6
  }
@@ -41,6 +44,7 @@ function removeFileExtension(path) {
41
44
  return idx === -1 ? path : path.slice(0, idx);
42
45
  }
43
46
  export {
47
+ appendExtension,
44
48
  appendForwardSlash,
45
49
  isRelativePath,
46
50
  joinPaths,
@@ -1,4 +1,5 @@
1
1
  import { Fragment, renderPage } from "../../runtime/server/index.js";
2
+ import { attachToResponse } from "../cookies/index.js";
2
3
  import { getParams } from "../routing/params.js";
3
4
  import { createResult } from "./result.js";
4
5
  import { callGetStaticPaths, findPathItemByKey } from "./route-cache.js";
@@ -98,7 +99,11 @@ async function render(opts) {
98
99
  components: Object.assign((pageProps == null ? void 0 : pageProps.components) ?? {}, { Fragment })
99
100
  });
100
101
  }
101
- return await renderPage(result, Component, pageProps, null, streaming);
102
+ const response = await renderPage(result, Component, pageProps, null, streaming);
103
+ if (result.cookies) {
104
+ attachToResponse(response, result.cookies);
105
+ }
106
+ return response;
102
107
  }
103
108
  export {
104
109
  GetParamsAndPropsError,
@@ -19,6 +19,7 @@ var __privateSet = (obj, member, value, setter) => {
19
19
  var _cache, _result, _slots, _loggingOpts;
20
20
  import { bold } from "kleur/colors";
21
21
  import { renderSlot } from "../../runtime/server/index.js";
22
+ import { AstroCookies } from "../cookies/index.js";
22
23
  import { warn } from "../logger/core.js";
23
24
  import { isScriptRequest } from "./script.js";
24
25
  import { isCSSRequest } from "./util.js";
@@ -123,10 +124,12 @@ function createResult(args) {
123
124
  enumerable: true,
124
125
  writable: false
125
126
  });
127
+ let cookies = void 0;
126
128
  const result = {
127
129
  styles: args.styles ?? /* @__PURE__ */ new Set(),
128
130
  scripts: args.scripts ?? /* @__PURE__ */ new Set(),
129
131
  links: args.links ?? /* @__PURE__ */ new Set(),
132
+ cookies,
130
133
  createAstro(astroGlobal, props, slots) {
131
134
  const astroSlots = new Slots(result, slots, args.logging);
132
135
  const Astro = {
@@ -145,6 +148,14 @@ function createResult(args) {
145
148
  }
146
149
  return Reflect.get(request, clientAddressSymbol);
147
150
  },
151
+ get cookies() {
152
+ if (cookies) {
153
+ return cookies;
154
+ }
155
+ cookies = new AstroCookies(request);
156
+ result.cookies = cookies;
157
+ return cookies;
158
+ },
148
159
  params,
149
160
  props,
150
161
  request,
@@ -229,6 +240,7 @@ const canonicalURL = new URL(Astro.url.pathname, Astro.site);
229
240
  renderers,
230
241
  pathname,
231
242
  hasHydrationScript: false,
243
+ hasRenderedHead: false,
232
244
  hasDirectives: /* @__PURE__ */ new Set()
233
245
  },
234
246
  response
@@ -62,14 +62,11 @@ class RouteCache {
62
62
  }
63
63
  function findPathItemByKey(staticPaths, params) {
64
64
  const paramsKey = stringifyParams(params);
65
- let matchedStaticPath = staticPaths.keyed.get(paramsKey);
65
+ const matchedStaticPath = staticPaths.keyed.get(paramsKey);
66
66
  if (matchedStaticPath) {
67
67
  return matchedStaticPath;
68
68
  }
69
69
  debug("findPathItemByKey", `Unexpected cache miss looking for ${paramsKey}`);
70
- matchedStaticPath = staticPaths.find(
71
- ({ params: _params }) => JSON.stringify(_params) === paramsKey
72
- );
73
70
  }
74
71
  export {
75
72
  RouteCache,
@@ -17,7 +17,7 @@ function stringifyParams(params) {
17
17
  const validatedParams = Object.entries(params).reduce((acc, next) => {
18
18
  validateGetStaticPathsParameter(next);
19
19
  const [key, value] = next;
20
- acc[key] = `${value}`;
20
+ acc[key] = typeof value === "undefined" ? void 0 : `${value}`;
21
21
  return acc;
22
22
  }, {});
23
23
  return JSON.stringify(validatedParams, Object.keys(params).sort());
package/dist/core/util.js CHANGED
@@ -5,7 +5,7 @@ import resolve from "resolve";
5
5
  import slash from "slash";
6
6
  import { fileURLToPath, pathToFileURL } from "url";
7
7
  import { prependForwardSlash, removeTrailingForwardSlash } from "./path.js";
8
- const ASTRO_VERSION = "1.3.0";
8
+ const ASTRO_VERSION = "1.4.0";
9
9
  function isObject(value) {
10
10
  return typeof value === "object" && value != null;
11
11
  }
@@ -87,7 +87,7 @@ function resolveDependency(dep, projectRoot) {
87
87
  return pathToFileURL(resolved).toString();
88
88
  }
89
89
  function viteID(filePath) {
90
- return slash(fileURLToPath(filePath) + filePath.search);
90
+ return slash(fileURLToPath(filePath) + filePath.search).replace(/\\/g, "/");
91
91
  }
92
92
  const VALID_ID_PREFIX = `/@id/`;
93
93
  function unwrapId(id) {
@@ -1,4 +1,4 @@
1
- const ASTRO_VERSION = "1.3.0";
1
+ const ASTRO_VERSION = "1.4.0";
2
2
  function createDeprecatedFetchContentFn() {
3
3
  return () => {
4
4
  throw new Error("Deprecated: Astro.fetchContent() has been replaced with Astro.glob().");
@@ -1,3 +1,3 @@
1
- import type { EndpointHandler, Params } from '../../@types/astro';
1
+ import type { APIContext, EndpointHandler } from '../../@types/astro';
2
2
  /** Renders an endpoint request to completion, returning the body. */
3
- export declare function renderEndpoint(mod: EndpointHandler, request: Request, params: Params): Promise<Response | import("../../@types/astro").EndpointOutput>;
3
+ export declare function renderEndpoint(mod: EndpointHandler, context: APIContext, ssr: boolean): Promise<Response | import("../../@types/astro").EndpointOutput>;
@@ -10,10 +10,15 @@ function getHandlerFromModule(mod, method) {
10
10
  }
11
11
  return void 0;
12
12
  }
13
- async function renderEndpoint(mod, request, params) {
13
+ async function renderEndpoint(mod, context, ssr) {
14
14
  var _a;
15
+ const { request, params } = context;
15
16
  const chosenMethod = (_a = request.method) == null ? void 0 : _a.toLowerCase();
16
17
  const handler = getHandlerFromModule(mod, chosenMethod);
18
+ if (!ssr && ssr === false && chosenMethod && chosenMethod !== "get") {
19
+ console.warn(`
20
+ ${chosenMethod} requests are not available when building a static site. Update your config to output: 'server' to handle ${chosenMethod} requests.`);
21
+ }
17
22
  if (!handler || typeof handler !== "function") {
18
23
  let response = new Response(null, {
19
24
  status: 404,
@@ -33,10 +38,6 @@ export function get({ params, request }) {
33
38
 
34
39
  Update your code to remove this warning.`);
35
40
  }
36
- const context = {
37
- request,
38
- params
39
- };
40
41
  const proxy = new Proxy(context, {
41
42
  get(target, prop) {
42
43
  if (prop in target) {
@@ -1,7 +1,6 @@
1
1
  import { escape } from 'html-escaper';
2
2
  export declare const escapeHTML: typeof escape;
3
3
  export declare class HTMLBytes extends Uint8Array {
4
- get [Symbol.toStringTag](): string;
5
4
  }
6
5
  /**
7
6
  * A "blessed" extension of String that tells Astro that the string
@@ -1,10 +1,12 @@
1
1
  import { escape } from "html-escaper";
2
2
  const escapeHTML = escape;
3
3
  class HTMLBytes extends Uint8Array {
4
- get [Symbol.toStringTag]() {
4
+ }
5
+ Object.defineProperty(HTMLBytes.prototype, Symbol.toStringTag, {
6
+ get() {
5
7
  return "HTMLBytes";
6
8
  }
7
- }
9
+ });
8
10
  class HTMLString extends String {
9
11
  get [Symbol.toStringTag]() {
10
12
  return "HTMLString";
@@ -59,7 +59,9 @@ function extractDirectives(inputProps) {
59
59
  }
60
60
  }
61
61
  } else if (key === "class:list") {
62
- extracted.props[key.slice(0, -5)] = serializeListValue(value);
62
+ if (value) {
63
+ extracted.props[key.slice(0, -5)] = serializeListValue(value);
64
+ }
63
65
  } else {
64
66
  extracted.props[key] = value;
65
67
  }
@@ -1,2 +1 @@
1
1
  export declare function renderChild(child: any): AsyncIterable<any>;
2
- export declare function renderSlot(result: any, slotted: string, fallback?: any): Promise<string>;
@@ -1,9 +1,14 @@
1
1
  import { escapeHTML, HTMLString, markHTMLString } from "../escape.js";
2
2
  import { AstroComponent, renderAstroComponent } from "./astro.js";
3
- import { stringifyChunk } from "./common.js";
3
+ import { SlotString } from "./slot.js";
4
4
  async function* renderChild(child) {
5
5
  child = await child;
6
- if (child instanceof HTMLString) {
6
+ if (child instanceof SlotString) {
7
+ if (child.instructions) {
8
+ yield* child.instructions;
9
+ }
10
+ yield child;
11
+ } else if (child instanceof HTMLString) {
7
12
  yield child;
8
13
  } else if (Array.isArray(child)) {
9
14
  for (const value of child) {
@@ -24,22 +29,6 @@ async function* renderChild(child) {
24
29
  yield child;
25
30
  }
26
31
  }
27
- async function renderSlot(result, slotted, fallback) {
28
- if (slotted) {
29
- let iterator = renderChild(slotted);
30
- let content = "";
31
- for await (const chunk of iterator) {
32
- if (chunk.type === "directive") {
33
- content += stringifyChunk(result, chunk);
34
- } else {
35
- content += chunk;
36
- }
37
- }
38
- return markHTMLString(content);
39
- }
40
- return fallback;
41
- }
42
32
  export {
43
- renderChild,
44
- renderSlot
33
+ renderChild
45
34
  };
@@ -2,15 +2,15 @@ import { markHTMLString } from "../escape.js";
2
2
  import { extractDirectives, generateHydrateScript } from "../hydration.js";
3
3
  import { serializeProps } from "../serialize.js";
4
4
  import { shorthash } from "../shorthash.js";
5
- import { renderSlot } from "./any.js";
6
5
  import {
7
6
  isAstroComponentFactory,
8
7
  renderAstroComponent,
9
8
  renderTemplate,
10
9
  renderToIterable
11
10
  } from "./astro.js";
12
- import { Fragment, Renderer } from "./common.js";
11
+ import { Fragment, Renderer, stringifyChunk } from "./common.js";
13
12
  import { componentIsHTMLElement, renderHTMLElement } from "./dom.js";
13
+ import { renderSlot, renderSlots } from "./slot.js";
14
14
  import { formatList, internalSpreadAttributes, renderElement, voidElementNames } from "./util.js";
15
15
  const rendererAliases = /* @__PURE__ */ new Map([["solid", "solid-js"]]);
16
16
  function guessRenderers(componentUrl) {
@@ -22,7 +22,7 @@ function guessRenderers(componentUrl) {
22
22
  return ["@astrojs/vue"];
23
23
  case "jsx":
24
24
  case "tsx":
25
- return ["@astrojs/react", "@astrojs/preact"];
25
+ return ["@astrojs/react", "@astrojs/preact", "@astrojs/vue (jsx)"];
26
26
  default:
27
27
  return ["@astrojs/react", "@astrojs/preact", "@astrojs/vue", "@astrojs/svelte"];
28
28
  }
@@ -51,18 +51,10 @@ async function renderComponent(result, displayName, Component, _props, slots = {
51
51
  return markHTMLString(children2);
52
52
  }
53
53
  case "html": {
54
- const children2 = {};
55
- if (slots) {
56
- await Promise.all(
57
- Object.entries(slots).map(
58
- ([key, value]) => renderSlot(result, value).then((output) => {
59
- children2[key] = output;
60
- })
61
- )
62
- );
63
- }
54
+ const { slotInstructions: slotInstructions2, children: children2 } = await renderSlots(result, slots);
64
55
  const html2 = Component.render({ slots: children2 });
65
- return markHTMLString(html2);
56
+ const hydrationHtml = slotInstructions2 ? slotInstructions2.map((instr) => stringifyChunk(result, instr)).join("") : "";
57
+ return markHTMLString(hydrationHtml + html2);
66
58
  }
67
59
  case "astro-factory": {
68
60
  async function* renderAstroComponentInline() {
@@ -97,16 +89,7 @@ There are no \`integrations\` set in your \`astro.config.mjs\` file.
97
89
  Did you mean to add ${formatList(probableRendererNames.map((r) => "`" + r + "`"))}?`;
98
90
  throw new Error(message);
99
91
  }
100
- const children = {};
101
- if (slots) {
102
- await Promise.all(
103
- Object.entries(slots).map(
104
- ([key, value]) => renderSlot(result, value).then((output) => {
105
- children[key] = output;
106
- })
107
- )
108
- );
109
- }
92
+ const { children, slotInstructions } = await renderSlots(result, slots);
110
93
  let renderer;
111
94
  if (metadata.hydrate !== "only") {
112
95
  if (Component && Component[Renderer]) {
@@ -259,6 +242,9 @@ ${serializeProps(
259
242
  island.props["await-children"] = "";
260
243
  }
261
244
  async function* renderAll() {
245
+ if (slotInstructions) {
246
+ yield* slotInstructions;
247
+ }
262
248
  yield { type: "directive", hydration, result };
263
249
  yield markHTMLString(renderElement("astro-island", island, false));
264
250
  }
@@ -1,5 +1,5 @@
1
1
  import { markHTMLString } from "../escape.js";
2
- import { renderSlot } from "./any.js";
2
+ import { renderSlot } from "./slot.js";
3
3
  import { toAttributeString } from "./util.js";
4
4
  function componentIsHTMLElement(Component) {
5
5
  return typeof HTMLElement !== "undefined" && HTMLElement.isPrototypeOf(Component);
@@ -5,9 +5,8 @@ const uniqueElements = (item, index, all) => {
5
5
  const children = item.children;
6
6
  return index === all.findIndex((i) => JSON.stringify(i.props) === props && i.children == children);
7
7
  };
8
- const alreadyHeadRenderedResults = /* @__PURE__ */ new WeakSet();
9
8
  function renderHead(result) {
10
- alreadyHeadRenderedResults.add(result);
9
+ result._metadata.hasRenderedHead = true;
11
10
  const styles = Array.from(result.styles).filter(uniqueElements).map((style) => renderElement("style", style));
12
11
  result.styles.clear();
13
12
  const scripts = Array.from(result.scripts).filter(uniqueElements).map((script, i) => {
@@ -17,7 +16,7 @@ function renderHead(result) {
17
16
  return markHTMLString(links.join("\n") + styles.join("\n") + scripts.join("\n"));
18
17
  }
19
18
  async function* maybeRenderHead(result) {
20
- if (alreadyHeadRenderedResults.has(result)) {
19
+ if (result._metadata.hasRenderedHead) {
21
20
  return;
22
21
  }
23
22
  yield renderHead(result);
@@ -1,11 +1,11 @@
1
1
  import { renderTemplate } from './astro.js';
2
- export { renderSlot } from './any.js';
3
2
  export { renderAstroComponent, renderTemplate, renderToString } from './astro.js';
4
3
  export { Fragment, Renderer, stringifyChunk } from './common.js';
5
4
  export { renderComponent } from './component.js';
6
5
  export { renderHTMLElement } from './dom.js';
7
6
  export { maybeRenderHead, renderHead } from './head.js';
8
7
  export { renderPage } from './page.js';
8
+ export { renderSlot } from './slot.js';
9
9
  export type { RenderInstruction } from './types';
10
10
  export { addAttribute, defineScriptVars, voidElementNames } from './util.js';
11
11
  export interface AstroComponentFactory {
@@ -1,10 +1,10 @@
1
- import { renderSlot } from "./any.js";
2
1
  import { renderAstroComponent, renderTemplate as renderTemplate2, renderToString } from "./astro.js";
3
2
  import { Fragment, Renderer, stringifyChunk } from "./common.js";
4
3
  import { renderComponent } from "./component.js";
5
4
  import { renderHTMLElement } from "./dom.js";
6
5
  import { maybeRenderHead, renderHead } from "./head.js";
7
6
  import { renderPage } from "./page.js";
7
+ import { renderSlot } from "./slot.js";
8
8
  import { addAttribute, defineScriptVars, voidElementNames } from "./util.js";
9
9
  export {
10
10
  Fragment,
@@ -88,9 +88,11 @@ async function renderPage(result, componentFactory, props, children, streaming)
88
88
  }
89
89
  let response = createResponse(body, { ...init, headers });
90
90
  return response;
91
- } else {
92
- return factoryReturnValue;
93
91
  }
92
+ if (!(factoryReturnValue instanceof Response)) {
93
+ throw new Error("Only instance of Response can be returned from an Astro file");
94
+ }
95
+ return factoryReturnValue;
94
96
  }
95
97
  export {
96
98
  renderPage
@@ -0,0 +1,14 @@
1
+ import type { SSRResult } from '../../../@types/astro.js';
2
+ import type { RenderInstruction } from './types.js';
3
+ import { HTMLString } from '../escape.js';
4
+ export declare class SlotString extends HTMLString {
5
+ instructions: null | RenderInstruction[];
6
+ constructor(content: string, instructions: null | RenderInstruction[]);
7
+ }
8
+ export declare function renderSlot(_result: any, slotted: string, fallback?: any): Promise<string>;
9
+ interface RenderSlotsResult {
10
+ slotInstructions: null | RenderInstruction[];
11
+ children: Record<string, string>;
12
+ }
13
+ export declare function renderSlots(result: SSRResult, slots?: any): Promise<RenderSlotsResult>;
14
+ export {};
@@ -0,0 +1,52 @@
1
+ import { HTMLString, markHTMLString } from "../escape.js";
2
+ import { renderChild } from "./any.js";
3
+ class SlotString extends HTMLString {
4
+ constructor(content, instructions) {
5
+ super(content);
6
+ this.instructions = instructions;
7
+ }
8
+ }
9
+ async function renderSlot(_result, slotted, fallback) {
10
+ if (slotted) {
11
+ let iterator = renderChild(slotted);
12
+ let content = "";
13
+ let instructions = null;
14
+ for await (const chunk of iterator) {
15
+ if (chunk.type === "directive") {
16
+ if (instructions === null) {
17
+ instructions = [];
18
+ }
19
+ instructions.push(chunk);
20
+ } else {
21
+ content += chunk;
22
+ }
23
+ }
24
+ return markHTMLString(new SlotString(content, instructions));
25
+ }
26
+ return fallback;
27
+ }
28
+ async function renderSlots(result, slots = {}) {
29
+ let slotInstructions = null;
30
+ let children = {};
31
+ if (slots) {
32
+ await Promise.all(
33
+ Object.entries(slots).map(
34
+ ([key, value]) => renderSlot(result, value).then((output) => {
35
+ if (output.instructions) {
36
+ if (slotInstructions === null) {
37
+ slotInstructions = [];
38
+ }
39
+ slotInstructions.push(...output.instructions);
40
+ }
41
+ children[key] = output;
42
+ })
43
+ )
44
+ );
45
+ }
46
+ return { slotInstructions, children };
47
+ }
48
+ export {
49
+ SlotString,
50
+ renderSlot,
51
+ renderSlots
52
+ };
@@ -5,7 +5,7 @@ const htmlBooleanAttributes = /^(allowfullscreen|async|autofocus|autoplay|contro
5
5
  const htmlEnumAttributes = /^(contenteditable|draggable|spellcheck|value)$/i;
6
6
  const svgEnumAttributes = /^(autoReverse|externalResourcesRequired|focusable|preserveAlpha)$/i;
7
7
  const STATIC_DIRECTIVES = /* @__PURE__ */ new Set(["set:html", "set:text"]);
8
- const toIdent = (k) => k.trim().replace(/(?:(?<!^)\b\w|\s+|[^\w]+)/g, (match, index) => {
8
+ const toIdent = (k) => k.trim().replace(/(?:(?!^)\b\w|\s+|[^\w]+)/g, (match, index) => {
9
9
  if (/[^\w]|\s/.test(match))
10
10
  return "";
11
11
  return index === 0 ? match : match.toUpperCase();
@@ -16,7 +16,7 @@ const toStyleString = (obj) => Object.entries(obj).map(([k, v]) => `${kebab(k)}:
16
16
  function defineScriptVars(vars) {
17
17
  let output = "";
18
18
  for (const [key, value] of Object.entries(vars)) {
19
- output += `let ${toIdent(key)} = ${JSON.stringify(value)};
19
+ output += `const ${toIdent(key)} = ${JSON.stringify(value)};
20
20
  `;
21
21
  }
22
22
  return markHTMLString(output);
@@ -3,9 +3,10 @@ import { invalidateCompilation, isCached } from "../core/compile/index.js";
3
3
  import { info } from "../core/logger/core.js";
4
4
  import * as msg from "../core/messages.js";
5
5
  import { isAstroScript } from "./query.js";
6
- const PKG_PREFIX = new URL("../../", import.meta.url);
6
+ const PKG_PREFIX = fileURLToPath(new URL("../../", import.meta.url));
7
+ const E2E_PREFIX = fileURLToPath(new URL("../../e2e", import.meta.url));
7
8
  const isPkgFile = (id) => {
8
- return (id == null ? void 0 : id.startsWith(fileURLToPath(PKG_PREFIX))) || (id == null ? void 0 : id.startsWith(PKG_PREFIX.pathname));
9
+ return id && id.startsWith(PKG_PREFIX) && !id.startsWith(E2E_PREFIX);
9
10
  };
10
11
  async function handleHotUpdate(ctx, { config, logging, compile }) {
11
12
  let isStyleOnlyChange = false;
@@ -1,5 +1,6 @@
1
1
  import mime from "mime";
2
2
  import { Readable } from "stream";
3
+ import { getSetCookiesFromResponse } from "../core/cookies/index.js";
3
4
  import { call as callEndpoint } from "../core/endpoint/dev/index.js";
4
5
  import {
5
6
  collectErrorMetadata,
@@ -34,6 +35,10 @@ async function writeWebResponse(res, webResponse) {
34
35
  } else {
35
36
  _headers = Object.fromEntries(headers.entries());
36
37
  }
38
+ const setCookieHeaders = Array.from(getSetCookiesFromResponse(webResponse));
39
+ if (setCookieHeaders.length) {
40
+ res.setHeader("Set-Cookie", setCookieHeaders);
41
+ }
37
42
  res.writeHead(status, _headers);
38
43
  if (body) {
39
44
  if (Symbol.for("astro.responseBody") in webResponse) {
@@ -1,6 +1,8 @@
1
1
  import { renderMarkdown } from "@astrojs/markdown-remark";
2
2
  import fs from "fs";
3
3
  import matter from "gray-matter";
4
+ import { fileURLToPath } from "node:url";
5
+ import { normalizePath } from "vite";
4
6
  import { collectErrorMetadata } from "../core/errors.js";
5
7
  import { warn } from "../core/logger/core.js";
6
8
  import { getFileInfo, safelyGetAstroData } from "../vite-plugin-utils/index.js";
@@ -12,6 +14,9 @@ function safeMatter(source, id) {
12
14
  throw collectErrorMetadata(e);
13
15
  }
14
16
  }
17
+ const astroJsxRuntimeModulePath = normalizePath(
18
+ fileURLToPath(new URL("../jsx-runtime/index.js", import.meta.url))
19
+ );
15
20
  function markdown({ settings, logging }) {
16
21
  return {
17
22
  enforce: "pre",
@@ -42,7 +47,7 @@ function markdown({ settings, logging }) {
42
47
  );
43
48
  }
44
49
  const code = escapeViteEnvReferences(`
45
- import { Fragment, jsx as h } from 'astro/jsx-runtime';
50
+ import { Fragment, jsx as h } from '${astroJsxRuntimeModulePath}';
46
51
  ${layout ? `import Layout from ${JSON.stringify(layout)};` : ""}
47
52
 
48
53
  const html = ${JSON.stringify(html)};
@@ -1,4 +1,4 @@
1
- import { appendForwardSlash } from "../core/path.js";
1
+ import { appendExtension, appendForwardSlash } from "../core/path.js";
2
2
  function getFileInfo(id, config) {
3
3
  const sitePathname = appendForwardSlash(
4
4
  config.site ? new URL(config.base, config.site).pathname : config.base
@@ -8,6 +8,9 @@ function getFileInfo(id, config) {
8
8
  if (fileUrl && config.trailingSlash === "always") {
9
9
  fileUrl = appendForwardSlash(fileUrl);
10
10
  }
11
+ if (fileUrl && config.build.format === "file") {
12
+ fileUrl = appendExtension(fileUrl, "html");
13
+ }
11
14
  return { fileId, fileUrl };
12
15
  }
13
16
  function isValidAstroData(obj) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "astro",
3
- "version": "1.3.0",
3
+ "version": "1.4.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",
@@ -82,11 +82,11 @@
82
82
  "vendor"
83
83
  ],
84
84
  "dependencies": {
85
- "@astrojs/compiler": "^0.24.0",
85
+ "@astrojs/compiler": "^0.25.0",
86
86
  "@astrojs/language-server": "^0.26.2",
87
- "@astrojs/markdown-remark": "^1.1.2",
88
- "@astrojs/telemetry": "^1.0.0",
89
- "@astrojs/webapi": "^1.0.0",
87
+ "@astrojs/markdown-remark": "^1.1.3",
88
+ "@astrojs/telemetry": "^1.0.1",
89
+ "@astrojs/webapi": "^1.1.0",
90
90
  "@babel/core": "^7.18.2",
91
91
  "@babel/generator": "^7.18.2",
92
92
  "@babel/parser": "^7.18.4",
@@ -101,6 +101,7 @@
101
101
  "boxen": "^6.2.1",
102
102
  "ci-info": "^3.3.1",
103
103
  "common-ancestor-path": "^1.0.1",
104
+ "cookie": "^0.5.0",
104
105
  "debug": "^4.3.4",
105
106
  "diff": "^5.1.0",
106
107
  "eol": "^0.9.1",
@@ -148,25 +149,34 @@
148
149
  "@types/chai": "^4.3.1",
149
150
  "@types/common-ancestor-path": "^1.0.0",
150
151
  "@types/connect": "^3.4.35",
152
+ "@types/cookie": "^0.5.1",
151
153
  "@types/debug": "^4.1.7",
152
154
  "@types/diff": "^5.0.2",
153
155
  "@types/estree": "^0.0.51",
156
+ "@types/hast": "^2.3.4",
154
157
  "@types/mime": "^2.0.3",
155
158
  "@types/mocha": "^9.1.1",
156
159
  "@types/parse5": "^6.0.3",
157
160
  "@types/path-browserify": "^1.0.0",
158
161
  "@types/prettier": "^2.6.3",
162
+ "@types/prompts": "^2.0.14",
159
163
  "@types/resolve": "^1.20.2",
160
164
  "@types/rimraf": "^3.0.2",
161
165
  "@types/send": "^0.17.1",
162
166
  "@types/unist": "^2.0.6",
163
167
  "ast-types": "^0.14.2",
164
- "astro-scripts": "0.0.7",
168
+ "astro-scripts": "0.0.8",
165
169
  "chai": "^4.3.6",
166
170
  "cheerio": "^1.0.0-rc.11",
167
171
  "mocha": "^9.2.2",
172
+ "node-fetch": "^3.2.5",
173
+ "rehype-autolink-headings": "^6.1.1",
174
+ "rehype-slug": "^5.0.1",
175
+ "rehype-toc": "^3.0.2",
176
+ "remark-code-titles": "^0.1.2",
168
177
  "sass": "^1.52.2",
169
- "srcset-parse": "^1.1.0"
178
+ "srcset-parse": "^1.1.0",
179
+ "unified": "^10.1.2"
170
180
  },
171
181
  "engines": {
172
182
  "node": "^14.18.0 || >=16.12.0",