@netlify/edge-bundler 14.2.2 → 14.4.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.
- package/deno/lib/common.ts +1 -1
- package/dist/node/bridge.d.ts +11 -9
- package/dist/node/bridge.js +8 -7
- package/dist/node/bundle.d.ts +2 -1
- package/dist/node/bundle.js +1 -0
- package/dist/node/bundler.js +20 -4
- package/dist/node/bundler.test.js +103 -4
- package/dist/node/config.js +5 -1
- package/dist/node/feature_flags.d.ts +6 -2
- package/dist/node/feature_flags.js +3 -1
- package/dist/node/formats/tarball.d.ts +18 -0
- package/dist/node/formats/tarball.js +92 -0
- package/dist/node/import_map.d.ts +5 -0
- package/dist/node/import_map.js +36 -4
- package/dist/node/npm_dependencies.js +1 -1
- package/dist/node/server/server.test.js +7 -2
- package/dist/node/utils/sha256.d.ts +3 -2
- package/dist/node/utils/sha256.js +30 -5
- package/dist/node/utils/typescript.d.ts +1 -0
- package/dist/node/utils/typescript.js +1 -0
- package/dist/test/util.d.ts +15 -6
- package/dist/test/util.js +62 -15
- package/package.json +4 -3
package/deno/lib/common.ts
CHANGED
|
@@ -42,7 +42,7 @@ const loadWithRetry = (specifier: string, delay = 1000, maxTry = 3) => {
|
|
|
42
42
|
maxTry,
|
|
43
43
|
});
|
|
44
44
|
} catch (error) {
|
|
45
|
-
if (
|
|
45
|
+
if (error instanceof Error && isTooManyTries(error)) {
|
|
46
46
|
console.error(`Loading ${specifier} failed after ${maxTry} tries.`);
|
|
47
47
|
}
|
|
48
48
|
throw error;
|
package/dist/node/bridge.d.ts
CHANGED
|
@@ -1,23 +1,26 @@
|
|
|
1
1
|
import { type WriteStream } from 'fs';
|
|
2
2
|
import { type ExecaChildProcess } from 'execa';
|
|
3
|
+
import { FeatureFlags } from './feature_flags.js';
|
|
3
4
|
import { Logger } from './logger.js';
|
|
4
|
-
declare const DENO_VERSION_RANGE = "1.39.0 - 2.2.4";
|
|
5
|
-
type OnBeforeDownloadHook = () => void | Promise<void>;
|
|
6
|
-
type OnAfterDownloadHook = (error?: Error) => void | Promise<void>;
|
|
7
|
-
interface DenoOptions {
|
|
5
|
+
export declare const DENO_VERSION_RANGE = "1.39.0 - 2.2.4";
|
|
6
|
+
export type OnBeforeDownloadHook = () => void | Promise<void>;
|
|
7
|
+
export type OnAfterDownloadHook = (error?: Error) => void | Promise<void>;
|
|
8
|
+
export interface DenoOptions {
|
|
8
9
|
cacheDirectory?: string;
|
|
9
10
|
debug?: boolean;
|
|
10
11
|
denoDir?: string;
|
|
12
|
+
featureFlags?: FeatureFlags;
|
|
11
13
|
logger?: Logger;
|
|
12
14
|
onAfterDownload?: OnAfterDownloadHook;
|
|
13
15
|
onBeforeDownload?: OnBeforeDownloadHook;
|
|
14
16
|
useGlobal?: boolean;
|
|
15
17
|
versionRange?: string;
|
|
16
18
|
}
|
|
17
|
-
interface ProcessRef {
|
|
19
|
+
export interface ProcessRef {
|
|
18
20
|
ps?: ExecaChildProcess<string>;
|
|
19
21
|
}
|
|
20
22
|
interface RunOptions {
|
|
23
|
+
cwd?: string;
|
|
21
24
|
env?: NodeJS.ProcessEnv;
|
|
22
25
|
extendEnv?: boolean;
|
|
23
26
|
pipeOutput?: boolean;
|
|
@@ -25,7 +28,7 @@ interface RunOptions {
|
|
|
25
28
|
stdout?: WriteStream;
|
|
26
29
|
rejectOnExitCode?: boolean;
|
|
27
30
|
}
|
|
28
|
-
declare class DenoBridge {
|
|
31
|
+
export declare class DenoBridge {
|
|
29
32
|
cacheDirectory: string;
|
|
30
33
|
currentDownload?: ReturnType<DenoBridge['downloadBinary']>;
|
|
31
34
|
debug: boolean;
|
|
@@ -51,8 +54,7 @@ declare class DenoBridge {
|
|
|
51
54
|
path: string;
|
|
52
55
|
}>;
|
|
53
56
|
getEnvironmentVariables(inputEnv?: NodeJS.ProcessEnv): NodeJS.ProcessEnv;
|
|
54
|
-
run(args: string[], { env: inputEnv, extendEnv, rejectOnExitCode, stderr, stdout }?: RunOptions): Promise<import("execa").ExecaReturnValue<string>>;
|
|
57
|
+
run(args: string[], { cwd, env: inputEnv, extendEnv, rejectOnExitCode, stderr, stdout }?: RunOptions): Promise<import("execa").ExecaReturnValue<string>>;
|
|
55
58
|
runInBackground(args: string[], ref?: ProcessRef, { env: inputEnv, extendEnv, pipeOutput, stderr, stdout }?: RunOptions): Promise<void>;
|
|
56
59
|
}
|
|
57
|
-
export {
|
|
58
|
-
export type { DenoOptions, OnAfterDownloadHook, OnBeforeDownloadHook, ProcessRef };
|
|
60
|
+
export {};
|
package/dist/node/bridge.js
CHANGED
|
@@ -12,10 +12,11 @@ const DENO_VERSION_FILE = 'version.txt';
|
|
|
12
12
|
// When updating DENO_VERSION_RANGE, ensure that the deno version
|
|
13
13
|
// on the netlify/buildbot build image satisfies this range!
|
|
14
14
|
// https://github.com/netlify/buildbot/blob/f9c03c9dcb091d6570e9d0778381560d469e78ad/build-image/noble/Dockerfile#L410
|
|
15
|
-
const DENO_VERSION_RANGE = '1.39.0 - 2.2.4';
|
|
16
|
-
|
|
15
|
+
export const DENO_VERSION_RANGE = '1.39.0 - 2.2.4';
|
|
16
|
+
const NEXT_DENO_VERSION_RANGE = '^2.4.2';
|
|
17
|
+
export class DenoBridge {
|
|
17
18
|
constructor(options) {
|
|
18
|
-
var _a, _b, _c, _d, _e;
|
|
19
|
+
var _a, _b, _c, _d, _e, _f;
|
|
19
20
|
this.cacheDirectory = (_a = options.cacheDirectory) !== null && _a !== void 0 ? _a : getPathInHome('deno-cli');
|
|
20
21
|
this.debug = (_b = options.debug) !== null && _b !== void 0 ? _b : false;
|
|
21
22
|
this.denoDir = options.denoDir;
|
|
@@ -23,7 +24,8 @@ class DenoBridge {
|
|
|
23
24
|
this.onAfterDownload = options.onAfterDownload;
|
|
24
25
|
this.onBeforeDownload = options.onBeforeDownload;
|
|
25
26
|
this.useGlobal = (_d = options.useGlobal) !== null && _d !== void 0 ? _d : true;
|
|
26
|
-
this.versionRange =
|
|
27
|
+
this.versionRange =
|
|
28
|
+
(_e = options.versionRange) !== null && _e !== void 0 ? _e : (((_f = options.featureFlags) === null || _f === void 0 ? void 0 : _f.edge_bundler_generate_tarball) ? NEXT_DENO_VERSION_RANGE : DENO_VERSION_RANGE);
|
|
27
29
|
}
|
|
28
30
|
async downloadBinary() {
|
|
29
31
|
var _a, _b, _c;
|
|
@@ -148,10 +150,10 @@ class DenoBridge {
|
|
|
148
150
|
}
|
|
149
151
|
// Runs the Deno CLI in the background and returns a reference to the child
|
|
150
152
|
// process, awaiting its execution.
|
|
151
|
-
async run(args, { env: inputEnv, extendEnv = true, rejectOnExitCode = true, stderr, stdout } = {}) {
|
|
153
|
+
async run(args, { cwd, env: inputEnv, extendEnv = true, rejectOnExitCode = true, stderr, stdout } = {}) {
|
|
152
154
|
const { path: binaryPath } = await this.getBinaryPath();
|
|
153
155
|
const env = this.getEnvironmentVariables(inputEnv);
|
|
154
|
-
const options = { env, extendEnv, reject: rejectOnExitCode };
|
|
156
|
+
const options = { cwd, env, extendEnv, reject: rejectOnExitCode };
|
|
155
157
|
return DenoBridge.runWithBinary(binaryPath, args, { options, stderr, stdout });
|
|
156
158
|
}
|
|
157
159
|
// Runs the Deno CLI in the background, assigning a reference of the child
|
|
@@ -166,4 +168,3 @@ class DenoBridge {
|
|
|
166
168
|
}
|
|
167
169
|
}
|
|
168
170
|
}
|
|
169
|
-
export { DENO_VERSION_RANGE, DenoBridge };
|
package/dist/node/bundle.d.ts
CHANGED
package/dist/node/bundle.js
CHANGED
package/dist/node/bundler.js
CHANGED
|
@@ -10,6 +10,7 @@ import { load as loadDeployConfig } from './deploy_config.js';
|
|
|
10
10
|
import { getFlags } from './feature_flags.js';
|
|
11
11
|
import { findFunctions } from './finder.js';
|
|
12
12
|
import { bundle as bundleESZIP } from './formats/eszip.js';
|
|
13
|
+
import { bundle as bundleTarball } from './formats/tarball.js';
|
|
13
14
|
import { ImportMap } from './import_map.js';
|
|
14
15
|
import { getLogger } from './logger.js';
|
|
15
16
|
import { writeManifest } from './manifest.js';
|
|
@@ -22,6 +23,7 @@ export const bundle = async (sourceDirectories, distDirectory, tomlDeclarations
|
|
|
22
23
|
const options = {
|
|
23
24
|
debug,
|
|
24
25
|
cacheDirectory,
|
|
26
|
+
featureFlags,
|
|
25
27
|
logger,
|
|
26
28
|
onAfterDownload,
|
|
27
29
|
onBeforeDownload,
|
|
@@ -58,10 +60,24 @@ export const bundle = async (sourceDirectories, distDirectory, tomlDeclarations
|
|
|
58
60
|
rootPath: rootPath !== null && rootPath !== void 0 ? rootPath : basePath,
|
|
59
61
|
vendorDirectory,
|
|
60
62
|
});
|
|
63
|
+
const bundles = [];
|
|
64
|
+
if (featureFlags.edge_bundler_generate_tarball) {
|
|
65
|
+
bundles.push(await bundleTarball({
|
|
66
|
+
basePath,
|
|
67
|
+
buildID,
|
|
68
|
+
debug,
|
|
69
|
+
deno,
|
|
70
|
+
distDirectory,
|
|
71
|
+
functions,
|
|
72
|
+
featureFlags,
|
|
73
|
+
importMap: importMap.clone(),
|
|
74
|
+
vendorDirectory: vendor === null || vendor === void 0 ? void 0 : vendor.directory,
|
|
75
|
+
}));
|
|
76
|
+
}
|
|
61
77
|
if (vendor) {
|
|
62
78
|
importMap.add(vendor.importMap);
|
|
63
79
|
}
|
|
64
|
-
|
|
80
|
+
bundles.push(await bundleESZIP({
|
|
65
81
|
basePath,
|
|
66
82
|
buildID,
|
|
67
83
|
debug,
|
|
@@ -72,11 +88,11 @@ export const bundle = async (sourceDirectories, distDirectory, tomlDeclarations
|
|
|
72
88
|
featureFlags,
|
|
73
89
|
importMap,
|
|
74
90
|
vendorDirectory: vendor === null || vendor === void 0 ? void 0 : vendor.directory,
|
|
75
|
-
});
|
|
91
|
+
}));
|
|
76
92
|
// The final file name of the bundles contains a SHA256 hash of the contents,
|
|
77
93
|
// which we can only compute now that the files have been generated. So let's
|
|
78
94
|
// rename the bundles to their permanent names.
|
|
79
|
-
await createFinalBundles(
|
|
95
|
+
await createFinalBundles(bundles, distDirectory, buildID);
|
|
80
96
|
// Retrieving a configuration object for each function.
|
|
81
97
|
// Run `getFunctionConfig` in parallel as it is a non-trivial operation and spins up deno
|
|
82
98
|
const internalConfigPromises = internalFunctions.map(async (func) => [func.name, await getFunctionConfig({ func, importMap, deno, log: logger })]);
|
|
@@ -92,7 +108,7 @@ export const bundle = async (sourceDirectories, distDirectory, tomlDeclarations
|
|
|
92
108
|
declarations,
|
|
93
109
|
});
|
|
94
110
|
const manifest = await writeManifest({
|
|
95
|
-
bundles
|
|
111
|
+
bundles,
|
|
96
112
|
declarations,
|
|
97
113
|
distDirectory,
|
|
98
114
|
featureFlags,
|
|
@@ -3,10 +3,11 @@ import { access, readdir, readFile, rm, writeFile } from 'fs/promises';
|
|
|
3
3
|
import { join, resolve } from 'path';
|
|
4
4
|
import process from 'process';
|
|
5
5
|
import { pathToFileURL } from 'url';
|
|
6
|
+
import { gte, lt } from 'semver';
|
|
6
7
|
import tmp from 'tmp-promise';
|
|
7
|
-
import { test, expect, vi } from 'vitest';
|
|
8
|
+
import { test, expect, vi, describe } from 'vitest';
|
|
8
9
|
import { importMapSpecifier } from '../shared/consts.js';
|
|
9
|
-
import { runESZIP, useFixture } from '../test/util.js';
|
|
10
|
+
import { denoVersion, runESZIP, runTarball, useFixture } from '../test/util.js';
|
|
10
11
|
import { BundleError } from './bundle_error.js';
|
|
11
12
|
import { bundle } from './bundler.js';
|
|
12
13
|
import { isFileNotFoundError } from './utils/error.js';
|
|
@@ -398,7 +399,7 @@ test('Loads npm modules from bare specifiers', async () => {
|
|
|
398
399
|
const manifest = JSON.parse(manifestFile);
|
|
399
400
|
const bundlePath = join(distPath, manifest.bundles[0].asset);
|
|
400
401
|
const { func1 } = await runESZIP(bundlePath, vendorDirectory.path);
|
|
401
|
-
expect(func1).toBe(`<parent-1><child-1>JavaScript</child-1></parent-1>, <parent-2><child-2><grandchild-1>APIs<cwd>${process.cwd()}</cwd></grandchild-1></child-2></parent-2>, <parent-3><child-2><grandchild-1>Markup<cwd>${process.cwd()}</cwd></grandchild-1></child-2></parent-3
|
|
402
|
+
expect(func1).toBe(`<parent-1><child-1>JavaScript</child-1></parent-1>, <parent-2><child-2><grandchild-1>APIs<cwd>${process.cwd()}</cwd></grandchild-1></child-2></parent-2>, <parent-3><child-2><grandchild-1>Markup<cwd>${process.cwd()}</cwd></grandchild-1></child-2></parent-3>, TmV0bGlmeQ==`);
|
|
402
403
|
await cleanup();
|
|
403
404
|
await rm(vendorDirectory.path, { force: true, recursive: true });
|
|
404
405
|
});
|
|
@@ -474,7 +475,7 @@ test('Loads npm modules in a monorepo setup', async () => {
|
|
|
474
475
|
await cleanup();
|
|
475
476
|
await rm(vendorDirectory.path, { force: true, recursive: true });
|
|
476
477
|
});
|
|
477
|
-
test('Loads JSON modules', async () => {
|
|
478
|
+
test('Loads JSON modules with `with` attribute', async () => {
|
|
478
479
|
const { basePath, cleanup, distPath } = await useFixture('imports_json');
|
|
479
480
|
const sourceDirectory = join(basePath, 'functions');
|
|
480
481
|
const declarations = [
|
|
@@ -496,6 +497,35 @@ test('Loads JSON modules', async () => {
|
|
|
496
497
|
await cleanup();
|
|
497
498
|
await rm(vendorDirectory.path, { force: true, recursive: true });
|
|
498
499
|
});
|
|
500
|
+
// We can't run this on versions above 2.0.0 because the bundling will fail
|
|
501
|
+
// entirely, and what we're asserting here is that we emit a system log when
|
|
502
|
+
// import assertions are detected on successful builds. Also, running it on
|
|
503
|
+
// earlier versions won't work either, since those won't even show a warning.
|
|
504
|
+
test.skipIf(lt(denoVersion, '1.46.3') || gte(denoVersion, '2.0.0'))('Emits a system log when import assertions are used', async () => {
|
|
505
|
+
const { basePath, cleanup, distPath } = await useFixture('with_import_assert');
|
|
506
|
+
const sourceDirectory = join(basePath, 'functions');
|
|
507
|
+
const declarations = [
|
|
508
|
+
{
|
|
509
|
+
function: 'func1',
|
|
510
|
+
path: '/func1',
|
|
511
|
+
},
|
|
512
|
+
];
|
|
513
|
+
const vendorDirectory = await tmp.dir();
|
|
514
|
+
const systemLogger = vi.fn();
|
|
515
|
+
await bundle([sourceDirectory], distPath, declarations, {
|
|
516
|
+
basePath,
|
|
517
|
+
systemLogger,
|
|
518
|
+
vendorDirectory: vendorDirectory.path,
|
|
519
|
+
});
|
|
520
|
+
const manifestFile = await readFile(resolve(distPath, 'manifest.json'), 'utf8');
|
|
521
|
+
const manifest = JSON.parse(manifestFile);
|
|
522
|
+
const bundlePath = join(distPath, manifest.bundles[0].asset);
|
|
523
|
+
const { func1 } = await runESZIP(bundlePath, vendorDirectory.path);
|
|
524
|
+
expect(func1).toBe(`{"foo":"bar"}`);
|
|
525
|
+
expect(systemLogger).toHaveBeenCalledWith(`Edge function uses import assertions: ${join(sourceDirectory, 'func1.ts')}`);
|
|
526
|
+
await cleanup();
|
|
527
|
+
await rm(vendorDirectory.path, { force: true, recursive: true });
|
|
528
|
+
});
|
|
499
529
|
test('Supports TSX and process.env', async () => {
|
|
500
530
|
const { basePath, cleanup, distPath } = await useFixture('tsx');
|
|
501
531
|
const sourceDirectory = join(basePath, 'functions');
|
|
@@ -550,3 +580,72 @@ test('Loads edge functions from the Frameworks API', async () => {
|
|
|
550
580
|
});
|
|
551
581
|
await cleanup();
|
|
552
582
|
});
|
|
583
|
+
describe.skipIf(lt(denoVersion, '2.4.2'))('Produces a tarball bundle', () => {
|
|
584
|
+
test('With only local imports', async () => {
|
|
585
|
+
const systemLogger = vi.fn();
|
|
586
|
+
const { basePath, cleanup, distPath } = await useFixture('imports_node_builtin', { copyDirectory: true });
|
|
587
|
+
const declarations = [
|
|
588
|
+
{
|
|
589
|
+
function: 'func1',
|
|
590
|
+
path: '/func1',
|
|
591
|
+
},
|
|
592
|
+
];
|
|
593
|
+
const vendorDirectory = await tmp.dir();
|
|
594
|
+
await bundle([join(basePath, 'netlify/edge-functions')], distPath, declarations, {
|
|
595
|
+
basePath,
|
|
596
|
+
configPath: join(basePath, '.netlify/edge-functions/config.json'),
|
|
597
|
+
featureFlags: {
|
|
598
|
+
edge_bundler_generate_tarball: true,
|
|
599
|
+
},
|
|
600
|
+
systemLogger,
|
|
601
|
+
});
|
|
602
|
+
expect(systemLogger.mock.calls.find((call) => call[0] === 'Could not track dependencies in edge function:')).toBeUndefined();
|
|
603
|
+
const expectedOutput = {
|
|
604
|
+
func1: 'ok',
|
|
605
|
+
};
|
|
606
|
+
const manifestFile = await readFile(resolve(distPath, 'manifest.json'), 'utf8');
|
|
607
|
+
const manifest = JSON.parse(manifestFile);
|
|
608
|
+
const tarballPath = join(distPath, manifest.bundles[0].asset);
|
|
609
|
+
const tarballResult = await runTarball(tarballPath);
|
|
610
|
+
expect(tarballResult).toStrictEqual(expectedOutput);
|
|
611
|
+
const eszipPath = join(distPath, manifest.bundles[1].asset);
|
|
612
|
+
const eszipResult = await runESZIP(eszipPath);
|
|
613
|
+
expect(eszipResult).toStrictEqual(expectedOutput);
|
|
614
|
+
await cleanup();
|
|
615
|
+
await rm(vendorDirectory.path, { force: true, recursive: true });
|
|
616
|
+
});
|
|
617
|
+
// TODO: https://github.com/denoland/deno/issues/30187
|
|
618
|
+
test.todo('Using npm modules', async () => {
|
|
619
|
+
const systemLogger = vi.fn();
|
|
620
|
+
const { basePath, cleanup, distPath } = await useFixture('imports_npm_module', { copyDirectory: true });
|
|
621
|
+
const sourceDirectory = join(basePath, 'functions');
|
|
622
|
+
const declarations = [
|
|
623
|
+
{
|
|
624
|
+
function: 'func1',
|
|
625
|
+
path: '/func1',
|
|
626
|
+
},
|
|
627
|
+
];
|
|
628
|
+
const vendorDirectory = await tmp.dir();
|
|
629
|
+
await bundle([sourceDirectory], distPath, declarations, {
|
|
630
|
+
basePath,
|
|
631
|
+
featureFlags: {
|
|
632
|
+
edge_bundler_generate_tarball: true,
|
|
633
|
+
},
|
|
634
|
+
importMapPaths: [join(basePath, 'import_map.json')],
|
|
635
|
+
vendorDirectory: vendorDirectory.path,
|
|
636
|
+
systemLogger,
|
|
637
|
+
});
|
|
638
|
+
expect(systemLogger.mock.calls.find((call) => call[0] === 'Could not track dependencies in edge function:')).toBeUndefined();
|
|
639
|
+
const expectedOutput = `<parent-1><child-1>JavaScript</child-1></parent-1>, <parent-2><child-2><grandchild-1>APIs<cwd>${process.cwd()}</cwd></grandchild-1></child-2></parent-2>, <parent-3><child-2><grandchild-1>Markup<cwd>${process.cwd()}</cwd></grandchild-1></child-2></parent-3>, TmV0bGlmeQ==`;
|
|
640
|
+
const manifestFile = await readFile(resolve(distPath, 'manifest.json'), 'utf8');
|
|
641
|
+
const manifest = JSON.parse(manifestFile);
|
|
642
|
+
const tarballPath = join(distPath, manifest.bundles[0].asset);
|
|
643
|
+
const tarballResult = await runTarball(tarballPath);
|
|
644
|
+
expect(tarballResult.func1).toBe(expectedOutput);
|
|
645
|
+
const eszipPath = join(distPath, manifest.bundles[1].asset);
|
|
646
|
+
const eszipResult = await runESZIP(eszipPath, vendorDirectory.path);
|
|
647
|
+
expect(eszipResult.func1).toBe(expectedOutput);
|
|
648
|
+
await cleanup();
|
|
649
|
+
await rm(vendorDirectory.path, { force: true, recursive: true });
|
|
650
|
+
});
|
|
651
|
+
}, 10000);
|
package/dist/node/config.js
CHANGED
|
@@ -37,10 +37,11 @@ export const getFunctionConfig = async ({ func, importMap, deno, log, }) => {
|
|
|
37
37
|
// the config function to write to stdout and stderr without that interfering
|
|
38
38
|
// with the extractor.
|
|
39
39
|
const collector = await tmp.file();
|
|
40
|
+
// Retrieving the version of Deno.
|
|
41
|
+
const version = new SemVer((await deno.getBinaryVersion((await deno.getBinaryPath({ silent: true })).path)) || '');
|
|
40
42
|
// The extractor will use its exit code to signal different error scenarios,
|
|
41
43
|
// based on the list of exit codes we send as an argument. We then capture
|
|
42
44
|
// the exit code to know exactly what happened and guide people accordingly.
|
|
43
|
-
const version = new SemVer((await deno.getBinaryVersion((await deno.getBinaryPath({ silent: true })).path)) || '');
|
|
44
45
|
const { exitCode, stderr, stdout } = await deno.run([
|
|
45
46
|
'run',
|
|
46
47
|
'--allow-env',
|
|
@@ -57,6 +58,9 @@ export const getFunctionConfig = async ({ func, importMap, deno, log, }) => {
|
|
|
57
58
|
pathToFileURL(collector.path).href,
|
|
58
59
|
JSON.stringify(ConfigExitCode),
|
|
59
60
|
].filter(Boolean), { rejectOnExitCode: false });
|
|
61
|
+
if (stderr.includes('Import assertions are deprecated')) {
|
|
62
|
+
log.system(`Edge function uses import assertions: ${func.path}`);
|
|
63
|
+
}
|
|
60
64
|
if (exitCode !== ConfigExitCode.Success) {
|
|
61
65
|
handleConfigError(func, exitCode, stderr, log);
|
|
62
66
|
return {};
|
|
@@ -1,6 +1,10 @@
|
|
|
1
|
-
declare const defaultFlags: {
|
|
1
|
+
declare const defaultFlags: {
|
|
2
|
+
edge_bundler_generate_tarball: boolean;
|
|
3
|
+
};
|
|
2
4
|
type FeatureFlag = keyof typeof defaultFlags;
|
|
3
5
|
type FeatureFlags = Partial<Record<FeatureFlag, boolean>>;
|
|
4
|
-
declare const getFlags: (input?: Record<string, boolean>, flags?: {
|
|
6
|
+
declare const getFlags: (input?: Record<string, boolean>, flags?: {
|
|
7
|
+
edge_bundler_generate_tarball: boolean;
|
|
8
|
+
}) => FeatureFlags;
|
|
5
9
|
export { defaultFlags, getFlags };
|
|
6
10
|
export type { FeatureFlag, FeatureFlags };
|
|
@@ -1,4 +1,6 @@
|
|
|
1
|
-
const defaultFlags = {
|
|
1
|
+
const defaultFlags = {
|
|
2
|
+
edge_bundler_generate_tarball: false,
|
|
3
|
+
};
|
|
2
4
|
const getFlags = (input = {}, flags = defaultFlags) => Object.entries(flags).reduce((result, [key, defaultValue]) => ({
|
|
3
5
|
...result,
|
|
4
6
|
[key]: input[key] === undefined ? defaultValue : input[key],
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { DenoBridge } from '../bridge.js';
|
|
2
|
+
import { Bundle } from '../bundle.js';
|
|
3
|
+
import { EdgeFunction } from '../edge_function.js';
|
|
4
|
+
import { FeatureFlags } from '../feature_flags.js';
|
|
5
|
+
import { ImportMap } from '../import_map.js';
|
|
6
|
+
interface BundleTarballOptions {
|
|
7
|
+
basePath: string;
|
|
8
|
+
buildID: string;
|
|
9
|
+
debug?: boolean;
|
|
10
|
+
deno: DenoBridge;
|
|
11
|
+
distDirectory: string;
|
|
12
|
+
featureFlags: FeatureFlags;
|
|
13
|
+
functions: EdgeFunction[];
|
|
14
|
+
importMap: ImportMap;
|
|
15
|
+
vendorDirectory?: string;
|
|
16
|
+
}
|
|
17
|
+
export declare const bundle: ({ basePath, buildID, deno, distDirectory, functions, importMap, vendorDirectory, }: BundleTarballOptions) => Promise<Bundle>;
|
|
18
|
+
export {};
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
import { promises as fs } from 'fs';
|
|
2
|
+
import path from 'path';
|
|
3
|
+
import commonPathPrefix from 'common-path-prefix';
|
|
4
|
+
import * as tar from 'tar';
|
|
5
|
+
import tmp from 'tmp-promise';
|
|
6
|
+
import { BundleFormat } from '../bundle.js';
|
|
7
|
+
import { getDirectoryHash, getStringHash } from '../utils/sha256.js';
|
|
8
|
+
const TARBALL_EXTENSION = '.tar';
|
|
9
|
+
const getUnixPath = (input) => input.split(path.sep).join('/');
|
|
10
|
+
export const bundle = async ({ basePath, buildID, deno, distDirectory, functions, importMap, vendorDirectory, }) => {
|
|
11
|
+
const sideFilesDir = await tmp.dir({ unsafeCleanup: true });
|
|
12
|
+
const cleanup = [sideFilesDir.cleanup];
|
|
13
|
+
let denoDir = vendorDirectory ? path.join(vendorDirectory, 'deno_dir') : undefined;
|
|
14
|
+
if (!denoDir) {
|
|
15
|
+
const tmpDir = await tmp.dir({ unsafeCleanup: true });
|
|
16
|
+
denoDir = tmpDir.path;
|
|
17
|
+
cleanup.push(tmpDir.cleanup);
|
|
18
|
+
}
|
|
19
|
+
const manifest = {
|
|
20
|
+
functions: {},
|
|
21
|
+
version: 1,
|
|
22
|
+
};
|
|
23
|
+
const entryPoints = functions.map((func) => func.path);
|
|
24
|
+
// `deno bundle` does not return the paths of the files it emits, so we have
|
|
25
|
+
// to infer them. When multiple entry points are supplied, it will find the
|
|
26
|
+
// common path prefix and use that as the base directory in `outdir`. When
|
|
27
|
+
// using a single entry point, `commonPathPrefix` returns an empty string,
|
|
28
|
+
// so we use the path of the first entry point's directory.
|
|
29
|
+
const commonPath = commonPathPrefix(entryPoints) || path.dirname(entryPoints[0]);
|
|
30
|
+
for (const func of functions) {
|
|
31
|
+
const relativePath = path.relative(commonPath, func.path);
|
|
32
|
+
const bundledPath = path.format({
|
|
33
|
+
...path.parse(relativePath),
|
|
34
|
+
base: undefined,
|
|
35
|
+
ext: '.js',
|
|
36
|
+
});
|
|
37
|
+
manifest.functions[func.name] = getUnixPath(bundledPath);
|
|
38
|
+
}
|
|
39
|
+
await deno.run([
|
|
40
|
+
'bundle',
|
|
41
|
+
'--import-map',
|
|
42
|
+
importMap.withNodeBuiltins().toDataURL(),
|
|
43
|
+
'--quiet',
|
|
44
|
+
'--code-splitting',
|
|
45
|
+
'--outdir',
|
|
46
|
+
distDirectory,
|
|
47
|
+
...functions.map((func) => func.path),
|
|
48
|
+
], {
|
|
49
|
+
cwd: basePath,
|
|
50
|
+
});
|
|
51
|
+
const manifestPath = path.join(sideFilesDir.path, 'manifest.json');
|
|
52
|
+
const manifestContents = JSON.stringify(manifest);
|
|
53
|
+
await fs.writeFile(manifestPath, manifestContents);
|
|
54
|
+
const denoConfigPath = path.join(sideFilesDir.path, 'deno.json');
|
|
55
|
+
const denoConfigContents = JSON.stringify(importMap.getContentsWithRelativePaths());
|
|
56
|
+
await fs.writeFile(denoConfigPath, denoConfigContents);
|
|
57
|
+
const rootLevel = await fs.readdir(distDirectory);
|
|
58
|
+
const hash = await getDirectoryHash(distDirectory);
|
|
59
|
+
const tarballPath = path.join(distDirectory, buildID + TARBALL_EXTENSION);
|
|
60
|
+
await fs.mkdir(path.dirname(tarballPath), { recursive: true });
|
|
61
|
+
// Adding all the bundled files.
|
|
62
|
+
await tar.create({
|
|
63
|
+
cwd: distDirectory,
|
|
64
|
+
file: tarballPath,
|
|
65
|
+
onWriteEntry(entry) {
|
|
66
|
+
entry.path = getUnixPath(`./${entry.path}`);
|
|
67
|
+
},
|
|
68
|
+
}, rootLevel);
|
|
69
|
+
// Adding `deno.json`.
|
|
70
|
+
await tar.update({
|
|
71
|
+
cwd: distDirectory,
|
|
72
|
+
file: tarballPath,
|
|
73
|
+
onWriteEntry(entry) {
|
|
74
|
+
entry.path = './deno.json';
|
|
75
|
+
},
|
|
76
|
+
}, [denoConfigPath]);
|
|
77
|
+
// Adding the manifest file.
|
|
78
|
+
await tar.update({
|
|
79
|
+
cwd: distDirectory,
|
|
80
|
+
file: tarballPath,
|
|
81
|
+
onWriteEntry(entry) {
|
|
82
|
+
entry.path = './___netlify-edge-functions.json';
|
|
83
|
+
},
|
|
84
|
+
}, [manifestPath]);
|
|
85
|
+
await Promise.all(cleanup);
|
|
86
|
+
const finalHash = [hash, getStringHash(manifestContents), getStringHash(denoConfigContents)].join('');
|
|
87
|
+
return {
|
|
88
|
+
extension: TARBALL_EXTENSION,
|
|
89
|
+
format: BundleFormat.TARBALL,
|
|
90
|
+
hash: finalHash,
|
|
91
|
+
};
|
|
92
|
+
};
|
|
@@ -24,6 +24,10 @@ export declare class ImportMap {
|
|
|
24
24
|
imports: Imports;
|
|
25
25
|
scopes: {};
|
|
26
26
|
};
|
|
27
|
+
getContentsWithRelativePaths(): {
|
|
28
|
+
imports: Imports;
|
|
29
|
+
scopes: Record<string, Imports>;
|
|
30
|
+
};
|
|
27
31
|
getContentsWithURLObjects(prefixes?: Record<string, string>): {
|
|
28
32
|
imports: Record<string, URL>;
|
|
29
33
|
scopes: Record<string, Record<string, URL>>;
|
|
@@ -34,6 +38,7 @@ export declare class ImportMap {
|
|
|
34
38
|
scopes: Record<string, Imports>;
|
|
35
39
|
};
|
|
36
40
|
toDataURL(): string;
|
|
41
|
+
withNodeBuiltins(): this;
|
|
37
42
|
writeToFile(path: string): Promise<void>;
|
|
38
43
|
}
|
|
39
44
|
export {};
|
package/dist/node/import_map.js
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
|
-
import { Buffer } from 'buffer';
|
|
2
|
-
import { promises as fs } from 'fs';
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
1
|
+
import { Buffer } from 'node:buffer';
|
|
2
|
+
import { promises as fs } from 'node:fs';
|
|
3
|
+
import { builtinModules } from 'node:module';
|
|
4
|
+
import { dirname, relative } from 'node:path';
|
|
5
|
+
import { fileURLToPath, pathToFileURL } from 'node:url';
|
|
5
6
|
import { parse } from '@import-maps/resolve';
|
|
6
7
|
import { isFileNotFoundError } from './utils/error.js';
|
|
7
8
|
const INTERNAL_IMPORTS = {
|
|
@@ -134,6 +135,24 @@ export class ImportMap {
|
|
|
134
135
|
scopes: transformedScopes,
|
|
135
136
|
};
|
|
136
137
|
}
|
|
138
|
+
getContentsWithRelativePaths() {
|
|
139
|
+
let imports = {};
|
|
140
|
+
let scopes = {};
|
|
141
|
+
this.sources.forEach((file) => {
|
|
142
|
+
imports = { ...imports, ...file.imports };
|
|
143
|
+
scopes = { ...scopes, ...file.scopes };
|
|
144
|
+
});
|
|
145
|
+
// Internal imports must come last, because we need to guarantee that
|
|
146
|
+
// `netlify:edge` isn't user-defined.
|
|
147
|
+
Object.entries(INTERNAL_IMPORTS).forEach((internalImport) => {
|
|
148
|
+
const [specifier, url] = internalImport;
|
|
149
|
+
imports[specifier] = url;
|
|
150
|
+
});
|
|
151
|
+
return {
|
|
152
|
+
imports,
|
|
153
|
+
scopes,
|
|
154
|
+
};
|
|
155
|
+
}
|
|
137
156
|
// The same as `getContents`, but the URLs are represented as URL objects
|
|
138
157
|
// instead of strings. This is compatible with the `ParsedImportMap` type
|
|
139
158
|
// from the `@import-maps/resolve` library.
|
|
@@ -182,6 +201,19 @@ export class ImportMap {
|
|
|
182
201
|
const encodedImportMap = Buffer.from(data).toString('base64');
|
|
183
202
|
return `data:application/json;base64,${encodedImportMap}`;
|
|
184
203
|
}
|
|
204
|
+
// Adds an import map source mapping Node.js built-in modules to their prefixed
|
|
205
|
+
// version (e.g. "path" => "node:path").
|
|
206
|
+
withNodeBuiltins() {
|
|
207
|
+
const imports = {};
|
|
208
|
+
for (const name of builtinModules) {
|
|
209
|
+
imports[name] = `node:${name}`;
|
|
210
|
+
}
|
|
211
|
+
this.sources.push({
|
|
212
|
+
baseURL: new URL(import.meta.url),
|
|
213
|
+
imports,
|
|
214
|
+
});
|
|
215
|
+
return this;
|
|
216
|
+
}
|
|
185
217
|
async writeToFile(path) {
|
|
186
218
|
const distDirectory = dirname(path);
|
|
187
219
|
await fs.mkdir(distDirectory, { recursive: true });
|
|
@@ -8,7 +8,7 @@ import { findUp } from 'find-up';
|
|
|
8
8
|
import { parseImports } from 'parse-imports';
|
|
9
9
|
import tmp from 'tmp-promise';
|
|
10
10
|
import { pathsBetween } from './utils/fs.js';
|
|
11
|
-
|
|
11
|
+
import { TYPESCRIPT_EXTENSIONS } from './utils/typescript.js';
|
|
12
12
|
const slugifyFileName = (specifier) => {
|
|
13
13
|
return specifier.replace(/\//g, '_');
|
|
14
14
|
};
|
|
@@ -2,6 +2,11 @@ import { createWriteStream } from 'fs';
|
|
|
2
2
|
import { readFile } from 'fs/promises';
|
|
3
3
|
import { join } from 'path';
|
|
4
4
|
import process from 'process';
|
|
5
|
+
// @ts-expect-error TypeScript is complaining about the values for the `module`
|
|
6
|
+
// and `moduleResolution` configuration properties, but changing those to more
|
|
7
|
+
// modern values causes other packages to fail. Leaving this for now, but we
|
|
8
|
+
// should have a proper fix for this.
|
|
9
|
+
import { getURL as getBootstrapURL } from '@netlify/edge-functions-bootstrap/version';
|
|
5
10
|
import getPort from 'get-port';
|
|
6
11
|
import tmp from 'tmp-promise';
|
|
7
12
|
import { v4 as uuidv4 } from 'uuid';
|
|
@@ -19,7 +24,7 @@ test('Starts a server and serves requests for edge functions', async () => {
|
|
|
19
24
|
const servePath = join(basePath, '.netlify', 'edge-functions-serve');
|
|
20
25
|
const server = await serve({
|
|
21
26
|
basePath,
|
|
22
|
-
bootstrapURL:
|
|
27
|
+
bootstrapURL: await getBootstrapURL(),
|
|
23
28
|
port,
|
|
24
29
|
servePath,
|
|
25
30
|
});
|
|
@@ -99,7 +104,7 @@ test('Serves edge functions in a monorepo setup', async () => {
|
|
|
99
104
|
const servePath = join(basePath, '.netlify', 'edge-functions-serve');
|
|
100
105
|
const server = await serve({
|
|
101
106
|
basePath,
|
|
102
|
-
bootstrapURL:
|
|
107
|
+
bootstrapURL: await getBootstrapURL(),
|
|
103
108
|
port,
|
|
104
109
|
rootPath,
|
|
105
110
|
servePath,
|
|
@@ -1,2 +1,3 @@
|
|
|
1
|
-
declare const
|
|
2
|
-
export
|
|
1
|
+
export declare const getDirectoryHash: (dirPath: string) => Promise<string>;
|
|
2
|
+
export declare const getFileHash: (path: string) => Promise<string>;
|
|
3
|
+
export declare const getStringHash: (input: string) => string;
|
|
@@ -1,10 +1,30 @@
|
|
|
1
|
-
import crypto from 'crypto';
|
|
2
|
-
import fs from 'fs';
|
|
3
|
-
|
|
1
|
+
import crypto from 'node:crypto';
|
|
2
|
+
import { createReadStream, promises as fs } from 'node:fs';
|
|
3
|
+
import path from 'node:path';
|
|
4
|
+
export const getDirectoryHash = async (dirPath) => {
|
|
5
|
+
const entries = [];
|
|
6
|
+
async function walk(currentPath) {
|
|
7
|
+
const dirents = await fs.readdir(currentPath, { withFileTypes: true });
|
|
8
|
+
for (const dirent of dirents) {
|
|
9
|
+
const fullPath = path.join(currentPath, dirent.name);
|
|
10
|
+
const relativePath = path.relative(dirPath, fullPath);
|
|
11
|
+
if (dirent.isDirectory()) {
|
|
12
|
+
await walk(fullPath);
|
|
13
|
+
}
|
|
14
|
+
else if (dirent.isFile() || dirent.isSymbolicLink()) {
|
|
15
|
+
const fileHash = await getFileHash(fullPath);
|
|
16
|
+
entries.push(`${relativePath}:${fileHash}`);
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
await walk(dirPath);
|
|
21
|
+
return getStringHash(entries.sort((a, b) => a.localeCompare(b)).join('\n'));
|
|
22
|
+
};
|
|
23
|
+
export const getFileHash = (path) => {
|
|
4
24
|
const hash = crypto.createHash('sha256');
|
|
5
25
|
hash.setEncoding('hex');
|
|
6
26
|
return new Promise((resolve, reject) => {
|
|
7
|
-
const file =
|
|
27
|
+
const file = createReadStream(path);
|
|
8
28
|
file.on('end', () => {
|
|
9
29
|
hash.end();
|
|
10
30
|
resolve(hash.read());
|
|
@@ -13,4 +33,9 @@ const getFileHash = (path) => {
|
|
|
13
33
|
file.pipe(hash);
|
|
14
34
|
});
|
|
15
35
|
};
|
|
16
|
-
export
|
|
36
|
+
export const getStringHash = (input) => {
|
|
37
|
+
const hash = crypto.createHash('sha256');
|
|
38
|
+
hash.setEncoding('hex');
|
|
39
|
+
hash.update(input);
|
|
40
|
+
return hash.digest('hex');
|
|
41
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare const TYPESCRIPT_EXTENSIONS: Set<string>;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export const TYPESCRIPT_EXTENSIONS = new Set(['.ts', '.tsx', '.cts', '.ctsx', '.mts', '.mtsx']);
|
package/dist/test/util.d.ts
CHANGED
|
@@ -1,11 +1,20 @@
|
|
|
1
1
|
import type { Manifest } from '../node/manifest.js';
|
|
2
|
-
declare const testLogger: import("../node/logger.js").Logger;
|
|
3
|
-
declare const fixturesDir: string;
|
|
4
|
-
|
|
2
|
+
export declare const testLogger: import("../node/logger.js").Logger;
|
|
3
|
+
export declare const fixturesDir: string;
|
|
4
|
+
interface UseFixtureOptions {
|
|
5
|
+
copyDirectory?: boolean;
|
|
6
|
+
}
|
|
7
|
+
export declare const useFixture: (fixtureName: string, { copyDirectory }?: UseFixtureOptions) => Promise<{
|
|
8
|
+
basePath: string;
|
|
9
|
+
cleanup: () => Promise<[PromiseSettledResult<() => Promise<void>>, PromiseSettledResult<() => Promise<void>>]>;
|
|
10
|
+
distPath: string;
|
|
11
|
+
} | {
|
|
5
12
|
basePath: string;
|
|
6
13
|
cleanup: () => Promise<void>;
|
|
7
14
|
distPath: string;
|
|
8
15
|
}>;
|
|
9
|
-
declare const getRouteMatcher: (manifest: Manifest) => (candidate: string) => import("../node/manifest.js").Route | undefined;
|
|
10
|
-
declare const runESZIP: (eszipPath: string, vendorDirectory?: string) => Promise<any>;
|
|
11
|
-
export
|
|
16
|
+
export declare const getRouteMatcher: (manifest: Manifest) => (candidate: string) => import("../node/manifest.js").Route | undefined;
|
|
17
|
+
export declare const runESZIP: (eszipPath: string, vendorDirectory?: string) => Promise<any>;
|
|
18
|
+
export declare const runTarball: (tarballPath: string) => Promise<any>;
|
|
19
|
+
export declare const denoVersion: string;
|
|
20
|
+
export {};
|
package/dist/test/util.js
CHANGED
|
@@ -1,27 +1,40 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
1
|
+
import { execSync } from 'node:child_process';
|
|
2
|
+
import { promises as fs } from 'node:fs';
|
|
3
|
+
import { join, resolve } from 'node:path';
|
|
4
|
+
import { stderr, stdout } from 'node:process';
|
|
5
|
+
import { fileURLToPath, pathToFileURL } from 'node:url';
|
|
6
|
+
import cpy from 'cpy';
|
|
5
7
|
import { execa } from 'execa';
|
|
8
|
+
import * as tar from 'tar';
|
|
6
9
|
import tmp from 'tmp-promise';
|
|
7
10
|
import { getLogger } from '../node/logger.js';
|
|
8
|
-
const testLogger = getLogger(() => {
|
|
11
|
+
export const testLogger = getLogger(() => {
|
|
9
12
|
// no-op
|
|
10
13
|
});
|
|
11
14
|
const url = new URL(import.meta.url);
|
|
12
15
|
const dirname = fileURLToPath(url);
|
|
13
|
-
const fixturesDir = resolve(dirname, '..', 'fixtures');
|
|
14
|
-
const useFixture = async (fixtureName) => {
|
|
15
|
-
const
|
|
16
|
+
export const fixturesDir = resolve(dirname, '..', 'fixtures');
|
|
17
|
+
export const useFixture = async (fixtureName, { copyDirectory } = {}) => {
|
|
18
|
+
const tmpDistDir = await tmp.dir({ unsafeCleanup: true });
|
|
16
19
|
const fixtureDir = resolve(fixturesDir, fixtureName);
|
|
17
|
-
const distPath = join(
|
|
20
|
+
const distPath = join(tmpDistDir.path, '.netlify', 'edge-functions-dist');
|
|
21
|
+
if (copyDirectory) {
|
|
22
|
+
const tmpFixtureDir = await tmp.dir({ unsafeCleanup: true });
|
|
23
|
+
// TODO: Replace with `fs.cp` once the Node.js version range allows.
|
|
24
|
+
await cpy(`${fixtureDir}/**`, tmpFixtureDir.path);
|
|
25
|
+
return {
|
|
26
|
+
basePath: tmpFixtureDir.path,
|
|
27
|
+
cleanup: () => Promise.allSettled([tmpDistDir.cleanup, tmpFixtureDir.cleanup]),
|
|
28
|
+
distPath,
|
|
29
|
+
};
|
|
30
|
+
}
|
|
18
31
|
return {
|
|
19
32
|
basePath: fixtureDir,
|
|
20
|
-
cleanup:
|
|
33
|
+
cleanup: tmpDistDir.cleanup,
|
|
21
34
|
distPath,
|
|
22
35
|
};
|
|
23
36
|
};
|
|
24
|
-
const
|
|
37
|
+
const inspectESZIPFunction = (path) => `
|
|
25
38
|
import { functions } from "${pathToFileURL(path)}.js";
|
|
26
39
|
|
|
27
40
|
const responses = {};
|
|
@@ -35,7 +48,25 @@ const inspectFunction = (path) => `
|
|
|
35
48
|
|
|
36
49
|
console.log(JSON.stringify(responses));
|
|
37
50
|
`;
|
|
38
|
-
const
|
|
51
|
+
const inspectTarballFunction = () => `
|
|
52
|
+
import path from "node:path";
|
|
53
|
+
import { pathToFileURL } from "node:url";
|
|
54
|
+
import manifest from "./___netlify-edge-functions.json" with { type: "json" };
|
|
55
|
+
|
|
56
|
+
const responses = {};
|
|
57
|
+
|
|
58
|
+
for (const functionName in manifest.functions) {
|
|
59
|
+
const req = new Request("https://test.netlify");
|
|
60
|
+
const entrypoint = path.resolve(manifest.functions[functionName]);
|
|
61
|
+
const func = await import(pathToFileURL(entrypoint))
|
|
62
|
+
const res = await func.default(req);
|
|
63
|
+
|
|
64
|
+
responses[functionName] = await res.text();
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
console.log(JSON.stringify(responses));
|
|
68
|
+
`;
|
|
69
|
+
export const getRouteMatcher = (manifest) => (candidate) => manifest.routes.find((route) => {
|
|
39
70
|
var _a, _b;
|
|
40
71
|
const regex = new RegExp(route.pattern);
|
|
41
72
|
if (!regex.test(candidate)) {
|
|
@@ -48,13 +79,14 @@ const getRouteMatcher = (manifest) => (candidate) => manifest.routes.find((route
|
|
|
48
79
|
const isExcluded = excludedPatterns.some((pattern) => new RegExp(pattern).test(candidate));
|
|
49
80
|
return !isExcluded;
|
|
50
81
|
});
|
|
51
|
-
const runESZIP = async (eszipPath, vendorDirectory) => {
|
|
82
|
+
export const runESZIP = async (eszipPath, vendorDirectory) => {
|
|
52
83
|
var _a, _b, _c;
|
|
53
84
|
const tmpDir = await tmp.dir({ unsafeCleanup: true });
|
|
54
85
|
// Extract ESZIP into temporary directory.
|
|
55
86
|
const extractCommand = execa('deno', [
|
|
56
87
|
'run',
|
|
57
88
|
'--allow-all',
|
|
89
|
+
'--no-lock',
|
|
58
90
|
'https://deno.land/x/eszip@v0.55.2/eszip.ts',
|
|
59
91
|
'x',
|
|
60
92
|
eszipPath,
|
|
@@ -76,10 +108,25 @@ const runESZIP = async (eszipPath, vendorDirectory) => {
|
|
|
76
108
|
}
|
|
77
109
|
await fs.rename(stage2Path, `${stage2Path}.js`);
|
|
78
110
|
// Run function that imports the extracted stage 2 and invokes each function.
|
|
79
|
-
const evalCommand = execa('deno', ['eval', '--import-map', importMapPath,
|
|
111
|
+
const evalCommand = execa('deno', ['eval', '--import-map', importMapPath, inspectESZIPFunction(stage2Path)]);
|
|
80
112
|
(_c = evalCommand.stderr) === null || _c === void 0 ? void 0 : _c.pipe(stderr);
|
|
81
113
|
const result = await evalCommand;
|
|
82
114
|
await tmpDir.cleanup();
|
|
83
115
|
return JSON.parse(result.stdout);
|
|
84
116
|
};
|
|
85
|
-
export
|
|
117
|
+
export const runTarball = async (tarballPath) => {
|
|
118
|
+
var _a;
|
|
119
|
+
const tmpDir = await tmp.dir({ unsafeCleanup: true });
|
|
120
|
+
await tar.extract({
|
|
121
|
+
cwd: tmpDir.path,
|
|
122
|
+
file: tarballPath,
|
|
123
|
+
});
|
|
124
|
+
const evalCommand = execa('deno', ['eval', inspectTarballFunction()], {
|
|
125
|
+
cwd: tmpDir.path,
|
|
126
|
+
});
|
|
127
|
+
(_a = evalCommand.stderr) === null || _a === void 0 ? void 0 : _a.pipe(stderr);
|
|
128
|
+
const result = await evalCommand;
|
|
129
|
+
await tmpDir.cleanup();
|
|
130
|
+
return JSON.parse(result.stdout);
|
|
131
|
+
};
|
|
132
|
+
export const denoVersion = execSync('deno eval --no-lock "console.log(Deno.version.deno)"').toString();
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@netlify/edge-bundler",
|
|
3
|
-
"version": "14.
|
|
3
|
+
"version": "14.4.0",
|
|
4
4
|
"description": "Intelligently prepare Netlify Edge Functions for deployment",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/node/index.js",
|
|
@@ -42,6 +42,7 @@
|
|
|
42
42
|
"test": "test/node"
|
|
43
43
|
},
|
|
44
44
|
"devDependencies": {
|
|
45
|
+
"@netlify/edge-functions-bootstrap": "^2.14.0",
|
|
45
46
|
"@types/node": "^18.19.111",
|
|
46
47
|
"@types/semver": "^7.3.9",
|
|
47
48
|
"@types/uuid": "^10.0.0",
|
|
@@ -51,7 +52,6 @@
|
|
|
51
52
|
"cpy": "^11.1.0",
|
|
52
53
|
"nock": "^14.0.0",
|
|
53
54
|
"npm-run-all2": "^6.0.0",
|
|
54
|
-
"tar": "^7.0.0",
|
|
55
55
|
"typescript": "^5.0.0",
|
|
56
56
|
"vitest": "^3.0.0"
|
|
57
57
|
},
|
|
@@ -77,9 +77,10 @@
|
|
|
77
77
|
"parse-imports": "^2.2.1",
|
|
78
78
|
"path-key": "^4.0.0",
|
|
79
79
|
"semver": "^7.3.8",
|
|
80
|
+
"tar": "^7.4.3",
|
|
80
81
|
"tmp-promise": "^3.0.3",
|
|
81
82
|
"urlpattern-polyfill": "8.0.2",
|
|
82
83
|
"uuid": "^11.0.0"
|
|
83
84
|
},
|
|
84
|
-
"gitHead": "
|
|
85
|
+
"gitHead": "1f098009f518b66b0d6604910aff38824d7f9a69"
|
|
85
86
|
}
|