@netlify/edge-bundler 3.1.1 → 4.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -5,7 +5,6 @@ import { platform, env } from 'process';
5
5
  import { PassThrough } from 'stream';
6
6
  import nock from 'nock';
7
7
  import semver from 'semver';
8
- import { spy } from 'sinon';
9
8
  import tmp from 'tmp-promise';
10
9
  import { test, expect } from 'vitest';
11
10
  import { DenoBridge, DENO_VERSION_RANGE } from './bridge.js';
@@ -27,12 +26,8 @@ const getMockDenoBridge = function (tmpDir, mockBinaryOutput) {
27
26
  nock('https://dl.deno.land')
28
27
  .get(`/release/v${latestVersion}/deno-${target}.zip`)
29
28
  .reply(200, () => data);
30
- const beforeDownload = spy();
31
- const afterDownload = spy();
32
29
  return new DenoBridge({
33
30
  cacheDirectory: tmpDir.path,
34
- onBeforeDownload: beforeDownload,
35
- onAfterDownload: afterDownload,
36
31
  useGlobal: false,
37
32
  });
38
33
  };
@@ -87,7 +87,6 @@ test('Uses the vendored eszip module instead of fetching it from deno.land', asy
87
87
  basePath: fixturesDir,
88
88
  featureFlags: {
89
89
  edge_functions_produce_eszip: true,
90
- edge_functions_use_vendored_eszip: true,
91
90
  },
92
91
  importMaps: [
93
92
  {
@@ -2,12 +2,12 @@ import { DenoBridge } from './bridge.js';
2
2
  import { EdgeFunction } from './edge_function.js';
3
3
  import { ImportMap } from './import_map.js';
4
4
  import { Logger } from './logger.js';
5
- export declare const enum Mode {
6
- BeforeCache = "before-cache",
7
- AfterCache = "after-cache"
5
+ export declare const enum Cache {
6
+ Off = "off",
7
+ Manual = "manual"
8
8
  }
9
9
  export interface FunctionConfig {
10
- mode?: Mode;
10
+ cache?: Cache;
11
11
  path?: string;
12
12
  }
13
13
  export declare const getFunctionConfig: (func: EdgeFunction, importMap: ImportMap, deno: DenoBridge, log: Logger) => Promise<FunctionConfig>;
@@ -3,7 +3,6 @@ import { join } from 'path';
3
3
  import { pathToFileURL } from 'url';
4
4
  import tmp from 'tmp-promise';
5
5
  import { getPackagePath } from './package_json.js';
6
- // eslint-disable-next-line no-shadow
7
6
  var ConfigExitCode;
8
7
  (function (ConfigExitCode) {
9
8
  ConfigExitCode[ConfigExitCode["Success"] = 0] = "Success";
@@ -2,9 +2,8 @@ import { promises as fs } from 'fs';
2
2
  import { join, resolve } from 'path';
3
3
  import { pathToFileURL } from 'url';
4
4
  import { deleteAsync } from 'del';
5
- import { stub } from 'sinon';
6
5
  import tmp from 'tmp-promise';
7
- import { test, expect } from 'vitest';
6
+ import { test, expect, vi } from 'vitest';
8
7
  import { fixturesDir } from '../test/util.js';
9
8
  import { DenoBridge } from './bridge.js';
10
9
  import { bundle } from './bundler.js';
@@ -101,8 +100,8 @@ test('`getFunctionConfig` extracts configuration properties from function file',
101
100
  ];
102
101
  for (const func of functions) {
103
102
  const logger = {
104
- user: stub().resolves(),
105
- system: stub().resolves(),
103
+ user: vi.fn().mockResolvedValue(null),
104
+ system: vi.fn().mockResolvedValue(null),
106
105
  };
107
106
  const path = join(tmpDir, `${func.name}.js`);
108
107
  await fs.writeFile(path, func.source);
@@ -112,10 +111,10 @@ test('`getFunctionConfig` extracts configuration properties from function file',
112
111
  }, new ImportMap([importMapFile]), deno, logger);
113
112
  expect(config).toEqual(func.expectedConfig);
114
113
  if (func.userLog) {
115
- expect(logger.user.firstCall.firstArg).toMatch(func.userLog);
114
+ expect(logger.user).toHaveBeenNthCalledWith(1, expect.stringMatching(func.userLog));
116
115
  }
117
116
  else {
118
- expect(logger.user.callCount).toBe(0);
117
+ expect(logger.user).not.toHaveBeenCalled();
119
118
  }
120
119
  }
121
120
  await deleteAsync(tmpDir, { force: true });
@@ -1,7 +1,7 @@
1
1
  import { FunctionConfig } from './config.js';
2
2
  interface BaseDeclaration {
3
+ cache?: string;
3
4
  function: string;
4
- mode?: string;
5
5
  name?: string;
6
6
  }
7
7
  declare type DeclarationWithPath = BaseDeclaration & {
@@ -2,7 +2,6 @@ const defaultFlags = {
2
2
  edge_functions_cache_deno_dir: false,
3
3
  edge_functions_config_export: false,
4
4
  edge_functions_produce_eszip: false,
5
- edge_functions_use_vendored_eszip: false,
6
5
  };
7
6
  const getFlags = (input = {}, flags = defaultFlags) => Object.entries(flags).reduce((result, [key, defaultValue]) => ({
8
7
  ...result,
@@ -13,5 +13,5 @@ interface BundleESZIPOptions {
13
13
  functions: EdgeFunction[];
14
14
  importMap: ImportMap;
15
15
  }
16
- declare const bundleESZIP: ({ basePath, buildID, debug, deno, distDirectory, featureFlags, functions, importMap, }: BundleESZIPOptions) => Promise<Bundle>;
16
+ declare const bundleESZIP: ({ basePath, buildID, debug, deno, distDirectory, functions, importMap, }: BundleESZIPOptions) => Promise<Bundle>;
17
17
  export { bundleESZIP as bundle };
@@ -2,7 +2,7 @@ import { join } from 'path';
2
2
  import { wrapBundleError } from '../bundle_error.js';
3
3
  import { getPackagePath } from '../package_json.js';
4
4
  import { getFileHash } from '../utils/sha256.js';
5
- const bundleESZIP = async ({ basePath, buildID, debug, deno, distDirectory, featureFlags, functions, importMap, }) => {
5
+ const bundleESZIP = async ({ basePath, buildID, debug, deno, distDirectory, functions, importMap, }) => {
6
6
  const extension = '.eszip';
7
7
  const destPath = join(distDirectory, `${buildID}${extension}`);
8
8
  const { bundler, importMap: bundlerImportMap } = getESZIPPaths();
@@ -18,9 +18,7 @@ const bundleESZIP = async ({ basePath, buildID, debug, deno, distDirectory, feat
18
18
  }
19
19
  // To actually vendor the eszip module, we need to supply the import map that
20
20
  // redirects `https://deno.land/` URLs to the local files.
21
- if (featureFlags.edge_functions_use_vendored_eszip) {
22
- flags.push(`--import-map=${bundlerImportMap}`);
23
- }
21
+ flags.push(`--import-map=${bundlerImportMap}`);
24
22
  try {
25
23
  await deno.run(['run', ...flags, bundler, JSON.stringify(payload)], { pipeOutput: true });
26
24
  }
@@ -1,5 +1,4 @@
1
- import { stub } from 'sinon';
2
- import { afterEach, test, expect } from 'vitest';
1
+ import { afterEach, test, expect, vi } from 'vitest';
3
2
  import { getLogger } from './logger.js';
4
3
  const consoleLog = console.log;
5
4
  const noopLogger = () => {
@@ -10,36 +9,36 @@ afterEach(() => {
10
9
  console.log = consoleLog;
11
10
  });
12
11
  test('Prints user logs to stdout', () => {
13
- const mockConsoleLog = stub();
12
+ const mockConsoleLog = vi.fn();
14
13
  console.log = mockConsoleLog;
15
14
  const logger1 = getLogger(noopLogger, true);
16
15
  const logger2 = getLogger(noopLogger, false);
17
16
  logger1.user('Hello with `debug: true`');
18
17
  logger2.user('Hello with `debug: false`');
19
- expect(mockConsoleLog.callCount).toBe(2);
20
- expect(mockConsoleLog.firstCall.firstArg).toBe('Hello with `debug: true`');
21
- expect(mockConsoleLog.secondCall.firstArg).toBe('Hello with `debug: false`');
18
+ expect(mockConsoleLog).toHaveBeenCalledTimes(2);
19
+ expect(mockConsoleLog).toHaveBeenNthCalledWith(1, 'Hello with `debug: true`');
20
+ expect(mockConsoleLog).toHaveBeenNthCalledWith(2, 'Hello with `debug: false`');
22
21
  });
23
22
  test('Prints system logs to the system logger provided', () => {
24
- const mockSystemLog = stub();
25
- const mockConsoleLog = stub();
23
+ const mockSystemLog = vi.fn();
24
+ const mockConsoleLog = vi.fn();
26
25
  console.log = mockSystemLog;
27
26
  const logger1 = getLogger(mockSystemLog, true);
28
27
  const logger2 = getLogger(mockSystemLog, false);
29
28
  logger1.system('Hello with `debug: true`');
30
29
  logger2.system('Hello with `debug: false`');
31
- expect(mockConsoleLog.callCount).toBe(0);
32
- expect(mockSystemLog.callCount).toBe(2);
33
- expect(mockSystemLog.firstCall.firstArg).toBe('Hello with `debug: true`');
34
- expect(mockSystemLog.secondCall.firstArg).toBe('Hello with `debug: false`');
30
+ expect(mockConsoleLog).toHaveBeenCalledTimes(0);
31
+ expect(mockSystemLog).toHaveBeenCalledTimes(2);
32
+ expect(mockSystemLog).toHaveBeenNthCalledWith(1, 'Hello with `debug: true`');
33
+ expect(mockSystemLog).toHaveBeenNthCalledWith(2, 'Hello with `debug: false`');
35
34
  });
36
35
  test('Prints system logs to stdout if there is no system logger provided and `debug` is enabled', () => {
37
- const mockConsoleLog = stub();
36
+ const mockConsoleLog = vi.fn();
38
37
  console.log = mockConsoleLog;
39
38
  const logger1 = getLogger(undefined, true);
40
39
  const logger2 = getLogger(undefined, false);
41
40
  logger1.system('Hello with `debug: true`');
42
41
  logger2.system('Hello with `debug: false`');
43
- expect(mockConsoleLog.callCount).toBe(1);
44
- expect(mockConsoleLog.firstCall.firstArg).toBe('Hello with `debug: true`');
42
+ expect(mockConsoleLog).toHaveBeenCalledTimes(1);
43
+ expect(mockConsoleLog).toHaveBeenNthCalledWith(1, 'Hello with `debug: true`');
45
44
  });
@@ -5,9 +5,8 @@ import { platform } from 'process';
5
5
  import { PassThrough } from 'stream';
6
6
  import nock from 'nock';
7
7
  import semver from 'semver';
8
- import { spy } from 'sinon';
9
8
  import tmp from 'tmp-promise';
10
- import { test, expect } from 'vitest';
9
+ import { test, expect, vi } from 'vitest';
11
10
  import { DenoBridge, DENO_VERSION_RANGE } from './bridge.js';
12
11
  import { getPlatformTarget } from './platform.js';
13
12
  const require = createRequire(import.meta.url);
@@ -27,8 +26,8 @@ test('Downloads the Deno CLI on demand and caches it for subsequent calls', asyn
27
26
  .get(`/release/v${latestVersion}/deno-${target}.zip`)
28
27
  .reply(200, () => data);
29
28
  const tmpDir = await tmp.dir();
30
- const beforeDownload = spy();
31
- const afterDownload = spy();
29
+ const beforeDownload = vi.fn();
30
+ const afterDownload = vi.fn();
32
31
  const deno = new DenoBridge({
33
32
  cacheDirectory: tmpDir.path,
34
33
  onBeforeDownload: beforeDownload,
@@ -42,7 +41,7 @@ test('Downloads the Deno CLI on demand and caches it for subsequent calls', asyn
42
41
  expect(downloadMock.isDone()).toBe(true);
43
42
  expect((_c = output1 === null || output1 === void 0 ? void 0 : output1.stdout) !== null && _c !== void 0 ? _c : '').toMatch(expectedOutput);
44
43
  expect((_d = output2 === null || output2 === void 0 ? void 0 : output2.stdout) !== null && _d !== void 0 ? _d : '').toMatch(expectedOutput);
45
- expect(beforeDownload.callCount).toBe(1);
46
- expect(afterDownload.callCount).toBe(1);
44
+ expect(beforeDownload).toHaveBeenCalledTimes(1);
45
+ expect(afterDownload).toHaveBeenCalledTimes(1);
47
46
  await fs.promises.rmdir(tmpDir.path, { recursive: true });
48
47
  });
@@ -18,7 +18,7 @@ const generateManifest = ({ bundles = [], declarations = [], functions }) => {
18
18
  name: declaration.name,
19
19
  pattern: serializablePattern,
20
20
  };
21
- if (declaration.mode === "after-cache" /* Mode.AfterCache */) {
21
+ if (declaration.cache === "manual" /* Cache.Manual */) {
22
22
  postCacheRoutes.push(route);
23
23
  }
24
24
  else {
@@ -98,8 +98,8 @@ test('Generates a manifest with pre and post-cache routes', () => {
98
98
  ];
99
99
  const declarations = [
100
100
  { function: 'func-1', path: '/f1' },
101
- { function: 'func-2', mode: 'not_a_supported_mode', path: '/f2' },
102
- { function: 'func-3', mode: 'after-cache', path: '/f3' },
101
+ { function: 'func-2', cache: 'not_a_supported_value', path: '/f2' },
102
+ { function: 'func-3', cache: 'manual', path: '/f3' },
103
103
  ];
104
104
  const manifest = generateManifest({ bundles: [bundle1, bundle2], declarations, functions });
105
105
  const expectedBundles = [
@@ -1,9 +1,8 @@
1
1
  import { promises as fs } from 'fs';
2
2
  import { join } from 'path';
3
3
  import nock from 'nock';
4
- import { stub } from 'sinon';
5
4
  import tmp from 'tmp-promise';
6
- import { test, expect } from 'vitest';
5
+ import { test, expect, vi } from 'vitest';
7
6
  import { testLogger } from '../test/util.js';
8
7
  import { DenoBridge } from './bridge.js';
9
8
  import { ensureLatestTypes } from './types.js';
@@ -16,14 +15,15 @@ test('`ensureLatestTypes` updates the Deno CLI cache if the local version of typ
16
15
  cacheDirectory: tmpDir.path,
17
16
  logger: testLogger,
18
17
  });
19
- const mock = stub(deno, 'run').resolves();
18
+ // @ts-expect-error return value not used
19
+ const mock = vi.spyOn(deno, 'run').mockResolvedValue({});
20
20
  await ensureLatestTypes(deno, testLogger, mockURL);
21
21
  const versionFile = await fs.readFile(join(tmpDir.path, 'types-version.txt'), 'utf8');
22
22
  expect(latestVersionMock.isDone()).toBe(true);
23
- expect(mock.callCount).toBe(1);
24
- expect(mock.firstCall.firstArg).toEqual(['cache', '-r', mockURL]);
23
+ expect(mock).toHaveBeenCalledTimes(1);
24
+ expect(mock).toHaveBeenCalledWith(['cache', '-r', mockURL]);
25
25
  expect(versionFile).toBe(mockVersion);
26
- mock.restore();
26
+ mock.mockRestore();
27
27
  await fs.rmdir(tmpDir.path, { recursive: true });
28
28
  });
29
29
  test('`ensureLatestTypes` does not update the Deno CLI cache if the local version of types is up-to-date', async () => {
@@ -37,11 +37,12 @@ test('`ensureLatestTypes` does not update the Deno CLI cache if the local versio
37
37
  cacheDirectory: tmpDir.path,
38
38
  logger: testLogger,
39
39
  });
40
- const mock = stub(deno, 'run').resolves();
40
+ // @ts-expect-error return value not used
41
+ const mock = vi.spyOn(deno, 'run').mockResolvedValue({});
41
42
  await ensureLatestTypes(deno, testLogger, mockURL);
42
43
  expect(latestVersionMock.isDone()).toBe(true);
43
- expect(mock.callCount).toBe(0);
44
- mock.restore();
44
+ expect(mock).not.toHaveBeenCalled();
45
+ mock.mockRestore();
45
46
  await fs.rmdir(tmpDir.path, { recursive: true });
46
47
  });
47
48
  test('`ensureLatestTypes` does not throw if the types URL is not available', async () => {
@@ -52,10 +53,11 @@ test('`ensureLatestTypes` does not throw if the types URL is not available', asy
52
53
  cacheDirectory: tmpDir.path,
53
54
  logger: testLogger,
54
55
  });
55
- const mock = stub(deno, 'run').resolves();
56
+ // @ts-expect-error return value not used
57
+ const mock = vi.spyOn(deno, 'run').mockResolvedValue({});
56
58
  await ensureLatestTypes(deno, testLogger, mockURL);
57
59
  expect(latestVersionMock.isDone()).toBe(true);
58
- expect(mock.callCount).toBe(0);
59
- mock.restore();
60
+ expect(mock).not.toHaveBeenCalled();
61
+ mock.mockRestore();
60
62
  await fs.rmdir(tmpDir.path, { recursive: true });
61
63
  });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@netlify/edge-bundler",
3
- "version": "3.1.1",
3
+ "version": "4.0.0",
4
4
  "description": "Intelligently prepare Netlify Edge Functions for deployment",
5
5
  "type": "module",
6
6
  "main": "./dist/node/index.js",
@@ -57,15 +57,14 @@
57
57
  "@types/semver": "^7.3.9",
58
58
  "@types/sinon": "^10.0.8",
59
59
  "@types/uuid": "^8.3.4",
60
- "@vitest/coverage-c8": "^0.24.0",
60
+ "@vitest/coverage-c8": "^0.25.0",
61
61
  "archiver": "^5.3.1",
62
62
  "husky": "^8.0.0",
63
63
  "nock": "^13.2.4",
64
- "sinon": "^14.0.0",
65
64
  "tar": "^6.1.11",
66
65
  "typescript": "^4.5.4",
67
66
  "vite": "^3.1.3",
68
- "vitest": "^0.24.0"
67
+ "vitest": "^0.25.0"
69
68
  },
70
69
  "engines": {
71
70
  "node": "^14.16.0 || >=16.0.0"