netlify-cli 17.5.1 → 17.5.3
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/npm-shrinkwrap.json +433 -433
- package/package.json +5 -5
- package/src/commands/completion/completion.mjs +2 -2
- package/src/commands/dev/dev.mjs +2 -2
- package/src/commands/functions/functions-create.mjs +4 -4
- package/src/commands/serve/serve.mjs +9 -2
- package/src/commands/sites/sites-create-template.mjs +2 -2
- package/src/lib/edge-functions/registry.mjs +306 -487
- package/src/lib/exec-fetcher.mjs +4 -4
- package/src/lib/functions/form-submissions-handler.mjs +1 -0
- package/src/lib/functions/registry.mjs +0 -1
- package/src/lib/images/proxy.mjs +27 -24
- package/src/utils/build-info.mjs +2 -2
- package/src/utils/command-helpers.mjs +8 -19
- package/src/utils/init/utils.mjs +1 -1
- package/src/utils/proxy.mjs +1 -0
- package/src/utils/shell.mjs +2 -2
- package/src/utils/telemetry/telemetry.mjs +1 -1
|
@@ -1,538 +1,357 @@
|
|
|
1
|
-
var __classPrivateFieldSet = (this && this.__classPrivateFieldSet) || function (receiver, state, value, kind, f) {
|
|
2
|
-
if (kind === "m") throw new TypeError("Private method is not writable");
|
|
3
|
-
if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a setter");
|
|
4
|
-
if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot write private member to an object whose class did not declare it");
|
|
5
|
-
return (kind === "a" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value)), value;
|
|
6
|
-
};
|
|
7
|
-
var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (receiver, state, kind, f) {
|
|
8
|
-
if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a getter");
|
|
9
|
-
if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot read private member from an object whose class did not declare it");
|
|
10
|
-
return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
|
|
11
|
-
};
|
|
12
|
-
var _EdgeFunctionsRegistry_instances, _a, _EdgeFunctionsRegistry_bundler, _EdgeFunctionsRegistry_configPath, _EdgeFunctionsRegistry_debug, _EdgeFunctionsRegistry_directories, _EdgeFunctionsRegistry_internalDirectories, _EdgeFunctionsRegistry_getUpdatedConfig, _EdgeFunctionsRegistry_runIsolate, _EdgeFunctionsRegistry_buildError, _EdgeFunctionsRegistry_declarationsFromDeployConfig, _EdgeFunctionsRegistry_declarationsFromTOML, _EdgeFunctionsRegistry_env, _EdgeFunctionsRegistry_directoryWatchers, _EdgeFunctionsRegistry_dependencyPaths, _EdgeFunctionsRegistry_functionPaths, _EdgeFunctionsRegistry_manifest, _EdgeFunctionsRegistry_userFunctions, _EdgeFunctionsRegistry_internalFunctions, _EdgeFunctionsRegistry_initialScan, _EdgeFunctionsRegistry_routes, _EdgeFunctionsRegistry_servePath, _EdgeFunctionsRegistry_doInitialScan, _EdgeFunctionsRegistry_functions_get, _EdgeFunctionsRegistry_build, _EdgeFunctionsRegistry_buildRoutes, _EdgeFunctionsRegistry_checkForAddedOrDeletedFunctions, _EdgeFunctionsRegistry_getDeclarationsFromTOML, _EdgeFunctionsRegistry_getEnvironmentVariables, _EdgeFunctionsRegistry_handleFileChange, _EdgeFunctionsRegistry_logEvent, _EdgeFunctionsRegistry_processGraph, _EdgeFunctionsRegistry_runBuild, _EdgeFunctionsRegistry_scanForFunctions, _EdgeFunctionsRegistry_setupWatchers, _EdgeFunctionsRegistry_setupWatcherForDirectory, _EdgeFunctionsRegistry_getDisplayName;
|
|
13
1
|
import { fileURLToPath } from 'url';
|
|
14
|
-
import { NETLIFYDEVERR, NETLIFYDEVLOG, NETLIFYDEVWARN, chalk, log, warn, watchDebounced, } from '../../utils/command-helpers.mjs';
|
|
15
|
-
/** @typedef {import('@netlify/edge-bundler').Declaration} Declaration */
|
|
16
|
-
/** @typedef {import('@netlify/edge-bundler').EdgeFunction} EdgeFunction */
|
|
17
|
-
/**
|
|
18
|
-
* @typedef {"buildError" | "loaded" | "reloaded" | "reloading" | "removed"} EdgeFunctionEvent
|
|
19
|
-
*/
|
|
20
|
-
/** @typedef {import('@netlify/edge-bundler').FunctionConfig} FunctionConfig */
|
|
21
|
-
/** @typedef {import('@netlify/edge-bundler').Manifest} Manifest */
|
|
22
|
-
/** @typedef {import('@netlify/edge-bundler').ModuleGraph} ModuleGraph */
|
|
23
|
-
/** @typedef {Awaited<ReturnType<typeof import('@netlify/edge-bundler').serve>>} RunIsolate */
|
|
24
|
-
/** @typedef {Omit<Manifest["routes"][0], "pattern"> & { pattern: RegExp }} Route */
|
|
2
|
+
import { NETLIFYDEVERR, NETLIFYDEVLOG, NETLIFYDEVWARN, nonNullable, chalk, log, warn, watchDebounced, isNodeError, } from '../../utils/command-helpers.mjs';
|
|
25
3
|
const featureFlags = { edge_functions_correct_order: true };
|
|
26
4
|
export class EdgeFunctionsRegistry {
|
|
5
|
+
constructor({ bundler, config, configPath, directories, env, getUpdatedConfig, internalDirectories, internalFunctions, projectDir, runIsolate, servePath, }) {
|
|
6
|
+
this.buildError = null;
|
|
7
|
+
this.dependencyPaths = new Map();
|
|
8
|
+
this.directoryWatchers = new Map();
|
|
9
|
+
this.functionPaths = new Map();
|
|
10
|
+
this.internalFunctions = [];
|
|
11
|
+
this.manifest = null;
|
|
12
|
+
this.routes = [];
|
|
13
|
+
this.userFunctions = [];
|
|
14
|
+
this.bundler = bundler;
|
|
15
|
+
this.configPath = configPath;
|
|
16
|
+
this.directories = directories;
|
|
17
|
+
this.internalDirectories = internalDirectories;
|
|
18
|
+
this.getUpdatedConfig = getUpdatedConfig;
|
|
19
|
+
this.runIsolate = runIsolate;
|
|
20
|
+
this.servePath = servePath;
|
|
21
|
+
this.declarationsFromDeployConfig = internalFunctions;
|
|
22
|
+
this.declarationsFromTOML = EdgeFunctionsRegistry.getDeclarationsFromTOML(config);
|
|
23
|
+
this.env = EdgeFunctionsRegistry.getEnvironmentVariables(env);
|
|
24
|
+
this.buildError = null;
|
|
25
|
+
this.directoryWatchers = new Map();
|
|
26
|
+
this.dependencyPaths = new Map();
|
|
27
|
+
this.functionPaths = new Map();
|
|
28
|
+
this.userFunctions = [];
|
|
29
|
+
this.internalFunctions = [];
|
|
30
|
+
this.initialScan = this.doInitialScan();
|
|
31
|
+
this.setupWatchers(projectDir);
|
|
32
|
+
}
|
|
33
|
+
async doInitialScan() {
|
|
34
|
+
await this.scanForFunctions();
|
|
35
|
+
try {
|
|
36
|
+
const { warnings } = await this.build();
|
|
37
|
+
this.functions.forEach((func) => {
|
|
38
|
+
this.logEvent('loaded', { functionName: func.name, warnings: warnings[func.name] });
|
|
39
|
+
});
|
|
40
|
+
}
|
|
41
|
+
catch {
|
|
42
|
+
// no-op
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
get functions() {
|
|
46
|
+
return [...this.internalFunctions, ...this.userFunctions];
|
|
47
|
+
}
|
|
48
|
+
async build() {
|
|
49
|
+
const warnings = {};
|
|
50
|
+
try {
|
|
51
|
+
const { functionsConfig, graph, npmSpecifiersWithExtraneousFiles, success } = await this.runBuild();
|
|
52
|
+
if (!success) {
|
|
53
|
+
throw new Error('Build error');
|
|
54
|
+
}
|
|
55
|
+
this.buildError = null;
|
|
56
|
+
// We use one index to loop over both internal and user function, because we know that this.#functions has internalFunctions first.
|
|
57
|
+
// functionsConfig therefore contains first all internal functionConfigs and then user functionConfigs
|
|
58
|
+
let index = 0;
|
|
59
|
+
const internalFunctionConfigs = this.internalFunctions.reduce(
|
|
60
|
+
// eslint-disable-next-line no-plusplus
|
|
61
|
+
(acc, func) => ({ ...acc, [func.name]: functionsConfig[index++] }), {});
|
|
62
|
+
const userFunctionConfigs = this.userFunctions.reduce(
|
|
63
|
+
// eslint-disable-next-line no-plusplus
|
|
64
|
+
(acc, func) => ({ ...acc, [func.name]: functionsConfig[index++] }), {});
|
|
65
|
+
const { manifest, routes, unroutedFunctions } = this.buildRoutes(internalFunctionConfigs, userFunctionConfigs);
|
|
66
|
+
this.manifest = manifest;
|
|
67
|
+
this.routes = routes;
|
|
68
|
+
unroutedFunctions.forEach((name) => {
|
|
69
|
+
warnings[name] = warnings[name] || [];
|
|
70
|
+
warnings[name].push(`Edge function is not accessible because it does not have a path configured. Learn more at https://ntl.fyi/edge-create.`);
|
|
71
|
+
});
|
|
72
|
+
for (const functionName in userFunctionConfigs) {
|
|
73
|
+
if ('paths' in userFunctionConfigs[functionName]) {
|
|
74
|
+
warnings[functionName] = warnings[functionName] || [];
|
|
75
|
+
warnings[functionName].push(`Unknown 'paths' configuration property. Did you mean 'path'?`);
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
this.processGraph(graph);
|
|
79
|
+
if (npmSpecifiersWithExtraneousFiles.length !== 0) {
|
|
80
|
+
const modules = npmSpecifiersWithExtraneousFiles.map((name) => chalk.yellow(name)).join(', ');
|
|
81
|
+
log(`${NETLIFYDEVWARN} The following npm modules, which are directly or indirectly imported by an edge function, may not be supported: ${modules}. For more information, visit https://ntl.fyi/edge-functions-npm.`);
|
|
82
|
+
}
|
|
83
|
+
return { warnings };
|
|
84
|
+
}
|
|
85
|
+
catch (error) {
|
|
86
|
+
if (error instanceof Error) {
|
|
87
|
+
this.buildError = error;
|
|
88
|
+
}
|
|
89
|
+
throw error;
|
|
90
|
+
}
|
|
91
|
+
}
|
|
27
92
|
/**
|
|
28
|
-
*
|
|
29
|
-
*
|
|
30
|
-
*
|
|
31
|
-
*
|
|
32
|
-
* @param {boolean} opts.debug
|
|
33
|
-
* @param {string[]} opts.directories
|
|
34
|
-
* @param {Record<string, { sources: string[], value: string}>} opts.env
|
|
35
|
-
* @param {() => Promise<object>} opts.getUpdatedConfig
|
|
36
|
-
* @param {string[]} opts.internalDirectories
|
|
37
|
-
* @param {Declaration[]} opts.internalFunctions
|
|
38
|
-
* @param {string} opts.projectDir
|
|
39
|
-
* @param {RunIsolate} opts.runIsolate
|
|
40
|
-
* @param {string} opts.servePath
|
|
93
|
+
* Builds a manifest and corresponding routes for the functions in the
|
|
94
|
+
* registry, taking into account the declarations from the TOML, from
|
|
95
|
+
* the deploy configuration API, and from the in-source configuration
|
|
96
|
+
* found in both internal and user functions.
|
|
41
97
|
*/
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
)
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
__classPrivateFieldSet(this, _EdgeFunctionsRegistry_runIsolate, runIsolate, "f");
|
|
131
|
-
__classPrivateFieldSet(this, _EdgeFunctionsRegistry_servePath, servePath, "f");
|
|
132
|
-
__classPrivateFieldSet(this, _EdgeFunctionsRegistry_declarationsFromDeployConfig, internalFunctions, "f");
|
|
133
|
-
__classPrivateFieldSet(this, _EdgeFunctionsRegistry_declarationsFromTOML, __classPrivateFieldGet(EdgeFunctionsRegistry, _a, "m", _EdgeFunctionsRegistry_getDeclarationsFromTOML).call(EdgeFunctionsRegistry, config), "f");
|
|
134
|
-
__classPrivateFieldSet(this, _EdgeFunctionsRegistry_env, __classPrivateFieldGet(EdgeFunctionsRegistry, _a, "m", _EdgeFunctionsRegistry_getEnvironmentVariables).call(EdgeFunctionsRegistry, env), "f");
|
|
135
|
-
__classPrivateFieldSet(this, _EdgeFunctionsRegistry_buildError, null, "f");
|
|
136
|
-
__classPrivateFieldSet(this, _EdgeFunctionsRegistry_directoryWatchers, new Map(), "f");
|
|
137
|
-
__classPrivateFieldSet(this, _EdgeFunctionsRegistry_dependencyPaths, new Map(), "f");
|
|
138
|
-
__classPrivateFieldSet(this, _EdgeFunctionsRegistry_functionPaths, new Map(), "f");
|
|
139
|
-
__classPrivateFieldSet(this, _EdgeFunctionsRegistry_userFunctions, [], "f");
|
|
140
|
-
__classPrivateFieldSet(this, _EdgeFunctionsRegistry_internalFunctions, [], "f");
|
|
141
|
-
__classPrivateFieldSet(this, _EdgeFunctionsRegistry_initialScan, __classPrivateFieldGet(this, _EdgeFunctionsRegistry_instances, "m", _EdgeFunctionsRegistry_doInitialScan).call(this), "f");
|
|
142
|
-
__classPrivateFieldGet(this, _EdgeFunctionsRegistry_instances, "m", _EdgeFunctionsRegistry_setupWatchers).call(this, projectDir);
|
|
98
|
+
buildRoutes(internalFunctionConfigs, userFunctionConfigs) {
|
|
99
|
+
const declarations = this.bundler.mergeDeclarations(this.declarationsFromTOML, userFunctionConfigs, internalFunctionConfigs, this.declarationsFromDeployConfig, featureFlags);
|
|
100
|
+
const { declarationsWithoutFunction, manifest, unroutedFunctions } = this.bundler.generateManifest({
|
|
101
|
+
declarations,
|
|
102
|
+
userFunctionConfig: userFunctionConfigs,
|
|
103
|
+
internalFunctionConfig: internalFunctionConfigs,
|
|
104
|
+
functions: this.functions,
|
|
105
|
+
featureFlags,
|
|
106
|
+
});
|
|
107
|
+
const routes = [...manifest.routes, ...manifest.post_cache_routes].map((route) => ({
|
|
108
|
+
...route,
|
|
109
|
+
pattern: new RegExp(route.pattern),
|
|
110
|
+
}));
|
|
111
|
+
return { declarationsWithoutFunction, manifest, routes, unroutedFunctions };
|
|
112
|
+
}
|
|
113
|
+
async checkForAddedOrDeletedFunctions() {
|
|
114
|
+
const { deleted: deletedFunctions, new: newFunctions } = await this.scanForFunctions();
|
|
115
|
+
if (newFunctions.length === 0 && deletedFunctions.length === 0) {
|
|
116
|
+
return;
|
|
117
|
+
}
|
|
118
|
+
try {
|
|
119
|
+
const { warnings } = await this.build();
|
|
120
|
+
deletedFunctions.forEach((func) => {
|
|
121
|
+
this.logEvent('removed', { functionName: func.name, warnings: warnings[func.name] });
|
|
122
|
+
});
|
|
123
|
+
newFunctions.forEach((func) => {
|
|
124
|
+
this.logEvent('loaded', { functionName: func.name, warnings: warnings[func.name] });
|
|
125
|
+
});
|
|
126
|
+
}
|
|
127
|
+
catch {
|
|
128
|
+
// no-op
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
static getDeclarationsFromTOML(config) {
|
|
132
|
+
const { edge_functions: edgeFunctions = [] } = config;
|
|
133
|
+
return edgeFunctions;
|
|
134
|
+
}
|
|
135
|
+
getDisplayName(func) {
|
|
136
|
+
const declarations = [...this.declarationsFromTOML, ...this.declarationsFromDeployConfig];
|
|
137
|
+
return declarations.find((declaration) => declaration.function === func)?.name ?? func;
|
|
138
|
+
}
|
|
139
|
+
static getEnvironmentVariables(envConfig) {
|
|
140
|
+
const env = Object.create(null);
|
|
141
|
+
Object.entries(envConfig).forEach(([key, variable]) => {
|
|
142
|
+
if (variable.sources.includes('ui') ||
|
|
143
|
+
variable.sources.includes('account') ||
|
|
144
|
+
variable.sources.includes('addons') ||
|
|
145
|
+
variable.sources.includes('internal') ||
|
|
146
|
+
variable.sources.some((source) => source.startsWith('.env'))) {
|
|
147
|
+
env[key] = variable.value;
|
|
148
|
+
}
|
|
149
|
+
});
|
|
150
|
+
env.DENO_REGION = 'local';
|
|
151
|
+
return env;
|
|
152
|
+
}
|
|
153
|
+
async handleFileChange(paths) {
|
|
154
|
+
const matchingFunctions = new Set([
|
|
155
|
+
...paths.map((path) => this.functionPaths.get(path)),
|
|
156
|
+
...paths.flatMap((path) => this.dependencyPaths.get(path)),
|
|
157
|
+
].filter(nonNullable));
|
|
158
|
+
// If the file is not associated with any function, there's no point in
|
|
159
|
+
// building. However, it might be that the path is in fact associated with
|
|
160
|
+
// a function but we just haven't registered it due to a build error. So if
|
|
161
|
+
// there was a build error, let's always build.
|
|
162
|
+
if (matchingFunctions.size === 0 && this.buildError === null) {
|
|
163
|
+
return;
|
|
164
|
+
}
|
|
165
|
+
this.logEvent('reloading', {});
|
|
166
|
+
try {
|
|
167
|
+
const { warnings } = await this.build();
|
|
168
|
+
const functionNames = [...matchingFunctions];
|
|
169
|
+
if (functionNames.length === 0) {
|
|
170
|
+
this.logEvent('reloaded', {});
|
|
171
|
+
}
|
|
172
|
+
else {
|
|
173
|
+
functionNames.forEach((functionName) => {
|
|
174
|
+
this.logEvent('reloaded', { functionName, warnings: warnings[functionName] });
|
|
175
|
+
});
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
catch (error) {
|
|
179
|
+
if (isNodeError(error)) {
|
|
180
|
+
this.logEvent('buildError', { buildError: error });
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
async initialize() {
|
|
185
|
+
return await this.initialScan;
|
|
143
186
|
}
|
|
144
187
|
/**
|
|
145
|
-
*
|
|
188
|
+
* Logs an event associated with functions.
|
|
146
189
|
*/
|
|
147
|
-
|
|
148
|
-
|
|
190
|
+
logEvent(event, { buildError, functionName, warnings = [] }) {
|
|
191
|
+
const subject = functionName ? `edge function ${chalk.yellow(this.getDisplayName(functionName))}` : 'edge functions';
|
|
192
|
+
const warningsText = warnings.length === 0 ? '' : ` with warnings:\n${warnings.map((warning) => ` - ${warning}`).join('\n')}`;
|
|
193
|
+
if (event === 'buildError') {
|
|
194
|
+
log(`${NETLIFYDEVERR} ${chalk.red('Failed to load')} ${subject}: ${buildError}`);
|
|
195
|
+
return;
|
|
196
|
+
}
|
|
197
|
+
if (event === 'loaded') {
|
|
198
|
+
const icon = warningsText ? NETLIFYDEVWARN : NETLIFYDEVLOG;
|
|
199
|
+
const color = warningsText ? chalk.yellow : chalk.green;
|
|
200
|
+
log(`${icon} ${color('Loaded')} ${subject}${warningsText}`);
|
|
201
|
+
return;
|
|
202
|
+
}
|
|
203
|
+
if (event === 'reloaded') {
|
|
204
|
+
const icon = warningsText ? NETLIFYDEVWARN : NETLIFYDEVLOG;
|
|
205
|
+
const color = warningsText ? chalk.yellow : chalk.green;
|
|
206
|
+
log(`${icon} ${color('Reloaded')} ${subject}${warningsText}`);
|
|
207
|
+
return;
|
|
208
|
+
}
|
|
209
|
+
if (event === 'reloading') {
|
|
210
|
+
log(`${NETLIFYDEVLOG} ${chalk.magenta('Reloading')} ${subject}...`);
|
|
211
|
+
return;
|
|
212
|
+
}
|
|
213
|
+
if (event === 'removed') {
|
|
214
|
+
log(`${NETLIFYDEVLOG} ${chalk.magenta('Removed')} ${subject}`);
|
|
215
|
+
}
|
|
149
216
|
}
|
|
150
217
|
/**
|
|
151
218
|
* Returns the functions in the registry that should run for a given URL path
|
|
152
219
|
* and HTTP method, based on the routes registered for each function.
|
|
153
|
-
*
|
|
154
|
-
* @param {string} urlPath
|
|
155
|
-
* @param {string} method
|
|
156
220
|
*/
|
|
157
|
-
// @ts-expect-error TS(7006) FIXME: Parameter 'urlPath' implicitly has an 'any' type.
|
|
158
221
|
matchURLPath(urlPath, method) {
|
|
159
|
-
/** @type string[] */
|
|
160
|
-
// @ts-expect-error TS(7034) FIXME: Variable 'functionNames' implicitly has type 'any[... Remove this comment to see the full error message
|
|
161
222
|
const functionNames = [];
|
|
162
|
-
/** @type number[] */
|
|
163
|
-
// @ts-expect-error TS(7034) FIXME: Variable 'routeIndexes' implicitly has type 'any[]... Remove this comment to see the full error message
|
|
164
223
|
const routeIndexes = [];
|
|
165
|
-
|
|
166
|
-
// @ts-expect-error TS(2339) FIXME: Property 'methods' does not exist on type 'never'.
|
|
224
|
+
this.routes.forEach((route, index) => {
|
|
167
225
|
if (route.methods && route.methods.length !== 0 && !route.methods.includes(method)) {
|
|
168
226
|
return;
|
|
169
227
|
}
|
|
170
|
-
// @ts-expect-error TS(2339) FIXME: Property 'pattern' does not exist on type 'never'.
|
|
171
228
|
if (!route.pattern.test(urlPath)) {
|
|
172
229
|
return;
|
|
173
230
|
}
|
|
174
|
-
|
|
175
|
-
const isExcluded = __classPrivateFieldGet(this, _EdgeFunctionsRegistry_manifest, "f")?.function_config[route.function]?.excluded_patterns?.some((pattern) => new RegExp(pattern).test(urlPath));
|
|
231
|
+
const isExcluded = this.manifest?.function_config[route.function]?.excluded_patterns?.some((pattern) => new RegExp(pattern).test(urlPath));
|
|
176
232
|
if (isExcluded) {
|
|
177
233
|
return;
|
|
178
234
|
}
|
|
179
|
-
// @ts-expect-error TS(2339) FIXME: Property 'function' does not exist on type 'never'... Remove this comment to see the full error message
|
|
180
235
|
functionNames.push(route.function);
|
|
181
236
|
routeIndexes.push(index);
|
|
182
237
|
});
|
|
238
|
+
const routes = [...(this.manifest?.routes || []), ...(this.manifest?.post_cache_routes || [])].map((route) => ({
|
|
239
|
+
function: route.function,
|
|
240
|
+
path: route.path,
|
|
241
|
+
pattern: route.pattern,
|
|
242
|
+
}));
|
|
183
243
|
const invocationMetadata = {
|
|
184
|
-
|
|
185
|
-
function_config: __classPrivateFieldGet(this, _EdgeFunctionsRegistry_manifest, "f")?.function_config,
|
|
186
|
-
// @ts-expect-error TS(7005) FIXME: Variable 'routeIndexes' implicitly has an 'any[]' ... Remove this comment to see the full error message
|
|
244
|
+
function_config: this.manifest?.function_config,
|
|
187
245
|
req_routes: routeIndexes,
|
|
188
|
-
|
|
189
|
-
routes: __classPrivateFieldGet(this, _EdgeFunctionsRegistry_manifest, "f")?.routes.map((route) => ({
|
|
190
|
-
function: route.function,
|
|
191
|
-
path: route.path,
|
|
192
|
-
pattern: route.pattern,
|
|
193
|
-
})),
|
|
246
|
+
routes,
|
|
194
247
|
};
|
|
195
|
-
// @ts-expect-error TS(7005) FIXME: Variable 'functionNames' implicitly has an 'any[]'... Remove this comment to see the full error message
|
|
196
248
|
return { functionNames, invocationMetadata };
|
|
197
249
|
}
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
250
|
+
/**
|
|
251
|
+
* Takes the module graph returned from the server and tracks dependencies of
|
|
252
|
+
* each function.
|
|
253
|
+
*/
|
|
254
|
+
processGraph(graph) {
|
|
255
|
+
if (!graph) {
|
|
256
|
+
warn('Could not process edge functions dependency graph. Live reload will not be available.');
|
|
257
|
+
return;
|
|
258
|
+
}
|
|
259
|
+
// Creating a Map from `this.functions` that maps function paths to function
|
|
260
|
+
// names. This allows us to match modules against functions in O(1) time as
|
|
261
|
+
// opposed to O(n).
|
|
262
|
+
// eslint-disable-next-line unicorn/prefer-spread
|
|
263
|
+
const functionPaths = new Map(Array.from(this.functions, (func) => [func.path, func.name]));
|
|
264
|
+
// Mapping file URLs to names of functions that use them as dependencies.
|
|
265
|
+
const dependencyPaths = new Map();
|
|
266
|
+
const { modules } = graph;
|
|
267
|
+
modules.forEach(({ dependencies = [], specifier }) => {
|
|
268
|
+
if (!specifier.startsWith('file://')) {
|
|
269
|
+
return;
|
|
270
|
+
}
|
|
271
|
+
const path = fileURLToPath(specifier);
|
|
272
|
+
const functionMatch = functionPaths.get(path);
|
|
273
|
+
if (!functionMatch) {
|
|
274
|
+
return;
|
|
275
|
+
}
|
|
276
|
+
dependencies.forEach((dependency) => {
|
|
277
|
+
// We're interested in tracking local dependencies, so we only look at
|
|
278
|
+
// specifiers with the `file:` protocol.
|
|
279
|
+
if (dependency.code === undefined ||
|
|
280
|
+
typeof dependency.code.specifier !== 'string' ||
|
|
281
|
+
!dependency.code.specifier.startsWith('file://')) {
|
|
282
|
+
return;
|
|
283
|
+
}
|
|
284
|
+
const { specifier: dependencyURL } = dependency.code;
|
|
285
|
+
const dependencyPath = fileURLToPath(dependencyURL);
|
|
286
|
+
const functions = dependencyPaths.get(dependencyPath) || [];
|
|
287
|
+
dependencyPaths.set(dependencyPath, [...functions, functionMatch]);
|
|
288
|
+
});
|
|
210
289
|
});
|
|
290
|
+
this.dependencyPaths = dependencyPaths;
|
|
291
|
+
this.functionPaths = functionPaths;
|
|
211
292
|
}
|
|
212
|
-
catch {
|
|
213
|
-
// no-op
|
|
214
|
-
}
|
|
215
|
-
}, _EdgeFunctionsRegistry_functions_get = function _EdgeFunctionsRegistry_functions_get() {
|
|
216
|
-
return [...__classPrivateFieldGet(this, _EdgeFunctionsRegistry_internalFunctions, "f"), ...__classPrivateFieldGet(this, _EdgeFunctionsRegistry_userFunctions, "f")];
|
|
217
|
-
}, _EdgeFunctionsRegistry_build =
|
|
218
|
-
/**
|
|
219
|
-
* @return {Promise<{warnings: Record<string, string[]>}>}
|
|
220
|
-
*/
|
|
221
|
-
async function _EdgeFunctionsRegistry_build() {
|
|
222
293
|
/**
|
|
223
|
-
*
|
|
294
|
+
* Thin wrapper for `#runIsolate` that skips running a build and returns an
|
|
295
|
+
* empty response if there are no functions in the registry.
|
|
224
296
|
*/
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
297
|
+
async runBuild() {
|
|
298
|
+
if (this.functions.length === 0) {
|
|
299
|
+
return {
|
|
300
|
+
functionsConfig: [],
|
|
301
|
+
npmSpecifiersWithExtraneousFiles: [],
|
|
302
|
+
success: true,
|
|
303
|
+
};
|
|
230
304
|
}
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
// functionsConfig therefore contains first all internal functionConfigs and then user functionConfigs
|
|
234
|
-
let index = 0;
|
|
235
|
-
/** @type {Record<string, FunctionConfig>} */
|
|
236
|
-
const internalFunctionConfigs = __classPrivateFieldGet(this, _EdgeFunctionsRegistry_internalFunctions, "f").reduce(
|
|
237
|
-
// @ts-expect-error TS(2339) FIXME: Property 'name' does not exist on type 'never'.
|
|
238
|
-
// eslint-disable-next-line no-plusplus
|
|
239
|
-
(acc, func) => ({ ...acc, [func.name]: functionsConfig[index++] }), {});
|
|
240
|
-
/** @type {Record<string, FunctionConfig>} */
|
|
241
|
-
const userFunctionConfigs = __classPrivateFieldGet(this, _EdgeFunctionsRegistry_userFunctions, "f").reduce(
|
|
242
|
-
// @ts-expect-error TS(2339) FIXME: Property 'name' does not exist on type 'never'.
|
|
243
|
-
// eslint-disable-next-line no-plusplus
|
|
244
|
-
(acc, func) => ({ ...acc, [func.name]: functionsConfig[index++] }), {});
|
|
245
|
-
const { manifest, routes, unroutedFunctions } = __classPrivateFieldGet(this, _EdgeFunctionsRegistry_instances, "m", _EdgeFunctionsRegistry_buildRoutes).call(this, internalFunctionConfigs, userFunctionConfigs);
|
|
246
|
-
__classPrivateFieldSet(this, _EdgeFunctionsRegistry_manifest, manifest, "f");
|
|
247
|
-
// @ts-expect-error TS(2322) FIXME: Type 'any[]' is not assignable to type 'never[]'.
|
|
248
|
-
__classPrivateFieldSet(this, _EdgeFunctionsRegistry_routes, routes, "f");
|
|
249
|
-
// @ts-expect-error TS(7006) FIXME: Parameter 'name' implicitly has an 'any' type.
|
|
250
|
-
unroutedFunctions.forEach((name) => {
|
|
251
|
-
// @ts-expect-error TS(7053) FIXME: Element implicitly has an 'any' type because expre... Remove this comment to see the full error message
|
|
252
|
-
warnings[name] = warnings[name] || [];
|
|
253
|
-
// @ts-expect-error TS(7053) FIXME: Element implicitly has an 'any' type because expre... Remove this comment to see the full error message
|
|
254
|
-
warnings[name].push(`Edge function is not accessible because it does not have a path configured. Learn more at https://ntl.fyi/edge-create.`);
|
|
305
|
+
const { functionsConfig, graph, npmSpecifiersWithExtraneousFiles, success } = await this.runIsolate(this.functions, this.env, {
|
|
306
|
+
getFunctionsConfig: true,
|
|
255
307
|
});
|
|
256
|
-
|
|
257
|
-
// @ts-expect-error TS(7053) FIXME: Element implicitly has an 'any' type because expre... Remove this comment to see the full error message
|
|
258
|
-
if ('paths' in userFunctionConfigs[functionName]) {
|
|
259
|
-
// @ts-expect-error TS(7053) FIXME: Element implicitly has an 'any' type because expre... Remove this comment to see the full error message
|
|
260
|
-
warnings[functionName] = warnings[functionName] || [];
|
|
261
|
-
// @ts-expect-error TS(7053) FIXME: Element implicitly has an 'any' type because expre... Remove this comment to see the full error message
|
|
262
|
-
warnings[functionName].push(`Unknown 'paths' configuration property. Did you mean 'path'?`);
|
|
263
|
-
}
|
|
264
|
-
}
|
|
265
|
-
__classPrivateFieldGet(this, _EdgeFunctionsRegistry_instances, "m", _EdgeFunctionsRegistry_processGraph).call(this, graph);
|
|
266
|
-
if (npmSpecifiersWithExtraneousFiles.length !== 0) {
|
|
267
|
-
// @ts-expect-error TS(7006) FIXME: Parameter 'name' implicitly has an 'any' type.
|
|
268
|
-
const modules = npmSpecifiersWithExtraneousFiles.map((name) => chalk.yellow(name)).join(', ');
|
|
269
|
-
log(`${NETLIFYDEVWARN} The following npm modules, which are directly or indirectly imported by an edge function, may not be supported: ${modules}. For more information, visit https://ntl.fyi/edge-functions-npm.`);
|
|
270
|
-
}
|
|
271
|
-
return { warnings };
|
|
308
|
+
return { functionsConfig, graph, npmSpecifiersWithExtraneousFiles, success };
|
|
272
309
|
}
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
userFunctionConfig: userFunctionConfigs,
|
|
283
|
-
internalFunctionConfig: internalFunctionConfigs,
|
|
284
|
-
functions: __classPrivateFieldGet(this, _EdgeFunctionsRegistry_instances, "a", _EdgeFunctionsRegistry_functions_get),
|
|
285
|
-
featureFlags,
|
|
286
|
-
});
|
|
287
|
-
const routes = [...manifest.routes, ...manifest.post_cache_routes].map((route) => ({
|
|
288
|
-
...route,
|
|
289
|
-
pattern: new RegExp(route.pattern),
|
|
290
|
-
}));
|
|
291
|
-
return { declarationsWithoutFunction, manifest, routes, unroutedFunctions };
|
|
292
|
-
}, _EdgeFunctionsRegistry_checkForAddedOrDeletedFunctions =
|
|
293
|
-
/**
|
|
294
|
-
* @returns {Promise<void>}
|
|
295
|
-
*/
|
|
296
|
-
async function _EdgeFunctionsRegistry_checkForAddedOrDeletedFunctions() {
|
|
297
|
-
const { deleted: deletedFunctions, new: newFunctions } = await __classPrivateFieldGet(this, _EdgeFunctionsRegistry_instances, "m", _EdgeFunctionsRegistry_scanForFunctions).call(this);
|
|
298
|
-
if (newFunctions.length === 0 && deletedFunctions.length === 0) {
|
|
299
|
-
return;
|
|
300
|
-
}
|
|
301
|
-
try {
|
|
302
|
-
const { warnings } = await __classPrivateFieldGet(this, _EdgeFunctionsRegistry_instances, "m", _EdgeFunctionsRegistry_build).call(this);
|
|
303
|
-
deletedFunctions.forEach((func) => {
|
|
304
|
-
// @ts-expect-error TS(2345) FIXME: Argument of type '{ functionName: any; warnings: a... Remove this comment to see the full error message
|
|
305
|
-
__classPrivateFieldGet(this, _EdgeFunctionsRegistry_instances, "m", _EdgeFunctionsRegistry_logEvent).call(this, 'removed', { functionName: func.name, warnings: warnings[func.name] });
|
|
310
|
+
async scanForFunctions() {
|
|
311
|
+
const [internalFunctions, userFunctions] = await Promise.all([
|
|
312
|
+
this.bundler.find(this.internalDirectories),
|
|
313
|
+
this.bundler.find(this.directories),
|
|
314
|
+
]);
|
|
315
|
+
const functions = [...internalFunctions, ...userFunctions];
|
|
316
|
+
const newFunctions = functions.filter((func) => {
|
|
317
|
+
const functionExists = this.functions.some((existingFunc) => func.name === existingFunc.name && func.path === existingFunc.path);
|
|
318
|
+
return !functionExists;
|
|
306
319
|
});
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
320
|
+
const deletedFunctions = this.functions.filter((existingFunc) => {
|
|
321
|
+
const functionExists = functions.some((func) => func.name === existingFunc.name && func.path === existingFunc.path);
|
|
322
|
+
return !functionExists;
|
|
310
323
|
});
|
|
324
|
+
this.internalFunctions = internalFunctions;
|
|
325
|
+
this.userFunctions = userFunctions;
|
|
326
|
+
return { all: functions, new: newFunctions, deleted: deletedFunctions };
|
|
311
327
|
}
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
}
|
|
315
|
-
}, _EdgeFunctionsRegistry_getDeclarationsFromTOML = function _EdgeFunctionsRegistry_getDeclarationsFromTOML(config) {
|
|
316
|
-
const { edge_functions: edgeFunctions = [] } = config;
|
|
317
|
-
return edgeFunctions;
|
|
318
|
-
}, _EdgeFunctionsRegistry_getEnvironmentVariables = function _EdgeFunctionsRegistry_getEnvironmentVariables(envConfig) {
|
|
319
|
-
const env = Object.create(null);
|
|
320
|
-
Object.entries(envConfig).forEach(([key, variable]) => {
|
|
321
|
-
if (
|
|
322
|
-
// @ts-expect-error TS(2571) FIXME: Object is of type 'unknown'.
|
|
323
|
-
variable.sources.includes('ui') ||
|
|
324
|
-
// @ts-expect-error TS(2571) FIXME: Object is of type 'unknown'.
|
|
325
|
-
variable.sources.includes('account') ||
|
|
326
|
-
// @ts-expect-error TS(2571) FIXME: Object is of type 'unknown'.
|
|
327
|
-
variable.sources.includes('addons') ||
|
|
328
|
-
// @ts-expect-error TS(2571) FIXME: Object is of type 'unknown'.
|
|
329
|
-
variable.sources.includes('internal') ||
|
|
330
|
-
// @ts-expect-error TS(2571) FIXME: Object is of type 'unknown'.
|
|
331
|
-
variable.sources.some((source) => source.startsWith('.env'))) {
|
|
332
|
-
// @ts-expect-error TS(2571) FIXME: Object is of type 'unknown'.
|
|
333
|
-
env[key] = variable.value;
|
|
334
|
-
}
|
|
335
|
-
});
|
|
336
|
-
env.DENO_REGION = 'local';
|
|
337
|
-
return env;
|
|
338
|
-
}, _EdgeFunctionsRegistry_handleFileChange =
|
|
339
|
-
/**
|
|
340
|
-
* @param {string[]} paths
|
|
341
|
-
* @returns {Promise<void>}
|
|
342
|
-
*/
|
|
343
|
-
// @ts-expect-error TS(7006) FIXME: Parameter 'paths' implicitly has an 'any' type.
|
|
344
|
-
async function _EdgeFunctionsRegistry_handleFileChange(paths) {
|
|
345
|
-
const matchingFunctions = new Set([
|
|
346
|
-
// @ts-expect-error TS(7006) FIXME: Parameter 'path' implicitly has an 'any' type.
|
|
347
|
-
...paths.map((path) => __classPrivateFieldGet(this, _EdgeFunctionsRegistry_functionPaths, "f").get(path)),
|
|
348
|
-
// @ts-expect-error TS(7006) FIXME: Parameter 'path' implicitly has an 'any' type.
|
|
349
|
-
...paths.flatMap((path) => __classPrivateFieldGet(this, _EdgeFunctionsRegistry_dependencyPaths, "f").get(path)),
|
|
350
|
-
].filter(Boolean));
|
|
351
|
-
// If the file is not associated with any function, there's no point in
|
|
352
|
-
// building. However, it might be that the path is in fact associated with
|
|
353
|
-
// a function but we just haven't registered it due to a build error. So if
|
|
354
|
-
// there was a build error, let's always build.
|
|
355
|
-
if (matchingFunctions.size === 0 && __classPrivateFieldGet(this, _EdgeFunctionsRegistry_buildError, "f") === null) {
|
|
356
|
-
return;
|
|
357
|
-
}
|
|
358
|
-
// @ts-expect-error TS(2345) FIXME: Argument of type '{}' is not assignable to paramet... Remove this comment to see the full error message
|
|
359
|
-
__classPrivateFieldGet(this, _EdgeFunctionsRegistry_instances, "m", _EdgeFunctionsRegistry_logEvent).call(this, 'reloading', {});
|
|
360
|
-
try {
|
|
361
|
-
const { warnings } = await __classPrivateFieldGet(this, _EdgeFunctionsRegistry_instances, "m", _EdgeFunctionsRegistry_build).call(this);
|
|
362
|
-
const functionNames = [...matchingFunctions];
|
|
363
|
-
if (functionNames.length === 0) {
|
|
364
|
-
// @ts-expect-error TS(2345) FIXME: Argument of type '{}' is not assignable to paramet... Remove this comment to see the full error message
|
|
365
|
-
__classPrivateFieldGet(this, _EdgeFunctionsRegistry_instances, "m", _EdgeFunctionsRegistry_logEvent).call(this, 'reloaded', {});
|
|
366
|
-
}
|
|
367
|
-
else {
|
|
368
|
-
functionNames.forEach((functionName) => {
|
|
369
|
-
// @ts-expect-error TS(2345) FIXME: Argument of type '{ functionName: any; warnings: a... Remove this comment to see the full error message
|
|
370
|
-
__classPrivateFieldGet(this, _EdgeFunctionsRegistry_instances, "m", _EdgeFunctionsRegistry_logEvent).call(this, 'reloaded', { functionName, warnings: warnings[functionName] });
|
|
371
|
-
});
|
|
372
|
-
}
|
|
373
|
-
}
|
|
374
|
-
catch (error) {
|
|
375
|
-
// @ts-expect-error TS(2345) FIXME: Argument of type '{ buildError: any; }' is not ass... Remove this comment to see the full error message
|
|
376
|
-
__classPrivateFieldGet(this, _EdgeFunctionsRegistry_instances, "m", _EdgeFunctionsRegistry_logEvent).call(this, 'buildError', { buildError: error?.message });
|
|
377
|
-
}
|
|
378
|
-
}, _EdgeFunctionsRegistry_logEvent = function _EdgeFunctionsRegistry_logEvent(event, { buildError, functionName, warnings = [] }) {
|
|
379
|
-
const subject = functionName
|
|
380
|
-
? `edge function ${chalk.yellow(__classPrivateFieldGet(this, _EdgeFunctionsRegistry_instances, "m", _EdgeFunctionsRegistry_getDisplayName).call(this, functionName))}`
|
|
381
|
-
: 'edge functions';
|
|
382
|
-
const warningsText = warnings.length === 0 ? '' : ` with warnings:\n${warnings.map((warning) => ` - ${warning}`).join('\n')}`;
|
|
383
|
-
if (event === 'buildError') {
|
|
384
|
-
log(`${NETLIFYDEVERR} ${chalk.red('Failed to load')} ${subject}: ${buildError}`);
|
|
385
|
-
return;
|
|
386
|
-
}
|
|
387
|
-
if (event === 'loaded') {
|
|
388
|
-
const icon = warningsText ? NETLIFYDEVWARN : NETLIFYDEVLOG;
|
|
389
|
-
const color = warningsText ? chalk.yellow : chalk.green;
|
|
390
|
-
log(`${icon} ${color('Loaded')} ${subject}${warningsText}`);
|
|
391
|
-
return;
|
|
392
|
-
}
|
|
393
|
-
if (event === 'reloaded') {
|
|
394
|
-
const icon = warningsText ? NETLIFYDEVWARN : NETLIFYDEVLOG;
|
|
395
|
-
const color = warningsText ? chalk.yellow : chalk.green;
|
|
396
|
-
log(`${icon} ${color('Reloaded')} ${subject}${warningsText}`);
|
|
397
|
-
return;
|
|
398
|
-
}
|
|
399
|
-
if (event === 'reloading') {
|
|
400
|
-
log(`${NETLIFYDEVLOG} ${chalk.magenta('Reloading')} ${subject}...`);
|
|
401
|
-
return;
|
|
402
|
-
}
|
|
403
|
-
if (event === 'removed') {
|
|
404
|
-
log(`${NETLIFYDEVLOG} ${chalk.magenta('Removed')} ${subject}`);
|
|
405
|
-
}
|
|
406
|
-
}, _EdgeFunctionsRegistry_processGraph = function _EdgeFunctionsRegistry_processGraph(graph) {
|
|
407
|
-
if (!graph) {
|
|
408
|
-
warn('Could not process edge functions dependency graph. Live reload will not be available.');
|
|
409
|
-
return;
|
|
410
|
-
}
|
|
411
|
-
// Creating a Map from `this.#functions` that map function paths to function
|
|
412
|
-
// names. This allows us to match modules against functions in O(1) time as
|
|
413
|
-
// opposed to O(n).
|
|
414
|
-
// @ts-expect-error TS(2339) FIXME: Property 'path' does not exist on type 'never'.
|
|
415
|
-
// eslint-disable-next-line unicorn/prefer-spread
|
|
416
|
-
const functionPaths = new Map(Array.from(__classPrivateFieldGet(this, _EdgeFunctionsRegistry_instances, "a", _EdgeFunctionsRegistry_functions_get), (func) => [func.path, func.name]));
|
|
417
|
-
// Mapping file URLs to names of functions that use them as dependencies.
|
|
418
|
-
const dependencyPaths = new Map();
|
|
419
|
-
// @ts-expect-error TS(7031) FIXME: Binding element 'specifier' implicitly has an 'any... Remove this comment to see the full error message
|
|
420
|
-
graph.modules.forEach(({ dependencies = [], specifier }) => {
|
|
421
|
-
if (!specifier.startsWith('file://')) {
|
|
328
|
+
async setupWatchers(projectDir) {
|
|
329
|
+
if (!this.configPath) {
|
|
422
330
|
return;
|
|
423
331
|
}
|
|
424
|
-
const path = fileURLToPath(specifier);
|
|
425
|
-
const functionMatch = functionPaths.get(path);
|
|
426
|
-
if (!functionMatch) {
|
|
427
|
-
return;
|
|
428
|
-
}
|
|
429
|
-
dependencies.forEach((dependency) => {
|
|
430
|
-
// We're interested in tracking local dependencies, so we only look at
|
|
431
|
-
// specifiers with the `file:` protocol.
|
|
432
|
-
if (
|
|
433
|
-
// @ts-expect-error TS(2339) FIXME: Property 'code' does not exist on type 'never'.
|
|
434
|
-
dependency.code === undefined ||
|
|
435
|
-
// @ts-expect-error TS(2339) FIXME: Property 'code' does not exist on type 'never'.
|
|
436
|
-
typeof dependency.code.specifier !== 'string' ||
|
|
437
|
-
// @ts-expect-error TS(2339) FIXME: Property 'code' does not exist on type 'never'.
|
|
438
|
-
!dependency.code.specifier.startsWith('file://')) {
|
|
439
|
-
return;
|
|
440
|
-
}
|
|
441
|
-
// @ts-expect-error TS(2339) FIXME: Property 'code' does not exist on type 'never'.
|
|
442
|
-
const { specifier: dependencyURL } = dependency.code;
|
|
443
|
-
const dependencyPath = fileURLToPath(dependencyURL);
|
|
444
|
-
const functions = dependencyPaths.get(dependencyPath) || [];
|
|
445
|
-
dependencyPaths.set(dependencyPath, [...functions, functionMatch]);
|
|
446
|
-
});
|
|
447
|
-
});
|
|
448
|
-
__classPrivateFieldSet(this, _EdgeFunctionsRegistry_dependencyPaths, dependencyPaths, "f");
|
|
449
|
-
__classPrivateFieldSet(this, _EdgeFunctionsRegistry_functionPaths, functionPaths, "f");
|
|
450
|
-
}, _EdgeFunctionsRegistry_runBuild =
|
|
451
|
-
/**
|
|
452
|
-
* Thin wrapper for `#runIsolate` that skips running a build and returns an
|
|
453
|
-
* empty response if there are no functions in the registry.
|
|
454
|
-
*/
|
|
455
|
-
async function _EdgeFunctionsRegistry_runBuild() {
|
|
456
|
-
if (__classPrivateFieldGet(this, _EdgeFunctionsRegistry_instances, "a", _EdgeFunctionsRegistry_functions_get).length === 0) {
|
|
457
|
-
return {
|
|
458
|
-
functionsConfig: [],
|
|
459
|
-
graph: {
|
|
460
|
-
modules: [],
|
|
461
|
-
},
|
|
462
|
-
npmSpecifiersWithExtraneousFiles: [],
|
|
463
|
-
success: true,
|
|
464
|
-
};
|
|
465
|
-
}
|
|
466
|
-
const { functionsConfig, graph, npmSpecifiersWithExtraneousFiles, success } = await __classPrivateFieldGet(this, _EdgeFunctionsRegistry_runIsolate, "f").call(this, __classPrivateFieldGet(this, _EdgeFunctionsRegistry_instances, "a", _EdgeFunctionsRegistry_functions_get), __classPrivateFieldGet(this, _EdgeFunctionsRegistry_env, "f"), {
|
|
467
|
-
getFunctionsConfig: true,
|
|
468
|
-
});
|
|
469
|
-
return { functionsConfig, graph, npmSpecifiersWithExtraneousFiles, success };
|
|
470
|
-
}, _EdgeFunctionsRegistry_scanForFunctions =
|
|
471
|
-
/**
|
|
472
|
-
* @returns {Promise<{all: EdgeFunction[], new: EdgeFunction[], deleted: EdgeFunction[]}>}
|
|
473
|
-
*/
|
|
474
|
-
async function _EdgeFunctionsRegistry_scanForFunctions() {
|
|
475
|
-
const [internalFunctions, userFunctions] = await Promise.all([
|
|
476
|
-
__classPrivateFieldGet(this, _EdgeFunctionsRegistry_bundler, "f").find(__classPrivateFieldGet(this, _EdgeFunctionsRegistry_internalDirectories, "f")),
|
|
477
|
-
__classPrivateFieldGet(this, _EdgeFunctionsRegistry_bundler, "f").find(__classPrivateFieldGet(this, _EdgeFunctionsRegistry_directories, "f")),
|
|
478
|
-
]);
|
|
479
|
-
const functions = [...internalFunctions, ...userFunctions];
|
|
480
|
-
const newFunctions = functions.filter((func) => {
|
|
481
|
-
const functionExists = __classPrivateFieldGet(this, _EdgeFunctionsRegistry_instances, "a", _EdgeFunctionsRegistry_functions_get).some(
|
|
482
|
-
// @ts-expect-error TS(2339) FIXME: Property 'name' does not exist on type 'never'.
|
|
483
|
-
(existingFunc) => func.name === existingFunc.name && func.path === existingFunc.path);
|
|
484
|
-
return !functionExists;
|
|
485
|
-
});
|
|
486
|
-
const deletedFunctions = __classPrivateFieldGet(this, _EdgeFunctionsRegistry_instances, "a", _EdgeFunctionsRegistry_functions_get).filter((existingFunc) => {
|
|
487
|
-
const functionExists = functions.some(
|
|
488
|
-
// @ts-expect-error TS(2339) FIXME: Property 'name' does not exist on type 'never'.
|
|
489
|
-
(func) => func.name === existingFunc.name && func.path === existingFunc.path);
|
|
490
|
-
return !functionExists;
|
|
491
|
-
});
|
|
492
|
-
__classPrivateFieldSet(this, _EdgeFunctionsRegistry_internalFunctions, internalFunctions, "f");
|
|
493
|
-
__classPrivateFieldSet(this, _EdgeFunctionsRegistry_userFunctions, userFunctions, "f");
|
|
494
|
-
return { all: functions, new: newFunctions, deleted: deletedFunctions };
|
|
495
|
-
}, _EdgeFunctionsRegistry_setupWatchers =
|
|
496
|
-
/**
|
|
497
|
-
* @param {string} projectDir
|
|
498
|
-
*/
|
|
499
|
-
// @ts-expect-error TS(7006) FIXME: Parameter 'projectDir' implicitly has an 'any' typ... Remove this comment to see the full error message
|
|
500
|
-
async function _EdgeFunctionsRegistry_setupWatchers(projectDir) {
|
|
501
|
-
if (__classPrivateFieldGet(this, _EdgeFunctionsRegistry_configPath, "f")) {
|
|
502
332
|
// Creating a watcher for the config file. When it changes, we update the
|
|
503
333
|
// declarations and see if we need to register or unregister any functions.
|
|
504
|
-
|
|
505
|
-
await watchDebounced(__classPrivateFieldGet(this, _EdgeFunctionsRegistry_configPath, "f"), {
|
|
334
|
+
await watchDebounced(this.configPath, {
|
|
506
335
|
onChange: async () => {
|
|
507
|
-
const newConfig = await
|
|
508
|
-
|
|
509
|
-
await
|
|
336
|
+
const newConfig = await this.getUpdatedConfig();
|
|
337
|
+
this.declarationsFromTOML = EdgeFunctionsRegistry.getDeclarationsFromTOML(newConfig);
|
|
338
|
+
await this.checkForAddedOrDeletedFunctions();
|
|
510
339
|
},
|
|
511
340
|
});
|
|
341
|
+
// While functions are guaranteed to be inside one of the configured
|
|
342
|
+
// directories, they might be importing files that are located in
|
|
343
|
+
// parent directories. So we watch the entire project directory for
|
|
344
|
+
// changes.
|
|
345
|
+
await this.setupWatcherForDirectory(projectDir);
|
|
512
346
|
}
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
async function _EdgeFunctionsRegistry_setupWatcherForDirectory(directory) {
|
|
525
|
-
const ignored = [`${__classPrivateFieldGet(this, _EdgeFunctionsRegistry_servePath, "f")}/**`];
|
|
526
|
-
const watcher = await watchDebounced(directory, {
|
|
527
|
-
// @ts-expect-error TS(2322) FIXME: Type 'string[]' is not assignable to type 'never[]... Remove this comment to see the full error message
|
|
528
|
-
ignored,
|
|
529
|
-
onAdd: () => __classPrivateFieldGet(this, _EdgeFunctionsRegistry_instances, "m", _EdgeFunctionsRegistry_checkForAddedOrDeletedFunctions).call(this),
|
|
530
|
-
// @ts-expect-error TS(2322) FIXME: Type '(paths: any) => Promise<void>' is not assign... Remove this comment to see the full error message
|
|
531
|
-
onChange: (paths) => __classPrivateFieldGet(this, _EdgeFunctionsRegistry_instances, "m", _EdgeFunctionsRegistry_handleFileChange).call(this, paths),
|
|
532
|
-
onUnlink: () => __classPrivateFieldGet(this, _EdgeFunctionsRegistry_instances, "m", _EdgeFunctionsRegistry_checkForAddedOrDeletedFunctions).call(this),
|
|
533
|
-
});
|
|
534
|
-
__classPrivateFieldGet(this, _EdgeFunctionsRegistry_directoryWatchers, "f").set(directory, watcher);
|
|
535
|
-
}, _EdgeFunctionsRegistry_getDisplayName = function _EdgeFunctionsRegistry_getDisplayName(func) {
|
|
536
|
-
const declarations = [...__classPrivateFieldGet(this, _EdgeFunctionsRegistry_declarationsFromTOML, "f"), ...__classPrivateFieldGet(this, _EdgeFunctionsRegistry_declarationsFromDeployConfig, "f")];
|
|
537
|
-
return declarations.find((declaration) => declaration.function === func)?.name ?? func;
|
|
538
|
-
};
|
|
347
|
+
async setupWatcherForDirectory(directory) {
|
|
348
|
+
const ignored = [`${this.servePath}/**`];
|
|
349
|
+
const watcher = await watchDebounced(directory, {
|
|
350
|
+
ignored,
|
|
351
|
+
onAdd: () => this.checkForAddedOrDeletedFunctions(),
|
|
352
|
+
onChange: (paths) => this.handleFileChange(paths),
|
|
353
|
+
onUnlink: () => this.checkForAddedOrDeletedFunctions(),
|
|
354
|
+
});
|
|
355
|
+
this.directoryWatchers.set(directory, watcher);
|
|
356
|
+
}
|
|
357
|
+
}
|