Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

@netlify/edge-bundler

Package Overview
Dependencies
Maintainers
21
Versions
134
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.12.3 to 8.13.0

18

dist/node/bundler.d.ts
import { OnAfterDownloadHook, OnBeforeDownloadHook } from './bridge.js';
import { Declaration } from './declaration.js';
import { EdgeFunction } from './edge_function.js';
import { FeatureFlags } from './feature_flags.js';

@@ -20,21 +19,6 @@ import { LogFunction } from './logger.js';

declare const bundle: (sourceDirectories: string[], distDirectory: string, tomlDeclarations?: Declaration[], { basePath: inputBasePath, cacheDirectory, configPath, debug, distImportMapPath, featureFlags: inputFeatureFlags, importMapPaths, onAfterDownload, onBeforeDownload, systemLogger, internalSrcFolder, }?: BundleOptions) => Promise<{
functions: EdgeFunction[];
functions: import("./edge_function.js").EdgeFunction[];
manifest: import("./manifest.js").Manifest;
}>;
export declare const addGeneratorFieldIfMissing: (declaration: Declaration, functions: EdgeFunction[], internalFunctionsPath?: string) => {
generator: string | undefined;
cache?: string | undefined;
function: string;
name?: string | undefined;
path: `/${string}`;
excludedPath?: `/${string}` | undefined;
} | {
generator: string | undefined;
cache?: string | undefined;
function: string;
name?: string | undefined;
pattern: string;
excludedPattern?: string | undefined;
};
export { bundle };
export type { BundleOptions };

58

dist/node/bundler.js
import { promises as fs } from 'fs';
import { join, resolve } from 'path';
import { join } from 'path';
import commonPathPrefix from 'common-path-prefix';
import isPathInside from 'is-path-inside';
import { v4 as uuidv4 } from 'uuid';

@@ -28,3 +27,2 @@ import { importMapSpecifier } from '../shared/consts.js';

};
const internalFunctionsPath = internalSrcFolder && resolve(internalSrcFolder);
if (cacheDirectory !== undefined) {

@@ -46,5 +44,8 @@ options.denoDir = join(cacheDirectory, 'deno_dir');

const externals = deployConfig.layers.map((layer) => layer.name);
const userSourceDirectories = sourceDirectories.filter((dir) => dir !== internalSrcFolder);
const importMap = new ImportMap();
await importMap.addFiles([deployConfig === null || deployConfig === void 0 ? void 0 : deployConfig.importMap, ...importMapPaths], logger);
const functions = await findFunctions(sourceDirectories);
const userFunctions = userSourceDirectories.length === 0 ? [] : await findFunctions(userSourceDirectories);
const internalFunctions = internalSrcFolder ? await findFunctions([internalSrcFolder]) : [];
const functions = [...internalFunctions, ...userFunctions];
const functionBundle = await bundleESZIP({

@@ -66,13 +67,15 @@ basePath,

// Retrieving a configuration object for each function.
const functionsConfig = await Promise.all(functions.map((func) => getFunctionConfig(func, importMap, deno, logger, featureFlags)));
// Run `getFunctionConfig` in parallel as it is a non-trivial operation and spins up deno
const internalConfigPromises = internalFunctions.map(async (func) => [func.name, await getFunctionConfig(func, importMap, deno, logger, featureFlags)]);
const userConfigPromises = userFunctions.map(async (func) => [func.name, await getFunctionConfig(func, importMap, deno, logger, featureFlags)]);
// Creating a hash of function names to configuration objects.
const functionsWithConfig = functions.reduce((acc, func, index) => ({ ...acc, [func.name]: functionsConfig[index] }), {});
const internalFunctionsWithConfig = Object.fromEntries(await Promise.all(internalConfigPromises));
const userFunctionsWithConfig = Object.fromEntries(await Promise.all(userConfigPromises));
// Creating a final declarations array by combining the TOML file with the
// deploy configuration API and the in-source configuration.
const declarationsFromConfig = mergeDeclarations(tomlDeclarations, functionsWithConfig, deployConfig.declarations);
// If any declarations are autogenerated and are missing the generator field
// add a default string.
const declarations = internalFunctionsPath
? declarationsFromConfig.map((declaration) => addGeneratorFieldIfMissing(declaration, functions, internalFunctionsPath))
: declarationsFromConfig;
const declarations = mergeDeclarations(tomlDeclarations, userFunctionsWithConfig, internalFunctionsWithConfig, deployConfig.declarations);
const internalFunctionConfig = createFunctionConfig({
internalFunctionsWithConfig,
declarations,
});
const manifest = await writeManifest({

@@ -84,3 +87,4 @@ bundles: [functionBundle],

functions,
functionConfig: functionsWithConfig,
userFunctionConfig: userFunctionsWithConfig,
internalFunctionConfig,
importMap: importMapSpecifier,

@@ -114,10 +118,24 @@ layers: deployConfig.layers,

};
export const addGeneratorFieldIfMissing = (declaration, functions, internalFunctionsPath) => {
var _a;
const fullFuncPath = (_a = functions === null || functions === void 0 ? void 0 : functions.find((func) => func.name === declaration.function)) === null || _a === void 0 ? void 0 : _a.path;
// If function path is in the internalFunctionsPath, we assume it is autogenerated.
const isInternal = Boolean(internalFunctionsPath && fullFuncPath && isPathInside(fullFuncPath, internalFunctionsPath));
const generatorFallback = isInternal ? 'internalFunc' : undefined;
return { ...declaration, generator: declaration.generator || generatorFallback };
// We used to allow the `name` and `generator` fields to be defined at the
// declaration level. We want these properties to live at the function level
// in their config object, so we translate that for backwards-compatibility.
const mergeWithDeclarationConfig = ({ functionName, config, declarations }) => {
const declaration = declarations === null || declarations === void 0 ? void 0 : declarations.find((decl) => decl.function === functionName);
return {
...config,
name: (declaration === null || declaration === void 0 ? void 0 : declaration.name) || config.name,
generator: (declaration === null || declaration === void 0 ? void 0 : declaration.generator) || config.generator,
};
};
const addGeneratorFallback = (config) => ({
...config,
generator: config.generator || 'internalFunc',
});
const createFunctionConfig = ({ internalFunctionsWithConfig, declarations }) => Object.entries(internalFunctionsWithConfig).reduce((acc, [functionName, config]) => {
const mergedConfigFields = mergeWithDeclarationConfig({ functionName, config, declarations });
return {
...acc,
[functionName]: addGeneratorFallback(mergedConfigFields),
};
}, {});
export { bundle };

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

});
test('Loads declarations and import maps from the deploy configuration', async () => {
test('Loads declarations and import maps from the deploy configuration and in-source config', async () => {
const { basePath, cleanup, distPath } = await useFixture('with_deploy_config');

@@ -287,12 +287,18 @@ const declarations = [

const manifest = JSON.parse(manifestFile);
const { routes, bundles, function_config: functionConfig } = manifest;
const { bundles, function_config: functionConfig } = manifest;
expect(bundles.length).toBe(1);
expect(bundles[0].format).toBe('eszip2');
expect(generatedFiles.includes(bundles[0].asset)).toBe(true);
expect(routes[0].generator).toBeUndefined();
expect(routes[1].name).toBe('Function two');
expect(routes[1].generator).toBe('@netlify/fake-plugin@1.0.0');
expect(routes[2].generator).toBe('internalFunc');
// respects excludedPath from deploy config
expect(functionConfig.func2).toEqual({ excluded_patterns: ['^/func2/skip/?$'] });
expect(functionConfig.func2).toEqual({
excluded_patterns: ['^/func2/skip/?$'],
name: 'Function two',
generator: '@netlify/fake-plugin@1.0.0',
});
// respects in-source config
expect(functionConfig.func3).toEqual({
name: 'in-config-function',
on_error: 'bypass',
generator: 'internalFunc',
});
await cleanup();

@@ -299,0 +305,0 @@ });

@@ -11,3 +11,3 @@ import { DenoBridge } from './bridge.js';

export type Path = `/${string}`;
export type OnError = 'fail' | 'bypass' | `/${string}`;
export type OnError = 'fail' | 'bypass' | Path;
export declare const isValidOnError: (value: unknown) => value is OnError;

@@ -19,3 +19,5 @@ export interface FunctionConfig {

onError?: OnError;
name?: string;
generator?: string;
}
export declare const getFunctionConfig: (func: EdgeFunction, importMap: ImportMap, deno: DenoBridge, log: Logger, featureFlags: FeatureFlags) => Promise<FunctionConfig>;

@@ -120,2 +120,21 @@ import { promises as fs } from 'fs';

},
{
testName: 'config with path, generator, name and onError`',
expectedConfig: {
path: '/home',
generator: '@netlify/fake-plugin@1.0.0',
name: 'a displayName',
onError: 'bypass',
},
name: 'func6',
source: `
export default async () => new Response("Hello from function three")
export const config = { path: "/home",
generator: '@netlify/fake-plugin@1.0.0',
name: 'a displayName',
onError: 'bypass',
}
`,
},
];

@@ -122,0 +141,0 @@ describe('`getFunctionConfig` extracts configuration properties from function file', () => {

@@ -17,4 +17,4 @@ import { FunctionConfig, Path } from './config.js';

export type Declaration = DeclarationWithPath | DeclarationWithPattern;
export declare const mergeDeclarations: (tomlDeclarations: Declaration[], functionsConfig: Record<string, FunctionConfig>, deployConfigDeclarations: Declaration[]) => Declaration[];
export declare const mergeDeclarations: (tomlDeclarations: Declaration[], userFunctionsConfig: Record<string, FunctionConfig>, internalFunctionsConfig: Record<string, FunctionConfig>, deployConfigDeclarations: Declaration[]) => Declaration[];
export declare const parsePattern: (pattern: string) => string;
export {};
import regexpAST from 'regexp-tree';
export const mergeDeclarations = (tomlDeclarations, functionsConfig, deployConfigDeclarations) => {
export const mergeDeclarations = (tomlDeclarations, userFunctionsConfig, internalFunctionsConfig, deployConfigDeclarations) => {
var _a;

@@ -11,3 +11,3 @@ const declarations = [];

for (const declaration of [...tomlDeclarations, ...deployConfigDeclarations]) {
const config = functionsConfig[declaration.function];
const config = userFunctionsConfig[declaration.function] || internalFunctionsConfig[declaration.function];
if (!config) {

@@ -34,4 +34,4 @@ // If no config is found, add the declaration as is.

// in the TOML at all.
for (const name in functionsConfig) {
const { cache, path } = functionsConfig[name];
for (const name in { ...internalFunctionsConfig, ...userFunctionsConfig }) {
const { cache, path } = internalFunctionsConfig[name] || userFunctionsConfig[name];
// If we have a path specified, create a declaration for each path.

@@ -41,3 +41,7 @@ if (!functionsVisited.has(name) && path) {

paths.forEach((singlePath) => {
declarations.push({ cache, function: name, path: singlePath });
const declaration = { function: name, path: singlePath };
if (cache) {
declaration.cache = cache;
}
declarations.push(declaration);
});

@@ -44,0 +48,0 @@ }

import { test, expect } from 'vitest';
import { mergeDeclarations } from './declaration.js';
// TODO: Add tests with the deploy config.
const deployConfigDeclarations = [];
test('Deploy config takes precedence over user config', () => {
const deployConfigDeclarations = [
{ function: 'framework-a', path: '/path1' },
{ function: 'framework-b', path: '/path2' },
];
const tomlConfig = [
{ function: 'user-a', path: '/path1' },
{ function: 'user-b', path: '/path2' },
];
const userFuncConfig = {
'user-c': { path: ['/path1', '/path2'] },
};
const internalFuncConfig = {
'framework-c': { path: ['/path1', '/path2'] },
};
expect(mergeDeclarations(tomlConfig, userFuncConfig, internalFuncConfig, deployConfigDeclarations)).toMatchSnapshot();
});
test('In-source config takes precedence over netlify.toml config', () => {

@@ -10,3 +26,3 @@ const tomlConfig = [

];
const funcConfig = {
const userFuncConfig = {
geolocation: { path: ['/geo-isc', '/*'], cache: 'manual' },

@@ -20,3 +36,3 @@ json: { path: '/json', cache: 'off' },

];
const declarations = mergeDeclarations(tomlConfig, funcConfig, deployConfigDeclarations);
const declarations = mergeDeclarations(tomlConfig, userFuncConfig, {}, deployConfigDeclarations);
expect(declarations).toEqual(expectedDeclarations);

@@ -29,3 +45,3 @@ });

];
const funcConfig = {
const userFuncConfig = {
geolocation: { path: ['/geo-isc'], cache: 'manual' },

@@ -38,3 +54,3 @@ json: {},

];
const declarations = mergeDeclarations(tomlConfig, funcConfig, deployConfigDeclarations);
const declarations = mergeDeclarations(tomlConfig, userFuncConfig, {}, deployConfigDeclarations);
expect(declarations).toEqual(expectedDeclarations);

@@ -56,5 +72,5 @@ });

const expectedDeclarationsWithoutISCPath = [{ function: 'geolocation', path: '/geo', cache: 'off' }];
const declarationsWithISCPath = mergeDeclarations(tomlConfig, funcConfigWithPath, deployConfigDeclarations);
const declarationsWithISCPath = mergeDeclarations(tomlConfig, funcConfigWithPath, {}, deployConfigDeclarations);
expect(declarationsWithISCPath).toEqual(expectedDeclarationsWithISCPath);
const declarationsWithoutISCPath = mergeDeclarations(tomlConfig, funcConfigWithoutPath, deployConfigDeclarations);
const declarationsWithoutISCPath = mergeDeclarations(tomlConfig, funcConfigWithoutPath, {}, deployConfigDeclarations);
expect(declarationsWithoutISCPath).toEqual(expectedDeclarationsWithoutISCPath);

@@ -68,3 +84,3 @@ });

const expectedDeclarations = [{ function: 'geolocation', path: '/geo', cache: 'manual' }];
expect(mergeDeclarations(tomlConfig, funcConfig, deployConfigDeclarations)).toEqual(expectedDeclarations);
expect(mergeDeclarations(tomlConfig, funcConfig, {}, deployConfigDeclarations)).toEqual(expectedDeclarations);
});

@@ -77,3 +93,3 @@ test("In-source config path property works if it's not an array", () => {

const expectedDeclarations = [{ function: 'json', path: '/json', cache: 'manual' }];
expect(mergeDeclarations(tomlConfig, funcConfig, deployConfigDeclarations)).toEqual(expectedDeclarations);
expect(mergeDeclarations(tomlConfig, funcConfig, {}, deployConfigDeclarations)).toEqual(expectedDeclarations);
});

@@ -89,3 +105,3 @@ test("In-source config path property works if it's not an array and it's not present in toml or deploy config", () => {

];
expect(mergeDeclarations(tomlConfig, funcConfig, deployConfigDeclarations)).toEqual(expectedDeclarations);
expect(mergeDeclarations(tomlConfig, funcConfig, {}, deployConfigDeclarations)).toEqual(expectedDeclarations);
});

@@ -98,3 +114,3 @@ test('In-source config works if path property is an empty array with cache value specified', () => {

const expectedDeclarations = [{ function: 'json', path: '/json-toml', cache: 'manual' }];
expect(mergeDeclarations(tomlConfig, funcConfig, deployConfigDeclarations)).toEqual(expectedDeclarations);
expect(mergeDeclarations(tomlConfig, funcConfig, {}, deployConfigDeclarations)).toEqual(expectedDeclarations);
});

@@ -105,4 +121,4 @@ test('netlify.toml-defined excludedPath are respected', () => {

const expectedDeclarations = [{ function: 'geolocation', path: '/geo/*', excludedPath: '/geo/exclude' }];
const declarations = mergeDeclarations(tomlConfig, funcConfig, deployConfigDeclarations);
const declarations = mergeDeclarations(tomlConfig, funcConfig, {}, deployConfigDeclarations);
expect(declarations).toEqual(expectedDeclarations);
});

@@ -7,6 +7,16 @@ import { rm } from 'fs/promises';

import tmp from 'tmp-promise';
import { beforeEach, afterEach, test, expect } from 'vitest';
import { beforeEach, afterEach, test, expect, vi } from 'vitest';
import { fixturesDir, testLogger } from '../test/util.js';
import { download } from './downloader.js';
import { getPlatformTarget } from './platform.js';
// This changes the defaults for p-retry
// minTimeout 1000 -> 10
// factor 2 -> 1
// This reduces the wait time in the tests from `2s, 4s, 8s` to `10ms, 10ms, 10ms` for 3 retries
vi.mock('p-retry', async (importOriginal) => {
const pRetry = (await importOriginal());
return {
default: (func, options) => pRetry.default(func, { minTimeout: 10, factor: 1, ...options }),
};
});
const streamError = () => {

@@ -13,0 +23,0 @@ const stream = new PassThrough();

@@ -9,5 +9,3 @@ import type { Bundle } from './bundle.js';

function: string;
name?: string;
pattern: string;
generator?: string;
}

@@ -17,2 +15,4 @@ interface EdgeFunctionConfig {

on_error?: string;
generator?: string;
name?: string;
}

@@ -39,7 +39,8 @@ interface Manifest {

functions: EdgeFunction[];
functionConfig?: Record<string, FunctionConfig>;
importMap?: string;
internalFunctionConfig?: Record<string, FunctionConfig>;
layers?: Layer[];
userFunctionConfig?: Record<string, FunctionConfig>;
}
declare const generateManifest: ({ bundles, declarations, featureFlags, functions, functionConfig, importMap, layers, }: GenerateManifestOptions) => Manifest;
declare const generateManifest: ({ bundles, declarations, featureFlags, functions, userFunctionConfig, internalFunctionConfig, importMap, layers, }: GenerateManifestOptions) => Manifest;
interface WriteManifestOptions extends GenerateManifestOptions {

@@ -46,0 +47,0 @@ distDirectory: string;

@@ -7,2 +7,8 @@ import { promises as fs } from 'fs';

import { nonNullable } from './utils/non_nullable.js';
const removeEmptyConfigValues = (functionConfig) => Object.entries(functionConfig).reduce((acc, [key, value]) => {
if (value && !(Array.isArray(value) && value.length === 0)) {
return { ...acc, [key]: value };
}
return acc;
}, {});
// JavaScript regular expressions are converted to strings with leading and

@@ -16,4 +22,5 @@ // trailing slashes, so any slashes inside the expression itself are escaped

for (const [name, functionConfig] of Object.entries(config)) {
if (functionConfig.excluded_patterns.length !== 0 || functionConfig.on_error) {
newConfig[name] = functionConfig;
const newFunctionConfig = removeEmptyConfigValues(functionConfig);
if (Object.keys(newFunctionConfig).length !== 0) {
newConfig[name] = newFunctionConfig;
}

@@ -23,7 +30,14 @@ }

};
const generateManifest = ({ bundles = [], declarations = [], featureFlags, functions, functionConfig = {}, importMap, layers = [], }) => {
const addExcludedPatterns = (name, manifestFunctionConfig, excludedPath) => {
if (excludedPath) {
const paths = Array.isArray(excludedPath) ? excludedPath : [excludedPath];
const excludedPatterns = paths.map(pathToRegularExpression).map(serializePattern);
manifestFunctionConfig[name].excluded_patterns.push(...excludedPatterns);
}
};
const generateManifest = ({ bundles = [], declarations = [], featureFlags, functions, userFunctionConfig = {}, internalFunctionConfig = {}, importMap, layers = [], }) => {
const preCacheRoutes = [];
const postCacheRoutes = [];
const manifestFunctionConfig = Object.fromEntries(functions.map(({ name }) => [name, { excluded_patterns: [] }]));
for (const [name, { excludedPath, onError }] of Object.entries(functionConfig)) {
for (const [name, { excludedPath, onError }] of Object.entries(userFunctionConfig)) {
// If the config block is for a function that is not defined, discard it.

@@ -33,10 +47,12 @@ if (manifestFunctionConfig[name] === undefined) {

}
if (excludedPath) {
const paths = Array.isArray(excludedPath) ? excludedPath : [excludedPath];
const excludedPatterns = paths.map(pathToRegularExpression).map(serializePattern);
manifestFunctionConfig[name].excluded_patterns.push(...excludedPatterns);
addExcludedPatterns(name, manifestFunctionConfig, excludedPath);
manifestFunctionConfig[name] = { ...manifestFunctionConfig[name], on_error: onError };
}
for (const [name, { excludedPath, path, onError, ...rest }] of Object.entries(internalFunctionConfig)) {
// If the config block is for a function that is not defined, discard it.
if (manifestFunctionConfig[name] === undefined) {
continue;
}
if (onError) {
manifestFunctionConfig[name].on_error = onError;
}
addExcludedPatterns(name, manifestFunctionConfig, excludedPath);
manifestFunctionConfig[name] = { ...manifestFunctionConfig[name], on_error: onError, ...rest };
}

@@ -51,5 +67,3 @@ declarations.forEach((declaration) => {

function: func.name,
name: declaration.name,
pattern: serializePattern(pattern),
generator: declaration.generator,
};

@@ -56,0 +70,0 @@ const excludedPattern = getExcludedRegularExpression(declaration, featureFlags === null || featureFlags === void 0 ? void 0 : featureFlags.edge_functions_fail_unsupported_regex);

@@ -29,15 +29,14 @@ import { env } from 'process';

test('Generates a manifest with display names', () => {
const functions = [
{ name: 'func-1', path: '/path/to/func-1.ts' },
{ name: 'func-2', path: '/path/to/func-2.ts' },
];
const declarations = [
{ function: 'func-1', name: 'Display Name', path: '/f1/*' },
{ function: 'func-2', path: '/f2/*' },
];
const manifest = generateManifest({ bundles: [], declarations, functions });
const expectedRoutes = [
{ function: 'func-1', name: 'Display Name', pattern: '^/f1/.*/?$' },
{ function: 'func-2', pattern: '^/f2/.*/?$' },
];
const functions = [{ name: 'func-1', path: '/path/to/func-1.ts' }];
const declarations = [{ function: 'func-1', path: '/f1/*' }];
const internalFunctionConfig = {
'func-1': {
name: 'Display Name',
},
};
const manifest = generateManifest({ bundles: [], declarations, functions, internalFunctionConfig });
const expectedRoutes = [{ function: 'func-1', pattern: '^/f1/.*/?$' }];
expect(manifest.function_config).toEqual({
'func-1': { name: 'Display Name' },
});
expect(manifest.routes).toEqual(expectedRoutes);

@@ -47,23 +46,37 @@ expect(manifest.bundler_version).toBe(env.npm_package_version);

test('Generates a manifest with a generator field', () => {
const functions = [{ name: 'func-1', path: '/path/to/func-1.ts' }];
const declarations = [{ function: 'func-1', path: '/f1/*' }];
const internalFunctionConfig = {
'func-1': {
generator: '@netlify/fake-plugin@1.0.0',
},
};
const manifest = generateManifest({ bundles: [], declarations, functions, internalFunctionConfig });
const expectedRoutes = [{ function: 'func-1', pattern: '^/f1/.*/?$' }];
const expectedFunctionConfig = { 'func-1': { generator: '@netlify/fake-plugin@1.0.0' } };
expect(manifest.routes).toEqual(expectedRoutes);
expect(manifest.function_config).toEqual(expectedFunctionConfig);
});
test('Generates a manifest with excluded paths and patterns', () => {
const functions = [
{ name: 'func-1', path: '/path/to/func-1.ts' },
{ name: 'func-2', path: '/path/to/func-2.ts' },
{ name: 'func-3', path: '/path/to/func-3.ts' },
];
const declarations = [
{ function: 'func-1', generator: '@netlify/fake-plugin@1.0.0', path: '/f1/*' },
{ function: 'func-2', path: '/f2/*' },
{ function: 'func-3', generator: '@netlify/fake-plugin@1.0.0', cache: 'manual', path: '/f3' },
{ function: 'func-1', path: '/f1/*', excludedPath: '/f1/exclude' },
{ function: 'func-2', pattern: '^/f2/.*/?$', excludedPattern: '^/f2/exclude$' },
];
const manifest = generateManifest({ bundles: [], declarations, functions });
const expectedRoutes = [
{ function: 'func-1', generator: '@netlify/fake-plugin@1.0.0', pattern: '^/f1/.*/?$' },
{ function: 'func-1', pattern: '^/f1/.*/?$' },
{ function: 'func-2', pattern: '^/f2/.*/?$' },
];
const expectedPostCacheRoutes = [{ function: 'func-3', generator: '@netlify/fake-plugin@1.0.0', pattern: '^/f3/?$' }];
expect(manifest.routes).toEqual(expectedRoutes);
expect(manifest.post_cache_routes).toEqual(expectedPostCacheRoutes);
expect(manifest.function_config).toEqual({
'func-1': { excluded_patterns: ['^/f1/exclude/?$'] },
'func-2': { excluded_patterns: ['^/f2/exclude$'] },
});
expect(manifest.bundler_version).toBe(env.npm_package_version);
});
test('Generates a manifest with excluded paths and patterns', () => {
test('Filters out internal in-source configurations in user created functions', () => {
const functions = [

@@ -74,16 +87,45 @@ { name: 'func-1', path: '/path/to/func-1.ts' },

const declarations = [
{ function: 'func-1', name: 'Display Name', path: '/f1/*', excludedPath: '/f1/exclude' },
{ function: 'func-2', pattern: '^/f2/.*/?$', excludedPattern: '^/f2/exclude$' },
];
const manifest = generateManifest({ bundles: [], declarations, functions });
const expectedRoutes = [
{ function: 'func-1', name: 'Display Name', pattern: '^/f1/.*/?$' },
{ function: 'func-1', path: '/f1/*' },
{ function: 'func-2', pattern: '^/f2/.*/?$' },
];
expect(manifest.routes).toEqual(expectedRoutes);
const userFunctionConfig = {
'func-1': {
onError: '/custom-error',
cache: "manual" /* Cache.Manual */,
excludedPath: '/f1/exclude',
path: '/path/to/func-1.ts',
name: 'User function',
generator: 'fake-generator',
},
};
const internalFunctionConfig = {
'func-2': {
onError: 'bypass',
cache: "off" /* Cache.Off */,
excludedPath: '/f2/exclude',
path: '/path/to/func-2.ts',
name: 'Internal function',
generator: 'internal-generator',
},
};
const manifest = generateManifest({
bundles: [],
declarations,
functions,
userFunctionConfig,
internalFunctionConfig,
});
expect(manifest.function_config).toEqual({
'func-1': { excluded_patterns: ['^/f1/exclude/?$'] },
'func-2': { excluded_patterns: ['^/f2/exclude$'] },
'func-1': {
on_error: '/custom-error',
excluded_patterns: ['^/f1/exclude/?$'],
},
'func-2': {
on_error: 'bypass',
cache: "off" /* Cache.Off */,
name: 'Internal function',
generator: 'internal-generator',
excluded_patterns: ['^/f2/exclude/?$'],
},
});
expect(manifest.bundler_version).toBe(env.npm_package_version);
});

@@ -96,6 +138,6 @@ test('Includes failure modes in manifest', () => {

const declarations = [
{ function: 'func-1', name: 'Display Name', path: '/f1/*' },
{ function: 'func-1', path: '/f1/*' },
{ function: 'func-2', pattern: '^/f2/.*/?$' },
];
const functionConfig = {
const userFunctionConfig = {
'func-1': {

@@ -105,5 +147,5 @@ onError: '/custom-error',

};
const manifest = generateManifest({ bundles: [], declarations, functions, functionConfig });
const manifest = generateManifest({ bundles: [], declarations, functions, userFunctionConfig });
expect(manifest.function_config).toEqual({
'func-1': { excluded_patterns: [], on_error: '/custom-error' },
'func-1': { on_error: '/custom-error' },
});

@@ -110,0 +152,0 @@ });

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

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

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

@@ -71,3 +71,3 @@ "chalk": "^4.1.2",

"typescript": "^4.5.4",
"vitest": "^0.29.2"
"vitest": "^0.29.7"
},

@@ -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