@netlify/edge-bundler 14.5.6 → 14.7.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/extract.ts +7 -0
- package/deno/lib/stage2.ts +1 -3
- package/deno/vendor/deno.land/x/eszip@v0.55.2/eszip.ts +192 -0
- package/dist/node/bridge.js +24 -18
- package/dist/node/bridge.test.js +7 -11
- package/dist/node/bundle_error.d.ts +5 -4
- package/dist/node/bundle_error.js +5 -5
- package/dist/node/bundler.js +58 -19
- package/dist/node/bundler.test.js +13 -14
- package/dist/node/config.d.ts +3 -4
- package/dist/node/config.js +17 -17
- package/dist/node/config.test.js +4 -16
- package/dist/node/declaration.js +2 -3
- package/dist/node/deploy_config.js +2 -3
- package/dist/node/downloader.js +1 -2
- package/dist/node/feature_flags.d.ts +2 -0
- package/dist/node/feature_flags.js +1 -0
- package/dist/node/formats/eszip.d.ts +7 -2
- package/dist/node/formats/eszip.js +14 -3
- package/dist/node/import_map.js +5 -0
- package/dist/node/logger.js +2 -2
- package/dist/node/main.test.js +3 -4
- package/dist/node/manifest.js +2 -3
- package/dist/node/manifest.test.js +2 -3
- package/dist/node/npm_dependencies.js +5 -7
- package/dist/node/server/server.js +3 -4
- package/dist/node/server/server.test.js +3 -3
- package/dist/node/server/util.js +2 -2
- package/dist/node/types.js +1 -1
- package/dist/node/utils/urlpattern.d.ts +1 -4
- package/dist/node/utils/urlpattern.js +4 -2
- package/dist/node/validation/manifest/error.js +3 -3
- package/dist/test/util.js +5 -8
- package/package.json +2 -2
package/deno/extract.ts
ADDED
package/deno/lib/stage2.ts
CHANGED
|
@@ -105,7 +105,7 @@ const stage2Loader = (
|
|
|
105
105
|
}
|
|
106
106
|
}
|
|
107
107
|
|
|
108
|
-
const writeStage2 = async ({
|
|
108
|
+
export const writeStage2 = async ({
|
|
109
109
|
basePath,
|
|
110
110
|
destPath,
|
|
111
111
|
externals,
|
|
@@ -122,5 +122,3 @@ const writeStage2 = async ({
|
|
|
122
122
|
|
|
123
123
|
return await Deno.writeFile(destPath, bytes)
|
|
124
124
|
}
|
|
125
|
-
|
|
126
|
-
export { writeStage2 }
|
|
@@ -0,0 +1,192 @@
|
|
|
1
|
+
// CLI utility to build/list/extract/run ESZIPs
|
|
2
|
+
|
|
3
|
+
import { build, Parser } from "./mod.ts";
|
|
4
|
+
import { dirname, join } from "https://deno.land/std@0.177.0/path/mod.ts";
|
|
5
|
+
|
|
6
|
+
function hasV2Header(bytes: Uint8Array) {
|
|
7
|
+
const magicV2 = new TextDecoder().decode(bytes.slice(0, 8));
|
|
8
|
+
return magicV2 === "ESZIP_V2";
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
interface ESZIP {
|
|
12
|
+
extract(dest: string): Promise<void>;
|
|
13
|
+
list(): string[];
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
interface V1Entry {
|
|
17
|
+
Source: {
|
|
18
|
+
source: string;
|
|
19
|
+
transpiled: string;
|
|
20
|
+
};
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
class V1 {
|
|
24
|
+
inner: Record<string, V1Entry>;
|
|
25
|
+
|
|
26
|
+
constructor(bytes: Uint8Array) {
|
|
27
|
+
const json = new TextDecoder().decode(bytes);
|
|
28
|
+
const eszip = JSON.parse(json);
|
|
29
|
+
this.inner = eszip;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
static load(bytes: Uint8Array) {
|
|
33
|
+
return Promise.resolve(new V1(bytes));
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
*entries() {
|
|
37
|
+
for (
|
|
38
|
+
const [
|
|
39
|
+
url,
|
|
40
|
+
{
|
|
41
|
+
Source: { source, transpiled },
|
|
42
|
+
},
|
|
43
|
+
] of Object.entries(this.inner.modules)
|
|
44
|
+
) {
|
|
45
|
+
yield { url, source, transpiled };
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
async extract(dest: string) {
|
|
50
|
+
for (const { url, source, transpiled } of this.entries()) {
|
|
51
|
+
await write(join(dest, "source", url2path(url)), source);
|
|
52
|
+
await write(
|
|
53
|
+
join(dest, "transpiled", url2path(url)),
|
|
54
|
+
transpiled ?? source,
|
|
55
|
+
);
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
list() {
|
|
60
|
+
return Array.from(this.entries()).map((e) => e.url);
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
class V2 {
|
|
65
|
+
parser: Parser;
|
|
66
|
+
specifiers: string[];
|
|
67
|
+
|
|
68
|
+
constructor(parser: Parser, specifiers: string[]) {
|
|
69
|
+
this.parser = parser;
|
|
70
|
+
this.specifiers = specifiers;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
static async load(bytes: Uint8Array) {
|
|
74
|
+
const parser = await Parser.createInstance();
|
|
75
|
+
const specifiers = await parser.parseBytes(bytes);
|
|
76
|
+
await parser.load();
|
|
77
|
+
return new V2(parser, specifiers as string[]);
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
async extract(dest: string) {
|
|
81
|
+
const imports: Record<string, string> = {};
|
|
82
|
+
|
|
83
|
+
for (const specifier of this.specifiers) {
|
|
84
|
+
const module = await this.parser.getModuleSource(specifier);
|
|
85
|
+
await write(join(dest, "source", url2path(specifier)), module);
|
|
86
|
+
// Track import
|
|
87
|
+
imports[specifier] = `./${url2path(specifier)}`;
|
|
88
|
+
}
|
|
89
|
+
// Write import map
|
|
90
|
+
const importMap = JSON.stringify({ imports }, null, 2);
|
|
91
|
+
await Deno.writeTextFile(
|
|
92
|
+
join(dest, "source", "import_map.json"),
|
|
93
|
+
importMap,
|
|
94
|
+
);
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
list() {
|
|
98
|
+
return this.specifiers;
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
export async function loadESZIP(filename: string): Promise<ESZIP> {
|
|
103
|
+
const bytes = await Deno.readFile(filename);
|
|
104
|
+
if (hasV2Header(bytes)) {
|
|
105
|
+
return await V2.load(bytes);
|
|
106
|
+
}
|
|
107
|
+
return await V1.load(bytes);
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
function url2path(urlString: string) {
|
|
111
|
+
const url = new URL(urlString);
|
|
112
|
+
const tail = url.pathname.split("/").filter(Boolean);
|
|
113
|
+
const relativePath = tail.length === 0 ? [".root"] : tail;
|
|
114
|
+
return join(url.hostname, ...relativePath);
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
async function write(path: string, content: string) {
|
|
118
|
+
await Deno.mkdir(dirname(path), { recursive: true });
|
|
119
|
+
await Deno.writeTextFile(path, content);
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
async function run(eszip: ESZIP, specifier: string) {
|
|
123
|
+
// Extract to tmp directory
|
|
124
|
+
const tmpDir = await Deno.makeTempDir({ prefix: "esz" });
|
|
125
|
+
try {
|
|
126
|
+
// Extract
|
|
127
|
+
await eszip.extract(tmpDir);
|
|
128
|
+
const importMap = join(tmpDir, "source", "import_map.json");
|
|
129
|
+
// Run
|
|
130
|
+
const p = new Deno.Command("deno", {
|
|
131
|
+
args: [
|
|
132
|
+
"run",
|
|
133
|
+
"-A",
|
|
134
|
+
"--no-check",
|
|
135
|
+
"--import-map",
|
|
136
|
+
importMap,
|
|
137
|
+
specifier,
|
|
138
|
+
],
|
|
139
|
+
});
|
|
140
|
+
await p.output();
|
|
141
|
+
} finally {
|
|
142
|
+
// Cleanup
|
|
143
|
+
await Deno.remove(tmpDir, { recursive: true });
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
// Main
|
|
148
|
+
async function main() {
|
|
149
|
+
const args = Deno.args;
|
|
150
|
+
const [subcmd, filename, ...rest] = args;
|
|
151
|
+
|
|
152
|
+
if (subcmd === "help") {
|
|
153
|
+
return console.log("TODO");
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
switch (subcmd) {
|
|
157
|
+
case "build":
|
|
158
|
+
case "b": {
|
|
159
|
+
const eszip = await build([filename]);
|
|
160
|
+
let out = rest[0];
|
|
161
|
+
if (!out) {
|
|
162
|
+
// Create outfile name from url filename
|
|
163
|
+
out = new URL(filename).pathname.split("/").pop() || "out";
|
|
164
|
+
}
|
|
165
|
+
console.log(`${out}.eszip: ${eszip.length} bytes`);
|
|
166
|
+
await Deno.writeFile(`${out}.eszip`, eszip);
|
|
167
|
+
return;
|
|
168
|
+
}
|
|
169
|
+
case "x":
|
|
170
|
+
case "extract": {
|
|
171
|
+
const eszip = await loadESZIP(filename);
|
|
172
|
+
return await eszip.extract(rest[0] ?? Deno.cwd());
|
|
173
|
+
}
|
|
174
|
+
case "l":
|
|
175
|
+
case "ls":
|
|
176
|
+
case "list": {
|
|
177
|
+
const eszip = await loadESZIP(filename);
|
|
178
|
+
return console.log(eszip.list().join("\n"));
|
|
179
|
+
}
|
|
180
|
+
case "r":
|
|
181
|
+
case "run": {
|
|
182
|
+
const eszip = await loadESZIP(filename);
|
|
183
|
+
const specifier = rest[0];
|
|
184
|
+
if (!specifier) {
|
|
185
|
+
return console.error("Please provide a specifier to run");
|
|
186
|
+
}
|
|
187
|
+
return await run(eszip, specifier);
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
await main();
|
package/dist/node/bridge.js
CHANGED
|
@@ -15,21 +15,28 @@ const DENO_VERSION_FILE = 'version.txt';
|
|
|
15
15
|
export const DENO_VERSION_RANGE = '1.39.0 - 2.2.4';
|
|
16
16
|
const NEXT_DENO_VERSION_RANGE = '^2.4.2';
|
|
17
17
|
export class DenoBridge {
|
|
18
|
+
cacheDirectory;
|
|
19
|
+
currentDownload;
|
|
20
|
+
debug;
|
|
21
|
+
denoDir;
|
|
22
|
+
logger;
|
|
23
|
+
onAfterDownload;
|
|
24
|
+
onBeforeDownload;
|
|
25
|
+
useGlobal;
|
|
26
|
+
versionRange;
|
|
18
27
|
constructor(options) {
|
|
19
|
-
|
|
20
|
-
this.
|
|
21
|
-
this.debug = (_b = options.debug) !== null && _b !== void 0 ? _b : false;
|
|
28
|
+
this.cacheDirectory = options.cacheDirectory ?? getPathInHome('deno-cli');
|
|
29
|
+
this.debug = options.debug ?? false;
|
|
22
30
|
this.denoDir = options.denoDir;
|
|
23
|
-
this.logger =
|
|
31
|
+
this.logger = options.logger ?? getLogger(undefined, undefined, options.debug);
|
|
24
32
|
this.onAfterDownload = options.onAfterDownload;
|
|
25
33
|
this.onBeforeDownload = options.onBeforeDownload;
|
|
26
|
-
this.useGlobal =
|
|
27
|
-
|
|
28
|
-
|
|
34
|
+
this.useGlobal = options.useGlobal ?? true;
|
|
35
|
+
const useNextDeno = options.featureFlags?.edge_bundler_generate_tarball || options.featureFlags?.edge_bundler_deno_v2;
|
|
36
|
+
this.versionRange = options.versionRange ?? (useNextDeno ? NEXT_DENO_VERSION_RANGE : DENO_VERSION_RANGE);
|
|
29
37
|
}
|
|
30
38
|
async downloadBinary() {
|
|
31
|
-
|
|
32
|
-
await ((_a = this.onBeforeDownload) === null || _a === void 0 ? void 0 : _a.call(this));
|
|
39
|
+
await this.onBeforeDownload?.();
|
|
33
40
|
await this.ensureCacheDirectory();
|
|
34
41
|
this.logger.system(`Downloading Deno CLI to ${this.cacheDirectory}`);
|
|
35
42
|
const binaryPath = await download(this.cacheDirectory, this.versionRange, this.logger);
|
|
@@ -39,12 +46,12 @@ export class DenoBridge {
|
|
|
39
46
|
// that the tests catch it.
|
|
40
47
|
if (downloadedVersion === undefined) {
|
|
41
48
|
const error = new Error('There was a problem setting up the Edge Functions environment. To try a manual installation, visit https://ntl.fyi/install-deno.');
|
|
42
|
-
await
|
|
49
|
+
await this.onAfterDownload?.(error);
|
|
43
50
|
this.logger.system('Could not run downloaded Deno CLI', error);
|
|
44
51
|
throw error;
|
|
45
52
|
}
|
|
46
53
|
await this.writeVersionFile(downloadedVersion);
|
|
47
|
-
await
|
|
54
|
+
await this.onAfterDownload?.();
|
|
48
55
|
return binaryPath;
|
|
49
56
|
}
|
|
50
57
|
async getBinaryVersion(binaryPath) {
|
|
@@ -97,19 +104,18 @@ export class DenoBridge {
|
|
|
97
104
|
return this.currentDownload;
|
|
98
105
|
}
|
|
99
106
|
static runWithBinary(binaryPath, args, { options, pipeOutput, stderr, stdout, }) {
|
|
100
|
-
var _a, _b, _c, _d;
|
|
101
107
|
const runDeno = execa(binaryPath, args, options);
|
|
102
108
|
if (stderr) {
|
|
103
|
-
|
|
109
|
+
runDeno.stderr?.pipe(stderr);
|
|
104
110
|
}
|
|
105
111
|
else if (pipeOutput) {
|
|
106
|
-
|
|
112
|
+
runDeno.stderr?.pipe(process.stderr);
|
|
107
113
|
}
|
|
108
114
|
if (stdout) {
|
|
109
|
-
|
|
115
|
+
runDeno.stdout?.pipe(stdout);
|
|
110
116
|
}
|
|
111
117
|
else if (pipeOutput) {
|
|
112
|
-
|
|
118
|
+
runDeno.stdout?.pipe(process.stdout);
|
|
113
119
|
}
|
|
114
120
|
return runDeno;
|
|
115
121
|
}
|
|
@@ -124,14 +130,14 @@ export class DenoBridge {
|
|
|
124
130
|
async getBinaryPath(options) {
|
|
125
131
|
const globalPath = await this.getGlobalBinary();
|
|
126
132
|
if (globalPath !== undefined) {
|
|
127
|
-
if (!
|
|
133
|
+
if (!options?.silent) {
|
|
128
134
|
this.logger.system('Using global installation of Deno CLI');
|
|
129
135
|
}
|
|
130
136
|
return { global: true, path: globalPath };
|
|
131
137
|
}
|
|
132
138
|
const cachedPath = await this.getCachedBinary();
|
|
133
139
|
if (cachedPath !== undefined) {
|
|
134
|
-
if (!
|
|
140
|
+
if (!options?.silent) {
|
|
135
141
|
this.logger.system('Using cached Deno CLI from', cachedPath);
|
|
136
142
|
}
|
|
137
143
|
return { global: false, path: cachedPath };
|
package/dist/node/bridge.test.js
CHANGED
|
@@ -12,8 +12,7 @@ import { getPlatformTarget } from './platform.js';
|
|
|
12
12
|
const require = createRequire(import.meta.url);
|
|
13
13
|
const archiver = require('archiver');
|
|
14
14
|
const getMockDenoBridge = function (tmpDir, mockBinaryOutput) {
|
|
15
|
-
|
|
16
|
-
const latestVersion = (_b = (_a = semver.minVersion(DENO_VERSION_RANGE)) === null || _a === void 0 ? void 0 : _a.version) !== null && _b !== void 0 ? _b : '';
|
|
15
|
+
const latestVersion = semver.minVersion(DENO_VERSION_RANGE)?.version ?? '';
|
|
17
16
|
const data = new PassThrough();
|
|
18
17
|
const archive = archiver('zip', { zlib: { level: 9 } });
|
|
19
18
|
archive.pipe(data);
|
|
@@ -32,7 +31,6 @@ const getMockDenoBridge = function (tmpDir, mockBinaryOutput) {
|
|
|
32
31
|
});
|
|
33
32
|
};
|
|
34
33
|
test('Does not inherit environment variables if `extendEnv` is false', async () => {
|
|
35
|
-
var _a;
|
|
36
34
|
const tmpDir = await tmp.dir();
|
|
37
35
|
const deno = getMockDenoBridge(tmpDir, `#!/usr/bin/env sh
|
|
38
36
|
|
|
@@ -46,9 +44,9 @@ test('Does not inherit environment variables if `extendEnv` is false', async ()
|
|
|
46
44
|
const referenceOutput = await deno.run(['test'], { env: {}, extendEnv: false });
|
|
47
45
|
env.TADA = 'TUDU';
|
|
48
46
|
const result = await deno.run(['test'], { env: { LULU: 'LALA' }, extendEnv: false });
|
|
49
|
-
let output =
|
|
47
|
+
let output = result?.stdout ?? '';
|
|
50
48
|
delete env.TADA;
|
|
51
|
-
referenceOutput
|
|
49
|
+
referenceOutput?.stdout.split('\n').forEach((line) => {
|
|
52
50
|
output = output.replace(line.trim(), '');
|
|
53
51
|
});
|
|
54
52
|
output = output.trim().replace(/\n+/g, '\n');
|
|
@@ -56,7 +54,6 @@ test('Does not inherit environment variables if `extendEnv` is false', async ()
|
|
|
56
54
|
await rm(tmpDir.path, { force: true, recursive: true, maxRetries: 10 });
|
|
57
55
|
});
|
|
58
56
|
test('Does inherit environment variables if `extendEnv` is true', async () => {
|
|
59
|
-
var _a;
|
|
60
57
|
const tmpDir = await tmp.dir();
|
|
61
58
|
const deno = getMockDenoBridge(tmpDir, `#!/usr/bin/env sh
|
|
62
59
|
|
|
@@ -70,9 +67,9 @@ test('Does inherit environment variables if `extendEnv` is true', async () => {
|
|
|
70
67
|
const referenceOutput = await deno.run(['test'], { env: {}, extendEnv: true });
|
|
71
68
|
env.TADA = 'TUDU';
|
|
72
69
|
const result = await deno.run(['test'], { env: { LULU: 'LALA' }, extendEnv: true });
|
|
73
|
-
let output =
|
|
70
|
+
let output = result?.stdout ?? '';
|
|
74
71
|
delete env.TADA;
|
|
75
|
-
referenceOutput
|
|
72
|
+
referenceOutput?.stdout.split('\n').forEach((line) => {
|
|
76
73
|
output = output.replace(line.trim(), '');
|
|
77
74
|
});
|
|
78
75
|
// lets remove holes, split lines and sort lines by name, as different OSes might order them different
|
|
@@ -81,7 +78,6 @@ test('Does inherit environment variables if `extendEnv` is true', async () => {
|
|
|
81
78
|
await rm(tmpDir.path, { force: true, recursive: true, maxRetries: 10 });
|
|
82
79
|
});
|
|
83
80
|
test('Does inherit environment variables if `extendEnv` is not set', async () => {
|
|
84
|
-
var _a;
|
|
85
81
|
const tmpDir = await tmp.dir();
|
|
86
82
|
const deno = getMockDenoBridge(tmpDir, `#!/usr/bin/env sh
|
|
87
83
|
|
|
@@ -95,9 +91,9 @@ test('Does inherit environment variables if `extendEnv` is not set', async () =>
|
|
|
95
91
|
const referenceOutput = await deno.run(['test'], { env: {}, extendEnv: true });
|
|
96
92
|
env.TADA = 'TUDU';
|
|
97
93
|
const result = await deno.run(['test'], { env: { LULU: 'LALA' } });
|
|
98
|
-
let output =
|
|
94
|
+
let output = result?.stdout ?? '';
|
|
99
95
|
delete env.TADA;
|
|
100
|
-
referenceOutput
|
|
96
|
+
referenceOutput?.stdout.split('\n').forEach((line) => {
|
|
101
97
|
output = output.replace(line.trim(), '');
|
|
102
98
|
});
|
|
103
99
|
// lets remove holes, split lines and sort lines by name, as different OSes might order them different
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
interface BundleErrorOptions {
|
|
2
|
-
|
|
2
|
+
cause?: unknown;
|
|
3
|
+
format?: string;
|
|
3
4
|
}
|
|
4
5
|
declare const getCustomErrorInfo: (options?: BundleErrorOptions) => {
|
|
5
6
|
location: {
|
|
@@ -8,12 +9,12 @@ declare const getCustomErrorInfo: (options?: BundleErrorOptions) => {
|
|
|
8
9
|
};
|
|
9
10
|
type: string;
|
|
10
11
|
};
|
|
11
|
-
declare class BundleError extends Error {
|
|
12
|
+
export declare class BundleError extends Error {
|
|
12
13
|
customErrorInfo: ReturnType<typeof getCustomErrorInfo>;
|
|
13
14
|
constructor(originalError: Error, options?: BundleErrorOptions);
|
|
14
15
|
}
|
|
15
16
|
/**
|
|
16
17
|
* BundleErrors are treated as user-error, so Netlify Team is not alerted about them.
|
|
17
18
|
*/
|
|
18
|
-
declare const wrapBundleError: (input: unknown, options?: BundleErrorOptions) => unknown;
|
|
19
|
-
export {
|
|
19
|
+
export declare const wrapBundleError: (input: unknown, options?: BundleErrorOptions) => unknown;
|
|
20
|
+
export {};
|
|
@@ -1,13 +1,14 @@
|
|
|
1
1
|
const getCustomErrorInfo = (options) => ({
|
|
2
2
|
location: {
|
|
3
|
-
format: options
|
|
3
|
+
format: options?.format,
|
|
4
4
|
runtime: 'deno',
|
|
5
5
|
},
|
|
6
6
|
type: 'functionsBundling',
|
|
7
7
|
});
|
|
8
|
-
class BundleError extends Error {
|
|
8
|
+
export class BundleError extends Error {
|
|
9
|
+
customErrorInfo;
|
|
9
10
|
constructor(originalError, options) {
|
|
10
|
-
super(originalError.message);
|
|
11
|
+
super(originalError.message, { cause: options?.cause });
|
|
11
12
|
this.customErrorInfo = getCustomErrorInfo(options);
|
|
12
13
|
this.name = 'BundleError';
|
|
13
14
|
this.stack = originalError.stack;
|
|
@@ -18,7 +19,7 @@ class BundleError extends Error {
|
|
|
18
19
|
/**
|
|
19
20
|
* BundleErrors are treated as user-error, so Netlify Team is not alerted about them.
|
|
20
21
|
*/
|
|
21
|
-
const wrapBundleError = (input, options) => {
|
|
22
|
+
export const wrapBundleError = (input, options) => {
|
|
22
23
|
if (input instanceof Error) {
|
|
23
24
|
if (input.message.includes("The module's source code could not be parsed")) {
|
|
24
25
|
input.message = input.stderr;
|
|
@@ -27,4 +28,3 @@ const wrapBundleError = (input, options) => {
|
|
|
27
28
|
}
|
|
28
29
|
return input;
|
|
29
30
|
};
|
|
30
|
-
export { BundleError, wrapBundleError };
|
package/dist/node/bundler.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { promises as fs } from 'fs';
|
|
2
|
-
import { join } from 'path';
|
|
2
|
+
import { join, relative } from 'path';
|
|
3
3
|
import commonPathPrefix from 'common-path-prefix';
|
|
4
4
|
import { v4 as uuidv4 } from 'uuid';
|
|
5
5
|
import { importMapSpecifier } from '../shared/consts.js';
|
|
@@ -9,7 +9,7 @@ import { mergeDeclarations } from './declaration.js';
|
|
|
9
9
|
import { load as loadDeployConfig } from './deploy_config.js';
|
|
10
10
|
import { getFlags } from './feature_flags.js';
|
|
11
11
|
import { findFunctions } from './finder.js';
|
|
12
|
-
import { bundle as bundleESZIP } from './formats/eszip.js';
|
|
12
|
+
import { bundle as bundleESZIP, extension as eszipExtension, extract as extractESZIP } from './formats/eszip.js';
|
|
13
13
|
import { bundle as bundleTarball } from './formats/tarball.js';
|
|
14
14
|
import { ImportMap } from './import_map.js';
|
|
15
15
|
import { getLogger } from './logger.js';
|
|
@@ -47,7 +47,7 @@ export const bundle = async (sourceDirectories, distDirectory, tomlDeclarations
|
|
|
47
47
|
const internalSrcFolders = (Array.isArray(internalSrcFolder) ? internalSrcFolder : [internalSrcFolder]).filter(nonNullable);
|
|
48
48
|
const userSourceDirectories = sourceDirectories.filter((dir) => !internalSrcFolders.includes(dir));
|
|
49
49
|
const importMap = new ImportMap();
|
|
50
|
-
await importMap.addFiles([deployConfig
|
|
50
|
+
await importMap.addFiles([deployConfig?.importMap, ...importMapPaths], logger);
|
|
51
51
|
const userFunctions = userSourceDirectories.length === 0 ? [] : await findFunctions(userSourceDirectories);
|
|
52
52
|
const internalFunctions = internalSrcFolder ? await findFunctions(internalSrcFolders) : [];
|
|
53
53
|
const functions = [...internalFunctions, ...userFunctions];
|
|
@@ -57,7 +57,7 @@ export const bundle = async (sourceDirectories, distDirectory, tomlDeclarations
|
|
|
57
57
|
functions,
|
|
58
58
|
importMap,
|
|
59
59
|
logger,
|
|
60
|
-
rootPath: rootPath
|
|
60
|
+
rootPath: rootPath ?? basePath,
|
|
61
61
|
vendorDirectory,
|
|
62
62
|
});
|
|
63
63
|
const bundles = [];
|
|
@@ -71,7 +71,7 @@ export const bundle = async (sourceDirectories, distDirectory, tomlDeclarations
|
|
|
71
71
|
functions,
|
|
72
72
|
featureFlags,
|
|
73
73
|
importMap: importMap.clone(),
|
|
74
|
-
vendorDirectory: vendor
|
|
74
|
+
vendorDirectory: vendor?.directory,
|
|
75
75
|
}));
|
|
76
76
|
}
|
|
77
77
|
if (vendor) {
|
|
@@ -87,19 +87,23 @@ export const bundle = async (sourceDirectories, distDirectory, tomlDeclarations
|
|
|
87
87
|
functions,
|
|
88
88
|
featureFlags,
|
|
89
89
|
importMap,
|
|
90
|
-
vendorDirectory: vendor
|
|
90
|
+
vendorDirectory: vendor?.directory,
|
|
91
91
|
}));
|
|
92
92
|
// The final file name of the bundles contains a SHA256 hash of the contents,
|
|
93
93
|
// which we can only compute now that the files have been generated. So let's
|
|
94
94
|
// rename the bundles to their permanent names.
|
|
95
|
-
await createFinalBundles(bundles, distDirectory, buildID);
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
95
|
+
const bundlePaths = await createFinalBundles(bundles, distDirectory, buildID);
|
|
96
|
+
const eszipPath = bundlePaths.find((path) => path.endsWith(eszipExtension));
|
|
97
|
+
const { internalFunctions: internalFunctionsWithConfig, userFunctions: userFunctionsWithConfig } = await getFunctionConfigs({
|
|
98
|
+
basePath,
|
|
99
|
+
deno,
|
|
100
|
+
eszipPath,
|
|
101
|
+
featureFlags,
|
|
102
|
+
importMap,
|
|
103
|
+
internalFunctions,
|
|
104
|
+
log: logger,
|
|
105
|
+
userFunctions,
|
|
106
|
+
});
|
|
103
107
|
// Creating a final declarations array by combining the TOML file with the
|
|
104
108
|
// deploy configuration API and the in-source configuration.
|
|
105
109
|
const declarations = mergeDeclarations(tomlDeclarations, userFunctionsWithConfig, internalFunctionsWithConfig, deployConfig.declarations, featureFlags);
|
|
@@ -118,19 +122,54 @@ export const bundle = async (sourceDirectories, distDirectory, tomlDeclarations
|
|
|
118
122
|
importMap: importMapSpecifier,
|
|
119
123
|
layers: deployConfig.layers,
|
|
120
124
|
});
|
|
121
|
-
await
|
|
125
|
+
await vendor?.cleanup();
|
|
122
126
|
if (distImportMapPath) {
|
|
123
127
|
await importMap.writeToFile(distImportMapPath);
|
|
124
128
|
}
|
|
125
129
|
return { functions, manifest };
|
|
126
130
|
};
|
|
131
|
+
const getFunctionConfigs = async ({ basePath, deno, eszipPath, featureFlags, importMap, log, internalFunctions, userFunctions, }) => {
|
|
132
|
+
try {
|
|
133
|
+
const internalConfigPromises = internalFunctions.map(async (func) => [func.name, await getFunctionConfig({ functionPath: func.path, importMap, deno, log })]);
|
|
134
|
+
const userConfigPromises = userFunctions.map(async (func) => [func.name, await getFunctionConfig({ functionPath: func.path, importMap, deno, log })]);
|
|
135
|
+
// Creating a hash of function names to configuration objects.
|
|
136
|
+
const internalFunctionsWithConfig = Object.fromEntries(await Promise.all(internalConfigPromises));
|
|
137
|
+
const userFunctionsWithConfig = Object.fromEntries(await Promise.all(userConfigPromises));
|
|
138
|
+
return {
|
|
139
|
+
internalFunctions: internalFunctionsWithConfig,
|
|
140
|
+
userFunctions: userFunctionsWithConfig,
|
|
141
|
+
};
|
|
142
|
+
}
|
|
143
|
+
catch (err) {
|
|
144
|
+
if (!(err instanceof Error && err.cause === 'IMPORT_ASSERT') || !eszipPath || !featureFlags?.edge_bundler_deno_v2) {
|
|
145
|
+
throw err;
|
|
146
|
+
}
|
|
147
|
+
// We failed to extract the configuration because there is an import assert
|
|
148
|
+
// in the function code, a deprecated feature that we used to support with
|
|
149
|
+
// Deno 1.x. To avoid a breaking change, we treat this error as a special
|
|
150
|
+
// case, using the generated ESZIP to extract the configuration. This works
|
|
151
|
+
// because import asserts are transpiled to import attributes.
|
|
152
|
+
const extractedESZIP = await extractESZIP(deno, eszipPath);
|
|
153
|
+
const configs = await Promise.all([...internalFunctions, ...userFunctions].map(async (func) => {
|
|
154
|
+
const relativePath = relative(basePath, func.path);
|
|
155
|
+
const functionPath = join(extractedESZIP.path, relativePath);
|
|
156
|
+
return [func.name, await getFunctionConfig({ functionPath, importMap, deno, log })];
|
|
157
|
+
}));
|
|
158
|
+
await extractedESZIP.cleanup();
|
|
159
|
+
return {
|
|
160
|
+
internalFunctions: Object.fromEntries(configs.slice(0, internalFunctions.length)),
|
|
161
|
+
userFunctions: Object.fromEntries(configs.slice(internalFunctions.length)),
|
|
162
|
+
};
|
|
163
|
+
}
|
|
164
|
+
};
|
|
127
165
|
const createFinalBundles = async (bundles, distDirectory, buildID) => {
|
|
128
166
|
const renamingOps = bundles.map(async ({ extension, hash }) => {
|
|
129
167
|
const tempBundlePath = join(distDirectory, `${buildID}${extension}`);
|
|
130
168
|
const finalBundlePath = join(distDirectory, `${hash}${extension}`);
|
|
131
169
|
await fs.rename(tempBundlePath, finalBundlePath);
|
|
170
|
+
return finalBundlePath;
|
|
132
171
|
});
|
|
133
|
-
await Promise.all(renamingOps);
|
|
172
|
+
return await Promise.all(renamingOps);
|
|
134
173
|
};
|
|
135
174
|
const getBasePath = (sourceDirectories, inputBasePath) => {
|
|
136
175
|
// If there's a specific base path supplied, that takes precedence.
|
|
@@ -148,11 +187,11 @@ const getBasePath = (sourceDirectories, inputBasePath) => {
|
|
|
148
187
|
// declaration level. We want these properties to live at the function level
|
|
149
188
|
// in their config object, so we translate that for backwards-compatibility.
|
|
150
189
|
const mergeWithDeclarationConfig = ({ functionName, config, declarations }) => {
|
|
151
|
-
const declaration = declarations
|
|
190
|
+
const declaration = declarations?.find((decl) => decl.function === functionName);
|
|
152
191
|
return {
|
|
153
192
|
...config,
|
|
154
|
-
name:
|
|
155
|
-
generator:
|
|
193
|
+
name: declaration?.name || config.name,
|
|
194
|
+
generator: declaration?.generator || config.generator,
|
|
156
195
|
};
|
|
157
196
|
};
|
|
158
197
|
const addGeneratorFallback = (config) => ({
|
|
@@ -3,7 +3,7 @@ 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 {
|
|
6
|
+
import { lt } from 'semver';
|
|
7
7
|
import * as tar from 'tar';
|
|
8
8
|
import tmp from 'tmp-promise';
|
|
9
9
|
import { test, expect, vi, describe } from 'vitest';
|
|
@@ -498,23 +498,16 @@ test('Loads JSON modules with `with` attribute', async () => {
|
|
|
498
498
|
await cleanup();
|
|
499
499
|
await rm(vendorDirectory.path, { force: true, recursive: true });
|
|
500
500
|
});
|
|
501
|
-
|
|
502
|
-
// entirely, and what we're asserting here is that we emit a system log when
|
|
503
|
-
// import assertions are detected on successful builds. Also, running it on
|
|
504
|
-
// earlier versions won't work either, since those won't even show a warning.
|
|
505
|
-
test.skipIf(lt(denoVersion, '1.46.3') || gte(denoVersion, '2.0.0'))('Emits a system log when import assertions are used', async () => {
|
|
501
|
+
test('Emits a system log when import assertions are used', async () => {
|
|
506
502
|
const { basePath, cleanup, distPath } = await useFixture('with_import_assert');
|
|
507
503
|
const sourceDirectory = join(basePath, 'functions');
|
|
508
|
-
const declarations = [
|
|
509
|
-
{
|
|
510
|
-
function: 'func1',
|
|
511
|
-
path: '/func1',
|
|
512
|
-
},
|
|
513
|
-
];
|
|
514
504
|
const vendorDirectory = await tmp.dir();
|
|
515
505
|
const systemLogger = vi.fn();
|
|
516
|
-
await bundle([sourceDirectory], distPath,
|
|
506
|
+
await bundle([sourceDirectory], distPath, [], {
|
|
517
507
|
basePath,
|
|
508
|
+
featureFlags: {
|
|
509
|
+
edge_bundler_deno_v2: true,
|
|
510
|
+
},
|
|
518
511
|
systemLogger,
|
|
519
512
|
vendorDirectory: vendorDirectory.path,
|
|
520
513
|
});
|
|
@@ -524,6 +517,12 @@ test.skipIf(lt(denoVersion, '1.46.3') || gte(denoVersion, '2.0.0'))('Emits a sys
|
|
|
524
517
|
const { func1 } = await runESZIP(bundlePath, vendorDirectory.path);
|
|
525
518
|
expect(func1).toBe(`{"foo":"bar"}`);
|
|
526
519
|
expect(systemLogger).toHaveBeenCalledWith(`Edge function uses import assertions: ${join(sourceDirectory, 'func1.ts')}`);
|
|
520
|
+
expect(manifest.routes[0]).toEqual({
|
|
521
|
+
function: 'func1',
|
|
522
|
+
pattern: '^/with-import-assert/?$',
|
|
523
|
+
excluded_patterns: [],
|
|
524
|
+
path: '/with-import-assert',
|
|
525
|
+
});
|
|
527
526
|
await cleanup();
|
|
528
527
|
await rm(vendorDirectory.path, { force: true, recursive: true });
|
|
529
528
|
});
|
|
@@ -656,4 +655,4 @@ describe.skipIf(lt(denoVersion, '2.4.3'))('Produces a tarball bundle', () => {
|
|
|
656
655
|
await cleanup();
|
|
657
656
|
await rm(vendorDirectory.path, { force: true, recursive: true });
|
|
658
657
|
});
|
|
659
|
-
},
|
|
658
|
+
}, 10_000);
|
package/dist/node/config.d.ts
CHANGED
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import { DenoBridge } from './bridge.js';
|
|
2
|
-
import { EdgeFunction } from './edge_function.js';
|
|
3
2
|
import { ImportMap } from './import_map.js';
|
|
4
3
|
import { Logger } from './logger.js';
|
|
5
4
|
import { RateLimit } from './rate_limit.js';
|
|
@@ -31,10 +30,10 @@ interface FunctionConfigWithPattern extends BaseFunctionConfig {
|
|
|
31
30
|
}
|
|
32
31
|
export type FunctionConfig = FunctionConfigWithPath | FunctionConfigWithPattern;
|
|
33
32
|
export type FunctionConfigWithAllPossibleFields = BaseFunctionConfig & Partial<FunctionConfigWithPath & FunctionConfigWithPattern>;
|
|
34
|
-
export declare const getFunctionConfig: ({
|
|
35
|
-
func: EdgeFunction;
|
|
36
|
-
importMap: ImportMap;
|
|
33
|
+
export declare const getFunctionConfig: ({ deno, functionPath, importMap, log, }: {
|
|
37
34
|
deno: DenoBridge;
|
|
35
|
+
functionPath: string;
|
|
36
|
+
importMap: ImportMap;
|
|
38
37
|
log: Logger;
|
|
39
38
|
}) => Promise<FunctionConfig>;
|
|
40
39
|
export {};
|
package/dist/node/config.js
CHANGED
|
@@ -27,7 +27,7 @@ const getConfigExtractor = () => {
|
|
|
27
27
|
const configExtractorPath = join(packagePath, 'deno', 'config.ts');
|
|
28
28
|
return configExtractorPath;
|
|
29
29
|
};
|
|
30
|
-
export const getFunctionConfig = async ({
|
|
30
|
+
export const getFunctionConfig = async ({ deno, functionPath, importMap, log, }) => {
|
|
31
31
|
// The extractor is a Deno script that will import the function and run its
|
|
32
32
|
// `config` export, if one exists.
|
|
33
33
|
const extractorPath = getConfigExtractor();
|
|
@@ -54,15 +54,12 @@ export const getFunctionConfig = async ({ func, importMap, deno, log, }) => {
|
|
|
54
54
|
'--node-modules-dir=false',
|
|
55
55
|
'--quiet',
|
|
56
56
|
extractorPath,
|
|
57
|
-
pathToFileURL(
|
|
57
|
+
pathToFileURL(functionPath).href,
|
|
58
58
|
pathToFileURL(collector.path).href,
|
|
59
59
|
JSON.stringify(ConfigExitCode),
|
|
60
60
|
].filter(Boolean), { rejectOnExitCode: false });
|
|
61
|
-
if (stderr.includes('Import assertions are deprecated')) {
|
|
62
|
-
log.system(`Edge function uses import assertions: ${func.path}`);
|
|
63
|
-
}
|
|
64
61
|
if (exitCode !== ConfigExitCode.Success) {
|
|
65
|
-
handleConfigError(
|
|
62
|
+
handleConfigError(functionPath, exitCode, stderr, log);
|
|
66
63
|
return {};
|
|
67
64
|
}
|
|
68
65
|
if (stdout !== '') {
|
|
@@ -74,35 +71,38 @@ export const getFunctionConfig = async ({ func, importMap, deno, log, }) => {
|
|
|
74
71
|
collectorData = JSON.parse(collectorDataJSON);
|
|
75
72
|
}
|
|
76
73
|
catch {
|
|
77
|
-
handleConfigError(
|
|
74
|
+
handleConfigError(functionPath, ConfigExitCode.UnhandledError, stderr, log);
|
|
78
75
|
}
|
|
79
76
|
finally {
|
|
80
77
|
await collector.cleanup();
|
|
81
78
|
}
|
|
82
79
|
if (!isValidOnError(collectorData.onError)) {
|
|
83
|
-
throw new BundleError(new Error(`The 'onError' configuration property in edge function at '${
|
|
80
|
+
throw new BundleError(new Error(`The 'onError' configuration property in edge function at '${functionPath}' must be one of 'fail', 'bypass', or a path starting with '/'. Got '${collectorData.onError}'. More on the Edge Functions API at https://ntl.fyi/edge-api.`));
|
|
84
81
|
}
|
|
85
82
|
return collectorData;
|
|
86
83
|
};
|
|
87
|
-
const handleConfigError = (
|
|
84
|
+
const handleConfigError = (functionPath, exitCode, stderr, log) => {
|
|
85
|
+
let cause;
|
|
86
|
+
if (stderr.includes('Import assertions are deprecated')) {
|
|
87
|
+
log.system(`Edge function uses import assertions: ${functionPath}`);
|
|
88
|
+
cause = 'IMPORT_ASSERT';
|
|
89
|
+
}
|
|
88
90
|
switch (exitCode) {
|
|
89
91
|
case ConfigExitCode.ImportError:
|
|
90
92
|
log.user(stderr);
|
|
91
|
-
throw new BundleError(new Error(`Could not load edge function at '${
|
|
92
|
-
break;
|
|
93
|
+
throw new BundleError(new Error(`Could not load edge function at '${functionPath}'. More on the Edge Functions API at https://ntl.fyi/edge-api.`), { cause });
|
|
93
94
|
case ConfigExitCode.NoConfig:
|
|
94
|
-
log.system(`No in-source config found for edge function at '${
|
|
95
|
+
log.system(`No in-source config found for edge function at '${functionPath}'`);
|
|
95
96
|
break;
|
|
96
97
|
case ConfigExitCode.InvalidExport:
|
|
97
|
-
throw new BundleError(new Error(`The 'config' export in edge function at '${
|
|
98
|
-
break;
|
|
98
|
+
throw new BundleError(new Error(`The 'config' export in edge function at '${functionPath}' must be an object. More on the Edge Functions API at https://ntl.fyi/edge-api.`));
|
|
99
99
|
case ConfigExitCode.SerializationError:
|
|
100
|
-
throw new BundleError(new Error(`The 'config' object in the edge function at '${
|
|
100
|
+
throw new BundleError(new Error(`The 'config' object in the edge function at '${functionPath}' must contain primitive values only. More on the Edge Functions API at https://ntl.fyi/edge-api.`));
|
|
101
101
|
break;
|
|
102
102
|
case ConfigExitCode.InvalidDefaultExport:
|
|
103
|
-
throw new BundleError(new Error(`Default export in '${
|
|
103
|
+
throw new BundleError(new Error(`Default export in '${functionPath}' must be a function. More on the Edge Functions API at https://ntl.fyi/edge-api.`));
|
|
104
104
|
default:
|
|
105
|
-
log.user(`Could not load configuration for edge function at '${
|
|
105
|
+
log.user(`Could not load configuration for edge function at '${functionPath}'`);
|
|
106
106
|
log.user(stderr);
|
|
107
107
|
}
|
|
108
108
|
};
|
package/dist/node/config.test.js
CHANGED
|
@@ -172,10 +172,7 @@ describe('`getFunctionConfig` extracts configuration properties from function fi
|
|
|
172
172
|
const path = join(tmpDir, `${func.name}.js`);
|
|
173
173
|
await fs.writeFile(path, func.source);
|
|
174
174
|
const funcCall = () => getFunctionConfig({
|
|
175
|
-
|
|
176
|
-
name: func.name,
|
|
177
|
-
path,
|
|
178
|
-
},
|
|
175
|
+
functionPath: path,
|
|
179
176
|
importMap: new ImportMap([importMapFile]),
|
|
180
177
|
deno,
|
|
181
178
|
log: logger,
|
|
@@ -349,10 +346,7 @@ test('Passes validation if default export exists and is a function', async () =>
|
|
|
349
346
|
const path = join(tmpDir, `${func.name}.ts`);
|
|
350
347
|
await fs.writeFile(path, func.source);
|
|
351
348
|
await expect(getFunctionConfig({
|
|
352
|
-
|
|
353
|
-
name: func.name,
|
|
354
|
-
path,
|
|
355
|
-
},
|
|
349
|
+
functionPath: path,
|
|
356
350
|
importMap: new ImportMap([importMapFile]),
|
|
357
351
|
deno,
|
|
358
352
|
log: logger,
|
|
@@ -378,10 +372,7 @@ test('Fails validation if default export is not function', async () => {
|
|
|
378
372
|
const path = join(tmpDir, `${func.name}.ts`);
|
|
379
373
|
await fs.writeFile(path, func.source);
|
|
380
374
|
const config = getFunctionConfig({
|
|
381
|
-
|
|
382
|
-
name: func.name,
|
|
383
|
-
path,
|
|
384
|
-
},
|
|
375
|
+
functionPath: path,
|
|
385
376
|
importMap: new ImportMap([importMapFile]),
|
|
386
377
|
deno,
|
|
387
378
|
log: logger,
|
|
@@ -407,10 +398,7 @@ test('Fails validation if default export is not present', async () => {
|
|
|
407
398
|
const path = join(tmpDir, `${func.name}.ts`);
|
|
408
399
|
await fs.writeFile(path, func.source);
|
|
409
400
|
const config = getFunctionConfig({
|
|
410
|
-
|
|
411
|
-
name: func.name,
|
|
412
|
-
path,
|
|
413
|
-
},
|
|
401
|
+
functionPath: path,
|
|
414
402
|
importMap: new ImportMap([importMapFile]),
|
|
415
403
|
deno,
|
|
416
404
|
log: logger,
|
package/dist/node/declaration.js
CHANGED
|
@@ -16,7 +16,6 @@ export const mergeDeclarations = (tomlDeclarations, userFunctionsConfig, interna
|
|
|
16
16
|
return declarations;
|
|
17
17
|
};
|
|
18
18
|
const getDeclarationsFromInput = (inputDeclarations, functionConfigs, functionsVisited) => {
|
|
19
|
-
var _a, _b;
|
|
20
19
|
const declarations = [];
|
|
21
20
|
// For any declaration for which we also have a function configuration object,
|
|
22
21
|
// we replace the path because that object takes precedence.
|
|
@@ -26,7 +25,7 @@ const getDeclarationsFromInput = (inputDeclarations, functionConfigs, functionsV
|
|
|
26
25
|
// If no config is found, add the declaration as is.
|
|
27
26
|
declarations.push(declaration);
|
|
28
27
|
}
|
|
29
|
-
else if ('pattern' in config &&
|
|
28
|
+
else if ('pattern' in config && config.pattern?.length) {
|
|
30
29
|
// If we have a pattern specified as either a string or non-empty array,
|
|
31
30
|
// create a declaration for each pattern.
|
|
32
31
|
const patterns = Array.isArray(config.pattern) ? config.pattern : [config.pattern];
|
|
@@ -34,7 +33,7 @@ const getDeclarationsFromInput = (inputDeclarations, functionConfigs, functionsV
|
|
|
34
33
|
declarations.push({ ...declaration, cache: config.cache, pattern });
|
|
35
34
|
});
|
|
36
35
|
}
|
|
37
|
-
else if ('path' in config &&
|
|
36
|
+
else if ('path' in config && config.path?.length) {
|
|
38
37
|
// If we have a path specified as either a string or non-empty array,
|
|
39
38
|
// create a declaration for each path.
|
|
40
39
|
const paths = Array.isArray(config.path) ? config.path : [config.path];
|
|
@@ -24,13 +24,12 @@ export const load = async (path, logger) => {
|
|
|
24
24
|
};
|
|
25
25
|
};
|
|
26
26
|
const parse = (data, path) => {
|
|
27
|
-
var _a, _b;
|
|
28
27
|
if (data.version !== 1) {
|
|
29
28
|
throw new Error(`Unsupported file version: ${data.version}`);
|
|
30
29
|
}
|
|
31
30
|
const config = {
|
|
32
|
-
declarations:
|
|
33
|
-
layers:
|
|
31
|
+
declarations: data.functions ?? [],
|
|
32
|
+
layers: data.layers ?? [],
|
|
34
33
|
};
|
|
35
34
|
if (data.import_map) {
|
|
36
35
|
const importMapPath = resolve(dirname(path), data.import_map);
|
package/dist/node/downloader.js
CHANGED
|
@@ -71,8 +71,7 @@ const getLatestVersion = async () => {
|
|
|
71
71
|
}
|
|
72
72
|
};
|
|
73
73
|
const getLatestVersionForRange = async (range) => {
|
|
74
|
-
|
|
75
|
-
const minimumVersion = (_a = semver.minVersion(range)) === null || _a === void 0 ? void 0 : _a.version;
|
|
74
|
+
const minimumVersion = semver.minVersion(range)?.version;
|
|
76
75
|
// We should never get here, because it means that `DENO_VERSION_RANGE` is
|
|
77
76
|
// a malformed semver range. If this does happen, let's throw an error so
|
|
78
77
|
// that the tests catch it.
|
|
@@ -1,10 +1,12 @@
|
|
|
1
1
|
declare const defaultFlags: {
|
|
2
2
|
edge_bundler_generate_tarball: boolean;
|
|
3
|
+
edge_bundler_deno_v2: boolean;
|
|
3
4
|
};
|
|
4
5
|
type FeatureFlag = keyof typeof defaultFlags;
|
|
5
6
|
type FeatureFlags = Partial<Record<FeatureFlag, boolean>>;
|
|
6
7
|
declare const getFlags: (input?: Record<string, boolean>, flags?: {
|
|
7
8
|
edge_bundler_generate_tarball: boolean;
|
|
9
|
+
edge_bundler_deno_v2: boolean;
|
|
8
10
|
}) => FeatureFlags;
|
|
9
11
|
export { defaultFlags, getFlags };
|
|
10
12
|
export type { FeatureFlag, FeatureFlags };
|
|
@@ -3,6 +3,7 @@ import { Bundle } from '../bundle.js';
|
|
|
3
3
|
import { EdgeFunction } from '../edge_function.js';
|
|
4
4
|
import { FeatureFlags } from '../feature_flags.js';
|
|
5
5
|
import { ImportMap } from '../import_map.js';
|
|
6
|
+
export declare const extension = ".eszip";
|
|
6
7
|
interface BundleESZIPOptions {
|
|
7
8
|
basePath: string;
|
|
8
9
|
buildID: string;
|
|
@@ -15,5 +16,9 @@ interface BundleESZIPOptions {
|
|
|
15
16
|
importMap: ImportMap;
|
|
16
17
|
vendorDirectory?: string;
|
|
17
18
|
}
|
|
18
|
-
declare const
|
|
19
|
-
export
|
|
19
|
+
export declare const bundle: ({ basePath, buildID, debug, deno, distDirectory, externals, functions, importMap, vendorDirectory, }: BundleESZIPOptions) => Promise<Bundle>;
|
|
20
|
+
export declare const extract: (deno: DenoBridge, functionPath: string) => Promise<{
|
|
21
|
+
cleanup: () => Promise<void>;
|
|
22
|
+
path: string;
|
|
23
|
+
}>;
|
|
24
|
+
export {};
|
|
@@ -1,13 +1,14 @@
|
|
|
1
1
|
import { join } from 'path';
|
|
2
2
|
import { pathToFileURL } from 'url';
|
|
3
|
+
import tmp from 'tmp-promise';
|
|
3
4
|
import { virtualRoot, virtualVendorRoot } from '../../shared/consts.js';
|
|
4
5
|
import { BundleFormat } from '../bundle.js';
|
|
5
6
|
import { wrapBundleError } from '../bundle_error.js';
|
|
6
7
|
import { wrapNpmImportError } from '../npm_import_error.js';
|
|
7
8
|
import { getPackagePath } from '../package_json.js';
|
|
8
9
|
import { getFileHash } from '../utils/sha256.js';
|
|
9
|
-
const
|
|
10
|
-
|
|
10
|
+
export const extension = '.eszip';
|
|
11
|
+
export const bundle = async ({ basePath, buildID, debug, deno, distDirectory, externals, functions, importMap, vendorDirectory, }) => {
|
|
11
12
|
const destPath = join(distDirectory, `${buildID}${extension}`);
|
|
12
13
|
const importMapPrefixes = {
|
|
13
14
|
[`${pathToFileURL(basePath)}/`]: virtualRoot,
|
|
@@ -44,7 +45,17 @@ const getESZIPPaths = () => {
|
|
|
44
45
|
const denoPath = join(getPackagePath(), 'deno');
|
|
45
46
|
return {
|
|
46
47
|
bundler: join(denoPath, 'bundle.ts'),
|
|
48
|
+
extractor: join(denoPath, 'extract.ts'),
|
|
47
49
|
importMap: join(denoPath, 'vendor', 'import_map.json'),
|
|
48
50
|
};
|
|
49
51
|
};
|
|
50
|
-
export
|
|
52
|
+
export const extract = async (deno, functionPath) => {
|
|
53
|
+
const tmpDir = await tmp.dir({ unsafeCleanup: true });
|
|
54
|
+
const { extractor, importMap } = getESZIPPaths();
|
|
55
|
+
const flags = ['--allow-all', '--no-config', '--no-lock', `--import-map=${importMap}`, '--quiet'];
|
|
56
|
+
await deno.run(['run', ...flags, extractor, functionPath, tmpDir.path], { pipeOutput: true });
|
|
57
|
+
return {
|
|
58
|
+
cleanup: tmpDir.cleanup,
|
|
59
|
+
path: join(tmpDir.path, 'source', 'root'),
|
|
60
|
+
};
|
|
61
|
+
};
|
package/dist/node/import_map.js
CHANGED
|
@@ -12,6 +12,11 @@ const INTERNAL_IMPORTS = {
|
|
|
12
12
|
// ImportMap can take several import map files and merge them into a final
|
|
13
13
|
// import map object, also adding the internal imports in the right order.
|
|
14
14
|
export class ImportMap {
|
|
15
|
+
// The root path which import maps can reference. If an import map attempts
|
|
16
|
+
// to reference a file outside this directory, an error will be thrown.
|
|
17
|
+
rootPath;
|
|
18
|
+
// The different import map files that make up the wider import map.
|
|
19
|
+
sources;
|
|
15
20
|
constructor(sources = [], rootPath = null) {
|
|
16
21
|
this.rootPath = rootPath;
|
|
17
22
|
this.sources = [];
|
package/dist/node/logger.js
CHANGED
|
@@ -5,8 +5,8 @@ const getLogger = (systemLogger, userLogger, debug = false) => {
|
|
|
5
5
|
// If there is a system logger configured, we'll use that. If there isn't,
|
|
6
6
|
// we'll pipe system logs to stdout if `debug` is enabled and swallow them
|
|
7
7
|
// otherwise.
|
|
8
|
-
const system = systemLogger
|
|
9
|
-
const user = userLogger
|
|
8
|
+
const system = systemLogger ?? (debug ? console.log : noopLogger);
|
|
9
|
+
const user = userLogger ?? console.log;
|
|
10
10
|
return {
|
|
11
11
|
system,
|
|
12
12
|
user,
|
package/dist/node/main.test.js
CHANGED
|
@@ -12,8 +12,7 @@ import { getPlatformTarget } from './platform.js';
|
|
|
12
12
|
const require = createRequire(import.meta.url);
|
|
13
13
|
const archiver = require('archiver');
|
|
14
14
|
test('Downloads the Deno CLI on demand and caches it for subsequent calls', async () => {
|
|
15
|
-
|
|
16
|
-
const latestVersion = (_b = (_a = semver.minVersion(DENO_VERSION_RANGE)) === null || _a === void 0 ? void 0 : _a.version) !== null && _b !== void 0 ? _b : '';
|
|
15
|
+
const latestVersion = semver.minVersion(DENO_VERSION_RANGE)?.version ?? '';
|
|
17
16
|
const mockBinaryOutput = `#!/usr/bin/env sh\n\necho "deno ${latestVersion}"`;
|
|
18
17
|
const data = new PassThrough();
|
|
19
18
|
const archive = archiver('zip', { zlib: { level: 9 } });
|
|
@@ -39,8 +38,8 @@ test('Downloads the Deno CLI on demand and caches it for subsequent calls', asyn
|
|
|
39
38
|
const expectedOutput = /^deno [\d.]+/;
|
|
40
39
|
expect(latestReleaseMock.isDone()).toBe(true);
|
|
41
40
|
expect(downloadMock.isDone()).toBe(true);
|
|
42
|
-
expect(
|
|
43
|
-
expect(
|
|
41
|
+
expect(output1?.stdout ?? '').toMatch(expectedOutput);
|
|
42
|
+
expect(output2?.stdout ?? '').toMatch(expectedOutput);
|
|
44
43
|
expect(beforeDownload).toHaveBeenCalledTimes(1);
|
|
45
44
|
expect(afterDownload).toHaveBeenCalledTimes(1);
|
|
46
45
|
await rm(tmpDir.path, { force: true, recursive: true, maxRetries: 10 });
|
package/dist/node/manifest.js
CHANGED
|
@@ -5,7 +5,7 @@ import { getHeaderMatchers, normalizePattern } from './declaration.js';
|
|
|
5
5
|
import { getPackageVersion } from './package_json.js';
|
|
6
6
|
import { RateLimitAction, RateLimitAlgorithm, RateLimitAggregator } from './rate_limit.js';
|
|
7
7
|
import { nonNullable } from './utils/non_nullable.js';
|
|
8
|
-
import {
|
|
8
|
+
import { getRegexpFromURLPatternPath } from './utils/urlpattern.js';
|
|
9
9
|
const removeEmptyConfigValues = (functionConfig) => Object.entries(functionConfig).reduce((acc, [key, value]) => {
|
|
10
10
|
if (value && !(Array.isArray(value) && value.length === 0)) {
|
|
11
11
|
return { ...acc, [key]: value };
|
|
@@ -176,10 +176,9 @@ const pathToRegularExpression = (path) => {
|
|
|
176
176
|
return null;
|
|
177
177
|
}
|
|
178
178
|
try {
|
|
179
|
-
const pattern = new ExtendedURLPattern({ pathname: path });
|
|
180
179
|
// Removing the `^` and `$` delimiters because we'll need to modify what's
|
|
181
180
|
// between them.
|
|
182
|
-
const source =
|
|
181
|
+
const source = getRegexpFromURLPatternPath(path).slice(1, -1);
|
|
183
182
|
// Wrapping the expression source with `^` and `$`. Also, adding an optional
|
|
184
183
|
// trailing slash, so that a declaration of `path: "/foo"` matches requests
|
|
185
184
|
// for both `/foo` and `/foo/`.
|
|
@@ -70,7 +70,6 @@ test('Generates a manifest with a generator field', () => {
|
|
|
70
70
|
expect(manifest.function_config).toEqual(expectedFunctionConfig);
|
|
71
71
|
});
|
|
72
72
|
test('Generates a manifest with excluded paths and patterns', () => {
|
|
73
|
-
var _a, _b;
|
|
74
73
|
const functions = [
|
|
75
74
|
{ name: 'func-1', path: '/path/to/func-1.ts' },
|
|
76
75
|
{ name: 'func-2', path: '/path/to/func-2.ts' },
|
|
@@ -104,8 +103,8 @@ test('Generates a manifest with excluded paths and patterns', () => {
|
|
|
104
103
|
expect(manifest.function_config).toEqual({});
|
|
105
104
|
expect(manifest.bundler_version).toBe(version);
|
|
106
105
|
const matcher = getRouteMatcher(manifest);
|
|
107
|
-
expect(
|
|
108
|
-
expect(
|
|
106
|
+
expect(matcher('/f1/hello')?.function).toBe('func-1');
|
|
107
|
+
expect(matcher('/grandparent/parent/child/grandchild.html')?.function).toBeUndefined();
|
|
109
108
|
});
|
|
110
109
|
test('TOML-defined paths can be combined with ISC-defined excluded paths', () => {
|
|
111
110
|
const functions = [{ name: 'func-1', path: '/path/to/func-1.ts' }];
|
|
@@ -36,7 +36,7 @@ const getTypePathFromTypesPackage = async (packageName, packageJsonPath) => {
|
|
|
36
36
|
return undefined;
|
|
37
37
|
}
|
|
38
38
|
const { types, typings } = JSON.parse(await fs.readFile(typesPackagePath, 'utf8'));
|
|
39
|
-
const declarationPath = types
|
|
39
|
+
const declarationPath = types ?? typings;
|
|
40
40
|
if (typeof declarationPath === 'string') {
|
|
41
41
|
return path.join(typesPackagePath, '..', declarationPath);
|
|
42
42
|
}
|
|
@@ -51,7 +51,7 @@ const getTypesPath = async (packageJsonPath) => {
|
|
|
51
51
|
const { name, types, typings } = JSON.parse(await fs.readFile(packageJsonPath, 'utf8'));
|
|
52
52
|
// this only looks at `.types` and `.typings` fields. there might also be data in `exports -> . -> types -> import/default`.
|
|
53
53
|
// we're ignoring that for now.
|
|
54
|
-
const declarationPath = types
|
|
54
|
+
const declarationPath = types ?? typings;
|
|
55
55
|
if (typeof declarationPath === 'string') {
|
|
56
56
|
return path.join(packageJsonPath, '..', declarationPath);
|
|
57
57
|
}
|
|
@@ -117,7 +117,6 @@ async function parseImportsForFile(file, rootPath) {
|
|
|
117
117
|
* to npm modules.
|
|
118
118
|
*/
|
|
119
119
|
const getNPMSpecifiers = async ({ basePath, functions, importMap, environment, rootPath }, alreadySeenPaths = new Set()) => {
|
|
120
|
-
var _a;
|
|
121
120
|
const baseURL = pathToFileURL(basePath);
|
|
122
121
|
const npmSpecifiers = [];
|
|
123
122
|
for (const func of functions) {
|
|
@@ -152,7 +151,7 @@ const getNPMSpecifiers = async ({ basePath, functions, importMap, environment, r
|
|
|
152
151
|
}
|
|
153
152
|
const { matched, resolvedImport } = resolve(specifier, importMap, baseURL);
|
|
154
153
|
if (matched) {
|
|
155
|
-
if (
|
|
154
|
+
if (resolvedImport?.protocol === 'file:') {
|
|
156
155
|
const newSpecifier = fileURLToPath(resolvedImport).replace(/\\/g, '/');
|
|
157
156
|
if (alreadySeenPaths.has(newSpecifier)) {
|
|
158
157
|
break;
|
|
@@ -161,7 +160,7 @@ const getNPMSpecifiers = async ({ basePath, functions, importMap, environment, r
|
|
|
161
160
|
npmSpecifiers.push(...(await getNPMSpecifiers({ basePath, functions: [newSpecifier], importMap, environment, rootPath }, alreadySeenPaths)));
|
|
162
161
|
}
|
|
163
162
|
}
|
|
164
|
-
else if (!
|
|
163
|
+
else if (!resolvedImport?.protocol?.startsWith('http')) {
|
|
165
164
|
const t = await safelyDetectTypes(specifier, basePath);
|
|
166
165
|
npmSpecifiers.push({
|
|
167
166
|
specifier: specifier,
|
|
@@ -235,8 +234,7 @@ export const vendorNPMSpecifiers = async ({ basePath, directory, functions, impo
|
|
|
235
234
|
});
|
|
236
235
|
outputFiles.push(...outputFilesFromEsBuild.map((file) => file.path));
|
|
237
236
|
await Promise.all(outputFilesFromEsBuild.map(async (file) => {
|
|
238
|
-
|
|
239
|
-
const types = (_a = ops.find((op) => path.basename(file.path) === path.basename(op.filePath))) === null || _a === void 0 ? void 0 : _a.types;
|
|
237
|
+
const types = ops.find((op) => path.basename(file.path) === path.basename(op.filePath))?.types;
|
|
240
238
|
let content = file.text;
|
|
241
239
|
if (types) {
|
|
242
240
|
content = `/// <reference types="${path.relative(path.dirname(file.path), types)}" />\n${content}`;
|
|
@@ -22,8 +22,7 @@ const cleanDirectory = async (directory, except) => {
|
|
|
22
22
|
const prepareServer = ({ basePath, bootstrapURL, deno, distDirectory, distImportMapPath, flags: denoFlags, formatExportTypeError, formatImportError, logger, port, rootPath, stderr, stdout, }) => {
|
|
23
23
|
const processRef = {};
|
|
24
24
|
const startServer = async (functions, env = {}, options = {}) => {
|
|
25
|
-
|
|
26
|
-
if ((processRef === null || processRef === void 0 ? void 0 : processRef.ps) !== undefined) {
|
|
25
|
+
if (processRef?.ps !== undefined) {
|
|
27
26
|
await killProcess(processRef.ps);
|
|
28
27
|
}
|
|
29
28
|
let graph = {
|
|
@@ -41,7 +40,7 @@ const prepareServer = ({ basePath, bootstrapURL, deno, distDirectory, distImport
|
|
|
41
40
|
});
|
|
42
41
|
const features = {};
|
|
43
42
|
const importMap = new ImportMap();
|
|
44
|
-
await importMap.addFiles(
|
|
43
|
+
await importMap.addFiles(options.importMapPaths ?? [], logger);
|
|
45
44
|
// we keep track of the files that are relevant to the user's code, so we can clean up leftovers from past executions later
|
|
46
45
|
const relevantFiles = [stage2Path];
|
|
47
46
|
const vendor = await vendorNPMSpecifiers({
|
|
@@ -84,7 +83,7 @@ const prepareServer = ({ basePath, bootstrapURL, deno, distDirectory, distImport
|
|
|
84
83
|
});
|
|
85
84
|
let functionsConfig = [];
|
|
86
85
|
if (options.getFunctionsConfig) {
|
|
87
|
-
functionsConfig = await Promise.all(functions.map((func) => getFunctionConfig({ func, importMap, deno, log: logger })));
|
|
86
|
+
functionsConfig = await Promise.all(functions.map((func) => getFunctionConfig({ functionPath: func.path, importMap, deno, log: logger })));
|
|
88
87
|
}
|
|
89
88
|
if (distImportMapPath) {
|
|
90
89
|
await importMap.writeToFile(distImportMapPath);
|
|
@@ -52,9 +52,9 @@ test('Starts a server and serves requests for edge functions', async () => {
|
|
|
52
52
|
expect(features).toEqual({ npmModules: true });
|
|
53
53
|
expect(success).toBe(true);
|
|
54
54
|
expect(functionsConfig).toEqual([{ path: '/my-function' }, {}, { path: '/global-netlify' }]);
|
|
55
|
-
const modules = graph
|
|
55
|
+
const modules = graph?.modules.filter(({ kind, mediaType }) => kind === 'esm' && mediaType === 'TypeScript');
|
|
56
56
|
for (const key in functions) {
|
|
57
|
-
const graphEntry = modules
|
|
57
|
+
const graphEntry = modules?.some(({ local }) => local === functions[key].path);
|
|
58
58
|
expect(graphEntry).toBe(true);
|
|
59
59
|
}
|
|
60
60
|
const response1 = await fetch(`http://0.0.0.0:${port}/foo`, {
|
|
@@ -127,7 +127,7 @@ test('Serves edge functions in a monorepo setup', async () => {
|
|
|
127
127
|
expect(success).toBe(true);
|
|
128
128
|
expect(functionsConfig).toEqual([{ path: '/func1' }]);
|
|
129
129
|
for (const key in functions) {
|
|
130
|
-
const graphEntry = graph
|
|
130
|
+
const graphEntry = graph?.modules.some(({ kind, mediaType, local }) => kind === 'esm' && mediaType === 'TypeScript' && local === functions[key].path);
|
|
131
131
|
expect(graphEntry).toBe(true);
|
|
132
132
|
}
|
|
133
133
|
const response1 = await fetch(`http://0.0.0.0:${port}/func1`, {
|
package/dist/node/server/util.js
CHANGED
|
@@ -10,7 +10,7 @@ const SERVER_POLL_TIMEOUT = 1e4;
|
|
|
10
10
|
const isServerReady = async (port, successRef, ps) => {
|
|
11
11
|
// If the process has been killed or if it exited with an error, we return
|
|
12
12
|
// early with `success: false`.
|
|
13
|
-
if (
|
|
13
|
+
if (ps?.killed || (ps?.exitCode && ps.exitCode > 0)) {
|
|
14
14
|
return true;
|
|
15
15
|
}
|
|
16
16
|
try {
|
|
@@ -24,7 +24,7 @@ const isServerReady = async (port, successRef, ps) => {
|
|
|
24
24
|
};
|
|
25
25
|
const killProcess = (ps) => {
|
|
26
26
|
// If the process is no longer running, there's nothing left to do.
|
|
27
|
-
if (
|
|
27
|
+
if (ps?.exitCode !== null) {
|
|
28
28
|
return;
|
|
29
29
|
}
|
|
30
30
|
return new Promise((resolve, reject) => {
|
package/dist/node/types.js
CHANGED
|
@@ -2,7 +2,7 @@ import { promises as fs } from 'fs';
|
|
|
2
2
|
import { join } from 'path';
|
|
3
3
|
const TYPES_URL = 'https://edge.netlify.com';
|
|
4
4
|
const ensureLatestTypes = async (deno, logger, customTypesURL) => {
|
|
5
|
-
const typesURL = customTypesURL
|
|
5
|
+
const typesURL = customTypesURL ?? TYPES_URL;
|
|
6
6
|
// eslint-disable-next-line prefer-const
|
|
7
7
|
let [localVersion, remoteVersion] = [await getLocalVersion(deno), ''];
|
|
8
8
|
try {
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
export default class ManifestValidationError extends Error {
|
|
2
|
+
customErrorInfo = {
|
|
3
|
+
type: 'functionsBundling',
|
|
4
|
+
};
|
|
2
5
|
constructor(message) {
|
|
3
6
|
super(`Validation of Edge Functions manifest failed\n${message}`);
|
|
4
|
-
this.customErrorInfo = {
|
|
5
|
-
type: 'functionsBundling',
|
|
6
|
-
};
|
|
7
7
|
this.name = 'ManifestValidationError';
|
|
8
8
|
// https://github.com/microsoft/TypeScript-wiki/blob/0fecbda7263f130c57394d779b8ca13f0a2e9123/Breaking-Changes.md#extending-built-ins-like-error-array-and-map-may-no-longer-work
|
|
9
9
|
Object.setPrototypeOf(this, ManifestValidationError.prototype);
|
package/dist/test/util.js
CHANGED
|
@@ -67,7 +67,6 @@ for (const functionName in manifest.functions) {
|
|
|
67
67
|
console.log(JSON.stringify(responses));
|
|
68
68
|
`;
|
|
69
69
|
export const getRouteMatcher = (manifest) => (candidate) => manifest.routes.find((route) => {
|
|
70
|
-
var _a, _b;
|
|
71
70
|
const regex = new RegExp(route.pattern);
|
|
72
71
|
if (!regex.test(candidate)) {
|
|
73
72
|
return false;
|
|
@@ -75,12 +74,11 @@ export const getRouteMatcher = (manifest) => (candidate) => manifest.routes.find
|
|
|
75
74
|
if (route.excluded_patterns.some((pattern) => new RegExp(pattern).test(candidate))) {
|
|
76
75
|
return false;
|
|
77
76
|
}
|
|
78
|
-
const excludedPatterns =
|
|
77
|
+
const excludedPatterns = manifest.function_config[route.function]?.excluded_patterns ?? [];
|
|
79
78
|
const isExcluded = excludedPatterns.some((pattern) => new RegExp(pattern).test(candidate));
|
|
80
79
|
return !isExcluded;
|
|
81
80
|
});
|
|
82
81
|
export const runESZIP = async (eszipPath, vendorDirectory) => {
|
|
83
|
-
var _a, _b, _c;
|
|
84
82
|
const tmpDir = await tmp.dir({ unsafeCleanup: true });
|
|
85
83
|
// Extract ESZIP into temporary directory.
|
|
86
84
|
const extractCommand = execa('deno', [
|
|
@@ -92,8 +90,8 @@ export const runESZIP = async (eszipPath, vendorDirectory) => {
|
|
|
92
90
|
eszipPath,
|
|
93
91
|
tmpDir.path,
|
|
94
92
|
]);
|
|
95
|
-
|
|
96
|
-
|
|
93
|
+
extractCommand.stderr?.pipe(stderr);
|
|
94
|
+
extractCommand.stdout?.pipe(stdout);
|
|
97
95
|
await extractCommand;
|
|
98
96
|
const virtualRootPath = join(tmpDir.path, 'source', 'root');
|
|
99
97
|
const stage2Path = join(virtualRootPath, '..', 'bootstrap-stage2');
|
|
@@ -109,13 +107,12 @@ export const runESZIP = async (eszipPath, vendorDirectory) => {
|
|
|
109
107
|
await fs.rename(stage2Path, `${stage2Path}.js`);
|
|
110
108
|
// Run function that imports the extracted stage 2 and invokes each function.
|
|
111
109
|
const evalCommand = execa('deno', ['eval', '--import-map', importMapPath, inspectESZIPFunction(stage2Path)]);
|
|
112
|
-
|
|
110
|
+
evalCommand.stderr?.pipe(stderr);
|
|
113
111
|
const result = await evalCommand;
|
|
114
112
|
await tmpDir.cleanup();
|
|
115
113
|
return JSON.parse(result.stdout);
|
|
116
114
|
};
|
|
117
115
|
export const runTarball = async (tarballPath) => {
|
|
118
|
-
var _a;
|
|
119
116
|
const tmpDir = await tmp.dir({ unsafeCleanup: true });
|
|
120
117
|
await tar.extract({
|
|
121
118
|
cwd: tmpDir.path,
|
|
@@ -124,7 +121,7 @@ export const runTarball = async (tarballPath) => {
|
|
|
124
121
|
const evalCommand = execa('deno', ['eval', inspectTarballFunction()], {
|
|
125
122
|
cwd: tmpDir.path,
|
|
126
123
|
});
|
|
127
|
-
|
|
124
|
+
evalCommand.stderr?.pipe(stderr);
|
|
128
125
|
const result = await evalCommand;
|
|
129
126
|
await tmpDir.cleanup();
|
|
130
127
|
return JSON.parse(result.stdout);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@netlify/edge-bundler",
|
|
3
|
-
"version": "14.
|
|
3
|
+
"version": "14.7.0",
|
|
4
4
|
"description": "Intelligently prepare Netlify Edge Functions for deployment",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/node/index.js",
|
|
@@ -80,5 +80,5 @@
|
|
|
80
80
|
"urlpattern-polyfill": "8.0.2",
|
|
81
81
|
"uuid": "^11.0.0"
|
|
82
82
|
},
|
|
83
|
-
"gitHead": "
|
|
83
|
+
"gitHead": "ff114da3f2bcb5bea83bb4a3747201192aecfec0"
|
|
84
84
|
}
|