astro 1.3.1 → 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.
@@ -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;
@@ -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();
@@ -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.1";
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, opts.ssr);
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.1";
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 `;
@@ -250,7 +250,7 @@ function printHelp({
250
250
  message.push(
251
251
  linebreak(),
252
252
  ` ${bgGreen(black(` ${commandName} `))} ${green(
253
- `v${"1.3.1"}`
253
+ `v${"1.4.0"}`
254
254
  )} ${headline}`
255
255
  );
256
256
  }
@@ -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
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.1";
8
+ const ASTRO_VERSION = "1.4.0";
9
9
  function isObject(value) {
10
10
  return typeof value === "object" && value != null;
11
11
  }
@@ -1,4 +1,4 @@
1
- const ASTRO_VERSION = "1.3.1";
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, ssr?: boolean): Promise<Response | import("../../@types/astro").EndpointOutput>;
3
+ export declare function renderEndpoint(mod: EndpointHandler, context: APIContext, ssr: boolean): Promise<Response | import("../../@types/astro").EndpointOutput>;
@@ -10,8 +10,9 @@ function getHandlerFromModule(mod, method) {
10
10
  }
11
11
  return void 0;
12
12
  }
13
- async function renderEndpoint(mod, request, params, ssr) {
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);
17
18
  if (!ssr && ssr === false && chosenMethod && chosenMethod !== "get") {
@@ -37,10 +38,6 @@ export function get({ params, request }) {
37
38
 
38
39
  Update your code to remove this warning.`);
39
40
  }
40
- const context = {
41
- request,
42
- params
43
- };
44
41
  const proxy = new Proxy(context, {
45
42
  get(target, prop) {
46
43
  if (prop in target) {
@@ -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,
@@ -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
+ };
@@ -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) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "astro",
3
- "version": "1.3.1",
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,10 +82,10 @@
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",
87
+ "@astrojs/markdown-remark": "^1.1.3",
88
+ "@astrojs/telemetry": "^1.0.1",
89
89
  "@astrojs/webapi": "^1.1.0",
90
90
  "@babel/core": "^7.18.2",
91
91
  "@babel/generator": "^7.18.2",
@@ -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,14 +149,17 @@
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",
@@ -165,8 +169,14 @@
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",