@sveltejs/kit 1.0.0-next.40 → 1.0.0-next.400

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 (48) hide show
  1. package/README.md +12 -9
  2. package/assets/app/env.js +13 -0
  3. package/assets/app/navigation.js +24 -0
  4. package/assets/app/paths.js +1 -0
  5. package/assets/{runtime/app → app}/stores.js +33 -29
  6. package/assets/client/singletons.js +13 -0
  7. package/assets/client/start.js +1845 -0
  8. package/assets/components/error.svelte +18 -2
  9. package/assets/env/dynamic/private.js +1 -0
  10. package/assets/env/dynamic/public.js +1 -0
  11. package/assets/env-private.js +9 -0
  12. package/assets/env-public.js +9 -0
  13. package/assets/env.js +8 -0
  14. package/assets/{runtime/chunks/paths.js → paths.js} +4 -3
  15. package/assets/server/index.js +3579 -0
  16. package/dist/chunks/error.js +12 -0
  17. package/dist/chunks/filesystem.js +110 -0
  18. package/dist/chunks/index.js +541 -3385
  19. package/dist/chunks/index2.js +15631 -473
  20. package/dist/chunks/index3.js +189 -217
  21. package/dist/chunks/multipart-parser.js +458 -0
  22. package/dist/chunks/sync.js +1368 -0
  23. package/dist/chunks/utils.js +40 -57
  24. package/dist/chunks/write_tsconfig.js +273 -0
  25. package/dist/cli.js +84 -513
  26. package/dist/hooks.js +28 -0
  27. package/dist/node/polyfills.js +17778 -0
  28. package/dist/node.js +348 -0
  29. package/dist/prerender.js +788 -0
  30. package/dist/vite.js +2520 -0
  31. package/package.json +98 -64
  32. package/svelte-kit.js +10 -1
  33. package/types/ambient.d.ts +375 -0
  34. package/types/index.d.ts +298 -0
  35. package/types/internal.d.ts +335 -0
  36. package/types/private.d.ts +235 -0
  37. package/CHANGELOG.md +0 -411
  38. package/assets/runtime/app/env.js +0 -5
  39. package/assets/runtime/app/navigation.js +0 -41
  40. package/assets/runtime/app/paths.js +0 -1
  41. package/assets/runtime/chunks/utils.js +0 -19
  42. package/assets/runtime/internal/singletons.js +0 -23
  43. package/assets/runtime/internal/start.js +0 -770
  44. package/dist/chunks/index4.js +0 -526
  45. package/dist/chunks/index5.js +0 -761
  46. package/dist/chunks/index6.js +0 -322
  47. package/dist/chunks/standard.js +0 -99
  48. package/dist/ssr.js +0 -2523
package/dist/cli.js CHANGED
@@ -1,546 +1,117 @@
1
- import { existsSync } from 'fs';
1
+ import fs__default from 'fs';
2
+ import path__default from 'path';
3
+ import { l as load_config, $ } from './chunks/index.js';
2
4
  import sade from 'sade';
3
- import { pathToFileURL, resolve as resolve$1 } from 'url';
4
- import path from 'path';
5
+ import { c as coalesce_to_error } from './chunks/error.js';
6
+ import 'url';
5
7
 
6
- let FORCE_COLOR, NODE_DISABLE_COLORS, NO_COLOR, TERM, isTTY=true;
7
- if (typeof process !== 'undefined') {
8
- ({ FORCE_COLOR, NODE_DISABLE_COLORS, NO_COLOR, TERM } = process.env);
9
- isTTY = process.stdout && process.stdout.isTTY;
10
- }
11
-
12
- const $ = {
13
- enabled: !NODE_DISABLE_COLORS && NO_COLOR == null && TERM !== 'dumb' && (
14
- FORCE_COLOR != null && FORCE_COLOR !== '0' || isTTY
15
- ),
16
-
17
- // modifiers
18
- reset: init(0, 0),
19
- bold: init(1, 22),
20
- dim: init(2, 22),
21
- italic: init(3, 23),
22
- underline: init(4, 24),
23
- inverse: init(7, 27),
24
- hidden: init(8, 28),
25
- strikethrough: init(9, 29),
26
-
27
- // colors
28
- black: init(30, 39),
29
- red: init(31, 39),
30
- green: init(32, 39),
31
- yellow: init(33, 39),
32
- blue: init(34, 39),
33
- magenta: init(35, 39),
34
- cyan: init(36, 39),
35
- white: init(37, 39),
36
- gray: init(90, 39),
37
- grey: init(90, 39),
38
-
39
- // background colors
40
- bgBlack: init(40, 49),
41
- bgRed: init(41, 49),
42
- bgGreen: init(42, 49),
43
- bgYellow: init(43, 49),
44
- bgBlue: init(44, 49),
45
- bgMagenta: init(45, 49),
46
- bgCyan: init(46, 49),
47
- bgWhite: init(47, 49)
48
- };
49
-
50
- function run(arr, str) {
51
- let i=0, tmp, beg='', end='';
52
- for (; i < arr.length; i++) {
53
- tmp = arr[i];
54
- beg += tmp.open;
55
- end += tmp.close;
56
- if (!!~str.indexOf(tmp.close)) {
57
- str = str.replace(tmp.rgx, tmp.close + tmp.open);
58
- }
59
- }
60
- return beg + str + end;
61
- }
62
-
63
- function chain(has, keys) {
64
- let ctx = { has, keys };
65
-
66
- ctx.reset = $.reset.bind(ctx);
67
- ctx.bold = $.bold.bind(ctx);
68
- ctx.dim = $.dim.bind(ctx);
69
- ctx.italic = $.italic.bind(ctx);
70
- ctx.underline = $.underline.bind(ctx);
71
- ctx.inverse = $.inverse.bind(ctx);
72
- ctx.hidden = $.hidden.bind(ctx);
73
- ctx.strikethrough = $.strikethrough.bind(ctx);
74
-
75
- ctx.black = $.black.bind(ctx);
76
- ctx.red = $.red.bind(ctx);
77
- ctx.green = $.green.bind(ctx);
78
- ctx.yellow = $.yellow.bind(ctx);
79
- ctx.blue = $.blue.bind(ctx);
80
- ctx.magenta = $.magenta.bind(ctx);
81
- ctx.cyan = $.cyan.bind(ctx);
82
- ctx.white = $.white.bind(ctx);
83
- ctx.gray = $.gray.bind(ctx);
84
- ctx.grey = $.grey.bind(ctx);
85
-
86
- ctx.bgBlack = $.bgBlack.bind(ctx);
87
- ctx.bgRed = $.bgRed.bind(ctx);
88
- ctx.bgGreen = $.bgGreen.bind(ctx);
89
- ctx.bgYellow = $.bgYellow.bind(ctx);
90
- ctx.bgBlue = $.bgBlue.bind(ctx);
91
- ctx.bgMagenta = $.bgMagenta.bind(ctx);
92
- ctx.bgCyan = $.bgCyan.bind(ctx);
93
- ctx.bgWhite = $.bgWhite.bind(ctx);
94
-
95
- return ctx;
96
- }
97
-
98
- function init(open, close) {
99
- let blk = {
100
- open: `\x1b[${open}m`,
101
- close: `\x1b[${close}m`,
102
- rgx: new RegExp(`\\x1b\\[${close}m`, 'g')
103
- };
104
- return function (txt) {
105
- if (this !== void 0 && this.has !== void 0) {
106
- !!~this.has.indexOf(open) || (this.has.push(open),this.keys.push(blk));
107
- return txt === void 0 ? this : $.enabled ? run(this.keys, txt+'') : txt+'';
108
- }
109
- return txt === void 0 ? chain([open], [blk]) : $.enabled ? run([blk], txt+'') : txt+'';
110
- };
111
- }
112
-
113
- const noop = () => {};
114
-
115
- /** @typedef {import('./types').ConfigDefinition} ConfigDefinition */
116
-
117
- /** @type {Record<string, ConfigDefinition>} */
118
- const options = {
119
- compilerOptions: {
120
- type: 'leaf',
121
- default: null,
122
- validate: noop
123
- },
124
-
125
- extensions: {
126
- type: 'leaf',
127
- default: ['.svelte'],
128
- validate: (option, keypath) => {
129
- if (!Array.isArray(option) || !option.every((page) => typeof page === 'string')) {
130
- throw new Error(`${keypath} must be an array of strings`);
131
- }
132
-
133
- option.forEach((extension) => {
134
- if (extension[0] !== '.') {
135
- throw new Error(`Each member of ${keypath} must start with '.' — saw '${extension}'`);
136
- }
137
-
138
- if (!/^(\.[a-z0-9]+)+$/i.test(extension)) {
139
- throw new Error(`File extensions must be alphanumeric — saw '${extension}'`);
140
- }
141
- });
142
-
143
- return option;
144
- }
145
- },
146
-
147
- kit: {
148
- type: 'branch',
149
- children: {
150
- adapter: {
151
- type: 'leaf',
152
- default: [null],
153
- validate: (option, keypath) => {
154
- // support both `adapter: 'foo'` and `adapter: ['foo', opts]`
155
- if (!Array.isArray(option)) {
156
- option = [option];
157
- }
158
-
159
- // TODO allow inline functions
160
- assert_is_string(option[0], keypath);
161
-
162
- return option;
163
- }
164
- },
165
-
166
- amp: expect_boolean(false),
167
-
168
- appDir: expect_string('_app', false),
169
-
170
- files: {
171
- type: 'branch',
172
- children: {
173
- assets: expect_string('static'),
174
- routes: expect_string('src/routes'),
175
- serviceWorker: expect_string('src/service-worker'),
176
- setup: expect_string('src/setup'),
177
- template: expect_string('src/app.html')
178
- }
179
- },
180
-
181
- host: expect_string(null),
182
-
183
- hostHeader: expect_string(null),
184
-
185
- paths: {
186
- type: 'branch',
187
- children: {
188
- base: expect_string(''),
189
- assets: expect_string('')
190
- }
191
- },
192
-
193
- prerender: {
194
- type: 'branch',
195
- children: {
196
- crawl: expect_boolean(true),
197
- enabled: expect_boolean(true),
198
- force: expect_boolean(false),
199
- pages: {
200
- type: 'leaf',
201
- default: ['*'],
202
- validate: (option, keypath) => {
203
- if (!Array.isArray(option) || !option.every((page) => typeof page === 'string')) {
204
- throw new Error(`${keypath} must be an array of strings`);
205
- }
206
-
207
- option.forEach((page) => {
208
- if (page !== '*' && page[0] !== '/') {
209
- throw new Error(
210
- `Each member of ${keypath} must be either '*' or an absolute path beginning with '/' — saw '${page}'`
211
- );
212
- }
213
- });
214
-
215
- return option;
216
- }
217
- }
218
- }
219
- },
220
-
221
- // used for testing
222
- startGlobal: expect_string(null),
223
-
224
- target: expect_string(null)
225
- }
226
- },
227
-
228
- preprocess: {
229
- type: 'leaf',
230
- default: null,
231
- validate: noop
232
- }
233
- };
234
-
235
- /**
236
- * @param {string} string
237
- * @param {boolean} allow_empty
238
- * @returns {ConfigDefinition}
239
- */
240
- function expect_string(string, allow_empty = true) {
241
- return {
242
- type: 'leaf',
243
- default: string,
244
- validate: (option, keypath) => {
245
- assert_is_string(option, keypath);
246
- if (!allow_empty && option === '') {
247
- throw new Error(`${keypath} cannot be empty`);
248
- }
249
- return option;
250
- }
251
- };
252
- }
253
-
254
- /**
255
- * @param {boolean} boolean
256
- * @returns {ConfigDefinition}
257
- */
258
- function expect_boolean(boolean) {
259
- return {
260
- type: 'leaf',
261
- default: boolean,
262
- validate: (option, keypath) => {
263
- if (typeof option !== 'boolean') {
264
- throw new Error(`${keypath} should be true or false, if specified`);
265
- }
266
- return option;
267
- }
268
- };
269
- }
270
-
271
- /**
272
- * @param {any} option
273
- * @param {string} keypath
274
- */
275
- function assert_is_string(option, keypath) {
276
- if (typeof option !== 'string') {
277
- throw new Error(`${keypath} should be a string, if specified`);
278
- }
279
- }
280
-
281
- /** @typedef {import('./types').ConfigDefinition} ConfigDefinition */
282
-
283
- /**
284
- * @param {Record<string, ConfigDefinition>} definition
285
- * @param {any} option
286
- * @param {string} keypath
287
- * @returns {any}
288
- */
289
- function validate(definition, option, keypath) {
290
- for (const key in option) {
291
- if (!(key in definition)) {
292
- let message = `Unexpected option ${keypath}.${key}`;
293
-
294
- if (keypath === 'config' && key in options.kit) {
295
- message += ` (did you mean config.kit.${key}?)`;
296
- } else if (keypath === 'config.kit' && key in options) {
297
- message += ` (did you mean config.${key}?)`;
298
- }
299
-
300
- throw new Error(message);
301
- }
302
- }
8
+ /** @param {unknown} e */
9
+ function handle_error(e) {
10
+ const error = coalesce_to_error(e);
303
11
 
304
- /** @type {Record<string, any>} */
305
- const merged = {};
12
+ if (error.name === 'SyntaxError') throw error;
306
13
 
307
- for (const key in definition) {
308
- const expected = definition[key];
309
- const actual = option[key];
310
-
311
- const child_keypath = `${keypath}.${key}`;
312
-
313
- if (key in option) {
314
- if (expected.type === 'branch') {
315
- if (actual && (typeof actual !== 'object' || Array.isArray(actual))) {
316
- throw new Error(`${keypath}.${key} should be an object`);
317
- }
318
-
319
- merged[key] = validate(expected.children, actual, child_keypath);
320
- } else {
321
- merged[key] = expected.validate(actual, child_keypath);
322
- }
323
- } else {
324
- merged[key] =
325
- expected.type === 'branch'
326
- ? validate(expected.children, {}, child_keypath)
327
- : expected.default;
328
- }
329
- }
330
-
331
- return merged;
332
- }
333
-
334
- /**
335
- * @param {string} from
336
- * @param {string} to
337
- */
338
- function resolve(from, to) {
339
- // the `/.` is weird, but allows `${assets}/images/blah.jpg` to work
340
- // when `assets` is empty
341
- return remove_trailing_slash(resolve$1(add_trailing_slash(from), to)) || '/.';
342
- }
343
-
344
- /**
345
- * @param {string} str
346
- */
347
- function add_trailing_slash(str) {
348
- return str.endsWith('/') ? str : `${str}/`;
349
- }
350
-
351
- /**
352
- * @param {string} str
353
- */
354
- function remove_trailing_slash(str) {
355
- return str.endsWith('/') ? str.slice(0, -1) : str;
356
- }
357
-
358
- async function load_config({ cwd = process.cwd() } = {}) {
359
- const config_file = path.join(cwd, 'svelte.config.cjs');
360
- const config = await import(pathToFileURL(config_file).href);
361
- const validated = validate_config(config.default);
362
-
363
- validated.kit.files.assets = path.resolve(cwd, validated.kit.files.assets);
364
- validated.kit.files.routes = path.resolve(cwd, validated.kit.files.routes);
365
- validated.kit.files.serviceWorker = path.resolve(cwd, validated.kit.files.serviceWorker);
366
- validated.kit.files.setup = path.resolve(cwd, validated.kit.files.setup);
367
- validated.kit.files.template = path.resolve(cwd, validated.kit.files.template);
368
-
369
- // TODO check all the `files` exist when the config is loaded?
370
- // TODO check that `target` is present in the provided template
371
-
372
- return validated;
373
- }
374
-
375
- /**
376
- * @param {import('../../../types').Config} config
377
- * @returns {import('../../types.js').ValidatedConfig}
378
- */
379
- function validate_config(config) {
380
- /** @type {import('../../types.js').ValidatedConfig} */
381
- const validated = validate(options, config, 'config');
382
-
383
- // resolve paths
384
- const { paths } = validated.kit;
385
-
386
- if (paths.base !== '' && !paths.base.startsWith('/')) {
387
- throw new Error('config.kit.paths.base must be a root-relative path');
14
+ console.error($.bold().red(`> ${error.message}`));
15
+ if (error.stack) {
16
+ console.error($.gray(error.stack.split('\n').slice(1).join('\n')));
388
17
  }
389
18
 
390
- paths.assets = resolve(paths.base, paths.assets);
391
-
392
- return validated;
393
- }
394
-
395
- async function get_config() {
396
- // TODO this is temporary, for the benefit of early adopters
397
- if (existsSync('snowpack.config.js') || existsSync('snowpack.config.cjs')) {
398
- // prettier-ignore
399
- console.error($.bold().red(
400
- 'SvelteKit now uses https://vitejs.dev. Please replace snowpack.config.js with vite.config.js:'
401
- ));
402
-
403
- // prettier-ignore
404
- console.error(`
405
- import { resolve } from 'path';
406
-
407
- export default {
408
- resolve: {
409
- alias: {
410
- $components: resolve('src/components')
411
- }
412
- }
413
- };
414
- `.replace(/^\t{3}/gm, '').replace(/\t/gm, ' ').trim());
415
- }
416
-
417
- try {
418
- return await load_config();
419
- } catch (error) {
420
- let message = error.message;
421
-
422
- if (error.code === 'MODULE_NOT_FOUND') {
423
- if (existsSync('svelte.config.js')) {
424
- // TODO this is temporary, for the benefit of early adopters
425
- message =
426
- 'You must rename svelte.config.js to svelte.config.cjs, and snowpack.config.js to snowpack.config.cjs';
427
- } else {
428
- message = 'Missing svelte.config.cjs';
429
- }
430
- } else if (error.name === 'SyntaxError') {
431
- message = 'Malformed svelte.config.cjs';
432
- }
433
-
434
- console.error($.bold().red(message));
435
- console.error($.grey(error.stack));
436
- process.exit(1);
437
- }
438
- }
439
-
440
- /** @param {Error} error */
441
- function handle_error(error) {
442
- console.log($.bold().red(`> ${error.message}`));
443
- console.log($.gray(error.stack));
444
19
  process.exit(1);
445
20
  }
446
21
 
447
- /** @param {number} port */
448
- async function launch(port) {
449
- const { exec } = await import('child_process');
450
- exec(`${process.platform == 'win32' ? 'start' : 'open'} http://localhost:${port}`);
451
- }
452
-
453
- const prog = sade('svelte-kit').version('1.0.0-next.40');
22
+ const prog = sade('svelte-kit').version('1.0.0-next.400');
454
23
 
455
24
  prog
456
- .command('dev')
457
- .describe('Start a development server')
458
- .option('-p, --port', 'Port', 3000)
459
- .option('-o, --open', 'Open a browser tab', false)
460
- .action(async ({ port, open }) => {
461
- process.env.NODE_ENV = 'development';
462
- const config = await get_config();
463
-
464
- const { dev } = await import('./chunks/index.js');
465
-
25
+ .command('package')
26
+ .describe('Create a package')
27
+ .option('-w, --watch', 'Rerun when files change', false)
28
+ .action(async ({ watch }) => {
466
29
  try {
467
- const watcher = await dev({ port, config });
30
+ const config = await load_config();
31
+ const packaging = await import('./chunks/index2.js');
468
32
 
469
- watcher.on('stdout', (data) => {
470
- process.stdout.write(data);
471
- });
472
-
473
- watcher.on('stderr', (data) => {
474
- process.stderr.write(data);
475
- });
476
-
477
- console.log($.bold().cyan(`> Listening on http://localhost:${watcher.port}`));
478
- if (open) launch(watcher.port);
33
+ await (watch ? packaging.watch(config) : packaging.build(config));
479
34
  } catch (error) {
480
35
  handle_error(error);
481
36
  }
482
37
  });
483
38
 
484
39
  prog
485
- .command('build')
486
- .describe('Create a production build of your app')
487
- .option('--verbose', 'Log more stuff', false)
488
- .action(async ({ verbose }) => {
489
- process.env.NODE_ENV = 'production';
490
- const config = await get_config();
491
-
492
- try {
493
- const { build } = await import('./chunks/index4.js');
494
- await build(config);
40
+ .command('sync')
41
+ .describe('Synchronise generated files')
42
+ .option('--mode', 'Specify a mode for loading environment variables', 'development')
43
+ .action(async ({ mode }) => {
44
+ const event = process.env.npm_lifecycle_event;
45
+
46
+ // TODO remove for 1.0
47
+ if (event === 'prepare') {
48
+ const pkg = JSON.parse(fs__default.readFileSync('package.json', 'utf8'));
49
+ const message =
50
+ pkg.scripts.prepare === 'svelte-kit sync'
51
+ ? `\`svelte-kit sync\` now runs on "postinstall" — please remove the "prepare" script from your package.json\n`
52
+ : `\`svelte-kit sync\` now runs on "postinstall" — please remove it from your "prepare" script\n`;
53
+
54
+ console.error($.bold().red(message));
55
+ return;
56
+ }
495
57
 
496
- console.log(`\nRun ${$.bold().cyan('npm start')} to try your app locally.`);
58
+ const cwd = event === 'postinstall' ? process.env.INIT_CWD ?? '' : process.cwd();
497
59
 
498
- if (config.kit.adapter[0]) {
499
- const { adapt } = await import('./chunks/index5.js');
500
- await adapt(config, { verbose });
501
- } else {
502
- console.log($.bold().yellow('\nNo adapter specified'));
60
+ const svelte_config_file = path__default.join(cwd, 'svelte.config.js');
61
+ if (!fs__default.existsSync(svelte_config_file)) {
62
+ console.warn(`Missing ${svelte_config_file} skipping`);
63
+ return;
64
+ }
503
65
 
504
- // prettier-ignore
505
- console.log(
506
- `See ${$.bold().cyan('https://kit.svelte.dev/docs#adapters')} to learn how to configure your app to run on the platform of your choosing`
507
- );
508
- }
66
+ try {
67
+ const config = await load_config({ cwd });
68
+ const sync = await import('./chunks/sync.js').then(function (n) { return n.f; });
69
+ sync.all(config, mode);
509
70
  } catch (error) {
510
71
  handle_error(error);
511
72
  }
512
73
  });
513
74
 
514
- prog
515
- .command('start')
516
- .describe('Serve an already-built app')
517
- .option('-p, --port', 'Port', 3000)
518
- .option('-o, --open', 'Open a browser tab', false)
519
- .action(async ({ port, open }) => {
520
- process.env.NODE_ENV = 'production';
521
- const config = await get_config();
75
+ // TODO remove for 1.0
76
+ replace('dev');
77
+ replace('build');
78
+ replace('preview');
522
79
 
523
- const { start } = await import('./chunks/index6.js');
80
+ prog.parse(process.argv, { unknown: (arg) => `Unknown option: ${arg}` });
524
81
 
525
- try {
526
- await start({ port, config });
82
+ /** @param {string} command */
83
+ function replace(command) {
84
+ prog
85
+ .command(command)
86
+ .describe(`No longer available — use vite ${command} instead`)
87
+ .action(async () => {
88
+ const message = `\n> svelte-kit ${command} is no longer available — use vite ${command} instead`;
89
+ console.error($.bold().red(message));
90
+
91
+ const steps = [
92
+ 'Install vite as a devDependency with npm/pnpm/etc',
93
+ 'Create a vite.config.js with the @sveltejs/kit/vite plugin (see below)',
94
+ `Update your package.json scripts to reference \`vite ${command}\` instead of \`svelte-kit ${command}\``
95
+ ];
96
+
97
+ steps.forEach((step, i) => {
98
+ console.error(` ${i + 1}. ${$.cyan(step)}`);
99
+ });
527
100
 
528
- console.log($.bold().cyan(`> Listening on http://localhost:${port}`));
529
- if (open) if (open) launch(port);
530
- } catch (error) {
531
- handle_error(error);
532
- }
533
- });
101
+ console.error(
102
+ `
103
+ ${$.grey('// vite.config.js')}
104
+ import { sveltekit } from '@sveltejs/kit/vite';
534
105
 
535
- // For the benefit of early-adopters. Can later be removed
536
- prog
537
- .command('adapt')
538
- .describe('Customise your production build for different platforms')
539
- .option('--verbose', 'Log more stuff', false)
540
- .action(async () => {
541
- console.log('"svelte-kit build" will now run the adapter');
542
- });
106
+ /** @type {import('vite').UserConfig} */
107
+ const config = {
108
+ plugins: [sveltekit()]
109
+ };
543
110
 
544
- prog.parse(process.argv, { unknown: (arg) => `Unknown option: ${arg}` });
111
+ export default config;
545
112
 
546
- export { $ };
113
+ `.replace(/^\t{4}/gm, '')
114
+ );
115
+ process.exit(1);
116
+ });
117
+ }
package/dist/hooks.js ADDED
@@ -0,0 +1,28 @@
1
+ /**
2
+ * @param {...import('types').Handle} handlers
3
+ * @returns {import('types').Handle}
4
+ */
5
+ function sequence(...handlers) {
6
+ const length = handlers.length;
7
+ if (!length) return ({ event, resolve }) => resolve(event);
8
+
9
+ return ({ event, resolve }) => {
10
+ return apply_handle(0, event);
11
+
12
+ /**
13
+ * @param {number} i
14
+ * @param {import('types').RequestEvent} event
15
+ * @returns {import('types').MaybePromise<Response>}
16
+ */
17
+ function apply_handle(i, event) {
18
+ const handle = handlers[i];
19
+
20
+ return handle({
21
+ event,
22
+ resolve: i < length - 1 ? (event) => apply_handle(i + 1, event) : resolve
23
+ });
24
+ }
25
+ };
26
+ }
27
+
28
+ export { sequence };