edge-functions 2.10.0 → 2.11.0-stage.2

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/.prettierignore CHANGED
@@ -5,4 +5,5 @@ CHANGELOG.md
5
5
  docker-compose.yml
6
6
  CODEOWNERS
7
7
  README.md
8
- docs/*
8
+ docs/*
9
+ lib/build/bundlers/polyfills/node/fs.js
package/CHANGELOG.md CHANGED
@@ -1,3 +1,17 @@
1
+ ## [2.11.0-stage.2](https://github.com/aziontech/vulcan/compare/v2.11.0-stage.1...v2.11.0-stage.2) (2024-07-09)
2
+
3
+
4
+ ### Features
5
+
6
+ * New preset Docusaurus ([#353](https://github.com/aziontech/vulcan/issues/353)) ([0c05e76](https://github.com/aziontech/vulcan/commit/0c05e76955afa500adc5c7e8762d007725c9b58b))
7
+
8
+ ## [2.11.0-stage.1](https://github.com/aziontech/vulcan/compare/v2.10.0...v2.11.0-stage.1) (2024-07-08)
9
+
10
+
11
+ ### Features
12
+
13
+ * use runtime in async fs ([#352](https://github.com/aziontech/vulcan/issues/352)) ([6a6f195](https://github.com/aziontech/vulcan/commit/6a6f19543a31ab9d39efbc4eb165fa6b2780c95e))
14
+
1
15
  ## [2.10.0](https://github.com/aziontech/vulcan/compare/v2.9.2...v2.10.0) (2024-07-02)
2
16
 
3
17
 
@@ -1,6 +1,8 @@
1
1
  import * as esbuild from 'esbuild';
2
2
  import ESBuildAzionModulePlugin from './azion-polyfills.plugins.js';
3
3
 
4
+ globalThis.vulcan = { buildProd: true };
5
+
4
6
  describe('Esbuild Azion Plugin', () => {
5
7
  it('should resolve the azion module: as external', async () => {
6
8
  const results = await esbuild.build({
@@ -1,6 +1,8 @@
1
1
  import * as esbuild from 'esbuild';
2
2
  import ESBuildNodeModulePlugin from './node-polyfills.plugins.js';
3
3
 
4
+ globalThis.vulcan = { buildProd: true };
5
+
4
6
  describe('Esbuild Node Plugin', () => {
5
7
  it('should check the env (NODE_ENV) in define options', async () => {
6
8
  const results = await esbuild.build({
@@ -1,5 +1,5 @@
1
1
  /* eslint-disable max-classes-per-file */
2
- import path from 'path-browserify';
2
+ import bPath from 'path-browserify';
3
3
  import { Buffer } from 'buffer';
4
4
 
5
5
  /* eslint-disable */
@@ -12,12 +12,10 @@ globalThis.vulcan.FS_PATHS_CHANGED = false;
12
12
  * fix mapped files paths based on path prefix
13
13
  */
14
14
  function fixMappedFilesPaths() {
15
- if (
16
- !globalThis.vulcan.FS_PATHS_CHANGED &&
17
- globalThis.vulcan.FS_PATH_PREFIX_TO_REMOVE !== ''
18
- ) {
15
+ const prefix = globalThis.vulcan.FS_PATH_PREFIX_TO_REMOVE;
16
+ if (!globalThis.vulcan.FS_PATHS_CHANGED && prefix !== "") {
19
17
  Object.keys(MEM_FILES).forEach((e) => {
20
- const newKey = e.replace(globalThis.vulcan.FS_PATH_PREFIX_TO_REMOVE, '');
18
+ const newKey = e.replace(prefix, '');
21
19
  MEM_FILES[newKey] = MEM_FILES[e];
22
20
  delete MEM_FILES[e];
23
21
  });
@@ -56,7 +54,9 @@ function getFileContent(file, returnBuffer = true) {
56
54
  * @returns {string[]} list of mapped files paths
57
55
  */
58
56
  function getAvailableFiles() {
59
- if (MEM_FILES && typeof MEM_FILES === 'object') return Object.keys(MEM_FILES);
57
+ if (MEM_FILES && typeof MEM_FILES === 'object') {
58
+ return Object.keys(MEM_FILES);
59
+ }
60
60
 
61
61
  return [];
62
62
  }
@@ -71,12 +71,12 @@ function getAvailableDirs(files) {
71
71
  const existingDirs = new Set();
72
72
 
73
73
  files.forEach((filePath) => {
74
- const dirPath = path.dirname(filePath);
74
+ const dirPath = bPath.dirname(filePath);
75
75
 
76
76
  let currentPath = '/';
77
77
  let pathSegments = dirPath.split('/');
78
78
  for (let i = 0; i < pathSegments.length; i++) {
79
- currentPath = path.join(currentPath, pathSegments[i]);
79
+ currentPath = bPath.join(currentPath, pathSegments[i]);
80
80
  if (!existingDirs.has(currentPath)) {
81
81
  existingDirs.add(currentPath);
82
82
  }
@@ -113,8 +113,13 @@ function getFilesInfos() {
113
113
  * @returns {string} - path to fix
114
114
  */
115
115
  function getValidatedPath(path) {
116
- if (path.endsWith('/')) path = path.slice(0, -1);
117
- if (!path.startsWith('/')) path = `/${path}`;
116
+ if (path.endsWith('/')) {
117
+ path = path.slice(0, -1);
118
+ }
119
+
120
+ if (!path.startsWith('/')) {
121
+ path = bPath.join('/', path);
122
+ }
118
123
 
119
124
  return path;
120
125
  }
@@ -147,12 +152,6 @@ function generateDefaultStat() {
147
152
  // ### fs polyfills
148
153
  // code based on node implementations
149
154
 
150
- const UV_FS_SYMLINK_DIR = 1;
151
- const UV_FS_SYMLINK_JUNCTION = 2;
152
- const O_RDONLY = 0;
153
- const O_WRONLY = 1;
154
- const O_RDWR = 2;
155
- const UV_DIRENT_UNKNOWN = 0;
156
155
  const UV_DIRENT_FILE = 1;
157
156
  const UV_DIRENT_DIR = 2;
158
157
  const UV_DIRENT_LINK = 3;
@@ -160,53 +159,10 @@ const UV_DIRENT_FIFO = 4;
160
159
  const UV_DIRENT_SOCKET = 5;
161
160
  const UV_DIRENT_CHAR = 6;
162
161
  const UV_DIRENT_BLOCK = 7;
163
- const S_IFMT = 61440;
164
- const S_IFREG = 32768;
165
- const S_IFDIR = 16384;
166
- const S_IFCHR = 8192;
167
- const S_IFBLK = 24576;
168
- const S_IFIFO = 4096;
169
- const S_IFLNK = 40960;
170
- const S_IFSOCK = 49152;
171
- const O_CREAT = 512;
172
- const O_EXCL = 2048;
173
- const UV_FS_O_FILEMAP = 0;
174
- const O_NOCTTY = 131072;
175
- const O_TRUNC = 1024;
176
- const O_APPEND = 8;
177
- const O_DIRECTORY = 1048576;
178
- const O_NOFOLLOW = 256;
179
- const O_SYNC = 128;
180
- const O_DSYNC = 4194304;
181
- const O_SYMLINK = 2097152;
182
- const O_NONBLOCK = 4;
183
- const S_IRWXU = 448;
184
- const S_IRUSR = 256;
185
- const S_IWUSR = 128;
186
- const S_IXUSR = 64;
187
- const S_IRWXG = 56;
188
- const S_IRGRP = 32;
189
- const S_IWGRP = 16;
190
- const S_IXGRP = 8;
191
- const S_IRWXO = 7;
192
- const S_IROTH = 4;
193
- const S_IWOTH = 2;
194
- const S_IXOTH = 1;
195
- const F_OK = 0;
196
- const R_OK = 4;
197
- const W_OK = 2;
198
- const X_OK = 1;
199
- const UV_FS_COPYFILE_EXCL = 1;
200
- const COPYFILE_EXCL = 1;
201
- const UV_FS_COPYFILE_FICLONE = 2;
202
- const COPYFILE_FICLONE = 2;
203
- const UV_FS_COPYFILE_FICLONE_FORCE = 4;
204
- const COPYFILE_FICLONE_FORCE = 4;
205
162
 
206
163
  const kType = Symbol('type');
207
- const kStats = Symbol('stats');
208
164
 
209
- class Dirent {
165
+ class CustomDirent {
210
166
  constructor(name, type, path) {
211
167
  this.name = name;
212
168
  this.path = path;
@@ -242,27 +198,12 @@ class Dirent {
242
198
  }
243
199
  }
244
200
 
245
- class DirentFromStats extends Dirent {
246
- constructor(name, stats, path) {
247
- super(name, null, path);
248
- this[kStats] = stats;
249
- }
250
- }
251
-
252
201
  const kEmptyObject = { __proto__: null };
253
202
 
254
203
  function defaultCloseCallback(err) {
255
204
  if (err != null) throw err;
256
205
  }
257
206
 
258
- function maybeCallback(cb) {
259
- if (typeof cb !== 'function') {
260
- throw new Error('Param is not a function!');
261
- }
262
-
263
- return cb;
264
- }
265
-
266
207
  function assertEncoding(encoding) {
267
208
  if (encoding && !Buffer.isEncoding(encoding)) {
268
209
  throw new Error('Invalid encoding!');
@@ -313,45 +254,6 @@ function closeSync(fd) {
313
254
  // (In-memory implementation doesn't require explicit closing)
314
255
  }
315
256
 
316
- /**
317
- * Asynchronously opens a file.
318
- * @param {string | Buffer | URL} path
319
- * @param {string | number} [flags='r']
320
- * @param {string | number} [mode=0o666]
321
- * @param {function(Error, number): any} [callback]
322
- * @returns {void}
323
- */
324
- function open(path, flags, mode, callback) {
325
- // handle function args (code from node)
326
- if (arguments.length < 3) {
327
- callback = flags;
328
- flags = 'r';
329
- mode = 0o666;
330
- } else if (typeof mode === 'function') {
331
- callback = mode;
332
- mode = 0o666;
333
- } else {
334
- mode = '0o666';
335
- }
336
-
337
- setTimeout(() => {
338
- path = getValidatedPath(path);
339
- const file = getFile(path);
340
- if (file !== undefined) {
341
- const fileDescriptor = Symbol(`File Descriptor for ${path}`);
342
-
343
- callback(null, fileDescriptor);
344
- } else {
345
- const error = new Error(
346
- `ENOENT: no such file or directory, fs.open call for path '${path}'`,
347
- );
348
- error.code = 'ENOENT';
349
-
350
- callback(error);
351
- }
352
- }, 0);
353
- }
354
-
355
257
  /**
356
258
  * Synchronously opens a file.
357
259
  * @param {string | Buffer | URL} path
@@ -376,47 +278,6 @@ function openSync(path, flags, mode) {
376
278
  }
377
279
  }
378
280
 
379
- /**
380
- * Asynchronously gets the stats of a file.
381
- * @param {string | Buffer | URL} path
382
- * @param {Object} [options] - Options object.
383
- * @param {boolean} [options.bigint=false]
384
- * @param {function(Error, any): any} [callback]
385
- * @returns {void}
386
- */
387
- async function stat(path, options = { bigint: false }, callback) {
388
- // handle function args (code from node)
389
- if (typeof options === 'function') {
390
- callback = options;
391
- options = kEmptyObject;
392
- }
393
-
394
- path = getValidatedPath(path);
395
-
396
- setTimeout(() => {
397
- const filesInfos = getFilesInfos();
398
- if (!filesInfos.paths.includes(path)) {
399
- const error = new Error(
400
- `ENOENT: no such file or directory, fs.stat call for path '${path}'`,
401
- );
402
- error.code = 'ENOENT';
403
- callback(error);
404
- }
405
-
406
- const file = getFile(path);
407
- const isFile = filesInfos.files.includes(path);
408
- const size = isFile ? file.content.length : 0;
409
-
410
- // generate file informations
411
- const stats = generateDefaultStat();
412
- stats.size = size;
413
- stats.isFile = () => isFile;
414
- stats.isDirectory = () => !isFile;
415
-
416
- callback(null, stats);
417
- }, 0);
418
- }
419
-
420
281
  /**
421
282
  * Synchronously retrieves the `fs.Stats`
422
283
  * for the `path`.
@@ -426,7 +287,7 @@ async function stat(path, options = { bigint: false }, callback) {
426
287
  * @param {boolean} [options.throwIfNoEntry]
427
288
  * @returns {any}
428
289
  */
429
- function statSync(path, options) {
290
+ function statSync(path, options = {}) {
430
291
  // checks final
431
292
  path = getValidatedPath(path);
432
293
 
@@ -454,46 +315,6 @@ function statSync(path, options) {
454
315
  return stats;
455
316
  }
456
317
 
457
- /**
458
- * Asynchronously reads the entire contents of a file.
459
- * @param {string | Buffer | URL | number} path
460
- * @param {Object | string} [options] - Options object or encoding string.
461
- * @param {string} [options.encoding] - The file encoding.
462
- * @param {string} [options.flag] - The flag.
463
- * @param {AbortSignal} [options.signal] - The signal.
464
- * @param {function(Error, (string | Buffer))} callback - Callback function.
465
- * @returns {void}
466
- */
467
- function readFile(path, options, callback) {
468
- // handle function args
469
- if (typeof options === 'function') {
470
- callback = options;
471
- options = { ...kEmptyObject };
472
- }
473
- callback = maybeCallback(callback || options);
474
- options = getOptions(options, { flag: 'r' });
475
- path = getValidatedPath(path);
476
-
477
- setTimeout(() => {
478
- const file = getFile(path);
479
- if (file !== undefined) {
480
- let content;
481
- if (options?.encoding === 'utf-8') {
482
- content = getFileContent(file, false);
483
- } else {
484
- content = getFileContent(file, true);
485
- }
486
- callback(null, content);
487
- } else {
488
- const error = new Error(
489
- `ENOENT: no such file or directory, fs.readFile call for path '${path}'`,
490
- );
491
- error.code = 'ENOENT';
492
- callback(error);
493
- }
494
- }, 0);
495
- }
496
-
497
318
  /**
498
319
  * Synchronously reads the entire contents of a file.
499
320
  * @param {string | Buffer | URL | number} path
@@ -502,7 +323,7 @@ function readFile(path, options, callback) {
502
323
  * @param {string} [options.flag] - The flag.
503
324
  * @returns {string | Buffer}
504
325
  */
505
- function readFileSync(path, options) {
326
+ function readFileSync(path, options = {}) {
506
327
  path = getValidatedPath(path);
507
328
  options = getOptions(options, { flag: 'r' });
508
329
 
@@ -531,7 +352,7 @@ function readFileSync(path, options) {
531
352
  * @param {boolean} [options.withFileTypes] - Whether to include file types.
532
353
  * @param {boolean} [options.recursive] - Whether to include subdirectories.
533
354
  */
534
- function readdirSync(path, options) {
355
+ function readdirSync(path, options = {}) {
535
356
  path = getValidatedPath(path);
536
357
 
537
358
  const filesInfos = getFilesInfos();
@@ -569,7 +390,7 @@ function readdirSync(path, options) {
569
390
  const name = element;
570
391
  const isFile = filesInfos.files.includes(`${path}/${element}`);
571
392
  const type = isFile ? UV_DIRENT_FILE : UV_DIRENT_DIR;
572
- return new Dirent(name, type, `${path}/${element}`);
393
+ return new CustomDirent(name, type, `${path}/${element}`);
573
394
  });
574
395
  } else {
575
396
  result = elementsInDir;
@@ -578,35 +399,126 @@ function readdirSync(path, options) {
578
399
  return result;
579
400
  }
580
401
 
581
- const promises = { readFile, stat };
402
+ // Use Cells node:fs API
403
+ const fsPolyfill = Object.create(SRC_NODE_FS);
404
+ fsPolyfill.close = close;
405
+ fsPolyfill.closeSync = closeSync;
406
+ fsPolyfill.openSync = openSync;
407
+ fsPolyfill.statSync = statSync;
408
+ fsPolyfill.lstatSync = statSync;
409
+ fsPolyfill.readFileSync = readFileSync;
410
+ fsPolyfill.readdirSync = readdirSync;
582
411
 
583
- const fs = {
584
- close,
585
- closeSync,
586
- open,
587
- openSync,
588
- stat,
589
- statSync,
590
- lstatSync: statSync,
591
- readFile,
592
- readFileSync,
593
- readdirSync,
594
- promises,
595
- };
596
-
597
- export default fs;
412
+ export default fsPolyfill;
598
413
 
599
414
  export {
600
415
  close,
601
416
  closeSync,
602
- open,
603
417
  openSync,
604
- stat,
605
418
  statSync,
606
419
  statSync as lstatSync,
607
- readFile,
608
420
  readFileSync,
609
421
  readdirSync,
610
- promises,
611
422
  };
423
+
424
+ export const {
425
+ access,
426
+ accessSync,
427
+ appendFile,
428
+ appendFileSync,
429
+ chmod,
430
+ chmodSync,
431
+ chown,
432
+ chownSync,
433
+ constants,
434
+ copyFile,
435
+ copyFileSync,
436
+ cp,
437
+ cpSync,
438
+ createReadStream,
439
+ createWriteStream,
440
+ Dir,
441
+ Dirent,
442
+ exists,
443
+ existsSync,
444
+ F_OK,
445
+ fdatasync,
446
+ fdatasyncSync,
447
+ fstat,
448
+ fstatSync,
449
+ fsync,
450
+ fsyncSync,
451
+ ftruncate,
452
+ ftruncateSync,
453
+ futimes,
454
+ futimesSync,
455
+ link,
456
+ linkSync,
457
+ lstat,
458
+ mkdir,
459
+ mkdirSync,
460
+ mkdtemp,
461
+ mkdtempSync,
462
+ O_APPEND,
463
+ O_CREAT,
464
+ O_DIRECTORY,
465
+ O_DSYNC,
466
+ O_EXCL,
467
+ O_NOCTTY,
468
+ O_NOFOLLOW,
469
+ O_NONBLOCK,
470
+ O_RDONLY,
471
+ O_RDWR,
472
+ O_SYMLINK,
473
+ O_SYNC,
474
+ O_TRUNC,
475
+ O_WRONLY,
476
+ open,
477
+ opendir,
478
+ opendirSync,
479
+ read,
480
+ readSync,
481
+ promises,
482
+ R_OK,
483
+ readdir,
484
+ readFile,
485
+ readlink,
486
+ readlinkSync,
487
+ ReadStream,
488
+ realpath,
489
+ realpathSync,
490
+ readv,
491
+ readvSync,
492
+ rename,
493
+ renameSync,
494
+ rmdir,
495
+ rmdirSync,
496
+ rm,
497
+ rmSync,
498
+ stat,
499
+ Stats,
500
+ statfs,
501
+ statfsSync,
502
+ symlink,
503
+ symlinkSync,
504
+ truncate,
505
+ truncateSync,
506
+ unlink,
507
+ unlinkSync,
508
+ unwatchFile,
509
+ utimes,
510
+ utimesSync,
511
+ W_OK,
512
+ watch,
513
+ watchFile,
514
+ write,
515
+ writeFile,
516
+ writev,
517
+ writevSync,
518
+ writeFileSync,
519
+ WriteStream,
520
+ writeSync,
521
+ X_OK,
522
+ } = SRC_NODE_FS;
523
+
612
524
  /* eslint-enable */
@@ -96,7 +96,6 @@ class PolyfillsManager {
96
96
  this.setLib('dgram', `${nodePolyfillsPath}/_empty.js`);
97
97
  this.setLib('dns', `${nodePolyfillsPath}/dns.js`);
98
98
  this.setLib('events', require.resolve('events/'));
99
- this.setLib('fs', `${nodePolyfillsPath}/fs.js`);
100
99
  this.setLib('http', require.resolve('stream-http'));
101
100
  this.setLib('http2', `${nodePolyfillsPath}/http2.js`);
102
101
  this.setLib('https', require.resolve('stream-http'));
@@ -169,6 +168,18 @@ class PolyfillsManager {
169
168
  `${externalPolyfillsPath}/azion/network-list/network-list.polyfills.js`,
170
169
  );
171
170
 
171
+ // fs temp solution for hybrid implementation (polyfill + runtime)
172
+ if (globalThis.vulcan.buildProd) {
173
+ this.setLib('fs', `${nodePolyfillsPath}/fs.js`);
174
+ this.setExternal('fs/promises', `${nodePolyfillsPath}/fs.promises.js`);
175
+ } else {
176
+ this.setExternal(
177
+ 'fs/promises',
178
+ `${externalPolyfillsPath}/fs/promises.polyfills.js`,
179
+ );
180
+ this.setExternal('fs', `${externalPolyfillsPath}/fs/fs.polyfills.js`);
181
+ }
182
+
172
183
  return {
173
184
  libs: this.libs,
174
185
  globals: this.globals,
@@ -1,9 +1,11 @@
1
1
  import { expect, it } from '@jest/globals';
2
2
  import PolyfillsManager from './index.js';
3
3
 
4
+ globalThis.vulcan = { buildProd: true };
5
+
4
6
  describe('Polyfills Manager', () => {
5
7
  it('Should return map of polyfills', () => {
6
- const expectedPolyfills = [
8
+ const expectedPolyfills = new Set([
7
9
  'accepts',
8
10
  'buffer',
9
11
  'child_process',
@@ -43,10 +45,10 @@ describe('Polyfills Manager', () => {
43
45
  'zlib',
44
46
  'next/dist/compiled/etag',
45
47
  '@fastly/http-compute-js',
46
- ];
47
- const arraylistOfAvailablePolyfills = Array.from(
48
+ ]);
49
+ const listOfAvailablePolyfills = new Set(
48
50
  PolyfillsManager.buildPolyfills().libs.keys(),
49
51
  );
50
- expect(arraylistOfAvailablePolyfills).toEqual(expectedPolyfills);
52
+ expect(listOfAvailablePolyfills).toEqual(expectedPolyfills);
51
53
  });
52
54
  });
@@ -4,6 +4,8 @@ import fs from 'fs';
4
4
  import tmp from 'tmp';
5
5
  import AzionPolyfillPlugin from './azion-polyfills.plugins.js';
6
6
 
7
+ globalThis.vulcan = { buildProd: true };
8
+
7
9
  describe('Webpack Azion Plugin', () => {
8
10
  let tmpDir;
9
11
  let tmpEntry;
@@ -4,6 +4,8 @@ import fs from 'fs';
4
4
  import tmp from 'tmp';
5
5
  import NodePolyfillPlugin from './node-polyfills.plugins.js';
6
6
 
7
+ globalThis.vulcan = { buildProd: true };
8
+
7
9
  describe('Webpack Node Plugin', () => {
8
10
  let tmpDir;
9
11
  let tmpEntry;
@@ -416,7 +416,7 @@ class Dispatcher {
416
416
  typeof removePathPrefix === 'string' &&
417
417
  removePathPrefix !== ''
418
418
  ? `${removePathPrefix}`
419
- : `''`;
419
+ : `""`;
420
420
 
421
421
  copyFilesToFS(injectionDirs, prefix);
422
422
  // eslint-disable-next-line
@@ -547,6 +547,18 @@ class Dispatcher {
547
547
  feedback.postbuild.info('Running postbuild actions...');
548
548
  await postbuild(buildConfig);
549
549
  }
550
+
551
+ // fs temp solution for hybrid implementation (polyfill + runtime)
552
+ if (this.useNodePolyfills) {
553
+ const outPath = '.edge/worker.js';
554
+ const content = readFileSync(outPath, 'utf-8');
555
+ let codeToAdd = '';
556
+ if (globalThis.vulcan.buildProd) {
557
+ codeToAdd = 'import SRC_NODE_FS from "node:fs";\n';
558
+ }
559
+ const newContent = `${codeToAdd}${content}`;
560
+ writeFileSync(outPath, newContent);
561
+ }
550
562
  }
551
563
  // manifest
552
564
  const azionConfigPath = await getAzionConfigPath();
@@ -0,0 +1,90 @@
1
+ /* eslint-disable */
2
+
3
+ import fs from 'fs';
4
+
5
+ const localFs = {};
6
+
7
+ export const {
8
+ open,
9
+ openSync,
10
+ close,
11
+ closeSync,
12
+ stat,
13
+ statSync,
14
+ lstat,
15
+ lstatSync,
16
+ readFile,
17
+ readFileSync,
18
+ readdir,
19
+ readdirSync,
20
+ mkdir,
21
+ rmdir,
22
+ copyFile,
23
+ cp,
24
+ Dir,
25
+ Dirent,
26
+ Stats,
27
+ constants,
28
+ F_OK,
29
+ O_APPEND,
30
+ O_CREAT,
31
+ O_DIRECTORY,
32
+ O_DSYNC,
33
+ O_EXCL,
34
+ O_NOCTTY,
35
+ O_NOFOLLOW,
36
+ O_NONBLOCK,
37
+ O_RDONLY,
38
+ O_RDWR,
39
+ O_SYMLINK,
40
+ O_SYNC,
41
+ O_TRUNC,
42
+ O_WRONLY,
43
+ R_OK,
44
+ W_OK,
45
+ X_OK,
46
+ } = fs;
47
+
48
+ export { promises } from 'fs';
49
+ localFs.promises = fs.promises;
50
+
51
+ localFs.open = open;
52
+ localFs.openSync = openSync;
53
+ localFs.close = close;
54
+ localFs.closeSync = closeSync;
55
+ localFs.stat = stat;
56
+ localFs.statSync = statSync;
57
+ localFs.lstat = lstat;
58
+ localFs.lstatSync = lstatSync;
59
+ localFs.readFile = readFile;
60
+ localFs.readFileSync = readFileSync;
61
+ localFs.readdir = readdir;
62
+ localFs.readdirSync = readdirSync;
63
+ localFs.mkdir = mkdir;
64
+ localFs.rmdir = rmdir;
65
+ localFs.copyFile = copyFile;
66
+ localFs.cp = cp;
67
+ localFs.Dir = Dir;
68
+ localFs.Dirent = Dirent;
69
+ localFs.Stats = Stats;
70
+ localFs.constants = constants;
71
+ localFs.F_OK = F_OK;
72
+ localFs.O_APPEND = O_APPEND;
73
+ localFs.O_CREAT = O_CREAT;
74
+ localFs.O_DIRECTORY = O_DIRECTORY;
75
+ localFs.O_DSYNC = O_DSYNC;
76
+ localFs.O_EXCL = O_EXCL;
77
+ localFs.O_NOCTTY = O_NOCTTY;
78
+ localFs.O_NOFOLLOW = O_NOFOLLOW;
79
+ localFs.O_NONBLOCK = O_NONBLOCK;
80
+ localFs.O_RDONLY = O_RDONLY;
81
+ localFs.O_RDWR = O_RDWR;
82
+ localFs.O_SYMLINK = O_SYMLINK;
83
+ localFs.O_SYNC = O_SYNC;
84
+ localFs.O_TRUNC = O_TRUNC;
85
+ localFs.O_WRONLY = O_WRONLY;
86
+ localFs.R_OK = R_OK;
87
+ localFs.W_OK = W_OK;
88
+ localFs.X_OK = X_OK;
89
+
90
+ export default localFs;
@@ -0,0 +1,3 @@
1
+ import fsContext from './fs.context.js';
2
+
3
+ export default { fsContext };
@@ -0,0 +1,220 @@
1
+ /* eslint-disable */
2
+ import { join } from 'path-browserify';
3
+ import promises from './promises.polyfills.js';
4
+
5
+ const localFs = {};
6
+
7
+ const BUILD_PATH_PREFIX = '.edge/storage';
8
+
9
+ function open(path, ...args) {
10
+ path = join(BUILD_PATH_PREFIX, path);
11
+ return FS_CONTEXT.open(path, ...args);
12
+ }
13
+
14
+ function openSync(path, ...args) {
15
+ path = join(BUILD_PATH_PREFIX, path);
16
+ return FS_CONTEXT.openSync(path, ...args);
17
+ }
18
+
19
+ function close(...args) {
20
+ return FS_CONTEXT.close(...args);
21
+ }
22
+
23
+ function closeSync(...args) {
24
+ return FS_CONTEXT.closeSync(...args);
25
+ }
26
+
27
+ function stat(path, ...args) {
28
+ path = join(BUILD_PATH_PREFIX, path);
29
+ return FS_CONTEXT.stat(path, ...args);
30
+ }
31
+
32
+ function statSync(path, ...args) {
33
+ path = join(BUILD_PATH_PREFIX, path);
34
+ return FS_CONTEXT.statSync(path, ...args);
35
+ }
36
+
37
+ function lstat(path, ...args) {
38
+ path = join(BUILD_PATH_PREFIX, path);
39
+ return FS_CONTEXT.lstat(path, ...args);
40
+ }
41
+
42
+ function lstatSync(path, ...args) {
43
+ path = join(BUILD_PATH_PREFIX, path);
44
+ return FS_CONTEXT.lstatSync(path, ...args);
45
+ }
46
+
47
+ function readFile(path, ...args) {
48
+ path = join(BUILD_PATH_PREFIX, path);
49
+ return FS_CONTEXT.readFile(path, ...args);
50
+ }
51
+
52
+ function readFileSync(path, ...args) {
53
+ path = join(BUILD_PATH_PREFIX, path);
54
+ return FS_CONTEXT.readFileSync(path, ...args);
55
+ }
56
+
57
+ function readdir(path, ...args) {
58
+ path = join(BUILD_PATH_PREFIX, path);
59
+ return FS_CONTEXT.readdir(path, ...args);
60
+ }
61
+
62
+ function readdirSync(path, ...args) {
63
+ path = join(BUILD_PATH_PREFIX, path);
64
+ return FS_CONTEXT.readdirSync(path, ...args);
65
+ }
66
+
67
+ function mkdir(path, ...args) {
68
+ path = join(BUILD_PATH_PREFIX, path);
69
+ return FS_CONTEXT.mkdir(path, ...args);
70
+ }
71
+
72
+ function rmdir(path, ...args) {
73
+ path = join(BUILD_PATH_PREFIX, path);
74
+ return FS_CONTEXT.rmdir(path, ...args);
75
+ }
76
+
77
+ function copyFile(src, dest, ...args) {
78
+ src = `${BUILD_PATH_PREFIX}/${src}`;
79
+ dest = `${BUILD_PATH_PREFIX}/${dest}`;
80
+ return FS_CONTEXT.copyFile(src, dest, ...args);
81
+ }
82
+
83
+ function cp(src, dest, ...args) {
84
+ src = `${BUILD_PATH_PREFIX}/${src}`;
85
+ dest = `${BUILD_PATH_PREFIX}/${dest}`;
86
+ return FS_CONTEXT.cp(src, dest, ...args);
87
+ }
88
+
89
+ const constants = {
90
+ COPYFILE_EXCL: 1,
91
+ COPYFILE_FICLONE: 2,
92
+ COPYFILE_FICLONE_FORCE: 4,
93
+ F_OK: 0,
94
+ O_APPEND: 8,
95
+ O_CREAT: 512,
96
+ O_DIRECTORY: 1048576,
97
+ O_DSYNC: 4194304,
98
+ O_EXCL: 2048,
99
+ O_NOCTTY: 131072,
100
+ O_NOFOLLOW: 256,
101
+ O_NONBLOCK: 4,
102
+ O_RDONLY: 0,
103
+ O_RDWR: 2,
104
+ O_SYMLINK: 2097152,
105
+ O_SYNC: 128,
106
+ O_TRUNC: 1024,
107
+ O_WRONLY: 1,
108
+ R_OK: 4,
109
+ S_IRGRP: 32,
110
+ S_IROTH: 4,
111
+ S_IRUSR: 256,
112
+ S_IWGRP: 16,
113
+ S_IWOTH: 2,
114
+ S_IWUSR: 128,
115
+ S_IXGRP: 8,
116
+ S_IXOTH: 1,
117
+ S_IXUSR: 64,
118
+ UV_FS_COPYFILE_EXCL: 1,
119
+ UV_FS_COPYFILE_FICLONE: 2,
120
+ UV_FS_COPYFILE_FICLONE_FORCE: 4,
121
+ W_OK: 2,
122
+ X_OK: 1,
123
+ };
124
+ const F_OK = 0;
125
+ const O_APPEND = 8;
126
+ const O_CREAT = 512;
127
+ const O_DIRECTORY = 1048576;
128
+ const O_DSYNC = 4194304;
129
+ const O_EXCL = 2048;
130
+ const O_NOCTTY = 131072;
131
+ const O_NOFOLLOW = 256;
132
+ const O_NONBLOCK = 4;
133
+ const O_RDONLY = 0;
134
+ const O_RDWR = 2;
135
+ const O_SYMLINK = 2097152;
136
+ const O_SYNC = 128;
137
+ const O_TRUNC = 1024;
138
+ const O_WRONLY = 1;
139
+ const R_OK = 4;
140
+ const W_OK = 2;
141
+ const X_OK = 1;
142
+
143
+ export {
144
+ promises,
145
+ open,
146
+ openSync,
147
+ close,
148
+ closeSync,
149
+ stat,
150
+ statSync,
151
+ lstat,
152
+ lstatSync,
153
+ readFile,
154
+ readFileSync,
155
+ readdir,
156
+ readdirSync,
157
+ mkdir,
158
+ rmdir,
159
+ copyFile,
160
+ cp,
161
+ constants,
162
+ F_OK,
163
+ O_APPEND,
164
+ O_CREAT,
165
+ O_DIRECTORY,
166
+ O_DSYNC,
167
+ O_EXCL,
168
+ O_NOCTTY,
169
+ O_NOFOLLOW,
170
+ O_NONBLOCK,
171
+ O_RDONLY,
172
+ O_RDWR,
173
+ O_SYMLINK,
174
+ O_SYNC,
175
+ O_TRUNC,
176
+ O_WRONLY,
177
+ R_OK,
178
+ W_OK,
179
+ X_OK,
180
+ };
181
+
182
+ localFs.promises = promises;
183
+
184
+ localFs.open = open;
185
+ localFs.openSync = openSync;
186
+ localFs.close = close;
187
+ localFs.closeSync = closeSync;
188
+ localFs.stat = stat;
189
+ localFs.statSync = statSync;
190
+ localFs.lstat = lstat;
191
+ localFs.lstatSync = lstatSync;
192
+ localFs.readFile = readFile;
193
+ localFs.readFileSync = readFileSync;
194
+ localFs.readdir = readdir;
195
+ localFs.readdirSync = readdirSync;
196
+ localFs.mkdir = mkdir;
197
+ localFs.rmdir = rmdir;
198
+ localFs.copyFile = copyFile;
199
+ localFs.cp = cp;
200
+ localFs.constants = constants;
201
+ localFs.F_OK = F_OK;
202
+ localFs.O_APPEND = O_APPEND;
203
+ localFs.O_CREAT = O_CREAT;
204
+ localFs.O_DIRECTORY = O_DIRECTORY;
205
+ localFs.O_DSYNC = O_DSYNC;
206
+ localFs.O_EXCL = O_EXCL;
207
+ localFs.O_NOCTTY = O_NOCTTY;
208
+ localFs.O_NOFOLLOW = O_NOFOLLOW;
209
+ localFs.O_NONBLOCK = O_NONBLOCK;
210
+ localFs.O_RDONLY = O_RDONLY;
211
+ localFs.O_RDWR = O_RDWR;
212
+ localFs.O_SYMLINK = O_SYMLINK;
213
+ localFs.O_SYNC = O_SYNC;
214
+ localFs.O_TRUNC = O_TRUNC;
215
+ localFs.O_WRONLY = O_WRONLY;
216
+ localFs.R_OK = R_OK;
217
+ localFs.W_OK = W_OK;
218
+ localFs.X_OK = X_OK;
219
+
220
+ export default localFs;
@@ -0,0 +1,8 @@
1
+ /* eslint-disable import/prefer-default-export */
2
+ /**
3
+ * We are not exporting the fs.polyfill.js from this structure due to the context definition in runtime.env.js.
4
+ * As we are proxying the Node.js fs lib, it is not possible to export the fs.polyfill.js file.
5
+ */
6
+ import fsContext from './context/fs.context.js';
7
+
8
+ export { fsContext };
@@ -0,0 +1,115 @@
1
+ /* eslint-disable */
2
+ import { join } from 'path-browserify';
3
+
4
+ const localFsPromises = {};
5
+
6
+ const BUILD_PATH_PREFIX = '.edge/storage';
7
+
8
+ async function open(path, ...args) {
9
+ path = join(BUILD_PATH_PREFIX, path);
10
+ return FS_CONTEXT.promises.open(path, ...args);
11
+ }
12
+
13
+ async function stat(path, ...args) {
14
+ path = join(BUILD_PATH_PREFIX, path);
15
+ return FS_CONTEXT.promises.stat(path, ...args);
16
+ }
17
+
18
+ async function lstat(path, ...args) {
19
+ path = join(BUILD_PATH_PREFIX, path);
20
+ return FS_CONTEXT.promises.lstat(path, ...args);
21
+ }
22
+
23
+ async function readFile(path, ...args) {
24
+ path = join(BUILD_PATH_PREFIX, path);
25
+ return FS_CONTEXT.promises.readFile(path, ...args);
26
+ }
27
+
28
+ async function readdir(path, ...args) {
29
+ path = join(BUILD_PATH_PREFIX, path);
30
+ return FS_CONTEXT.promises.readdir(path, ...args);
31
+ }
32
+
33
+ async function mkdir(path, ...args) {
34
+ path = join(BUILD_PATH_PREFIX, path);
35
+ return FS_CONTEXT.promises.mkdir(path, ...args);
36
+ }
37
+
38
+ async function rmdir(path, ...args) {
39
+ path = join(BUILD_PATH_PREFIX, path);
40
+ return FS_CONTEXT.promises.rmdir(path, ...args);
41
+ }
42
+
43
+ async function copyFile(src, dest, ...args) {
44
+ src = `${BUILD_PATH_PREFIX}/${src}`;
45
+ dest = `${BUILD_PATH_PREFIX}/${dest}`;
46
+ return FS_CONTEXT.promises.copyFile(src, dest, ...args);
47
+ }
48
+
49
+ async function cp(src, dest, ...args) {
50
+ src = `${BUILD_PATH_PREFIX}/${src}`;
51
+ dest = `${BUILD_PATH_PREFIX}/${dest}`;
52
+ return FS_CONTEXT.promises.cp(src, dest, ...args);
53
+ }
54
+
55
+ const constants = {
56
+ COPYFILE_EXCL: 1,
57
+ COPYFILE_FICLONE: 2,
58
+ COPYFILE_FICLONE_FORCE: 4,
59
+ F_OK: 0,
60
+ O_APPEND: 8,
61
+ O_CREAT: 512,
62
+ O_DIRECTORY: 1048576,
63
+ O_DSYNC: 4194304,
64
+ O_EXCL: 2048,
65
+ O_NOCTTY: 131072,
66
+ O_NOFOLLOW: 256,
67
+ O_NONBLOCK: 4,
68
+ O_RDONLY: 0,
69
+ O_RDWR: 2,
70
+ O_SYMLINK: 2097152,
71
+ O_SYNC: 128,
72
+ O_TRUNC: 1024,
73
+ O_WRONLY: 1,
74
+ R_OK: 4,
75
+ S_IRGRP: 32,
76
+ S_IROTH: 4,
77
+ S_IRUSR: 256,
78
+ S_IWGRP: 16,
79
+ S_IWOTH: 2,
80
+ S_IWUSR: 128,
81
+ S_IXGRP: 8,
82
+ S_IXOTH: 1,
83
+ S_IXUSR: 64,
84
+ UV_FS_COPYFILE_EXCL: 1,
85
+ UV_FS_COPYFILE_FICLONE: 2,
86
+ UV_FS_COPYFILE_FICLONE_FORCE: 4,
87
+ W_OK: 2,
88
+ X_OK: 1,
89
+ };
90
+
91
+ export {
92
+ open,
93
+ stat,
94
+ lstat,
95
+ readFile,
96
+ readdir,
97
+ mkdir,
98
+ rmdir,
99
+ copyFile,
100
+ cp,
101
+ constants,
102
+ };
103
+
104
+ localFsPromises.open = open;
105
+ localFsPromises.stat = stat;
106
+ localFsPromises.lstat = lstat;
107
+ localFsPromises.readFile = readFile;
108
+ localFsPromises.readdir = readdir;
109
+ localFsPromises.mkdir = mkdir;
110
+ localFsPromises.rmdir = rmdir;
111
+ localFsPromises.copyFile = copyFile;
112
+ localFsPromises.cp = cp;
113
+ localFsPromises.constants = constants;
114
+
115
+ export default localFsPromises;
@@ -4,6 +4,7 @@ import { AsyncHooksContext } from './async-hooks/index.js';
4
4
  import { StorageContext } from './azion/storage/index.js';
5
5
  import EnvVarsContext from './azion/env-vars/index.js';
6
6
  import NetworkListContext from './azion/network-list/index.js';
7
+ import { fsContext } from './fs/index.js';
7
8
 
8
9
  export {
9
10
  fetchContext,
@@ -12,4 +13,5 @@ export {
12
13
  StorageContext,
13
14
  EnvVarsContext,
14
15
  NetworkListContext,
16
+ fsContext,
15
17
  };
@@ -7,6 +7,7 @@ import {
7
7
  StorageContext,
8
8
  EnvVarsContext,
9
9
  NetworkListContext,
10
+ fsContext,
10
11
  } from './polyfills/index.js';
11
12
  import FirewallEventContext from './polyfills/azion/firewall-event/index.js';
12
13
 
@@ -83,6 +84,9 @@ function runtime(code, isFirewallEvent = false) {
83
84
  // Network List Context
84
85
  context.NETWORK_LIST_CONTEXT = NetworkListContext;
85
86
 
87
+ // FS Context
88
+ context.FS_CONTEXT = fsContext;
89
+
86
90
  return context;
87
91
  };
88
92
 
@@ -0,0 +1,50 @@
1
+ const AzionConfig = {
2
+ origin: [
3
+ {
4
+ name: 'origin-storage-default',
5
+ type: 'object_storage',
6
+ },
7
+ ],
8
+ rules: {
9
+ request: [
10
+ {
11
+ name: 'Set Storage Origin for All Requests',
12
+ match: '^\\/',
13
+ behavior: {
14
+ setOrigin: {
15
+ name: 'origin-storage-default',
16
+ type: 'object_storage',
17
+ },
18
+ },
19
+ },
20
+ {
21
+ name: 'Deliver Static Assets',
22
+ match:
23
+ '.(css|js|ttf|woff|woff2|pdf|svg|jpg|jpeg|gif|bmp|png|ico|mp4|json|xml|html)$',
24
+ behavior: {
25
+ setOrigin: {
26
+ name: 'origin-storage-default',
27
+ type: 'object_storage',
28
+ },
29
+ deliver: true,
30
+ },
31
+ },
32
+ {
33
+ name: 'Redirect to index.html',
34
+ match: '.*/$',
35
+ behavior: {
36
+ rewrite: '${uri}index.html',
37
+ },
38
+ },
39
+ {
40
+ name: 'Redirect to index.html for Subpaths',
41
+ match: '^(?!.*\\/$)(?![\\s\\S]*\\.[a-zA-Z0-9]+$).*',
42
+ behavior: {
43
+ rewrite: '${uri}/index.html',
44
+ },
45
+ },
46
+ ],
47
+ },
48
+ };
49
+
50
+ export default AzionConfig;
@@ -0,0 +1,10 @@
1
+ /**
2
+ * Config to be used in build context.
3
+ */
4
+ const config = {
5
+ builder: 'webpack',
6
+ useNodePolyfills: false,
7
+ custom: {},
8
+ };
9
+
10
+ export default config;
@@ -0,0 +1,16 @@
1
+ import { mountSSG, ErrorHTML } from '#edge';
2
+ /**
3
+ * Handles the 'fetch' event.
4
+ * @param {any} event - The fetch event.
5
+ * @returns {Promise<Response>} The response for the request.
6
+ */
7
+ async function handler(event) {
8
+ try {
9
+ const myApp = await mountSSG(event.request.url);
10
+ return myApp;
11
+ } catch (error) {
12
+ return ErrorHTML('404');
13
+ }
14
+ }
15
+
16
+ export default handler;
@@ -0,0 +1,21 @@
1
+ import { rm } from 'fs/promises';
2
+ import { exec, getPackageManager, copyDirectory } from '#utils';
3
+
4
+ const packageManager = await getPackageManager();
5
+
6
+ /**
7
+ * Runs custom prebuild actions
8
+ */
9
+ async function prebuild() {
10
+ const newOutDir = '.edge/storage';
11
+ const outDir = 'build';
12
+
13
+ await exec(`${packageManager} run build`, 'Docusaurus', true);
14
+
15
+ // move files to vulcan default path
16
+ copyDirectory(outDir, newOutDir);
17
+
18
+ rm(outDir, { recursive: true, force: true });
19
+ }
20
+
21
+ export default prebuild;
@@ -11,6 +11,7 @@ describe('getPresetsList utils', () => {
11
11
  const expectedOutput = [
12
12
  'angular',
13
13
  'astro',
14
+ 'docusaurus',
14
15
  'eleventy',
15
16
  'emscripten',
16
17
  'gatsby',
@@ -75,6 +76,7 @@ describe('getPresetsList utils', () => {
75
76
  const expectedResult = [
76
77
  'Angular (Deliver)',
77
78
  'Astro (Deliver)',
79
+ 'Docusaurus (Deliver)',
78
80
  'Eleventy (Deliver)',
79
81
  'Emscripten (Compute)',
80
82
  'Gatsby (Deliver)',
@@ -102,6 +104,7 @@ describe('getPresetsList utils', () => {
102
104
  'typescript',
103
105
  'angular',
104
106
  'astro',
107
+ 'docusaurus',
105
108
  'eleventy',
106
109
  'emscripten',
107
110
  'hexo',
@@ -120,6 +123,7 @@ describe('getPresetsList utils', () => {
120
123
  ['Deliver'],
121
124
  ['Deliver'],
122
125
  ['Deliver'],
126
+ ['Deliver'],
123
127
  ['Compute'],
124
128
  ['Deliver'],
125
129
  ['Deliver'],
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "edge-functions",
3
3
  "type": "module",
4
- "version": "2.10.0",
4
+ "version": "2.11.0-stage.2",
5
5
  "description": "Tool to launch and build JavaScript/Frameworks. This tool automates polyfills for Edge Computing and assists in creating Workers, notably for the Azion platform.",
6
6
  "main": "lib/main.js",
7
7
  "bin": {
@@ -24,7 +24,7 @@
24
24
  "e2e:start": "yarn submodule:update && tests/scripts/start-e2e-env.sh",
25
25
  "e2e:stop": "tests/scripts/stop-e2e-env.sh",
26
26
  "e2e:destroy": "tests/scripts/destroy-e2e-env.sh",
27
- "test:e2e": "yarn e2e:start && jest --maxWorkers 1 tests/e2e/ --json --outputFile e2e_results.json && yarn e2e:reports && yarn e2e:stop; yarn task:reports",
27
+ "test:e2e": "yarn e2e:start && jest --maxWorkers 1 tests/e2e/ --json --outputFile e2e_results.json && yarn e2e:stop; yarn task:reports",
28
28
  "prepare": "husky install",
29
29
  "submodule:update": "git submodule update --init --recursive && git submodule foreach git pull origin main"
30
30
  },