@sveltejs/kit 1.0.0-next.47 → 1.0.0-next.470

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 (115) hide show
  1. package/README.md +12 -9
  2. package/package.json +93 -64
  3. package/scripts/special-types/$env+dynamic+private.md +8 -0
  4. package/scripts/special-types/$env+dynamic+public.md +8 -0
  5. package/scripts/special-types/$env+static+private.md +19 -0
  6. package/scripts/special-types/$env+static+public.md +7 -0
  7. package/scripts/special-types/$lib.md +1 -0
  8. package/src/cli.js +112 -0
  9. package/src/constants.js +7 -0
  10. package/src/core/adapt/builder.js +207 -0
  11. package/src/core/adapt/index.js +31 -0
  12. package/src/core/config/default-error.html +56 -0
  13. package/src/core/config/index.js +105 -0
  14. package/src/core/config/options.js +502 -0
  15. package/src/core/config/types.d.ts +1 -0
  16. package/src/core/env.js +121 -0
  17. package/src/core/generate_manifest/index.js +92 -0
  18. package/src/core/prerender/crawl.js +194 -0
  19. package/src/core/prerender/prerender.js +425 -0
  20. package/src/core/prerender/queue.js +80 -0
  21. package/src/core/sync/create_manifest_data/index.js +472 -0
  22. package/src/core/sync/create_manifest_data/types.d.ts +37 -0
  23. package/src/core/sync/sync.js +59 -0
  24. package/src/core/sync/utils.js +33 -0
  25. package/src/core/sync/write_ambient.js +53 -0
  26. package/src/core/sync/write_client_manifest.js +94 -0
  27. package/src/core/sync/write_matchers.js +25 -0
  28. package/src/core/sync/write_root.js +91 -0
  29. package/src/core/sync/write_tsconfig.js +195 -0
  30. package/src/core/sync/write_types/index.js +595 -0
  31. package/src/core/utils.js +70 -0
  32. package/src/exports/hooks/index.js +1 -0
  33. package/src/exports/hooks/sequence.js +44 -0
  34. package/src/exports/index.js +45 -0
  35. package/src/exports/node/index.js +145 -0
  36. package/src/exports/node/polyfills.js +40 -0
  37. package/src/exports/vite/build/build_server.js +358 -0
  38. package/src/exports/vite/build/build_service_worker.js +90 -0
  39. package/src/exports/vite/build/utils.js +162 -0
  40. package/src/exports/vite/dev/index.js +547 -0
  41. package/src/exports/vite/index.js +601 -0
  42. package/src/exports/vite/preview/index.js +186 -0
  43. package/src/exports/vite/types.d.ts +3 -0
  44. package/src/exports/vite/utils.js +345 -0
  45. package/src/runtime/app/env.js +1 -0
  46. package/src/runtime/app/environment.js +11 -0
  47. package/src/runtime/app/navigation.js +23 -0
  48. package/src/runtime/app/paths.js +1 -0
  49. package/src/runtime/app/stores.js +102 -0
  50. package/src/runtime/client/ambient.d.ts +24 -0
  51. package/src/runtime/client/client.js +1494 -0
  52. package/src/runtime/client/fetcher.js +107 -0
  53. package/src/runtime/client/parse.js +60 -0
  54. package/src/runtime/client/singletons.js +21 -0
  55. package/src/runtime/client/start.js +45 -0
  56. package/src/runtime/client/types.d.ts +91 -0
  57. package/src/runtime/client/utils.js +159 -0
  58. package/src/runtime/components/error.svelte +16 -0
  59. package/{assets → src/runtime}/components/layout.svelte +0 -0
  60. package/src/runtime/control.js +33 -0
  61. package/src/runtime/env/dynamic/private.js +1 -0
  62. package/src/runtime/env/dynamic/public.js +1 -0
  63. package/src/runtime/env-private.js +6 -0
  64. package/src/runtime/env-public.js +6 -0
  65. package/src/runtime/env.js +6 -0
  66. package/src/runtime/hash.js +16 -0
  67. package/src/runtime/paths.js +11 -0
  68. package/src/runtime/server/data/index.js +146 -0
  69. package/src/runtime/server/endpoint.js +63 -0
  70. package/src/runtime/server/index.js +354 -0
  71. package/src/runtime/server/page/cookie.js +25 -0
  72. package/src/runtime/server/page/crypto.js +239 -0
  73. package/src/runtime/server/page/csp.js +249 -0
  74. package/src/runtime/server/page/fetch.js +282 -0
  75. package/src/runtime/server/page/index.js +404 -0
  76. package/src/runtime/server/page/load_data.js +124 -0
  77. package/src/runtime/server/page/render.js +358 -0
  78. package/src/runtime/server/page/respond_with_error.js +92 -0
  79. package/src/runtime/server/page/serialize_data.js +72 -0
  80. package/src/runtime/server/page/types.d.ts +45 -0
  81. package/src/runtime/server/utils.js +209 -0
  82. package/src/utils/array.js +9 -0
  83. package/src/utils/error.js +22 -0
  84. package/src/utils/escape.js +46 -0
  85. package/src/utils/filesystem.js +108 -0
  86. package/src/utils/functions.js +16 -0
  87. package/src/utils/http.js +55 -0
  88. package/src/utils/misc.js +1 -0
  89. package/src/utils/routing.js +117 -0
  90. package/src/utils/url.js +142 -0
  91. package/svelte-kit.js +1 -1
  92. package/types/ambient.d.ts +356 -0
  93. package/types/index.d.ts +356 -0
  94. package/types/internal.d.ts +386 -0
  95. package/types/private.d.ts +213 -0
  96. package/CHANGELOG.md +0 -463
  97. package/assets/components/error.svelte +0 -13
  98. package/assets/runtime/app/env.js +0 -5
  99. package/assets/runtime/app/navigation.js +0 -44
  100. package/assets/runtime/app/paths.js +0 -1
  101. package/assets/runtime/app/stores.js +0 -93
  102. package/assets/runtime/chunks/utils.js +0 -22
  103. package/assets/runtime/internal/singletons.js +0 -23
  104. package/assets/runtime/internal/start.js +0 -773
  105. package/assets/runtime/paths.js +0 -12
  106. package/dist/chunks/index.js +0 -3517
  107. package/dist/chunks/index2.js +0 -587
  108. package/dist/chunks/index3.js +0 -246
  109. package/dist/chunks/index4.js +0 -530
  110. package/dist/chunks/index5.js +0 -763
  111. package/dist/chunks/index6.js +0 -322
  112. package/dist/chunks/standard.js +0 -99
  113. package/dist/chunks/utils.js +0 -83
  114. package/dist/cli.js +0 -553
  115. package/dist/ssr.js +0 -2581
@@ -0,0 +1,45 @@
1
+ import { HttpError, Redirect } from '../runtime/control.js';
2
+
3
+ /**
4
+ * Creates an `HttpError` object with an HTTP status code and an optional message.
5
+ * This object, if thrown during request handling, will cause SvelteKit to
6
+ * return an error response without invoking `handleError`
7
+ * @param {number} status
8
+ * @param {string | undefined} [message]
9
+ */
10
+ export function error(status, message) {
11
+ return new HttpError(status, message);
12
+ }
13
+
14
+ /**
15
+ * Creates a `Redirect` object. If thrown during request handling, SvelteKit will
16
+ * return a redirect response.
17
+ * @param {number} status
18
+ * @param {string} location
19
+ */
20
+ export function redirect(status, location) {
21
+ if (isNaN(status) || status < 300 || status > 399) {
22
+ throw new Error('Invalid status code');
23
+ }
24
+
25
+ return new Redirect(status, location);
26
+ }
27
+
28
+ /**
29
+ * Generates a JSON `Response` object from the supplied data.
30
+ * @param {any} data
31
+ * @param {ResponseInit} [init]
32
+ */
33
+ export function json(data, init) {
34
+ // TODO deprecate this in favour of `Response.json` when it's
35
+ // more widely supported
36
+ const headers = new Headers(init?.headers);
37
+ if (!headers.has('content-type')) {
38
+ headers.set('content-type', 'application/json');
39
+ }
40
+
41
+ return new Response(JSON.stringify(data), {
42
+ ...init,
43
+ headers
44
+ });
45
+ }
@@ -0,0 +1,145 @@
1
+ import * as set_cookie_parser from 'set-cookie-parser';
2
+
3
+ /** @param {import('http').IncomingMessage} req */
4
+ function get_raw_body(req) {
5
+ const h = req.headers;
6
+
7
+ if (!h['content-type']) {
8
+ return null;
9
+ }
10
+
11
+ const length = Number(h['content-length']);
12
+
13
+ // check if no request body
14
+ // https://github.com/jshttp/type-is/blob/c1f4388c71c8a01f79934e68f630ca4a15fffcd6/index.js#L81-L95
15
+ if (isNaN(length) && h['transfer-encoding'] == null) {
16
+ return null;
17
+ }
18
+
19
+ if (req.destroyed) {
20
+ const readable = new ReadableStream();
21
+ readable.cancel();
22
+ return readable;
23
+ }
24
+
25
+ let size = 0;
26
+ let cancelled = false;
27
+
28
+ return new ReadableStream({
29
+ start(controller) {
30
+ req.on('error', (error) => {
31
+ controller.error(error);
32
+ });
33
+
34
+ req.on('end', () => {
35
+ if (cancelled) return;
36
+ controller.close();
37
+ });
38
+
39
+ req.on('data', (chunk) => {
40
+ if (cancelled) return;
41
+
42
+ size += chunk.length;
43
+ if (size > length) {
44
+ controller.error(new Error('content-length exceeded'));
45
+ return;
46
+ }
47
+
48
+ controller.enqueue(chunk);
49
+
50
+ if (controller.desiredSize === null || controller.desiredSize <= 0) {
51
+ req.pause();
52
+ }
53
+ });
54
+ },
55
+
56
+ pull() {
57
+ req.resume();
58
+ },
59
+
60
+ cancel(reason) {
61
+ cancelled = true;
62
+ req.destroy(reason);
63
+ }
64
+ });
65
+ }
66
+
67
+ /** @type {import('@sveltejs/kit/node').getRequest} */
68
+ export async function getRequest(base, req) {
69
+ let headers = /** @type {Record<string, string>} */ (req.headers);
70
+ if (req.httpVersionMajor === 2) {
71
+ // we need to strip out the HTTP/2 pseudo-headers because node-fetch's
72
+ // Request implementation doesn't like them
73
+ // TODO is this still true with Node 18
74
+ headers = Object.assign({}, headers);
75
+ delete headers[':method'];
76
+ delete headers[':path'];
77
+ delete headers[':authority'];
78
+ delete headers[':scheme'];
79
+ }
80
+
81
+ return new Request(base + req.url, {
82
+ method: req.method,
83
+ headers,
84
+ body: get_raw_body(req)
85
+ });
86
+ }
87
+
88
+ /** @type {import('@sveltejs/kit/node').setResponse} */
89
+ export async function setResponse(res, response) {
90
+ const headers = Object.fromEntries(response.headers);
91
+
92
+ if (response.headers.has('set-cookie')) {
93
+ const header = /** @type {string} */ (response.headers.get('set-cookie'));
94
+ const split = set_cookie_parser.splitCookiesString(header);
95
+
96
+ // @ts-expect-error
97
+ headers['set-cookie'] = split;
98
+ }
99
+
100
+ res.writeHead(response.status, headers);
101
+
102
+ if (!response.body) {
103
+ res.end();
104
+ return;
105
+ }
106
+
107
+ const reader = response.body.getReader();
108
+
109
+ if (res.destroyed) {
110
+ reader.cancel();
111
+ return;
112
+ }
113
+
114
+ const cancel = (/** @type {Error|undefined} */ error) => {
115
+ res.off('close', cancel);
116
+ res.off('error', cancel);
117
+
118
+ // If the reader has already been interrupted with an error earlier,
119
+ // then it will appear here, it is useless, but it needs to be catch.
120
+ reader.cancel(error).catch(() => {});
121
+ if (error) res.destroy(error);
122
+ };
123
+
124
+ res.on('close', cancel);
125
+ res.on('error', cancel);
126
+
127
+ next();
128
+ async function next() {
129
+ try {
130
+ for (;;) {
131
+ const { done, value } = await reader.read();
132
+
133
+ if (done) break;
134
+
135
+ if (!res.write(value)) {
136
+ res.once('drain', next);
137
+ return;
138
+ }
139
+ }
140
+ res.end();
141
+ } catch (error) {
142
+ cancel(error instanceof Error ? error : new Error(String(error)));
143
+ }
144
+ }
145
+ }
@@ -0,0 +1,40 @@
1
+ import { fetch, Response, Request, Headers } from 'undici';
2
+ import { ReadableStream, TransformStream, WritableStream } from 'stream/web';
3
+ import { Readable } from 'stream';
4
+ import { Request as NodeFetchRequest } from 'node-fetch';
5
+ import { webcrypto as crypto } from 'crypto';
6
+
7
+ /** @type {Record<string, any>} */
8
+ const globals = {
9
+ crypto,
10
+ fetch,
11
+ Response,
12
+ // TODO remove the superclass as soon as Undici supports formData
13
+ // https://github.com/nodejs/undici/issues/974
14
+ Request: class extends Request {
15
+ // @ts-expect-error
16
+ formData() {
17
+ return new NodeFetchRequest(this.url, {
18
+ method: this.method,
19
+ headers: this.headers,
20
+ body: this.body && Readable.from(this.body)
21
+ }).formData();
22
+ }
23
+ },
24
+ Headers,
25
+ ReadableStream,
26
+ TransformStream,
27
+ WritableStream
28
+ };
29
+
30
+ // exported for dev/preview and node environments
31
+ export function installPolyfills() {
32
+ for (const name in globals) {
33
+ Object.defineProperty(globalThis, name, {
34
+ enumerable: true,
35
+ configurable: true,
36
+ writable: true,
37
+ value: globals[name]
38
+ });
39
+ }
40
+ }
@@ -0,0 +1,358 @@
1
+ import fs from 'fs';
2
+ import path from 'path';
3
+ import { mkdirp, posixify } from '../../../utils/filesystem.js';
4
+ import { get_vite_config, merge_vite_configs, resolve_entry } from '../utils.js';
5
+ import { load_error_page, load_template } from '../../../core/config/index.js';
6
+ import { runtime_directory } from '../../../core/utils.js';
7
+ import { create_build, find_deps, get_default_build_config, is_http_method } from './utils.js';
8
+ import { s } from '../../../utils/misc.js';
9
+
10
+ /**
11
+ * @param {{
12
+ * hooks: string;
13
+ * config: import('types').ValidatedConfig;
14
+ * has_service_worker: boolean;
15
+ * runtime: string;
16
+ * template: string;
17
+ * error_page: string;
18
+ * }} opts
19
+ */
20
+ const server_template = ({ config, hooks, has_service_worker, runtime, template, error_page }) => `
21
+ import root from '__GENERATED__/root.svelte';
22
+ import { respond } from '${runtime}/server/index.js';
23
+ import { set_paths, assets, base } from '${runtime}/paths.js';
24
+ import { set_prerendering } from '${runtime}/env.js';
25
+ import { set_private_env } from '${runtime}/env-private.js';
26
+ import { set_public_env } from '${runtime}/env-public.js';
27
+
28
+ const app_template = ({ head, body, assets, nonce }) => ${s(template)
29
+ .replace('%sveltekit.head%', '" + head + "')
30
+ .replace('%sveltekit.body%', '" + body + "')
31
+ .replace(/%sveltekit\.assets%/g, '" + assets + "')
32
+ .replace(/%sveltekit\.nonce%/g, '" + nonce + "')};
33
+
34
+ const error_template = ({ status, message }) => ${s(error_page)
35
+ .replace(/%sveltekit\.status%/g, '" + status + "')
36
+ .replace(/%sveltekit\.message%/g, '" + message + "')};
37
+
38
+ let read = null;
39
+
40
+ set_paths(${s(config.kit.paths)});
41
+
42
+ let default_protocol = 'https';
43
+
44
+ // allow paths to be globally overridden
45
+ // in svelte-kit preview and in prerendering
46
+ export function override(settings) {
47
+ default_protocol = settings.protocol || default_protocol;
48
+ set_paths(settings.paths);
49
+ set_prerendering(settings.prerendering);
50
+ read = settings.read;
51
+ }
52
+
53
+ export class Server {
54
+ constructor(manifest) {
55
+ this.options = {
56
+ csp: ${s(config.kit.csp)},
57
+ csrf: {
58
+ check_origin: ${s(config.kit.csrf.checkOrigin)},
59
+ },
60
+ dev: false,
61
+ get_stack: error => String(error), // for security
62
+ handle_error: (error, event) => {
63
+ this.options.hooks.handleError({
64
+ error,
65
+ event,
66
+
67
+ // TODO remove for 1.0
68
+ // @ts-expect-error
69
+ get request() {
70
+ throw new Error('request in handleError has been replaced with event. See https://github.com/sveltejs/kit/pull/3384 for details');
71
+ }
72
+ });
73
+ error.stack = this.options.get_stack(error);
74
+ },
75
+ hooks: null,
76
+ manifest,
77
+ method_override: ${s(config.kit.methodOverride)},
78
+ paths: { base, assets },
79
+ public_env: {},
80
+ read,
81
+ root,
82
+ service_worker: ${has_service_worker ? "base + '/service-worker.js'" : 'null'},
83
+ app_template,
84
+ app_template_contains_nonce: ${template.includes('%sveltekit.nonce%')},
85
+ error_template,
86
+ trailing_slash: ${s(config.kit.trailingSlash)}
87
+ };
88
+ }
89
+
90
+ /**
91
+ * Take care: Some adapters may have to call \`Server.init\` per-request to set env vars,
92
+ * so anything that shouldn't be rerun should be wrapped in an \`if\` block to make sure it hasn't
93
+ * been done already.
94
+ */
95
+ async init({ env }) {
96
+ const entries = Object.entries(env);
97
+
98
+ const prv = Object.fromEntries(entries.filter(([k]) => !k.startsWith('${
99
+ config.kit.env.publicPrefix
100
+ }')));
101
+
102
+ const pub = Object.fromEntries(entries.filter(([k]) => k.startsWith('${
103
+ config.kit.env.publicPrefix
104
+ }')));
105
+
106
+ set_private_env(prv);
107
+ set_public_env(pub);
108
+
109
+ this.options.public_env = pub;
110
+
111
+ if (!this.options.hooks) {
112
+ const module = await import(${s(hooks)});
113
+
114
+ // TODO remove this for 1.0
115
+ if (module.externalFetch) {
116
+ throw new Error('externalFetch has been removed — use handleFetch instead. See https://github.com/sveltejs/kit/pull/6565 for details');
117
+ }
118
+
119
+ this.options.hooks = {
120
+ handle: module.handle || (({ event, resolve }) => resolve(event)),
121
+ handleError: module.handleError || (({ error }) => console.error(error.stack)),
122
+ handleFetch: module.handleFetch || (({ request, fetch }) => fetch(request))
123
+ };
124
+ }
125
+ }
126
+
127
+ async respond(request, options = {}) {
128
+ if (!(request instanceof Request)) {
129
+ throw new Error('The first argument to server.respond must be a Request object. See https://github.com/sveltejs/kit/pull/3384 for details');
130
+ }
131
+
132
+ return respond(request, this.options, options);
133
+ }
134
+ }
135
+ `;
136
+
137
+ /**
138
+ * @param {{
139
+ * cwd: string;
140
+ * config: import('types').ValidatedConfig;
141
+ * vite_config: import('vite').ResolvedConfig;
142
+ * vite_config_env: import('vite').ConfigEnv;
143
+ * manifest_data: import('types').ManifestData;
144
+ * build_dir: string;
145
+ * output_dir: string;
146
+ * service_worker_entry_file: string | null;
147
+ * }} options
148
+ * @param {{ vite_manifest: import('vite').Manifest, assets: import('rollup').OutputAsset[] }} client
149
+ */
150
+ export async function build_server(options, client) {
151
+ const {
152
+ cwd,
153
+ config,
154
+ vite_config,
155
+ vite_config_env,
156
+ manifest_data,
157
+ build_dir,
158
+ output_dir,
159
+ service_worker_entry_file
160
+ } = options;
161
+
162
+ let hooks_file = resolve_entry(config.kit.files.hooks);
163
+ if (!hooks_file || !fs.existsSync(hooks_file)) {
164
+ hooks_file = path.join(config.kit.outDir, 'build/hooks.js');
165
+ fs.writeFileSync(hooks_file, '');
166
+ }
167
+
168
+ /** @type {Record<string, string>} */
169
+ const input = {
170
+ index: `${build_dir}/index.js`
171
+ };
172
+
173
+ // add entry points for every endpoint...
174
+ manifest_data.routes.forEach((route) => {
175
+ if (route.endpoint) {
176
+ const resolved = path.resolve(cwd, route.endpoint.file);
177
+ const relative = decodeURIComponent(path.relative(config.kit.files.routes, resolved));
178
+ const name = posixify(path.join('entries/endpoints', relative.replace(/\.js$/, '')));
179
+ input[name] = resolved;
180
+ }
181
+ });
182
+
183
+ // ...and every component used by pages...
184
+ manifest_data.nodes.forEach((node) => {
185
+ for (const file of [node.component, node.shared, node.server]) {
186
+ if (file) {
187
+ const resolved = path.resolve(cwd, file);
188
+ const relative = decodeURIComponent(path.relative(config.kit.files.routes, resolved));
189
+
190
+ const name = relative.startsWith('..')
191
+ ? posixify(path.join('entries/fallbacks', path.basename(file)))
192
+ : posixify(path.join('entries/pages', relative.replace(/\.js$/, '')));
193
+ input[name] = resolved;
194
+ }
195
+ }
196
+ });
197
+
198
+ // ...and every matcher
199
+ Object.entries(manifest_data.matchers).forEach(([key, file]) => {
200
+ const name = posixify(path.join('entries/matchers', key));
201
+ input[name] = path.resolve(cwd, file);
202
+ });
203
+
204
+ /** @type {(file: string) => string} */
205
+ const app_relative = (file) => {
206
+ const relative_file = path.relative(build_dir, path.resolve(cwd, file));
207
+ return relative_file[0] === '.' ? relative_file : `./${relative_file}`;
208
+ };
209
+
210
+ fs.writeFileSync(
211
+ input.index,
212
+ server_template({
213
+ config,
214
+ hooks: app_relative(hooks_file),
215
+ has_service_worker: config.kit.serviceWorker.register && !!service_worker_entry_file,
216
+ runtime: posixify(path.relative(build_dir, runtime_directory)),
217
+ template: load_template(cwd, config),
218
+ error_page: load_error_page(config)
219
+ })
220
+ );
221
+
222
+ const merged_config = merge_vite_configs(
223
+ get_default_build_config({ config, input, ssr: true, outDir: `${output_dir}/server` }),
224
+ await get_vite_config(vite_config, vite_config_env)
225
+ );
226
+
227
+ const { chunks } = await create_build(merged_config);
228
+
229
+ /** @type {import('vite').Manifest} */
230
+ const vite_manifest = JSON.parse(
231
+ fs.readFileSync(`${output_dir}/server/${vite_config.build.manifest}`, 'utf-8')
232
+ );
233
+
234
+ mkdirp(`${output_dir}/server/nodes`);
235
+ mkdirp(`${output_dir}/server/stylesheets`);
236
+
237
+ const stylesheet_lookup = new Map();
238
+
239
+ client.assets.forEach((asset) => {
240
+ if (asset.fileName.endsWith('.css')) {
241
+ if (asset.source.length < config.kit.inlineStyleThreshold) {
242
+ const index = stylesheet_lookup.size;
243
+ const file = `${output_dir}/server/stylesheets/${index}.js`;
244
+
245
+ fs.writeFileSync(file, `// ${asset.fileName}\nexport default ${s(asset.source)};`);
246
+ stylesheet_lookup.set(asset.fileName, index);
247
+ }
248
+ }
249
+ });
250
+
251
+ manifest_data.nodes.forEach((node, i) => {
252
+ /** @type {string[]} */
253
+ const imports = [];
254
+
255
+ // String representation of
256
+ /** @type {import('types').SSRNode} */
257
+ /** @type {string[]} */
258
+ const exports = [`export const index = ${i};`];
259
+
260
+ /** @type {string[]} */
261
+ const imported = [];
262
+
263
+ /** @type {string[]} */
264
+ const stylesheets = [];
265
+
266
+ if (node.component) {
267
+ const entry = find_deps(client.vite_manifest, node.component, true);
268
+
269
+ imported.push(...entry.imports);
270
+ stylesheets.push(...entry.stylesheets);
271
+
272
+ exports.push(
273
+ `export const component = async () => (await import('../${
274
+ vite_manifest[node.component].file
275
+ }')).default;`,
276
+ `export const file = '${entry.file}';` // TODO what is this?
277
+ );
278
+ }
279
+
280
+ if (node.shared) {
281
+ const entry = find_deps(client.vite_manifest, node.shared, true);
282
+
283
+ imported.push(...entry.imports);
284
+ stylesheets.push(...entry.stylesheets);
285
+
286
+ imports.push(`import * as shared from '../${vite_manifest[node.shared].file}';`);
287
+ exports.push(`export { shared };`);
288
+ }
289
+
290
+ if (node.server) {
291
+ imports.push(`import * as server from '../${vite_manifest[node.server].file}';`);
292
+ exports.push(`export { server };`);
293
+ }
294
+
295
+ exports.push(
296
+ `export const imports = ${s(imported)};`,
297
+ `export const stylesheets = ${s(stylesheets)};`
298
+ );
299
+
300
+ /** @type {string[]} */
301
+ const styles = [];
302
+
303
+ stylesheets.forEach((file) => {
304
+ if (stylesheet_lookup.has(file)) {
305
+ const index = stylesheet_lookup.get(file);
306
+ const name = `stylesheet_${index}`;
307
+ imports.push(`import ${name} from '../stylesheets/${index}.js';`);
308
+ styles.push(`\t${s(file)}: ${name}`);
309
+ }
310
+ });
311
+
312
+ if (styles.length > 0) {
313
+ exports.push(`export const inline_styles = () => ({\n${styles.join(',\n')}\n});`);
314
+ }
315
+
316
+ const out = `${output_dir}/server/nodes/${i}.js`;
317
+ fs.writeFileSync(out, `${imports.join('\n')}\n\n${exports.join('\n')}\n`);
318
+ });
319
+
320
+ return {
321
+ chunks,
322
+ vite_manifest,
323
+ methods: get_methods(cwd, chunks, manifest_data)
324
+ };
325
+ }
326
+
327
+ /**
328
+ * @param {string} cwd
329
+ * @param {import('rollup').OutputChunk[]} output
330
+ * @param {import('types').ManifestData} manifest_data
331
+ */
332
+ function get_methods(cwd, output, manifest_data) {
333
+ /** @type {Record<string, string[]>} */
334
+ const lookup = {};
335
+ output.forEach((chunk) => {
336
+ if (!chunk.facadeModuleId) return;
337
+ const id = chunk.facadeModuleId.slice(cwd.length + 1);
338
+ lookup[id] = chunk.exports;
339
+ });
340
+
341
+ /** @type {Record<string, import('types').HttpMethod[]>} */
342
+ const methods = {};
343
+ manifest_data.routes.forEach((route) => {
344
+ if (route.endpoint) {
345
+ if (lookup[route.endpoint.file]) {
346
+ methods[route.endpoint.file] = lookup[route.endpoint.file].filter(is_http_method);
347
+ }
348
+ }
349
+
350
+ if (route.leaf?.server) {
351
+ if (lookup[route.leaf.server]) {
352
+ methods[route.leaf.server] = lookup[route.leaf.server].filter(is_http_method);
353
+ }
354
+ }
355
+ });
356
+
357
+ return methods;
358
+ }
@@ -0,0 +1,90 @@
1
+ import fs from 'fs';
2
+ import * as vite from 'vite';
3
+ import { s } from '../../../utils/misc.js';
4
+ import { assets_base } from './utils.js';
5
+
6
+ /**
7
+ * @param {{
8
+ * config: import('types').ValidatedConfig;
9
+ * vite_config: import('vite').ResolvedConfig;
10
+ * vite_config_env: import('vite').ConfigEnv;
11
+ * manifest_data: import('types').ManifestData;
12
+ * output_dir: string;
13
+ * service_worker_entry_file: string | null;
14
+ * }} options
15
+ * @param {import('types').Prerendered} prerendered
16
+ * @param {import('vite').Manifest} client_manifest
17
+ */
18
+ export async function build_service_worker(
19
+ { config, manifest_data, output_dir, service_worker_entry_file },
20
+ prerendered,
21
+ client_manifest
22
+ ) {
23
+ const build = new Set();
24
+ for (const key in client_manifest) {
25
+ const { file, css = [], assets = [] } = client_manifest[key];
26
+ build.add(file);
27
+ css.forEach((file) => build.add(file));
28
+ assets.forEach((file) => build.add(file));
29
+ }
30
+
31
+ const service_worker = `${config.kit.outDir}/generated/service-worker.js`;
32
+
33
+ fs.writeFileSync(
34
+ service_worker,
35
+ `
36
+ // TODO remove for 1.0
37
+ export const timestamp = {
38
+ toString: () => {
39
+ throw new Error('\`timestamp\` has been removed from $service-worker. Use \`version\` instead');
40
+ }
41
+ };
42
+
43
+ export const build = [
44
+ ${Array.from(build)
45
+ .map((file) => `${s(`${config.kit.paths.base}/${file}`)}`)
46
+ .join(',\n\t\t\t\t')}
47
+ ];
48
+
49
+ export const files = [
50
+ ${manifest_data.assets
51
+ .filter((asset) => config.kit.serviceWorker.files(asset.file))
52
+ .map((asset) => `${s(`${config.kit.paths.base}/${asset.file}`)}`)
53
+ .join(',\n\t\t\t\t')}
54
+ ];
55
+
56
+ export const prerendered = [
57
+ ${prerendered.paths.map((path) => s(path)).join(',\n\t\t\t\t')}
58
+ ];
59
+
60
+ export const version = ${s(config.kit.version.name)};
61
+ `
62
+ .replace(/^\t{3}/gm, '')
63
+ .trim()
64
+ );
65
+
66
+ await vite.build({
67
+ base: assets_base(config.kit),
68
+ build: {
69
+ lib: {
70
+ entry: /** @type {string} */ (service_worker_entry_file),
71
+ name: 'app',
72
+ formats: ['es']
73
+ },
74
+ rollupOptions: {
75
+ output: {
76
+ entryFileNames: 'service-worker.js'
77
+ }
78
+ },
79
+ outDir: `${output_dir}/client`,
80
+ emptyOutDir: false
81
+ },
82
+ configFile: false,
83
+ resolve: {
84
+ alias: {
85
+ '$service-worker': service_worker,
86
+ $lib: config.kit.files.lib
87
+ }
88
+ }
89
+ });
90
+ }