@sveltejs/adapter-netlify 1.0.0-next.7 → 1.0.0-next.70

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.
package/files/edge.js ADDED
@@ -0,0 +1,53 @@
1
+ import { Server } from '0SERVER';
2
+ import { manifest, prerendered } from 'MANIFEST';
3
+
4
+ const server = new Server(manifest);
5
+ const prefix = `/${manifest.appDir}/`;
6
+
7
+ /**
8
+ * @param { Request } request
9
+ * @param { any } context
10
+ * @returns { Promise<Response> }
11
+ */
12
+ export default function handler(request, context) {
13
+ if (is_static_file(request)) {
14
+ // Static files can skip the handler
15
+ // TODO can we serve _app/immutable files with an immutable cache header?
16
+ return;
17
+ }
18
+
19
+ return server.respond(request, {
20
+ platform: { context },
21
+ getClientAddress() {
22
+ return context.ip;
23
+ }
24
+ });
25
+ }
26
+
27
+ /**
28
+ * @param {Request} request
29
+ */
30
+ function is_static_file(request) {
31
+ const url = new URL(request.url);
32
+
33
+ // Assets in the app dir
34
+ if (url.pathname.startsWith(prefix)) {
35
+ return true;
36
+ }
37
+
38
+ // prerendered pages and index.html files
39
+ const pathname = url.pathname.replace(/\/$/, '');
40
+ let file = pathname.substring(1);
41
+
42
+ try {
43
+ file = decodeURIComponent(file);
44
+ } catch (err) {
45
+ // ignore
46
+ }
47
+
48
+ return (
49
+ manifest.assets.has(file) ||
50
+ manifest.assets.has(file + '/index.html') ||
51
+ prerendered.has(pathname || '/')
52
+ );
53
+ }
@@ -0,0 +1,330 @@
1
+ import './shims.js';
2
+ import { Server } from '0SERVER';
3
+ import 'assert';
4
+ import 'net';
5
+ import 'http';
6
+ import 'stream';
7
+ import 'buffer';
8
+ import 'util';
9
+ import 'stream/web';
10
+ import 'perf_hooks';
11
+ import 'util/types';
12
+ import 'events';
13
+ import 'tls';
14
+ import 'async_hooks';
15
+ import 'console';
16
+ import 'zlib';
17
+ import 'crypto';
18
+
19
+ var setCookie = {exports: {}};
20
+
21
+ var defaultParseOptions = {
22
+ decodeValues: true,
23
+ map: false,
24
+ silent: false,
25
+ };
26
+
27
+ function isNonEmptyString(str) {
28
+ return typeof str === "string" && !!str.trim();
29
+ }
30
+
31
+ function parseString(setCookieValue, options) {
32
+ var parts = setCookieValue.split(";").filter(isNonEmptyString);
33
+ var nameValue = parts.shift().split("=");
34
+ var name = nameValue.shift();
35
+ var value = nameValue.join("="); // everything after the first =, joined by a "=" if there was more than one part
36
+
37
+ options = options
38
+ ? Object.assign({}, defaultParseOptions, options)
39
+ : defaultParseOptions;
40
+
41
+ try {
42
+ value = options.decodeValues ? decodeURIComponent(value) : value; // decode cookie value
43
+ } catch (e) {
44
+ console.error(
45
+ "set-cookie-parser encountered an error while decoding a cookie with value '" +
46
+ value +
47
+ "'. Set options.decodeValues to false to disable this feature.",
48
+ e
49
+ );
50
+ }
51
+
52
+ var cookie = {
53
+ name: name, // grab everything before the first =
54
+ value: value,
55
+ };
56
+
57
+ parts.forEach(function (part) {
58
+ var sides = part.split("=");
59
+ var key = sides.shift().trimLeft().toLowerCase();
60
+ var value = sides.join("=");
61
+ if (key === "expires") {
62
+ cookie.expires = new Date(value);
63
+ } else if (key === "max-age") {
64
+ cookie.maxAge = parseInt(value, 10);
65
+ } else if (key === "secure") {
66
+ cookie.secure = true;
67
+ } else if (key === "httponly") {
68
+ cookie.httpOnly = true;
69
+ } else if (key === "samesite") {
70
+ cookie.sameSite = value;
71
+ } else {
72
+ cookie[key] = value;
73
+ }
74
+ });
75
+
76
+ return cookie;
77
+ }
78
+
79
+ function parse(input, options) {
80
+ options = options
81
+ ? Object.assign({}, defaultParseOptions, options)
82
+ : defaultParseOptions;
83
+
84
+ if (!input) {
85
+ if (!options.map) {
86
+ return [];
87
+ } else {
88
+ return {};
89
+ }
90
+ }
91
+
92
+ if (input.headers && input.headers["set-cookie"]) {
93
+ // fast-path for node.js (which automatically normalizes header names to lower-case
94
+ input = input.headers["set-cookie"];
95
+ } else if (input.headers) {
96
+ // slow-path for other environments - see #25
97
+ var sch =
98
+ input.headers[
99
+ Object.keys(input.headers).find(function (key) {
100
+ return key.toLowerCase() === "set-cookie";
101
+ })
102
+ ];
103
+ // warn if called on a request-like object with a cookie header rather than a set-cookie header - see #34, 36
104
+ if (!sch && input.headers.cookie && !options.silent) {
105
+ console.warn(
106
+ "Warning: set-cookie-parser appears to have been called on a request object. It is designed to parse Set-Cookie headers from responses, not Cookie headers from requests. Set the option {silent: true} to suppress this warning."
107
+ );
108
+ }
109
+ input = sch;
110
+ }
111
+ if (!Array.isArray(input)) {
112
+ input = [input];
113
+ }
114
+
115
+ options = options
116
+ ? Object.assign({}, defaultParseOptions, options)
117
+ : defaultParseOptions;
118
+
119
+ if (!options.map) {
120
+ return input.filter(isNonEmptyString).map(function (str) {
121
+ return parseString(str, options);
122
+ });
123
+ } else {
124
+ var cookies = {};
125
+ return input.filter(isNonEmptyString).reduce(function (cookies, str) {
126
+ var cookie = parseString(str, options);
127
+ cookies[cookie.name] = cookie;
128
+ return cookies;
129
+ }, cookies);
130
+ }
131
+ }
132
+
133
+ /*
134
+ Set-Cookie header field-values are sometimes comma joined in one string. This splits them without choking on commas
135
+ that are within a single set-cookie field-value, such as in the Expires portion.
136
+
137
+ This is uncommon, but explicitly allowed - see https://tools.ietf.org/html/rfc2616#section-4.2
138
+ Node.js does this for every header *except* set-cookie - see https://github.com/nodejs/node/blob/d5e363b77ebaf1caf67cd7528224b651c86815c1/lib/_http_incoming.js#L128
139
+ React Native's fetch does this for *every* header, including set-cookie.
140
+
141
+ Based on: https://github.com/google/j2objc/commit/16820fdbc8f76ca0c33472810ce0cb03d20efe25
142
+ Credits to: https://github.com/tomball for original and https://github.com/chrusart for JavaScript implementation
143
+ */
144
+ function splitCookiesString(cookiesString) {
145
+ if (Array.isArray(cookiesString)) {
146
+ return cookiesString;
147
+ }
148
+ if (typeof cookiesString !== "string") {
149
+ return [];
150
+ }
151
+
152
+ var cookiesStrings = [];
153
+ var pos = 0;
154
+ var start;
155
+ var ch;
156
+ var lastComma;
157
+ var nextStart;
158
+ var cookiesSeparatorFound;
159
+
160
+ function skipWhitespace() {
161
+ while (pos < cookiesString.length && /\s/.test(cookiesString.charAt(pos))) {
162
+ pos += 1;
163
+ }
164
+ return pos < cookiesString.length;
165
+ }
166
+
167
+ function notSpecialChar() {
168
+ ch = cookiesString.charAt(pos);
169
+
170
+ return ch !== "=" && ch !== ";" && ch !== ",";
171
+ }
172
+
173
+ while (pos < cookiesString.length) {
174
+ start = pos;
175
+ cookiesSeparatorFound = false;
176
+
177
+ while (skipWhitespace()) {
178
+ ch = cookiesString.charAt(pos);
179
+ if (ch === ",") {
180
+ // ',' is a cookie separator if we have later first '=', not ';' or ','
181
+ lastComma = pos;
182
+ pos += 1;
183
+
184
+ skipWhitespace();
185
+ nextStart = pos;
186
+
187
+ while (pos < cookiesString.length && notSpecialChar()) {
188
+ pos += 1;
189
+ }
190
+
191
+ // currently special character
192
+ if (pos < cookiesString.length && cookiesString.charAt(pos) === "=") {
193
+ // we found cookies separator
194
+ cookiesSeparatorFound = true;
195
+ // pos is inside the next cookie, so back up and return it.
196
+ pos = nextStart;
197
+ cookiesStrings.push(cookiesString.substring(start, lastComma));
198
+ start = pos;
199
+ } else {
200
+ // in param ',' or param separator ';',
201
+ // we continue from that comma
202
+ pos = lastComma + 1;
203
+ }
204
+ } else {
205
+ pos += 1;
206
+ }
207
+ }
208
+
209
+ if (!cookiesSeparatorFound || pos >= cookiesString.length) {
210
+ cookiesStrings.push(cookiesString.substring(start, cookiesString.length));
211
+ }
212
+ }
213
+
214
+ return cookiesStrings;
215
+ }
216
+
217
+ setCookie.exports = parse;
218
+ setCookie.exports.parse = parse;
219
+ setCookie.exports.parseString = parseString;
220
+ var splitCookiesString_1 = setCookie.exports.splitCookiesString = splitCookiesString;
221
+
222
+ /**
223
+ * Splits headers into two categories: single value and multi value
224
+ * @param {Headers} headers
225
+ * @returns {{
226
+ * headers: Record<string, string>,
227
+ * multiValueHeaders: Record<string, string[]>
228
+ * }}
229
+ */
230
+ function split_headers(headers) {
231
+ /** @type {Record<string, string>} */
232
+ const h = {};
233
+
234
+ /** @type {Record<string, string[]>} */
235
+ const m = {};
236
+
237
+ headers.forEach((value, key) => {
238
+ if (key === 'set-cookie') {
239
+ m[key] = splitCookiesString_1(value);
240
+ } else {
241
+ h[key] = value;
242
+ }
243
+ });
244
+
245
+ return {
246
+ headers: h,
247
+ multiValueHeaders: m
248
+ };
249
+ }
250
+
251
+ /**
252
+ * @param {import('@sveltejs/kit').SSRManifest} manifest
253
+ * @returns {import('@netlify/functions').Handler}
254
+ */
255
+ function init(manifest) {
256
+ const server = new Server(manifest);
257
+
258
+ return async (event, context) => {
259
+ const response = await server.respond(to_request(event), {
260
+ platform: { context },
261
+ getClientAddress() {
262
+ return event.headers['x-nf-client-connection-ip'];
263
+ }
264
+ });
265
+
266
+ const partial_response = {
267
+ statusCode: response.status,
268
+ ...split_headers(response.headers)
269
+ };
270
+
271
+ if (!is_text(response.headers.get('content-type'))) {
272
+ // Function responses should be strings (or undefined), and responses with binary
273
+ // content should be base64 encoded and set isBase64Encoded to true.
274
+ // https://github.com/netlify/functions/blob/main/src/function/response.ts
275
+ return {
276
+ ...partial_response,
277
+ isBase64Encoded: true,
278
+ body: Buffer.from(await response.arrayBuffer()).toString('base64')
279
+ };
280
+ }
281
+
282
+ return {
283
+ ...partial_response,
284
+ body: await response.text()
285
+ };
286
+ };
287
+ }
288
+
289
+ /**
290
+ * @param {import('@netlify/functions').HandlerEvent} event
291
+ * @returns {Request}
292
+ */
293
+ function to_request(event) {
294
+ const { httpMethod, headers, rawUrl, body, isBase64Encoded } = event;
295
+
296
+ /** @type {RequestInit} */
297
+ const init = {
298
+ method: httpMethod,
299
+ headers: new Headers(headers)
300
+ };
301
+
302
+ if (httpMethod !== 'GET' && httpMethod !== 'HEAD') {
303
+ const encoding = isBase64Encoded ? 'base64' : 'utf-8';
304
+ init.body = typeof body === 'string' ? Buffer.from(body, encoding) : body;
305
+ }
306
+
307
+ return new Request(rawUrl, init);
308
+ }
309
+
310
+ const text_types = new Set([
311
+ 'application/xml',
312
+ 'application/json',
313
+ 'application/x-www-form-urlencoded',
314
+ 'multipart/form-data'
315
+ ]);
316
+
317
+ /**
318
+ * Decides how the body should be parsed based on its mime type
319
+ *
320
+ * @param {string | undefined | null} content_type The `content-type` header of a request/response.
321
+ * @returns {boolean}
322
+ */
323
+ function is_text(content_type) {
324
+ if (!content_type) return true; // defaults to json
325
+ const type = content_type.split(';')[0].toLowerCase(); // get the mime type
326
+
327
+ return type.startsWith('text/') || type.endsWith('+xml') || text_types.has(type);
328
+ }
329
+
330
+ export { init };