@netlify/edge-bundler 8.13.0 → 8.13.1
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/dist/node/bundler.js +1 -1
- package/dist/node/declaration.d.ts +2 -1
- package/dist/node/declaration.js +39 -12
- package/dist/node/declaration.test.js +33 -8
- package/dist/node/feature_flags.d.ts +2 -2
- package/dist/node/feature_flags.js +1 -1
- package/dist/node/finder.d.ts +1 -0
- package/dist/node/finder.js +19 -7
- package/dist/node/finder.test.d.ts +1 -0
- package/dist/node/finder.test.js +17 -0
- package/dist/node/validation/manifest/index.d.ts +1 -1
- package/dist/node/validation/manifest/index.js +5 -4
- package/dist/node/validation/manifest/index.test.js +5 -22
- package/dist/node/validation/manifest/schema.js +2 -2
- package/package.json +4 -4
package/dist/node/bundler.js
CHANGED
|
@@ -70,7 +70,7 @@ const bundle = async (sourceDirectories, distDirectory, tomlDeclarations = [], {
|
|
|
70
70
|
const userFunctionsWithConfig = Object.fromEntries(await Promise.all(userConfigPromises));
|
|
71
71
|
// Creating a final declarations array by combining the TOML file with the
|
|
72
72
|
// deploy configuration API and the in-source configuration.
|
|
73
|
-
const declarations = mergeDeclarations(tomlDeclarations, userFunctionsWithConfig, internalFunctionsWithConfig, deployConfig.declarations);
|
|
73
|
+
const declarations = mergeDeclarations(tomlDeclarations, userFunctionsWithConfig, internalFunctionsWithConfig, deployConfig.declarations, featureFlags);
|
|
74
74
|
const internalFunctionConfig = createFunctionConfig({
|
|
75
75
|
internalFunctionsWithConfig,
|
|
76
76
|
declarations,
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { FunctionConfig, Path } from './config.js';
|
|
2
|
+
import { FeatureFlags } from './feature_flags.js';
|
|
2
3
|
interface BaseDeclaration {
|
|
3
4
|
cache?: string;
|
|
4
5
|
function: string;
|
|
@@ -14,6 +15,6 @@ type DeclarationWithPattern = BaseDeclaration & {
|
|
|
14
15
|
excludedPattern?: string;
|
|
15
16
|
};
|
|
16
17
|
export type Declaration = DeclarationWithPath | DeclarationWithPattern;
|
|
17
|
-
export declare const mergeDeclarations: (tomlDeclarations: Declaration[], userFunctionsConfig: Record<string, FunctionConfig>, internalFunctionsConfig: Record<string, FunctionConfig>, deployConfigDeclarations: Declaration[]) => Declaration[];
|
|
18
|
+
export declare const mergeDeclarations: (tomlDeclarations: Declaration[], userFunctionsConfig: Record<string, FunctionConfig>, internalFunctionsConfig: Record<string, FunctionConfig>, deployConfigDeclarations: Declaration[], featureFlags?: FeatureFlags) => Declaration[];
|
|
18
19
|
export declare const parsePattern: (pattern: string) => string;
|
|
19
20
|
export {};
|
package/dist/node/declaration.js
CHANGED
|
@@ -1,14 +1,39 @@
|
|
|
1
1
|
import regexpAST from 'regexp-tree';
|
|
2
|
-
export const mergeDeclarations = (tomlDeclarations, userFunctionsConfig, internalFunctionsConfig, deployConfigDeclarations) => {
|
|
2
|
+
export const mergeDeclarations = (tomlDeclarations, userFunctionsConfig, internalFunctionsConfig, deployConfigDeclarations, featureFlags = {}) => {
|
|
3
|
+
const functionsVisited = new Set();
|
|
4
|
+
let declarations = getDeclarationsFromInput(deployConfigDeclarations, internalFunctionsConfig, functionsVisited);
|
|
5
|
+
// eslint-disable-next-line unicorn/prefer-ternary
|
|
6
|
+
if (featureFlags.edge_functions_correct_order) {
|
|
7
|
+
declarations = [
|
|
8
|
+
// INTEGRATIONS
|
|
9
|
+
// 1. Declarations from the integrations deploy config
|
|
10
|
+
...getDeclarationsFromInput(deployConfigDeclarations, internalFunctionsConfig, functionsVisited),
|
|
11
|
+
// 2. Declarations from the integrations ISC
|
|
12
|
+
...createDeclarationsFromFunctionConfigs(internalFunctionsConfig, functionsVisited),
|
|
13
|
+
// USER
|
|
14
|
+
// 3. Declarations from the users toml config
|
|
15
|
+
...getDeclarationsFromInput(tomlDeclarations, userFunctionsConfig, functionsVisited),
|
|
16
|
+
// 4. Declarations from the users ISC
|
|
17
|
+
...createDeclarationsFromFunctionConfigs(userFunctionsConfig, functionsVisited),
|
|
18
|
+
];
|
|
19
|
+
}
|
|
20
|
+
else {
|
|
21
|
+
declarations = [
|
|
22
|
+
...getDeclarationsFromInput(tomlDeclarations, userFunctionsConfig, functionsVisited),
|
|
23
|
+
...getDeclarationsFromInput(deployConfigDeclarations, internalFunctionsConfig, functionsVisited),
|
|
24
|
+
...createDeclarationsFromFunctionConfigs(internalFunctionsConfig, functionsVisited),
|
|
25
|
+
...createDeclarationsFromFunctionConfigs(userFunctionsConfig, functionsVisited),
|
|
26
|
+
];
|
|
27
|
+
}
|
|
28
|
+
return declarations;
|
|
29
|
+
};
|
|
30
|
+
const getDeclarationsFromInput = (inputDeclarations, functionConfigs, functionsVisited) => {
|
|
3
31
|
var _a;
|
|
4
32
|
const declarations = [];
|
|
5
|
-
|
|
6
|
-
//
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
// takes precedence.
|
|
10
|
-
for (const declaration of [...tomlDeclarations, ...deployConfigDeclarations]) {
|
|
11
|
-
const config = userFunctionsConfig[declaration.function] || internalFunctionsConfig[declaration.function];
|
|
33
|
+
// For any declaration for which we also have a function configuration object,
|
|
34
|
+
// we replace the path because that object takes precedence.
|
|
35
|
+
for (const declaration of inputDeclarations) {
|
|
36
|
+
const config = functionConfigs[declaration.function];
|
|
12
37
|
if (!config) {
|
|
13
38
|
// If no config is found, add the declaration as is.
|
|
14
39
|
declarations.push(declaration);
|
|
@@ -28,10 +53,12 @@ export const mergeDeclarations = (tomlDeclarations, userFunctionsConfig, interna
|
|
|
28
53
|
}
|
|
29
54
|
functionsVisited.add(declaration.function);
|
|
30
55
|
}
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
56
|
+
return declarations;
|
|
57
|
+
};
|
|
58
|
+
const createDeclarationsFromFunctionConfigs = (functionConfigs, functionsVisited) => {
|
|
59
|
+
const declarations = [];
|
|
60
|
+
for (const name in functionConfigs) {
|
|
61
|
+
const { cache, path } = functionConfigs[name];
|
|
35
62
|
// If we have a path specified, create a declaration for each path.
|
|
36
63
|
if (!functionsVisited.has(name) && path) {
|
|
37
64
|
const paths = Array.isArray(path) ? path : [path];
|
|
@@ -1,22 +1,47 @@
|
|
|
1
1
|
import { test, expect } from 'vitest';
|
|
2
2
|
import { mergeDeclarations } from './declaration.js';
|
|
3
3
|
const deployConfigDeclarations = [];
|
|
4
|
-
test('
|
|
4
|
+
test('Ensure the order of edge functions with FF', () => {
|
|
5
5
|
const deployConfigDeclarations = [
|
|
6
|
-
{ function: 'framework-a', path: '/path1' },
|
|
7
|
-
{ function: 'framework-
|
|
6
|
+
{ function: 'framework-manifest-a', path: '/path1' },
|
|
7
|
+
{ function: 'framework-manifest-c', path: '/path3' },
|
|
8
|
+
{ function: 'framework-manifest-b', path: '/path2' },
|
|
8
9
|
];
|
|
9
10
|
const tomlConfig = [
|
|
10
|
-
{ function: 'user-a', path: '/path1' },
|
|
11
|
-
{ function: 'user-
|
|
11
|
+
{ function: 'user-toml-a', path: '/path1' },
|
|
12
|
+
{ function: 'user-toml-c', path: '/path3' },
|
|
13
|
+
{ function: 'user-toml-b', path: '/path2' },
|
|
12
14
|
];
|
|
13
15
|
const userFuncConfig = {
|
|
14
|
-
'user-c': { path: ['/path1', '/path2'] },
|
|
16
|
+
'user-isc-c': { path: ['/path1', '/path2'] },
|
|
15
17
|
};
|
|
16
18
|
const internalFuncConfig = {
|
|
17
|
-
'framework-c': { path: ['/path1', '/path2'] },
|
|
19
|
+
'framework-isc-c': { path: ['/path1', '/path2'] },
|
|
18
20
|
};
|
|
19
|
-
expect(mergeDeclarations(tomlConfig, userFuncConfig, internalFuncConfig, deployConfigDeclarations
|
|
21
|
+
expect(mergeDeclarations(tomlConfig, userFuncConfig, internalFuncConfig, deployConfigDeclarations, {
|
|
22
|
+
edge_functions_correct_order: true,
|
|
23
|
+
})).toMatchSnapshot();
|
|
24
|
+
});
|
|
25
|
+
test('Ensure the order of edge functions without FF', () => {
|
|
26
|
+
const deployConfigDeclarations = [
|
|
27
|
+
{ function: 'framework-manifest-a', path: '/path1' },
|
|
28
|
+
{ function: 'framework-manifest-c', path: '/path3' },
|
|
29
|
+
{ function: 'framework-manifest-b', path: '/path2' },
|
|
30
|
+
];
|
|
31
|
+
const tomlConfig = [
|
|
32
|
+
{ function: 'user-toml-a', path: '/path1' },
|
|
33
|
+
{ function: 'user-toml-c', path: '/path3' },
|
|
34
|
+
{ function: 'user-toml-b', path: '/path2' },
|
|
35
|
+
];
|
|
36
|
+
const userFuncConfig = {
|
|
37
|
+
'user-isc-c': { path: ['/path1', '/path2'] },
|
|
38
|
+
};
|
|
39
|
+
const internalFuncConfig = {
|
|
40
|
+
'framework-isc-c': { path: ['/path1', '/path2'] },
|
|
41
|
+
};
|
|
42
|
+
expect(mergeDeclarations(tomlConfig, userFuncConfig, internalFuncConfig, deployConfigDeclarations, {
|
|
43
|
+
edge_functions_correct_order: false,
|
|
44
|
+
})).toMatchSnapshot();
|
|
20
45
|
});
|
|
21
46
|
test('In-source config takes precedence over netlify.toml config', () => {
|
|
22
47
|
const tomlConfig = [
|
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
declare const defaultFlags: {
|
|
2
|
+
edge_functions_correct_order: boolean;
|
|
2
3
|
edge_functions_fail_unsupported_regex: boolean;
|
|
3
4
|
edge_functions_invalid_config_throw: boolean;
|
|
4
|
-
edge_functions_manifest_validate_slash: boolean;
|
|
5
5
|
};
|
|
6
6
|
type FeatureFlag = keyof typeof defaultFlags;
|
|
7
7
|
type FeatureFlags = Partial<Record<FeatureFlag, boolean>>;
|
|
8
8
|
declare const getFlags: (input?: Record<string, boolean>, flags?: {
|
|
9
|
+
edge_functions_correct_order: boolean;
|
|
9
10
|
edge_functions_fail_unsupported_regex: boolean;
|
|
10
11
|
edge_functions_invalid_config_throw: boolean;
|
|
11
|
-
edge_functions_manifest_validate_slash: boolean;
|
|
12
12
|
}) => FeatureFlags;
|
|
13
13
|
export { defaultFlags, getFlags };
|
|
14
14
|
export type { FeatureFlag, FeatureFlags };
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
const defaultFlags = {
|
|
2
|
+
edge_functions_correct_order: false,
|
|
2
3
|
edge_functions_fail_unsupported_regex: false,
|
|
3
4
|
edge_functions_invalid_config_throw: false,
|
|
4
|
-
edge_functions_manifest_validate_slash: false,
|
|
5
5
|
};
|
|
6
6
|
const getFlags = (input = {}, flags = defaultFlags) => Object.entries(flags).reduce((result, [key, defaultValue]) => ({
|
|
7
7
|
...result,
|
package/dist/node/finder.d.ts
CHANGED
package/dist/node/finder.js
CHANGED
|
@@ -1,12 +1,24 @@
|
|
|
1
1
|
import { promises as fs } from 'fs';
|
|
2
|
-
import { basename, extname, join } from 'path';
|
|
2
|
+
import { basename, extname, join, parse } from 'path';
|
|
3
3
|
import { nonNullable } from './utils/non_nullable.js';
|
|
4
|
-
|
|
4
|
+
// the order of the allowed extensions is also the order we remove duplicates
|
|
5
|
+
// with a lower index meaning a higher precedence over the others
|
|
6
|
+
const ALLOWED_EXTENSIONS = ['.js', '.jsx', '.ts', '.tsx'];
|
|
7
|
+
export const removeDuplicatesByExtension = (functions) => {
|
|
8
|
+
const seen = new Map();
|
|
9
|
+
return Object.values(functions.reduce((acc, path) => {
|
|
10
|
+
const { ext, name } = parse(path);
|
|
11
|
+
const extIndex = ALLOWED_EXTENSIONS.indexOf(ext);
|
|
12
|
+
if (!seen.has(name) || seen.get(name) > extIndex) {
|
|
13
|
+
seen.set(name, extIndex);
|
|
14
|
+
return { ...acc, [name]: path };
|
|
15
|
+
}
|
|
16
|
+
return acc;
|
|
17
|
+
}, {}));
|
|
18
|
+
};
|
|
5
19
|
const findFunctionInDirectory = async (directory) => {
|
|
6
20
|
const name = basename(directory);
|
|
7
|
-
const candidatePaths = [
|
|
8
|
-
.flatMap((extension) => [`${name}${extension}`, `index${extension}`])
|
|
9
|
-
.map((filename) => join(directory, filename));
|
|
21
|
+
const candidatePaths = ALLOWED_EXTENSIONS.flatMap((extension) => [`${name}${extension}`, `index${extension}`]).map((filename) => join(directory, filename));
|
|
10
22
|
let functionPath;
|
|
11
23
|
for (const candidatePath of candidatePaths) {
|
|
12
24
|
try {
|
|
@@ -35,14 +47,14 @@ const findFunctionInPath = async (path) => {
|
|
|
35
47
|
return findFunctionInDirectory(path);
|
|
36
48
|
}
|
|
37
49
|
const extension = extname(path);
|
|
38
|
-
if (ALLOWED_EXTENSIONS.
|
|
50
|
+
if (ALLOWED_EXTENSIONS.includes(extension)) {
|
|
39
51
|
return { name: basename(path, extension), path };
|
|
40
52
|
}
|
|
41
53
|
};
|
|
42
54
|
const findFunctionsInDirectory = async (baseDirectory) => {
|
|
43
55
|
let items = [];
|
|
44
56
|
try {
|
|
45
|
-
items = await fs.readdir(baseDirectory);
|
|
57
|
+
items = await fs.readdir(baseDirectory).then(removeDuplicatesByExtension);
|
|
46
58
|
}
|
|
47
59
|
catch {
|
|
48
60
|
// no-op
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { test, expect } from 'vitest';
|
|
2
|
+
import { removeDuplicatesByExtension } from './finder.js';
|
|
3
|
+
test('filters out any duplicate files based on the extension', () => {
|
|
4
|
+
const functions = [
|
|
5
|
+
'file1.js',
|
|
6
|
+
'file1.ts',
|
|
7
|
+
'file2.tsx',
|
|
8
|
+
'file2.jsx',
|
|
9
|
+
'file3.tsx',
|
|
10
|
+
'file3.js',
|
|
11
|
+
'file4.ts',
|
|
12
|
+
'file5.ts',
|
|
13
|
+
'file5.tsx',
|
|
14
|
+
];
|
|
15
|
+
const expected = ['file1.js', 'file2.jsx', 'file3.js', 'file4.ts', 'file5.ts'];
|
|
16
|
+
expect(removeDuplicatesByExtension(functions)).toStrictEqual(expected);
|
|
17
|
+
});
|
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
import { FeatureFlags } from '../../feature_flags.js';
|
|
2
2
|
import ManifestValidationError from './error.js';
|
|
3
|
-
export declare const validateManifest: (manifestData: unknown,
|
|
3
|
+
export declare const validateManifest: (manifestData: unknown, _featureFlags?: FeatureFlags) => void;
|
|
4
4
|
export { ManifestValidationError };
|
|
@@ -4,13 +4,13 @@ import betterAjvErrors from 'better-ajv-errors';
|
|
|
4
4
|
import ManifestValidationError from './error.js';
|
|
5
5
|
import edgeManifestSchema from './schema.js';
|
|
6
6
|
let manifestValidator;
|
|
7
|
-
const initializeValidator = (
|
|
7
|
+
const initializeValidator = () => {
|
|
8
8
|
if (manifestValidator === undefined) {
|
|
9
9
|
const ajv = new Ajv({ allErrors: true });
|
|
10
10
|
ajvErrors(ajv);
|
|
11
11
|
// regex pattern for manifest route pattern
|
|
12
12
|
// checks if the pattern string starts with ^ and ends with $
|
|
13
|
-
const normalizedPatternRegex =
|
|
13
|
+
const normalizedPatternRegex = /^\^.*\$$/;
|
|
14
14
|
ajv.addFormat('regexPattern', {
|
|
15
15
|
validate: (data) => normalizedPatternRegex.test(data),
|
|
16
16
|
});
|
|
@@ -19,8 +19,9 @@ const initializeValidator = (featureFlags) => {
|
|
|
19
19
|
return manifestValidator;
|
|
20
20
|
};
|
|
21
21
|
// throws on validation error
|
|
22
|
-
|
|
23
|
-
|
|
22
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
23
|
+
export const validateManifest = (manifestData, _featureFlags = {}) => {
|
|
24
|
+
const validate = initializeValidator();
|
|
24
25
|
const valid = validate(manifestData);
|
|
25
26
|
if (!valid) {
|
|
26
27
|
let errorOutput;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import chalk from 'chalk';
|
|
2
|
-
import { test, expect, describe
|
|
2
|
+
import { test, expect, describe } from 'vitest';
|
|
3
3
|
import { validateManifest, ManifestValidationError } from './index.js';
|
|
4
4
|
// We need to disable all color outputs for the tests as they are different on different platforms, CI, etc.
|
|
5
5
|
// This only works if this is the same instance of chalk that better-ajv-errors uses
|
|
@@ -92,42 +92,25 @@ describe('bundle', () => {
|
|
|
92
92
|
});
|
|
93
93
|
});
|
|
94
94
|
describe('route', () => {
|
|
95
|
-
let freshValidateManifest;
|
|
96
|
-
beforeEach(async () => {
|
|
97
|
-
// reset all modules, to get a fresh AJV validator for FF changes
|
|
98
|
-
vi.resetModules();
|
|
99
|
-
const indexImport = await import('./index.js');
|
|
100
|
-
freshValidateManifest = indexImport.validateManifest;
|
|
101
|
-
});
|
|
102
95
|
test('should throw on additional property', () => {
|
|
103
96
|
const manifest = getBaseManifest();
|
|
104
97
|
manifest.routes[0].foo = 'bar';
|
|
105
|
-
expect(() =>
|
|
98
|
+
expect(() => validateManifest(manifest)).toThrowErrorMatchingSnapshot();
|
|
106
99
|
});
|
|
107
100
|
test('should throw on invalid pattern', () => {
|
|
108
101
|
const manifest = getBaseManifest();
|
|
109
102
|
manifest.routes[0].pattern = '/^/hello/?$/';
|
|
110
|
-
expect(() =>
|
|
111
|
-
});
|
|
112
|
-
test('should not throw on missing beginning slash without FF', () => {
|
|
113
|
-
const manifest = getBaseManifest();
|
|
114
|
-
manifest.routes[0].pattern = '^hello/?$';
|
|
115
|
-
expect(() => freshValidateManifest(manifest, { edge_functions_manifest_validate_slash: false })).not.toThrowError();
|
|
116
|
-
});
|
|
117
|
-
test('should throw on missing beginning slash with FF', () => {
|
|
118
|
-
const manifest = getBaseManifest();
|
|
119
|
-
manifest.routes[0].pattern = '^hello/?$';
|
|
120
|
-
expect(() => freshValidateManifest(manifest, { edge_functions_manifest_validate_slash: true })).toThrowErrorMatchingSnapshot();
|
|
103
|
+
expect(() => validateManifest(manifest)).toThrowErrorMatchingSnapshot();
|
|
121
104
|
});
|
|
122
105
|
test('should throw on missing function', () => {
|
|
123
106
|
const manifest = getBaseManifest();
|
|
124
107
|
delete manifest.routes[0].function;
|
|
125
|
-
expect(() =>
|
|
108
|
+
expect(() => validateManifest(manifest)).toThrowErrorMatchingSnapshot();
|
|
126
109
|
});
|
|
127
110
|
test('should throw on missing pattern', () => {
|
|
128
111
|
const manifest = getBaseManifest();
|
|
129
112
|
delete manifest.routes[0].pattern;
|
|
130
|
-
expect(() =>
|
|
113
|
+
expect(() => validateManifest(manifest)).toThrowErrorMatchingSnapshot();
|
|
131
114
|
});
|
|
132
115
|
});
|
|
133
116
|
// No tests for post_cache_routes as schema shared with routes
|
|
@@ -16,7 +16,7 @@ const routesSchema = {
|
|
|
16
16
|
pattern: {
|
|
17
17
|
type: 'string',
|
|
18
18
|
format: 'regexPattern',
|
|
19
|
-
errorMessage: 'pattern
|
|
19
|
+
errorMessage: 'pattern must be a regex that starts with ^ and ends with $ (e.g. ^/blog/[d]{4}$)',
|
|
20
20
|
},
|
|
21
21
|
generator: { type: 'string' },
|
|
22
22
|
},
|
|
@@ -31,7 +31,7 @@ const functionConfigSchema = {
|
|
|
31
31
|
items: {
|
|
32
32
|
type: 'string',
|
|
33
33
|
format: 'regexPattern',
|
|
34
|
-
errorMessage: 'excluded_patterns
|
|
34
|
+
errorMessage: 'excluded_patterns must be an array of regex that starts with ^ and ends with $ (e.g. ^/blog/[d]{4}$)',
|
|
35
35
|
},
|
|
36
36
|
},
|
|
37
37
|
on_error: { type: 'string' },
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@netlify/edge-bundler",
|
|
3
|
-
"version": "8.13.
|
|
3
|
+
"version": "8.13.1",
|
|
4
4
|
"description": "Intelligently prepare Netlify Edge Functions for deployment",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/node/index.js",
|
|
@@ -58,7 +58,7 @@
|
|
|
58
58
|
"@types/node": "^14.18.32",
|
|
59
59
|
"@types/semver": "^7.3.9",
|
|
60
60
|
"@types/uuid": "^9.0.0",
|
|
61
|
-
"@vitest/coverage-c8": "^0.
|
|
61
|
+
"@vitest/coverage-c8": "^0.30.0",
|
|
62
62
|
"archiver": "^5.3.1",
|
|
63
63
|
"chalk": "^4.1.2",
|
|
64
64
|
"cpy": "^9.0.1",
|
|
@@ -66,8 +66,8 @@
|
|
|
66
66
|
"husky": "^8.0.0",
|
|
67
67
|
"nock": "^13.2.4",
|
|
68
68
|
"tar": "^6.1.11",
|
|
69
|
-
"typescript": "^
|
|
70
|
-
"vitest": "^0.
|
|
69
|
+
"typescript": "^5.0.0",
|
|
70
|
+
"vitest": "^0.30.0"
|
|
71
71
|
},
|
|
72
72
|
"engines": {
|
|
73
73
|
"node": "^14.16.0 || >=16.0.0"
|