New Case Study:See how Anthropic automated 95% of dependency reviews with Socket.Learn More
Socket
Sign inDemoInstall
Socket

@netlify/edge-bundler

Package Overview
Dependencies
Maintainers
21
Versions
137
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@netlify/edge-bundler - npm Package Compare versions

Comparing version 8.13.0 to 8.13.1

dist/node/finder.test.d.ts

2

dist/node/bundler.js

@@ -73,3 +73,3 @@ import { promises as fs } from 'fs';

// deploy configuration API and the in-source configuration.
const declarations = mergeDeclarations(tomlDeclarations, userFunctionsWithConfig, internalFunctionsWithConfig, deployConfig.declarations);
const declarations = mergeDeclarations(tomlDeclarations, userFunctionsWithConfig, internalFunctionsWithConfig, deployConfig.declarations, featureFlags);
const internalFunctionConfig = createFunctionConfig({

@@ -76,0 +76,0 @@ internalFunctionsWithConfig,

import { FunctionConfig, Path } from './config.js';
import { FeatureFlags } from './feature_flags.js';
interface BaseDeclaration {

@@ -17,4 +18,4 @@ cache?: string;

export type Declaration = DeclarationWithPath | DeclarationWithPattern;
export declare const mergeDeclarations: (tomlDeclarations: Declaration[], userFunctionsConfig: Record<string, FunctionConfig>, internalFunctionsConfig: Record<string, FunctionConfig>, deployConfigDeclarations: Declaration[]) => Declaration[];
export declare const mergeDeclarations: (tomlDeclarations: Declaration[], userFunctionsConfig: Record<string, FunctionConfig>, internalFunctionsConfig: Record<string, FunctionConfig>, deployConfigDeclarations: Declaration[], featureFlags?: FeatureFlags) => Declaration[];
export declare const parsePattern: (pattern: string) => string;
export {};
import regexpAST from 'regexp-tree';
export const mergeDeclarations = (tomlDeclarations, userFunctionsConfig, internalFunctionsConfig, deployConfigDeclarations) => {
export const mergeDeclarations = (tomlDeclarations, userFunctionsConfig, internalFunctionsConfig, deployConfigDeclarations, featureFlags = {}) => {
const functionsVisited = new Set();
let declarations = getDeclarationsFromInput(deployConfigDeclarations, internalFunctionsConfig, functionsVisited);
// eslint-disable-next-line unicorn/prefer-ternary
if (featureFlags.edge_functions_correct_order) {
declarations = [
// INTEGRATIONS
// 1. Declarations from the integrations deploy config
...getDeclarationsFromInput(deployConfigDeclarations, internalFunctionsConfig, functionsVisited),
// 2. Declarations from the integrations ISC
...createDeclarationsFromFunctionConfigs(internalFunctionsConfig, functionsVisited),
// USER
// 3. Declarations from the users toml config
...getDeclarationsFromInput(tomlDeclarations, userFunctionsConfig, functionsVisited),
// 4. Declarations from the users ISC
...createDeclarationsFromFunctionConfigs(userFunctionsConfig, functionsVisited),
];
}
else {
declarations = [
...getDeclarationsFromInput(tomlDeclarations, userFunctionsConfig, functionsVisited),
...getDeclarationsFromInput(deployConfigDeclarations, internalFunctionsConfig, functionsVisited),
...createDeclarationsFromFunctionConfigs(internalFunctionsConfig, functionsVisited),
...createDeclarationsFromFunctionConfigs(userFunctionsConfig, functionsVisited),
];
}
return declarations;
};
const getDeclarationsFromInput = (inputDeclarations, functionConfigs, functionsVisited) => {
var _a;
const declarations = [];
const functionsVisited = new Set();
// We start by iterating over all the declarations in the TOML file and in
// the deploy configuration file. For any declaration for which we also have
// a function configuration object, we replace the path because that object
// takes precedence.
for (const declaration of [...tomlDeclarations, ...deployConfigDeclarations]) {
const config = userFunctionsConfig[declaration.function] || internalFunctionsConfig[declaration.function];
// For any declaration for which we also have a function configuration object,
// we replace the path because that object takes precedence.
for (const declaration of inputDeclarations) {
const config = functionConfigs[declaration.function];
if (!config) {

@@ -31,6 +56,8 @@ // If no config is found, add the declaration as is.

}
// Finally, we must create declarations for functions that are not declared
// in the TOML at all.
for (const name in { ...internalFunctionsConfig, ...userFunctionsConfig }) {
const { cache, path } = internalFunctionsConfig[name] || userFunctionsConfig[name];
return declarations;
};
const createDeclarationsFromFunctionConfigs = (functionConfigs, functionsVisited) => {
const declarations = [];
for (const name in functionConfigs) {
const { cache, path } = functionConfigs[name];
// If we have a path specified, create a declaration for each path.

@@ -37,0 +64,0 @@ if (!functionsVisited.has(name) && path) {

import { test, expect } from 'vitest';
import { mergeDeclarations } from './declaration.js';
const deployConfigDeclarations = [];
test('Deploy config takes precedence over user config', () => {
test('Ensure the order of edge functions with FF', () => {
const deployConfigDeclarations = [
{ function: 'framework-a', path: '/path1' },
{ function: 'framework-b', path: '/path2' },
{ function: 'framework-manifest-a', path: '/path1' },
{ function: 'framework-manifest-c', path: '/path3' },
{ function: 'framework-manifest-b', path: '/path2' },
];
const tomlConfig = [
{ function: 'user-a', path: '/path1' },
{ function: 'user-b', path: '/path2' },
{ function: 'user-toml-a', path: '/path1' },
{ function: 'user-toml-c', path: '/path3' },
{ function: 'user-toml-b', path: '/path2' },
];
const userFuncConfig = {
'user-c': { path: ['/path1', '/path2'] },
'user-isc-c': { path: ['/path1', '/path2'] },
};
const internalFuncConfig = {
'framework-c': { path: ['/path1', '/path2'] },
'framework-isc-c': { path: ['/path1', '/path2'] },
};
expect(mergeDeclarations(tomlConfig, userFuncConfig, internalFuncConfig, deployConfigDeclarations)).toMatchSnapshot();
expect(mergeDeclarations(tomlConfig, userFuncConfig, internalFuncConfig, deployConfigDeclarations, {
edge_functions_correct_order: true,
})).toMatchSnapshot();
});
test('Ensure the order of edge functions without FF', () => {
const deployConfigDeclarations = [
{ function: 'framework-manifest-a', path: '/path1' },
{ function: 'framework-manifest-c', path: '/path3' },
{ function: 'framework-manifest-b', path: '/path2' },
];
const tomlConfig = [
{ function: 'user-toml-a', path: '/path1' },
{ function: 'user-toml-c', path: '/path3' },
{ function: 'user-toml-b', path: '/path2' },
];
const userFuncConfig = {
'user-isc-c': { path: ['/path1', '/path2'] },
};
const internalFuncConfig = {
'framework-isc-c': { path: ['/path1', '/path2'] },
};
expect(mergeDeclarations(tomlConfig, userFuncConfig, internalFuncConfig, deployConfigDeclarations, {
edge_functions_correct_order: false,
})).toMatchSnapshot();
});
test('In-source config takes precedence over netlify.toml config', () => {

@@ -22,0 +47,0 @@ const tomlConfig = [

declare const defaultFlags: {
edge_functions_correct_order: boolean;
edge_functions_fail_unsupported_regex: boolean;
edge_functions_invalid_config_throw: boolean;
edge_functions_manifest_validate_slash: boolean;
};

@@ -9,7 +9,7 @@ type FeatureFlag = keyof typeof defaultFlags;

declare const getFlags: (input?: Record<string, boolean>, flags?: {
edge_functions_correct_order: boolean;
edge_functions_fail_unsupported_regex: boolean;
edge_functions_invalid_config_throw: boolean;
edge_functions_manifest_validate_slash: boolean;
}) => FeatureFlags;
export { defaultFlags, getFlags };
export type { FeatureFlag, FeatureFlags };
const defaultFlags = {
edge_functions_correct_order: false,
edge_functions_fail_unsupported_regex: false,
edge_functions_invalid_config_throw: false,
edge_functions_manifest_validate_slash: false,
};

@@ -6,0 +6,0 @@ const getFlags = (input = {}, flags = defaultFlags) => Object.entries(flags).reduce((result, [key, defaultValue]) => ({

import { EdgeFunction } from './edge_function.js';
export declare const removeDuplicatesByExtension: (functions: string[]) => string[];
declare const findFunctions: (directories: string[]) => Promise<EdgeFunction[]>;
export { findFunctions };
import { promises as fs } from 'fs';
import { basename, extname, join } from 'path';
import { basename, extname, join, parse } from 'path';
import { nonNullable } from './utils/non_nullable.js';
const ALLOWED_EXTENSIONS = new Set(['.js', '.jsx', '.ts', '.tsx']);
// the order of the allowed extensions is also the order we remove duplicates
// with a lower index meaning a higher precedence over the others
const ALLOWED_EXTENSIONS = ['.js', '.jsx', '.ts', '.tsx'];
export const removeDuplicatesByExtension = (functions) => {
const seen = new Map();
return Object.values(functions.reduce((acc, path) => {
const { ext, name } = parse(path);
const extIndex = ALLOWED_EXTENSIONS.indexOf(ext);
if (!seen.has(name) || seen.get(name) > extIndex) {
seen.set(name, extIndex);
return { ...acc, [name]: path };
}
return acc;
}, {}));
};
const findFunctionInDirectory = async (directory) => {
const name = basename(directory);
const candidatePaths = [...ALLOWED_EXTENSIONS]
.flatMap((extension) => [`${name}${extension}`, `index${extension}`])
.map((filename) => join(directory, filename));
const candidatePaths = ALLOWED_EXTENSIONS.flatMap((extension) => [`${name}${extension}`, `index${extension}`]).map((filename) => join(directory, filename));
let functionPath;

@@ -38,3 +50,3 @@ for (const candidatePath of candidatePaths) {

const extension = extname(path);
if (ALLOWED_EXTENSIONS.has(extension)) {
if (ALLOWED_EXTENSIONS.includes(extension)) {
return { name: basename(path, extension), path };

@@ -46,3 +58,3 @@ }

try {
items = await fs.readdir(baseDirectory);
items = await fs.readdir(baseDirectory).then(removeDuplicatesByExtension);
}

@@ -49,0 +61,0 @@ catch {

import { FeatureFlags } from '../../feature_flags.js';
import ManifestValidationError from './error.js';
export declare const validateManifest: (manifestData: unknown, featureFlags?: FeatureFlags) => void;
export declare const validateManifest: (manifestData: unknown, _featureFlags?: FeatureFlags) => void;
export { ManifestValidationError };

@@ -7,3 +7,3 @@ import Ajv from 'ajv';

let manifestValidator;
const initializeValidator = (featureFlags) => {
const initializeValidator = () => {
if (manifestValidator === undefined) {

@@ -14,3 +14,3 @@ const ajv = new Ajv({ allErrors: true });

// checks if the pattern string starts with ^ and ends with $
const normalizedPatternRegex = featureFlags.edge_functions_manifest_validate_slash ? /^\^\/.*\$$/ : /^\^.*\$$/;
const normalizedPatternRegex = /^\^.*\$$/;
ajv.addFormat('regexPattern', {

@@ -24,4 +24,5 @@ validate: (data) => normalizedPatternRegex.test(data),

// throws on validation error
export const validateManifest = (manifestData, featureFlags = {}) => {
const validate = initializeValidator(featureFlags);
// eslint-disable-next-line @typescript-eslint/no-unused-vars
export const validateManifest = (manifestData, _featureFlags = {}) => {
const validate = initializeValidator();
const valid = validate(manifestData);

@@ -28,0 +29,0 @@ if (!valid) {

import chalk from 'chalk';
import { test, expect, describe, beforeEach, vi } from 'vitest';
import { test, expect, describe } from 'vitest';
import { validateManifest, ManifestValidationError } from './index.js';

@@ -95,13 +95,6 @@ // We need to disable all color outputs for the tests as they are different on different platforms, CI, etc.

describe('route', () => {
let freshValidateManifest;
beforeEach(async () => {
// reset all modules, to get a fresh AJV validator for FF changes
vi.resetModules();
const indexImport = await import('./index.js');
freshValidateManifest = indexImport.validateManifest;
});
test('should throw on additional property', () => {
const manifest = getBaseManifest();
manifest.routes[0].foo = 'bar';
expect(() => freshValidateManifest(manifest)).toThrowErrorMatchingSnapshot();
expect(() => validateManifest(manifest)).toThrowErrorMatchingSnapshot();
});

@@ -111,18 +104,8 @@ test('should throw on invalid pattern', () => {

manifest.routes[0].pattern = '/^/hello/?$/';
expect(() => freshValidateManifest(manifest)).toThrowErrorMatchingSnapshot();
expect(() => validateManifest(manifest)).toThrowErrorMatchingSnapshot();
});
test('should not throw on missing beginning slash without FF', () => {
const manifest = getBaseManifest();
manifest.routes[0].pattern = '^hello/?$';
expect(() => freshValidateManifest(manifest, { edge_functions_manifest_validate_slash: false })).not.toThrowError();
});
test('should throw on missing beginning slash with FF', () => {
const manifest = getBaseManifest();
manifest.routes[0].pattern = '^hello/?$';
expect(() => freshValidateManifest(manifest, { edge_functions_manifest_validate_slash: true })).toThrowErrorMatchingSnapshot();
});
test('should throw on missing function', () => {
const manifest = getBaseManifest();
delete manifest.routes[0].function;
expect(() => freshValidateManifest(manifest)).toThrowErrorMatchingSnapshot();
expect(() => validateManifest(manifest)).toThrowErrorMatchingSnapshot();
});

@@ -132,3 +115,3 @@ test('should throw on missing pattern', () => {

delete manifest.routes[0].pattern;
expect(() => freshValidateManifest(manifest)).toThrowErrorMatchingSnapshot();
expect(() => validateManifest(manifest)).toThrowErrorMatchingSnapshot();
});

@@ -135,0 +118,0 @@ });

@@ -19,3 +19,3 @@ const bundlesSchema = {

format: 'regexPattern',
errorMessage: 'pattern needs to be a regex that starts with ^ followed by / and ends with $ without any additional slashes before and afterwards',
errorMessage: 'pattern must be a regex that starts with ^ and ends with $ (e.g. ^/blog/[d]{4}$)',
},

@@ -35,3 +35,3 @@ generator: { type: 'string' },

format: 'regexPattern',
errorMessage: 'excluded_patterns needs to be an array of regex that starts with ^ followed by / and ends with $ without any additional slashes before and afterwards',
errorMessage: 'excluded_patterns must be an array of regex that starts with ^ and ends with $ (e.g. ^/blog/[d]{4}$)',
},

@@ -38,0 +38,0 @@ },

{
"name": "@netlify/edge-bundler",
"version": "8.13.0",
"version": "8.13.1",
"description": "Intelligently prepare Netlify Edge Functions for deployment",

@@ -61,3 +61,3 @@ "type": "module",

"@types/uuid": "^9.0.0",
"@vitest/coverage-c8": "^0.29.7",
"@vitest/coverage-c8": "^0.30.0",
"archiver": "^5.3.1",

@@ -70,4 +70,4 @@ "chalk": "^4.1.2",

"tar": "^6.1.11",
"typescript": "^4.5.4",
"vitest": "^0.29.7"
"typescript": "^5.0.0",
"vitest": "^0.30.0"
},

@@ -74,0 +74,0 @@ "engines": {

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc