@cloudflare/deploy-helpers 0.1.0 → 0.1.2
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/dist/index.d.mts +191 -2
- package/dist/index.mjs +2525 -0
- package/dist/metafile-esm.json +1 -1
- package/package.json +10 -6
package/dist/index.mjs
CHANGED
|
@@ -1 +1,2526 @@
|
|
|
1
|
+
import { getHostFromRoute, retryOnAPIFailure, UserError, getComplianceRegionSubdomain, configFileName, formatTime, ParseError, getSubdomainMixedStateCheckDisabled } from '@cloudflare/workers-utils';
|
|
2
|
+
import process2 from 'node:process';
|
|
3
|
+
import os from 'node:os';
|
|
4
|
+
import tty from 'node:tty';
|
|
1
5
|
|
|
6
|
+
var __create = Object.create;
|
|
7
|
+
var __defProp = Object.defineProperty;
|
|
8
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
9
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
10
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
11
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
12
|
+
var __name = (target, value) => __defProp(target, "name", { value, configurable: true });
|
|
13
|
+
var __commonJS = (cb, mod) => function __require() {
|
|
14
|
+
return mod || (0, cb[__getOwnPropNames(cb)[0]])((mod = { exports: {} }).exports, mod), mod.exports;
|
|
15
|
+
};
|
|
16
|
+
var __copyProps = (to, from, except, desc) => {
|
|
17
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
18
|
+
for (let key of __getOwnPropNames(from))
|
|
19
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
20
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
21
|
+
}
|
|
22
|
+
return to;
|
|
23
|
+
};
|
|
24
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
25
|
+
// If the importer is in node compatibility mode or this is not an ESM
|
|
26
|
+
// file that has been converted to a CommonJS file using a Babel-
|
|
27
|
+
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
28
|
+
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
29
|
+
__defProp(target, "default", { value: mod, enumerable: true }) ,
|
|
30
|
+
mod
|
|
31
|
+
));
|
|
32
|
+
|
|
33
|
+
// ../../node_modules/.pnpm/eventemitter3@5.0.1/node_modules/eventemitter3/index.js
|
|
34
|
+
var require_eventemitter3 = __commonJS({
|
|
35
|
+
"../../node_modules/.pnpm/eventemitter3@5.0.1/node_modules/eventemitter3/index.js"(exports, module) {
|
|
36
|
+
var has = Object.prototype.hasOwnProperty;
|
|
37
|
+
var prefix = "~";
|
|
38
|
+
function Events() {
|
|
39
|
+
}
|
|
40
|
+
__name(Events, "Events");
|
|
41
|
+
if (Object.create) {
|
|
42
|
+
Events.prototype = /* @__PURE__ */ Object.create(null);
|
|
43
|
+
if (!new Events().__proto__) prefix = false;
|
|
44
|
+
}
|
|
45
|
+
function EE(fn, context, once) {
|
|
46
|
+
this.fn = fn;
|
|
47
|
+
this.context = context;
|
|
48
|
+
this.once = once || false;
|
|
49
|
+
}
|
|
50
|
+
__name(EE, "EE");
|
|
51
|
+
function addListener(emitter, event, fn, context, once) {
|
|
52
|
+
if (typeof fn !== "function") {
|
|
53
|
+
throw new TypeError("The listener must be a function");
|
|
54
|
+
}
|
|
55
|
+
var listener = new EE(fn, context || emitter, once), evt = prefix ? prefix + event : event;
|
|
56
|
+
if (!emitter._events[evt]) emitter._events[evt] = listener, emitter._eventsCount++;
|
|
57
|
+
else if (!emitter._events[evt].fn) emitter._events[evt].push(listener);
|
|
58
|
+
else emitter._events[evt] = [emitter._events[evt], listener];
|
|
59
|
+
return emitter;
|
|
60
|
+
}
|
|
61
|
+
__name(addListener, "addListener");
|
|
62
|
+
function clearEvent(emitter, evt) {
|
|
63
|
+
if (--emitter._eventsCount === 0) emitter._events = new Events();
|
|
64
|
+
else delete emitter._events[evt];
|
|
65
|
+
}
|
|
66
|
+
__name(clearEvent, "clearEvent");
|
|
67
|
+
function EventEmitter2() {
|
|
68
|
+
this._events = new Events();
|
|
69
|
+
this._eventsCount = 0;
|
|
70
|
+
}
|
|
71
|
+
__name(EventEmitter2, "EventEmitter");
|
|
72
|
+
EventEmitter2.prototype.eventNames = /* @__PURE__ */ __name(function eventNames() {
|
|
73
|
+
var names = [], events, name;
|
|
74
|
+
if (this._eventsCount === 0) return names;
|
|
75
|
+
for (name in events = this._events) {
|
|
76
|
+
if (has.call(events, name)) names.push(prefix ? name.slice(1) : name);
|
|
77
|
+
}
|
|
78
|
+
if (Object.getOwnPropertySymbols) {
|
|
79
|
+
return names.concat(Object.getOwnPropertySymbols(events));
|
|
80
|
+
}
|
|
81
|
+
return names;
|
|
82
|
+
}, "eventNames");
|
|
83
|
+
EventEmitter2.prototype.listeners = /* @__PURE__ */ __name(function listeners(event) {
|
|
84
|
+
var evt = prefix ? prefix + event : event, handlers = this._events[evt];
|
|
85
|
+
if (!handlers) return [];
|
|
86
|
+
if (handlers.fn) return [handlers.fn];
|
|
87
|
+
for (var i = 0, l = handlers.length, ee = new Array(l); i < l; i++) {
|
|
88
|
+
ee[i] = handlers[i].fn;
|
|
89
|
+
}
|
|
90
|
+
return ee;
|
|
91
|
+
}, "listeners");
|
|
92
|
+
EventEmitter2.prototype.listenerCount = /* @__PURE__ */ __name(function listenerCount(event) {
|
|
93
|
+
var evt = prefix ? prefix + event : event, listeners = this._events[evt];
|
|
94
|
+
if (!listeners) return 0;
|
|
95
|
+
if (listeners.fn) return 1;
|
|
96
|
+
return listeners.length;
|
|
97
|
+
}, "listenerCount");
|
|
98
|
+
EventEmitter2.prototype.emit = /* @__PURE__ */ __name(function emit(event, a1, a2, a3, a4, a5) {
|
|
99
|
+
var evt = prefix ? prefix + event : event;
|
|
100
|
+
if (!this._events[evt]) return false;
|
|
101
|
+
var listeners = this._events[evt], len = arguments.length, args, i;
|
|
102
|
+
if (listeners.fn) {
|
|
103
|
+
if (listeners.once) this.removeListener(event, listeners.fn, void 0, true);
|
|
104
|
+
switch (len) {
|
|
105
|
+
case 1:
|
|
106
|
+
return listeners.fn.call(listeners.context), true;
|
|
107
|
+
case 2:
|
|
108
|
+
return listeners.fn.call(listeners.context, a1), true;
|
|
109
|
+
case 3:
|
|
110
|
+
return listeners.fn.call(listeners.context, a1, a2), true;
|
|
111
|
+
case 4:
|
|
112
|
+
return listeners.fn.call(listeners.context, a1, a2, a3), true;
|
|
113
|
+
case 5:
|
|
114
|
+
return listeners.fn.call(listeners.context, a1, a2, a3, a4), true;
|
|
115
|
+
case 6:
|
|
116
|
+
return listeners.fn.call(listeners.context, a1, a2, a3, a4, a5), true;
|
|
117
|
+
}
|
|
118
|
+
for (i = 1, args = new Array(len - 1); i < len; i++) {
|
|
119
|
+
args[i - 1] = arguments[i];
|
|
120
|
+
}
|
|
121
|
+
listeners.fn.apply(listeners.context, args);
|
|
122
|
+
} else {
|
|
123
|
+
var length = listeners.length, j;
|
|
124
|
+
for (i = 0; i < length; i++) {
|
|
125
|
+
if (listeners[i].once) this.removeListener(event, listeners[i].fn, void 0, true);
|
|
126
|
+
switch (len) {
|
|
127
|
+
case 1:
|
|
128
|
+
listeners[i].fn.call(listeners[i].context);
|
|
129
|
+
break;
|
|
130
|
+
case 2:
|
|
131
|
+
listeners[i].fn.call(listeners[i].context, a1);
|
|
132
|
+
break;
|
|
133
|
+
case 3:
|
|
134
|
+
listeners[i].fn.call(listeners[i].context, a1, a2);
|
|
135
|
+
break;
|
|
136
|
+
case 4:
|
|
137
|
+
listeners[i].fn.call(listeners[i].context, a1, a2, a3);
|
|
138
|
+
break;
|
|
139
|
+
default:
|
|
140
|
+
if (!args) for (j = 1, args = new Array(len - 1); j < len; j++) {
|
|
141
|
+
args[j - 1] = arguments[j];
|
|
142
|
+
}
|
|
143
|
+
listeners[i].fn.apply(listeners[i].context, args);
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
return true;
|
|
148
|
+
}, "emit");
|
|
149
|
+
EventEmitter2.prototype.on = /* @__PURE__ */ __name(function on(event, fn, context) {
|
|
150
|
+
return addListener(this, event, fn, context, false);
|
|
151
|
+
}, "on");
|
|
152
|
+
EventEmitter2.prototype.once = /* @__PURE__ */ __name(function once(event, fn, context) {
|
|
153
|
+
return addListener(this, event, fn, context, true);
|
|
154
|
+
}, "once");
|
|
155
|
+
EventEmitter2.prototype.removeListener = /* @__PURE__ */ __name(function removeListener(event, fn, context, once) {
|
|
156
|
+
var evt = prefix ? prefix + event : event;
|
|
157
|
+
if (!this._events[evt]) return this;
|
|
158
|
+
if (!fn) {
|
|
159
|
+
clearEvent(this, evt);
|
|
160
|
+
return this;
|
|
161
|
+
}
|
|
162
|
+
var listeners = this._events[evt];
|
|
163
|
+
if (listeners.fn) {
|
|
164
|
+
if (listeners.fn === fn && (!once || listeners.once) && (!context || listeners.context === context)) {
|
|
165
|
+
clearEvent(this, evt);
|
|
166
|
+
}
|
|
167
|
+
} else {
|
|
168
|
+
for (var i = 0, events = [], length = listeners.length; i < length; i++) {
|
|
169
|
+
if (listeners[i].fn !== fn || once && !listeners[i].once || context && listeners[i].context !== context) {
|
|
170
|
+
events.push(listeners[i]);
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
if (events.length) this._events[evt] = events.length === 1 ? events[0] : events;
|
|
174
|
+
else clearEvent(this, evt);
|
|
175
|
+
}
|
|
176
|
+
return this;
|
|
177
|
+
}, "removeListener");
|
|
178
|
+
EventEmitter2.prototype.removeAllListeners = /* @__PURE__ */ __name(function removeAllListeners(event) {
|
|
179
|
+
var evt;
|
|
180
|
+
if (event) {
|
|
181
|
+
evt = prefix ? prefix + event : event;
|
|
182
|
+
if (this._events[evt]) clearEvent(this, evt);
|
|
183
|
+
} else {
|
|
184
|
+
this._events = new Events();
|
|
185
|
+
this._eventsCount = 0;
|
|
186
|
+
}
|
|
187
|
+
return this;
|
|
188
|
+
}, "removeAllListeners");
|
|
189
|
+
EventEmitter2.prototype.off = EventEmitter2.prototype.removeListener;
|
|
190
|
+
EventEmitter2.prototype.addListener = EventEmitter2.prototype.on;
|
|
191
|
+
EventEmitter2.prefixed = prefix;
|
|
192
|
+
EventEmitter2.EventEmitter = EventEmitter2;
|
|
193
|
+
if ("undefined" !== typeof module) {
|
|
194
|
+
module.exports = EventEmitter2;
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
});
|
|
198
|
+
|
|
199
|
+
// ../../node_modules/.pnpm/chalk@5.3.0/node_modules/chalk/source/vendor/ansi-styles/index.js
|
|
200
|
+
var ANSI_BACKGROUND_OFFSET = 10;
|
|
201
|
+
var wrapAnsi16 = /* @__PURE__ */ __name((offset = 0) => (code) => `\x1B[${code + offset}m`, "wrapAnsi16");
|
|
202
|
+
var wrapAnsi256 = /* @__PURE__ */ __name((offset = 0) => (code) => `\x1B[${38 + offset};5;${code}m`, "wrapAnsi256");
|
|
203
|
+
var wrapAnsi16m = /* @__PURE__ */ __name((offset = 0) => (red, green, blue) => `\x1B[${38 + offset};2;${red};${green};${blue}m`, "wrapAnsi16m");
|
|
204
|
+
var styles = {
|
|
205
|
+
modifier: {
|
|
206
|
+
reset: [0, 0],
|
|
207
|
+
// 21 isn't widely supported and 22 does the same thing
|
|
208
|
+
bold: [1, 22],
|
|
209
|
+
dim: [2, 22],
|
|
210
|
+
italic: [3, 23],
|
|
211
|
+
underline: [4, 24],
|
|
212
|
+
overline: [53, 55],
|
|
213
|
+
inverse: [7, 27],
|
|
214
|
+
hidden: [8, 28],
|
|
215
|
+
strikethrough: [9, 29]
|
|
216
|
+
},
|
|
217
|
+
color: {
|
|
218
|
+
black: [30, 39],
|
|
219
|
+
red: [31, 39],
|
|
220
|
+
green: [32, 39],
|
|
221
|
+
yellow: [33, 39],
|
|
222
|
+
blue: [34, 39],
|
|
223
|
+
magenta: [35, 39],
|
|
224
|
+
cyan: [36, 39],
|
|
225
|
+
white: [37, 39],
|
|
226
|
+
// Bright color
|
|
227
|
+
blackBright: [90, 39],
|
|
228
|
+
gray: [90, 39],
|
|
229
|
+
// Alias of `blackBright`
|
|
230
|
+
grey: [90, 39],
|
|
231
|
+
// Alias of `blackBright`
|
|
232
|
+
redBright: [91, 39],
|
|
233
|
+
greenBright: [92, 39],
|
|
234
|
+
yellowBright: [93, 39],
|
|
235
|
+
blueBright: [94, 39],
|
|
236
|
+
magentaBright: [95, 39],
|
|
237
|
+
cyanBright: [96, 39],
|
|
238
|
+
whiteBright: [97, 39]
|
|
239
|
+
},
|
|
240
|
+
bgColor: {
|
|
241
|
+
bgBlack: [40, 49],
|
|
242
|
+
bgRed: [41, 49],
|
|
243
|
+
bgGreen: [42, 49],
|
|
244
|
+
bgYellow: [43, 49],
|
|
245
|
+
bgBlue: [44, 49],
|
|
246
|
+
bgMagenta: [45, 49],
|
|
247
|
+
bgCyan: [46, 49],
|
|
248
|
+
bgWhite: [47, 49],
|
|
249
|
+
// Bright color
|
|
250
|
+
bgBlackBright: [100, 49],
|
|
251
|
+
bgGray: [100, 49],
|
|
252
|
+
// Alias of `bgBlackBright`
|
|
253
|
+
bgGrey: [100, 49],
|
|
254
|
+
// Alias of `bgBlackBright`
|
|
255
|
+
bgRedBright: [101, 49],
|
|
256
|
+
bgGreenBright: [102, 49],
|
|
257
|
+
bgYellowBright: [103, 49],
|
|
258
|
+
bgBlueBright: [104, 49],
|
|
259
|
+
bgMagentaBright: [105, 49],
|
|
260
|
+
bgCyanBright: [106, 49],
|
|
261
|
+
bgWhiteBright: [107, 49]
|
|
262
|
+
}
|
|
263
|
+
};
|
|
264
|
+
Object.keys(styles.modifier);
|
|
265
|
+
var foregroundColorNames = Object.keys(styles.color);
|
|
266
|
+
var backgroundColorNames = Object.keys(styles.bgColor);
|
|
267
|
+
[...foregroundColorNames, ...backgroundColorNames];
|
|
268
|
+
function assembleStyles() {
|
|
269
|
+
const codes = /* @__PURE__ */ new Map();
|
|
270
|
+
for (const [groupName, group] of Object.entries(styles)) {
|
|
271
|
+
for (const [styleName, style] of Object.entries(group)) {
|
|
272
|
+
styles[styleName] = {
|
|
273
|
+
open: `\x1B[${style[0]}m`,
|
|
274
|
+
close: `\x1B[${style[1]}m`
|
|
275
|
+
};
|
|
276
|
+
group[styleName] = styles[styleName];
|
|
277
|
+
codes.set(style[0], style[1]);
|
|
278
|
+
}
|
|
279
|
+
Object.defineProperty(styles, groupName, {
|
|
280
|
+
value: group,
|
|
281
|
+
enumerable: false
|
|
282
|
+
});
|
|
283
|
+
}
|
|
284
|
+
Object.defineProperty(styles, "codes", {
|
|
285
|
+
value: codes,
|
|
286
|
+
enumerable: false
|
|
287
|
+
});
|
|
288
|
+
styles.color.close = "\x1B[39m";
|
|
289
|
+
styles.bgColor.close = "\x1B[49m";
|
|
290
|
+
styles.color.ansi = wrapAnsi16();
|
|
291
|
+
styles.color.ansi256 = wrapAnsi256();
|
|
292
|
+
styles.color.ansi16m = wrapAnsi16m();
|
|
293
|
+
styles.bgColor.ansi = wrapAnsi16(ANSI_BACKGROUND_OFFSET);
|
|
294
|
+
styles.bgColor.ansi256 = wrapAnsi256(ANSI_BACKGROUND_OFFSET);
|
|
295
|
+
styles.bgColor.ansi16m = wrapAnsi16m(ANSI_BACKGROUND_OFFSET);
|
|
296
|
+
Object.defineProperties(styles, {
|
|
297
|
+
rgbToAnsi256: {
|
|
298
|
+
value(red, green, blue) {
|
|
299
|
+
if (red === green && green === blue) {
|
|
300
|
+
if (red < 8) {
|
|
301
|
+
return 16;
|
|
302
|
+
}
|
|
303
|
+
if (red > 248) {
|
|
304
|
+
return 231;
|
|
305
|
+
}
|
|
306
|
+
return Math.round((red - 8) / 247 * 24) + 232;
|
|
307
|
+
}
|
|
308
|
+
return 16 + 36 * Math.round(red / 255 * 5) + 6 * Math.round(green / 255 * 5) + Math.round(blue / 255 * 5);
|
|
309
|
+
},
|
|
310
|
+
enumerable: false
|
|
311
|
+
},
|
|
312
|
+
hexToRgb: {
|
|
313
|
+
value(hex) {
|
|
314
|
+
const matches = /[a-f\d]{6}|[a-f\d]{3}/i.exec(hex.toString(16));
|
|
315
|
+
if (!matches) {
|
|
316
|
+
return [0, 0, 0];
|
|
317
|
+
}
|
|
318
|
+
let [colorString] = matches;
|
|
319
|
+
if (colorString.length === 3) {
|
|
320
|
+
colorString = [...colorString].map((character) => character + character).join("");
|
|
321
|
+
}
|
|
322
|
+
const integer = Number.parseInt(colorString, 16);
|
|
323
|
+
return [
|
|
324
|
+
/* eslint-disable no-bitwise */
|
|
325
|
+
integer >> 16 & 255,
|
|
326
|
+
integer >> 8 & 255,
|
|
327
|
+
integer & 255
|
|
328
|
+
/* eslint-enable no-bitwise */
|
|
329
|
+
];
|
|
330
|
+
},
|
|
331
|
+
enumerable: false
|
|
332
|
+
},
|
|
333
|
+
hexToAnsi256: {
|
|
334
|
+
value: /* @__PURE__ */ __name((hex) => styles.rgbToAnsi256(...styles.hexToRgb(hex)), "value"),
|
|
335
|
+
enumerable: false
|
|
336
|
+
},
|
|
337
|
+
ansi256ToAnsi: {
|
|
338
|
+
value(code) {
|
|
339
|
+
if (code < 8) {
|
|
340
|
+
return 30 + code;
|
|
341
|
+
}
|
|
342
|
+
if (code < 16) {
|
|
343
|
+
return 90 + (code - 8);
|
|
344
|
+
}
|
|
345
|
+
let red;
|
|
346
|
+
let green;
|
|
347
|
+
let blue;
|
|
348
|
+
if (code >= 232) {
|
|
349
|
+
red = ((code - 232) * 10 + 8) / 255;
|
|
350
|
+
green = red;
|
|
351
|
+
blue = red;
|
|
352
|
+
} else {
|
|
353
|
+
code -= 16;
|
|
354
|
+
const remainder = code % 36;
|
|
355
|
+
red = Math.floor(code / 36) / 5;
|
|
356
|
+
green = Math.floor(remainder / 6) / 5;
|
|
357
|
+
blue = remainder % 6 / 5;
|
|
358
|
+
}
|
|
359
|
+
const value = Math.max(red, green, blue) * 2;
|
|
360
|
+
if (value === 0) {
|
|
361
|
+
return 30;
|
|
362
|
+
}
|
|
363
|
+
let result = 30 + (Math.round(blue) << 2 | Math.round(green) << 1 | Math.round(red));
|
|
364
|
+
if (value === 2) {
|
|
365
|
+
result += 60;
|
|
366
|
+
}
|
|
367
|
+
return result;
|
|
368
|
+
},
|
|
369
|
+
enumerable: false
|
|
370
|
+
},
|
|
371
|
+
rgbToAnsi: {
|
|
372
|
+
value: /* @__PURE__ */ __name((red, green, blue) => styles.ansi256ToAnsi(styles.rgbToAnsi256(red, green, blue)), "value"),
|
|
373
|
+
enumerable: false
|
|
374
|
+
},
|
|
375
|
+
hexToAnsi: {
|
|
376
|
+
value: /* @__PURE__ */ __name((hex) => styles.ansi256ToAnsi(styles.hexToAnsi256(hex)), "value"),
|
|
377
|
+
enumerable: false
|
|
378
|
+
}
|
|
379
|
+
});
|
|
380
|
+
return styles;
|
|
381
|
+
}
|
|
382
|
+
__name(assembleStyles, "assembleStyles");
|
|
383
|
+
var ansiStyles = assembleStyles();
|
|
384
|
+
var ansi_styles_default = ansiStyles;
|
|
385
|
+
function hasFlag(flag, argv = globalThis.Deno ? globalThis.Deno.args : process2.argv) {
|
|
386
|
+
const prefix = flag.startsWith("-") ? "" : flag.length === 1 ? "-" : "--";
|
|
387
|
+
const position = argv.indexOf(prefix + flag);
|
|
388
|
+
const terminatorPosition = argv.indexOf("--");
|
|
389
|
+
return position !== -1 && (terminatorPosition === -1 || position < terminatorPosition);
|
|
390
|
+
}
|
|
391
|
+
__name(hasFlag, "hasFlag");
|
|
392
|
+
var { env } = process2;
|
|
393
|
+
var flagForceColor;
|
|
394
|
+
if (hasFlag("no-color") || hasFlag("no-colors") || hasFlag("color=false") || hasFlag("color=never")) {
|
|
395
|
+
flagForceColor = 0;
|
|
396
|
+
} else if (hasFlag("color") || hasFlag("colors") || hasFlag("color=true") || hasFlag("color=always")) {
|
|
397
|
+
flagForceColor = 1;
|
|
398
|
+
}
|
|
399
|
+
function envForceColor() {
|
|
400
|
+
if ("FORCE_COLOR" in env) {
|
|
401
|
+
if (env.FORCE_COLOR === "true") {
|
|
402
|
+
return 1;
|
|
403
|
+
}
|
|
404
|
+
if (env.FORCE_COLOR === "false") {
|
|
405
|
+
return 0;
|
|
406
|
+
}
|
|
407
|
+
return env.FORCE_COLOR.length === 0 ? 1 : Math.min(Number.parseInt(env.FORCE_COLOR, 10), 3);
|
|
408
|
+
}
|
|
409
|
+
}
|
|
410
|
+
__name(envForceColor, "envForceColor");
|
|
411
|
+
function translateLevel(level) {
|
|
412
|
+
if (level === 0) {
|
|
413
|
+
return false;
|
|
414
|
+
}
|
|
415
|
+
return {
|
|
416
|
+
level,
|
|
417
|
+
hasBasic: true,
|
|
418
|
+
has256: level >= 2,
|
|
419
|
+
has16m: level >= 3
|
|
420
|
+
};
|
|
421
|
+
}
|
|
422
|
+
__name(translateLevel, "translateLevel");
|
|
423
|
+
function _supportsColor(haveStream, { streamIsTTY, sniffFlags = true } = {}) {
|
|
424
|
+
const noFlagForceColor = envForceColor();
|
|
425
|
+
if (noFlagForceColor !== void 0) {
|
|
426
|
+
flagForceColor = noFlagForceColor;
|
|
427
|
+
}
|
|
428
|
+
const forceColor = sniffFlags ? flagForceColor : noFlagForceColor;
|
|
429
|
+
if (forceColor === 0) {
|
|
430
|
+
return 0;
|
|
431
|
+
}
|
|
432
|
+
if (sniffFlags) {
|
|
433
|
+
if (hasFlag("color=16m") || hasFlag("color=full") || hasFlag("color=truecolor")) {
|
|
434
|
+
return 3;
|
|
435
|
+
}
|
|
436
|
+
if (hasFlag("color=256")) {
|
|
437
|
+
return 2;
|
|
438
|
+
}
|
|
439
|
+
}
|
|
440
|
+
if ("TF_BUILD" in env && "AGENT_NAME" in env) {
|
|
441
|
+
return 1;
|
|
442
|
+
}
|
|
443
|
+
if (haveStream && !streamIsTTY && forceColor === void 0) {
|
|
444
|
+
return 0;
|
|
445
|
+
}
|
|
446
|
+
const min = forceColor || 0;
|
|
447
|
+
if (env.TERM === "dumb") {
|
|
448
|
+
return min;
|
|
449
|
+
}
|
|
450
|
+
if (process2.platform === "win32") {
|
|
451
|
+
const osRelease = os.release().split(".");
|
|
452
|
+
if (Number(osRelease[0]) >= 10 && Number(osRelease[2]) >= 10586) {
|
|
453
|
+
return Number(osRelease[2]) >= 14931 ? 3 : 2;
|
|
454
|
+
}
|
|
455
|
+
return 1;
|
|
456
|
+
}
|
|
457
|
+
if ("CI" in env) {
|
|
458
|
+
if ("GITHUB_ACTIONS" in env || "GITEA_ACTIONS" in env) {
|
|
459
|
+
return 3;
|
|
460
|
+
}
|
|
461
|
+
if (["TRAVIS", "CIRCLECI", "APPVEYOR", "GITLAB_CI", "BUILDKITE", "DRONE"].some((sign) => sign in env) || env.CI_NAME === "codeship") {
|
|
462
|
+
return 1;
|
|
463
|
+
}
|
|
464
|
+
return min;
|
|
465
|
+
}
|
|
466
|
+
if ("TEAMCITY_VERSION" in env) {
|
|
467
|
+
return /^(9\.(0*[1-9]\d*)\.|\d{2,}\.)/.test(env.TEAMCITY_VERSION) ? 1 : 0;
|
|
468
|
+
}
|
|
469
|
+
if (env.COLORTERM === "truecolor") {
|
|
470
|
+
return 3;
|
|
471
|
+
}
|
|
472
|
+
if (env.TERM === "xterm-kitty") {
|
|
473
|
+
return 3;
|
|
474
|
+
}
|
|
475
|
+
if ("TERM_PROGRAM" in env) {
|
|
476
|
+
const version = Number.parseInt((env.TERM_PROGRAM_VERSION || "").split(".")[0], 10);
|
|
477
|
+
switch (env.TERM_PROGRAM) {
|
|
478
|
+
case "iTerm.app": {
|
|
479
|
+
return version >= 3 ? 3 : 2;
|
|
480
|
+
}
|
|
481
|
+
case "Apple_Terminal": {
|
|
482
|
+
return 2;
|
|
483
|
+
}
|
|
484
|
+
}
|
|
485
|
+
}
|
|
486
|
+
if (/-256(color)?$/i.test(env.TERM)) {
|
|
487
|
+
return 2;
|
|
488
|
+
}
|
|
489
|
+
if (/^screen|^xterm|^vt100|^vt220|^rxvt|color|ansi|cygwin|linux/i.test(env.TERM)) {
|
|
490
|
+
return 1;
|
|
491
|
+
}
|
|
492
|
+
if ("COLORTERM" in env) {
|
|
493
|
+
return 1;
|
|
494
|
+
}
|
|
495
|
+
return min;
|
|
496
|
+
}
|
|
497
|
+
__name(_supportsColor, "_supportsColor");
|
|
498
|
+
function createSupportsColor(stream, options = {}) {
|
|
499
|
+
const level = _supportsColor(stream, {
|
|
500
|
+
streamIsTTY: stream && stream.isTTY,
|
|
501
|
+
...options
|
|
502
|
+
});
|
|
503
|
+
return translateLevel(level);
|
|
504
|
+
}
|
|
505
|
+
__name(createSupportsColor, "createSupportsColor");
|
|
506
|
+
var supportsColor = {
|
|
507
|
+
stdout: createSupportsColor({ isTTY: tty.isatty(1) }),
|
|
508
|
+
stderr: createSupportsColor({ isTTY: tty.isatty(2) })
|
|
509
|
+
};
|
|
510
|
+
var supports_color_default = supportsColor;
|
|
511
|
+
|
|
512
|
+
// ../../node_modules/.pnpm/chalk@5.3.0/node_modules/chalk/source/utilities.js
|
|
513
|
+
function stringReplaceAll(string, substring, replacer) {
|
|
514
|
+
let index = string.indexOf(substring);
|
|
515
|
+
if (index === -1) {
|
|
516
|
+
return string;
|
|
517
|
+
}
|
|
518
|
+
const substringLength = substring.length;
|
|
519
|
+
let endIndex = 0;
|
|
520
|
+
let returnValue = "";
|
|
521
|
+
do {
|
|
522
|
+
returnValue += string.slice(endIndex, index) + substring + replacer;
|
|
523
|
+
endIndex = index + substringLength;
|
|
524
|
+
index = string.indexOf(substring, endIndex);
|
|
525
|
+
} while (index !== -1);
|
|
526
|
+
returnValue += string.slice(endIndex);
|
|
527
|
+
return returnValue;
|
|
528
|
+
}
|
|
529
|
+
__name(stringReplaceAll, "stringReplaceAll");
|
|
530
|
+
function stringEncaseCRLFWithFirstIndex(string, prefix, postfix, index) {
|
|
531
|
+
let endIndex = 0;
|
|
532
|
+
let returnValue = "";
|
|
533
|
+
do {
|
|
534
|
+
const gotCR = string[index - 1] === "\r";
|
|
535
|
+
returnValue += string.slice(endIndex, gotCR ? index - 1 : index) + prefix + (gotCR ? "\r\n" : "\n") + postfix;
|
|
536
|
+
endIndex = index + 1;
|
|
537
|
+
index = string.indexOf("\n", endIndex);
|
|
538
|
+
} while (index !== -1);
|
|
539
|
+
returnValue += string.slice(endIndex);
|
|
540
|
+
return returnValue;
|
|
541
|
+
}
|
|
542
|
+
__name(stringEncaseCRLFWithFirstIndex, "stringEncaseCRLFWithFirstIndex");
|
|
543
|
+
|
|
544
|
+
// ../../node_modules/.pnpm/chalk@5.3.0/node_modules/chalk/source/index.js
|
|
545
|
+
var { stdout: stdoutColor, stderr: stderrColor } = supports_color_default;
|
|
546
|
+
var GENERATOR = Symbol("GENERATOR");
|
|
547
|
+
var STYLER = Symbol("STYLER");
|
|
548
|
+
var IS_EMPTY = Symbol("IS_EMPTY");
|
|
549
|
+
var levelMapping = [
|
|
550
|
+
"ansi",
|
|
551
|
+
"ansi",
|
|
552
|
+
"ansi256",
|
|
553
|
+
"ansi16m"
|
|
554
|
+
];
|
|
555
|
+
var styles2 = /* @__PURE__ */ Object.create(null);
|
|
556
|
+
var applyOptions = /* @__PURE__ */ __name((object, options = {}) => {
|
|
557
|
+
if (options.level && !(Number.isInteger(options.level) && options.level >= 0 && options.level <= 3)) {
|
|
558
|
+
throw new Error("The `level` option should be an integer from 0 to 3");
|
|
559
|
+
}
|
|
560
|
+
const colorLevel = stdoutColor ? stdoutColor.level : 0;
|
|
561
|
+
object.level = options.level === void 0 ? colorLevel : options.level;
|
|
562
|
+
}, "applyOptions");
|
|
563
|
+
var chalkFactory = /* @__PURE__ */ __name((options) => {
|
|
564
|
+
const chalk2 = /* @__PURE__ */ __name((...strings) => strings.join(" "), "chalk");
|
|
565
|
+
applyOptions(chalk2, options);
|
|
566
|
+
Object.setPrototypeOf(chalk2, createChalk.prototype);
|
|
567
|
+
return chalk2;
|
|
568
|
+
}, "chalkFactory");
|
|
569
|
+
function createChalk(options) {
|
|
570
|
+
return chalkFactory(options);
|
|
571
|
+
}
|
|
572
|
+
__name(createChalk, "createChalk");
|
|
573
|
+
Object.setPrototypeOf(createChalk.prototype, Function.prototype);
|
|
574
|
+
for (const [styleName, style] of Object.entries(ansi_styles_default)) {
|
|
575
|
+
styles2[styleName] = {
|
|
576
|
+
get() {
|
|
577
|
+
const builder = createBuilder(this, createStyler(style.open, style.close, this[STYLER]), this[IS_EMPTY]);
|
|
578
|
+
Object.defineProperty(this, styleName, { value: builder });
|
|
579
|
+
return builder;
|
|
580
|
+
}
|
|
581
|
+
};
|
|
582
|
+
}
|
|
583
|
+
styles2.visible = {
|
|
584
|
+
get() {
|
|
585
|
+
const builder = createBuilder(this, this[STYLER], true);
|
|
586
|
+
Object.defineProperty(this, "visible", { value: builder });
|
|
587
|
+
return builder;
|
|
588
|
+
}
|
|
589
|
+
};
|
|
590
|
+
var getModelAnsi = /* @__PURE__ */ __name((model, level, type, ...arguments_) => {
|
|
591
|
+
if (model === "rgb") {
|
|
592
|
+
if (level === "ansi16m") {
|
|
593
|
+
return ansi_styles_default[type].ansi16m(...arguments_);
|
|
594
|
+
}
|
|
595
|
+
if (level === "ansi256") {
|
|
596
|
+
return ansi_styles_default[type].ansi256(ansi_styles_default.rgbToAnsi256(...arguments_));
|
|
597
|
+
}
|
|
598
|
+
return ansi_styles_default[type].ansi(ansi_styles_default.rgbToAnsi(...arguments_));
|
|
599
|
+
}
|
|
600
|
+
if (model === "hex") {
|
|
601
|
+
return getModelAnsi("rgb", level, type, ...ansi_styles_default.hexToRgb(...arguments_));
|
|
602
|
+
}
|
|
603
|
+
return ansi_styles_default[type][model](...arguments_);
|
|
604
|
+
}, "getModelAnsi");
|
|
605
|
+
var usedModels = ["rgb", "hex", "ansi256"];
|
|
606
|
+
for (const model of usedModels) {
|
|
607
|
+
styles2[model] = {
|
|
608
|
+
get() {
|
|
609
|
+
const { level } = this;
|
|
610
|
+
return function(...arguments_) {
|
|
611
|
+
const styler = createStyler(getModelAnsi(model, levelMapping[level], "color", ...arguments_), ansi_styles_default.color.close, this[STYLER]);
|
|
612
|
+
return createBuilder(this, styler, this[IS_EMPTY]);
|
|
613
|
+
};
|
|
614
|
+
}
|
|
615
|
+
};
|
|
616
|
+
const bgModel = "bg" + model[0].toUpperCase() + model.slice(1);
|
|
617
|
+
styles2[bgModel] = {
|
|
618
|
+
get() {
|
|
619
|
+
const { level } = this;
|
|
620
|
+
return function(...arguments_) {
|
|
621
|
+
const styler = createStyler(getModelAnsi(model, levelMapping[level], "bgColor", ...arguments_), ansi_styles_default.bgColor.close, this[STYLER]);
|
|
622
|
+
return createBuilder(this, styler, this[IS_EMPTY]);
|
|
623
|
+
};
|
|
624
|
+
}
|
|
625
|
+
};
|
|
626
|
+
}
|
|
627
|
+
var proto = Object.defineProperties(() => {
|
|
628
|
+
}, {
|
|
629
|
+
...styles2,
|
|
630
|
+
level: {
|
|
631
|
+
enumerable: true,
|
|
632
|
+
get() {
|
|
633
|
+
return this[GENERATOR].level;
|
|
634
|
+
},
|
|
635
|
+
set(level) {
|
|
636
|
+
this[GENERATOR].level = level;
|
|
637
|
+
}
|
|
638
|
+
}
|
|
639
|
+
});
|
|
640
|
+
var createStyler = /* @__PURE__ */ __name((open, close, parent) => {
|
|
641
|
+
let openAll;
|
|
642
|
+
let closeAll;
|
|
643
|
+
if (parent === void 0) {
|
|
644
|
+
openAll = open;
|
|
645
|
+
closeAll = close;
|
|
646
|
+
} else {
|
|
647
|
+
openAll = parent.openAll + open;
|
|
648
|
+
closeAll = close + parent.closeAll;
|
|
649
|
+
}
|
|
650
|
+
return {
|
|
651
|
+
open,
|
|
652
|
+
close,
|
|
653
|
+
openAll,
|
|
654
|
+
closeAll,
|
|
655
|
+
parent
|
|
656
|
+
};
|
|
657
|
+
}, "createStyler");
|
|
658
|
+
var createBuilder = /* @__PURE__ */ __name((self, _styler, _isEmpty) => {
|
|
659
|
+
const builder = /* @__PURE__ */ __name((...arguments_) => applyStyle(builder, arguments_.length === 1 ? "" + arguments_[0] : arguments_.join(" ")), "builder");
|
|
660
|
+
Object.setPrototypeOf(builder, proto);
|
|
661
|
+
builder[GENERATOR] = self;
|
|
662
|
+
builder[STYLER] = _styler;
|
|
663
|
+
builder[IS_EMPTY] = _isEmpty;
|
|
664
|
+
return builder;
|
|
665
|
+
}, "createBuilder");
|
|
666
|
+
var applyStyle = /* @__PURE__ */ __name((self, string) => {
|
|
667
|
+
if (self.level <= 0 || !string) {
|
|
668
|
+
return self[IS_EMPTY] ? "" : string;
|
|
669
|
+
}
|
|
670
|
+
let styler = self[STYLER];
|
|
671
|
+
if (styler === void 0) {
|
|
672
|
+
return string;
|
|
673
|
+
}
|
|
674
|
+
const { openAll, closeAll } = styler;
|
|
675
|
+
if (string.includes("\x1B")) {
|
|
676
|
+
while (styler !== void 0) {
|
|
677
|
+
string = stringReplaceAll(string, styler.close, styler.open);
|
|
678
|
+
styler = styler.parent;
|
|
679
|
+
}
|
|
680
|
+
}
|
|
681
|
+
const lfIndex = string.indexOf("\n");
|
|
682
|
+
if (lfIndex !== -1) {
|
|
683
|
+
string = stringEncaseCRLFWithFirstIndex(string, closeAll, openAll, lfIndex);
|
|
684
|
+
}
|
|
685
|
+
return openAll + string + closeAll;
|
|
686
|
+
}, "applyStyle");
|
|
687
|
+
Object.defineProperties(createChalk.prototype, styles2);
|
|
688
|
+
var chalk = createChalk();
|
|
689
|
+
createChalk({ level: stderrColor ? stderrColor.level : 0 });
|
|
690
|
+
var source_default = chalk;
|
|
691
|
+
|
|
692
|
+
// ../../node_modules/.pnpm/eventemitter3@5.0.1/node_modules/eventemitter3/index.mjs
|
|
693
|
+
var import_index = __toESM(require_eventemitter3());
|
|
694
|
+
|
|
695
|
+
// ../../node_modules/.pnpm/p-timeout@7.0.1/node_modules/p-timeout/index.js
|
|
696
|
+
var TimeoutError = class _TimeoutError extends Error {
|
|
697
|
+
static {
|
|
698
|
+
__name(this, "TimeoutError");
|
|
699
|
+
}
|
|
700
|
+
name = "TimeoutError";
|
|
701
|
+
constructor(message, options) {
|
|
702
|
+
super(message, options);
|
|
703
|
+
Error.captureStackTrace?.(this, _TimeoutError);
|
|
704
|
+
}
|
|
705
|
+
};
|
|
706
|
+
var getAbortedReason = /* @__PURE__ */ __name((signal) => signal.reason ?? new DOMException("This operation was aborted.", "AbortError"), "getAbortedReason");
|
|
707
|
+
function pTimeout(promise, options) {
|
|
708
|
+
const {
|
|
709
|
+
milliseconds,
|
|
710
|
+
fallback,
|
|
711
|
+
message,
|
|
712
|
+
customTimers = { setTimeout, clearTimeout },
|
|
713
|
+
signal
|
|
714
|
+
} = options;
|
|
715
|
+
let timer;
|
|
716
|
+
let abortHandler;
|
|
717
|
+
const wrappedPromise = new Promise((resolve, reject) => {
|
|
718
|
+
if (typeof milliseconds !== "number" || Math.sign(milliseconds) !== 1) {
|
|
719
|
+
throw new TypeError(`Expected \`milliseconds\` to be a positive number, got \`${milliseconds}\``);
|
|
720
|
+
}
|
|
721
|
+
if (signal?.aborted) {
|
|
722
|
+
reject(getAbortedReason(signal));
|
|
723
|
+
return;
|
|
724
|
+
}
|
|
725
|
+
if (signal) {
|
|
726
|
+
abortHandler = /* @__PURE__ */ __name(() => {
|
|
727
|
+
reject(getAbortedReason(signal));
|
|
728
|
+
}, "abortHandler");
|
|
729
|
+
signal.addEventListener("abort", abortHandler, { once: true });
|
|
730
|
+
}
|
|
731
|
+
promise.then(resolve, reject);
|
|
732
|
+
if (milliseconds === Number.POSITIVE_INFINITY) {
|
|
733
|
+
return;
|
|
734
|
+
}
|
|
735
|
+
const timeoutError = new TimeoutError();
|
|
736
|
+
timer = customTimers.setTimeout.call(void 0, () => {
|
|
737
|
+
if (fallback) {
|
|
738
|
+
try {
|
|
739
|
+
resolve(fallback());
|
|
740
|
+
} catch (error) {
|
|
741
|
+
reject(error);
|
|
742
|
+
}
|
|
743
|
+
return;
|
|
744
|
+
}
|
|
745
|
+
if (typeof promise.cancel === "function") {
|
|
746
|
+
promise.cancel();
|
|
747
|
+
}
|
|
748
|
+
if (message === false) {
|
|
749
|
+
resolve();
|
|
750
|
+
} else if (message instanceof Error) {
|
|
751
|
+
reject(message);
|
|
752
|
+
} else {
|
|
753
|
+
timeoutError.message = message ?? `Promise timed out after ${milliseconds} milliseconds`;
|
|
754
|
+
reject(timeoutError);
|
|
755
|
+
}
|
|
756
|
+
}, milliseconds);
|
|
757
|
+
});
|
|
758
|
+
const cancelablePromise = wrappedPromise.finally(() => {
|
|
759
|
+
cancelablePromise.clear();
|
|
760
|
+
if (abortHandler && signal) {
|
|
761
|
+
signal.removeEventListener("abort", abortHandler);
|
|
762
|
+
}
|
|
763
|
+
});
|
|
764
|
+
cancelablePromise.clear = () => {
|
|
765
|
+
customTimers.clearTimeout.call(void 0, timer);
|
|
766
|
+
timer = void 0;
|
|
767
|
+
};
|
|
768
|
+
return cancelablePromise;
|
|
769
|
+
}
|
|
770
|
+
__name(pTimeout, "pTimeout");
|
|
771
|
+
|
|
772
|
+
// ../../node_modules/.pnpm/p-queue@9.0.0/node_modules/p-queue/dist/lower-bound.js
|
|
773
|
+
function lowerBound(array, value, comparator) {
|
|
774
|
+
let first = 0;
|
|
775
|
+
let count = array.length;
|
|
776
|
+
while (count > 0) {
|
|
777
|
+
const step = Math.trunc(count / 2);
|
|
778
|
+
let it = first + step;
|
|
779
|
+
if (comparator(array[it], value) <= 0) {
|
|
780
|
+
first = ++it;
|
|
781
|
+
count -= step + 1;
|
|
782
|
+
} else {
|
|
783
|
+
count = step;
|
|
784
|
+
}
|
|
785
|
+
}
|
|
786
|
+
return first;
|
|
787
|
+
}
|
|
788
|
+
__name(lowerBound, "lowerBound");
|
|
789
|
+
|
|
790
|
+
// ../../node_modules/.pnpm/p-queue@9.0.0/node_modules/p-queue/dist/priority-queue.js
|
|
791
|
+
var PriorityQueue = class {
|
|
792
|
+
static {
|
|
793
|
+
__name(this, "PriorityQueue");
|
|
794
|
+
}
|
|
795
|
+
#queue = [];
|
|
796
|
+
enqueue(run, options) {
|
|
797
|
+
const { priority = 0, id } = options ?? {};
|
|
798
|
+
const element = {
|
|
799
|
+
priority,
|
|
800
|
+
id,
|
|
801
|
+
run
|
|
802
|
+
};
|
|
803
|
+
if (this.size === 0 || this.#queue[this.size - 1].priority >= priority) {
|
|
804
|
+
this.#queue.push(element);
|
|
805
|
+
return;
|
|
806
|
+
}
|
|
807
|
+
const index = lowerBound(this.#queue, element, (a, b) => b.priority - a.priority);
|
|
808
|
+
this.#queue.splice(index, 0, element);
|
|
809
|
+
}
|
|
810
|
+
setPriority(id, priority) {
|
|
811
|
+
const index = this.#queue.findIndex((element) => element.id === id);
|
|
812
|
+
if (index === -1) {
|
|
813
|
+
throw new ReferenceError(`No promise function with the id "${id}" exists in the queue.`);
|
|
814
|
+
}
|
|
815
|
+
const [item] = this.#queue.splice(index, 1);
|
|
816
|
+
this.enqueue(item.run, { priority, id });
|
|
817
|
+
}
|
|
818
|
+
dequeue() {
|
|
819
|
+
const item = this.#queue.shift();
|
|
820
|
+
return item?.run;
|
|
821
|
+
}
|
|
822
|
+
filter(options) {
|
|
823
|
+
return this.#queue.filter((element) => element.priority === options.priority).map((element) => element.run);
|
|
824
|
+
}
|
|
825
|
+
get size() {
|
|
826
|
+
return this.#queue.length;
|
|
827
|
+
}
|
|
828
|
+
};
|
|
829
|
+
|
|
830
|
+
// ../../node_modules/.pnpm/p-queue@9.0.0/node_modules/p-queue/dist/index.js
|
|
831
|
+
var PQueue = class extends import_index.default {
|
|
832
|
+
static {
|
|
833
|
+
__name(this, "PQueue");
|
|
834
|
+
}
|
|
835
|
+
#carryoverIntervalCount;
|
|
836
|
+
#isIntervalIgnored;
|
|
837
|
+
#intervalCount = 0;
|
|
838
|
+
#intervalCap;
|
|
839
|
+
#rateLimitedInInterval = false;
|
|
840
|
+
#rateLimitFlushScheduled = false;
|
|
841
|
+
#interval;
|
|
842
|
+
#intervalEnd = 0;
|
|
843
|
+
#lastExecutionTime = 0;
|
|
844
|
+
#intervalId;
|
|
845
|
+
#timeoutId;
|
|
846
|
+
#queue;
|
|
847
|
+
#queueClass;
|
|
848
|
+
#pending = 0;
|
|
849
|
+
// The `!` is needed because of https://github.com/microsoft/TypeScript/issues/32194
|
|
850
|
+
#concurrency;
|
|
851
|
+
#isPaused;
|
|
852
|
+
// Use to assign a unique identifier to a promise function, if not explicitly specified
|
|
853
|
+
#idAssigner = 1n;
|
|
854
|
+
// Track currently running tasks for debugging
|
|
855
|
+
#runningTasks = /* @__PURE__ */ new Map();
|
|
856
|
+
/**
|
|
857
|
+
Get or set the default timeout for all tasks. Can be changed at runtime.
|
|
858
|
+
|
|
859
|
+
Operations will throw a `TimeoutError` if they don't complete within the specified time.
|
|
860
|
+
|
|
861
|
+
The timeout begins when the operation is dequeued and starts execution, not while it's waiting in the queue.
|
|
862
|
+
|
|
863
|
+
@example
|
|
864
|
+
```
|
|
865
|
+
const queue = new PQueue({timeout: 5000});
|
|
866
|
+
|
|
867
|
+
// Change timeout for all future tasks
|
|
868
|
+
queue.timeout = 10000;
|
|
869
|
+
```
|
|
870
|
+
*/
|
|
871
|
+
timeout;
|
|
872
|
+
constructor(options) {
|
|
873
|
+
super();
|
|
874
|
+
options = {
|
|
875
|
+
carryoverIntervalCount: false,
|
|
876
|
+
intervalCap: Number.POSITIVE_INFINITY,
|
|
877
|
+
interval: 0,
|
|
878
|
+
concurrency: Number.POSITIVE_INFINITY,
|
|
879
|
+
autoStart: true,
|
|
880
|
+
queueClass: PriorityQueue,
|
|
881
|
+
...options
|
|
882
|
+
};
|
|
883
|
+
if (!(typeof options.intervalCap === "number" && options.intervalCap >= 1)) {
|
|
884
|
+
throw new TypeError(`Expected \`intervalCap\` to be a number from 1 and up, got \`${options.intervalCap?.toString() ?? ""}\` (${typeof options.intervalCap})`);
|
|
885
|
+
}
|
|
886
|
+
if (options.interval === void 0 || !(Number.isFinite(options.interval) && options.interval >= 0)) {
|
|
887
|
+
throw new TypeError(`Expected \`interval\` to be a finite number >= 0, got \`${options.interval?.toString() ?? ""}\` (${typeof options.interval})`);
|
|
888
|
+
}
|
|
889
|
+
this.#carryoverIntervalCount = options.carryoverIntervalCount ?? options.carryoverConcurrencyCount ?? false;
|
|
890
|
+
this.#isIntervalIgnored = options.intervalCap === Number.POSITIVE_INFINITY || options.interval === 0;
|
|
891
|
+
this.#intervalCap = options.intervalCap;
|
|
892
|
+
this.#interval = options.interval;
|
|
893
|
+
this.#queue = new options.queueClass();
|
|
894
|
+
this.#queueClass = options.queueClass;
|
|
895
|
+
this.concurrency = options.concurrency;
|
|
896
|
+
if (options.timeout !== void 0 && !(Number.isFinite(options.timeout) && options.timeout > 0)) {
|
|
897
|
+
throw new TypeError(`Expected \`timeout\` to be a positive finite number, got \`${options.timeout}\` (${typeof options.timeout})`);
|
|
898
|
+
}
|
|
899
|
+
this.timeout = options.timeout;
|
|
900
|
+
this.#isPaused = options.autoStart === false;
|
|
901
|
+
this.#setupRateLimitTracking();
|
|
902
|
+
}
|
|
903
|
+
get #doesIntervalAllowAnother() {
|
|
904
|
+
return this.#isIntervalIgnored || this.#intervalCount < this.#intervalCap;
|
|
905
|
+
}
|
|
906
|
+
get #doesConcurrentAllowAnother() {
|
|
907
|
+
return this.#pending < this.#concurrency;
|
|
908
|
+
}
|
|
909
|
+
#next() {
|
|
910
|
+
this.#pending--;
|
|
911
|
+
if (this.#pending === 0) {
|
|
912
|
+
this.emit("pendingZero");
|
|
913
|
+
}
|
|
914
|
+
this.#tryToStartAnother();
|
|
915
|
+
this.emit("next");
|
|
916
|
+
}
|
|
917
|
+
#onResumeInterval() {
|
|
918
|
+
this.#onInterval();
|
|
919
|
+
this.#initializeIntervalIfNeeded();
|
|
920
|
+
this.#timeoutId = void 0;
|
|
921
|
+
}
|
|
922
|
+
get #isIntervalPaused() {
|
|
923
|
+
const now = Date.now();
|
|
924
|
+
if (this.#intervalId === void 0) {
|
|
925
|
+
const delay = this.#intervalEnd - now;
|
|
926
|
+
if (delay < 0) {
|
|
927
|
+
if (this.#lastExecutionTime > 0) {
|
|
928
|
+
const timeSinceLastExecution = now - this.#lastExecutionTime;
|
|
929
|
+
if (timeSinceLastExecution < this.#interval) {
|
|
930
|
+
this.#createIntervalTimeout(this.#interval - timeSinceLastExecution);
|
|
931
|
+
return true;
|
|
932
|
+
}
|
|
933
|
+
}
|
|
934
|
+
this.#intervalCount = this.#carryoverIntervalCount ? this.#pending : 0;
|
|
935
|
+
} else {
|
|
936
|
+
this.#createIntervalTimeout(delay);
|
|
937
|
+
return true;
|
|
938
|
+
}
|
|
939
|
+
}
|
|
940
|
+
return false;
|
|
941
|
+
}
|
|
942
|
+
#createIntervalTimeout(delay) {
|
|
943
|
+
if (this.#timeoutId !== void 0) {
|
|
944
|
+
return;
|
|
945
|
+
}
|
|
946
|
+
this.#timeoutId = setTimeout(() => {
|
|
947
|
+
this.#onResumeInterval();
|
|
948
|
+
}, delay);
|
|
949
|
+
}
|
|
950
|
+
#clearIntervalTimer() {
|
|
951
|
+
if (this.#intervalId) {
|
|
952
|
+
clearInterval(this.#intervalId);
|
|
953
|
+
this.#intervalId = void 0;
|
|
954
|
+
}
|
|
955
|
+
}
|
|
956
|
+
#clearTimeoutTimer() {
|
|
957
|
+
if (this.#timeoutId) {
|
|
958
|
+
clearTimeout(this.#timeoutId);
|
|
959
|
+
this.#timeoutId = void 0;
|
|
960
|
+
}
|
|
961
|
+
}
|
|
962
|
+
#tryToStartAnother() {
|
|
963
|
+
if (this.#queue.size === 0) {
|
|
964
|
+
this.#clearIntervalTimer();
|
|
965
|
+
this.emit("empty");
|
|
966
|
+
if (this.#pending === 0) {
|
|
967
|
+
this.#clearTimeoutTimer();
|
|
968
|
+
this.emit("idle");
|
|
969
|
+
}
|
|
970
|
+
return false;
|
|
971
|
+
}
|
|
972
|
+
let taskStarted = false;
|
|
973
|
+
if (!this.#isPaused) {
|
|
974
|
+
const canInitializeInterval = !this.#isIntervalPaused;
|
|
975
|
+
if (this.#doesIntervalAllowAnother && this.#doesConcurrentAllowAnother) {
|
|
976
|
+
const job = this.#queue.dequeue();
|
|
977
|
+
if (!this.#isIntervalIgnored) {
|
|
978
|
+
this.#intervalCount++;
|
|
979
|
+
this.#scheduleRateLimitUpdate();
|
|
980
|
+
}
|
|
981
|
+
this.emit("active");
|
|
982
|
+
this.#lastExecutionTime = Date.now();
|
|
983
|
+
job();
|
|
984
|
+
if (canInitializeInterval) {
|
|
985
|
+
this.#initializeIntervalIfNeeded();
|
|
986
|
+
}
|
|
987
|
+
taskStarted = true;
|
|
988
|
+
}
|
|
989
|
+
}
|
|
990
|
+
return taskStarted;
|
|
991
|
+
}
|
|
992
|
+
#initializeIntervalIfNeeded() {
|
|
993
|
+
if (this.#isIntervalIgnored || this.#intervalId !== void 0) {
|
|
994
|
+
return;
|
|
995
|
+
}
|
|
996
|
+
this.#intervalId = setInterval(() => {
|
|
997
|
+
this.#onInterval();
|
|
998
|
+
}, this.#interval);
|
|
999
|
+
this.#intervalEnd = Date.now() + this.#interval;
|
|
1000
|
+
}
|
|
1001
|
+
#onInterval() {
|
|
1002
|
+
if (this.#intervalCount === 0 && this.#pending === 0 && this.#intervalId) {
|
|
1003
|
+
this.#clearIntervalTimer();
|
|
1004
|
+
}
|
|
1005
|
+
this.#intervalCount = this.#carryoverIntervalCount ? this.#pending : 0;
|
|
1006
|
+
this.#processQueue();
|
|
1007
|
+
this.#scheduleRateLimitUpdate();
|
|
1008
|
+
}
|
|
1009
|
+
/**
|
|
1010
|
+
Executes all queued functions until it reaches the limit.
|
|
1011
|
+
*/
|
|
1012
|
+
#processQueue() {
|
|
1013
|
+
while (this.#tryToStartAnother()) {
|
|
1014
|
+
}
|
|
1015
|
+
}
|
|
1016
|
+
get concurrency() {
|
|
1017
|
+
return this.#concurrency;
|
|
1018
|
+
}
|
|
1019
|
+
set concurrency(newConcurrency) {
|
|
1020
|
+
if (!(typeof newConcurrency === "number" && newConcurrency >= 1)) {
|
|
1021
|
+
throw new TypeError(`Expected \`concurrency\` to be a number from 1 and up, got \`${newConcurrency}\` (${typeof newConcurrency})`);
|
|
1022
|
+
}
|
|
1023
|
+
this.#concurrency = newConcurrency;
|
|
1024
|
+
this.#processQueue();
|
|
1025
|
+
}
|
|
1026
|
+
async #throwOnAbort(signal) {
|
|
1027
|
+
return new Promise((_resolve, reject) => {
|
|
1028
|
+
signal.addEventListener("abort", () => {
|
|
1029
|
+
reject(signal.reason);
|
|
1030
|
+
}, { once: true });
|
|
1031
|
+
});
|
|
1032
|
+
}
|
|
1033
|
+
/**
|
|
1034
|
+
Updates the priority of a promise function by its id, affecting its execution order. Requires a defined concurrency limit to take effect.
|
|
1035
|
+
|
|
1036
|
+
For example, this can be used to prioritize a promise function to run earlier.
|
|
1037
|
+
|
|
1038
|
+
```js
|
|
1039
|
+
import PQueue from 'p-queue';
|
|
1040
|
+
|
|
1041
|
+
const queue = new PQueue({concurrency: 1});
|
|
1042
|
+
|
|
1043
|
+
queue.add(async () => '🦄', {priority: 1});
|
|
1044
|
+
queue.add(async () => '🦀', {priority: 0, id: '🦀'});
|
|
1045
|
+
queue.add(async () => '🦄', {priority: 1});
|
|
1046
|
+
queue.add(async () => '🦄', {priority: 1});
|
|
1047
|
+
|
|
1048
|
+
queue.setPriority('🦀', 2);
|
|
1049
|
+
```
|
|
1050
|
+
|
|
1051
|
+
In this case, the promise function with `id: '🦀'` runs second.
|
|
1052
|
+
|
|
1053
|
+
You can also deprioritize a promise function to delay its execution:
|
|
1054
|
+
|
|
1055
|
+
```js
|
|
1056
|
+
import PQueue from 'p-queue';
|
|
1057
|
+
|
|
1058
|
+
const queue = new PQueue({concurrency: 1});
|
|
1059
|
+
|
|
1060
|
+
queue.add(async () => '🦄', {priority: 1});
|
|
1061
|
+
queue.add(async () => '🦀', {priority: 1, id: '🦀'});
|
|
1062
|
+
queue.add(async () => '🦄');
|
|
1063
|
+
queue.add(async () => '🦄', {priority: 0});
|
|
1064
|
+
|
|
1065
|
+
queue.setPriority('🦀', -1);
|
|
1066
|
+
```
|
|
1067
|
+
Here, the promise function with `id: '🦀'` executes last.
|
|
1068
|
+
*/
|
|
1069
|
+
setPriority(id, priority) {
|
|
1070
|
+
if (typeof priority !== "number" || !Number.isFinite(priority)) {
|
|
1071
|
+
throw new TypeError(`Expected \`priority\` to be a finite number, got \`${priority}\` (${typeof priority})`);
|
|
1072
|
+
}
|
|
1073
|
+
this.#queue.setPriority(id, priority);
|
|
1074
|
+
}
|
|
1075
|
+
async add(function_, options = {}) {
|
|
1076
|
+
options.id ??= (this.#idAssigner++).toString();
|
|
1077
|
+
options = {
|
|
1078
|
+
timeout: this.timeout,
|
|
1079
|
+
...options
|
|
1080
|
+
};
|
|
1081
|
+
return new Promise((resolve, reject) => {
|
|
1082
|
+
const taskSymbol = Symbol(`task-${options.id}`);
|
|
1083
|
+
this.#queue.enqueue(async () => {
|
|
1084
|
+
this.#pending++;
|
|
1085
|
+
this.#runningTasks.set(taskSymbol, {
|
|
1086
|
+
id: options.id,
|
|
1087
|
+
priority: options.priority ?? 0,
|
|
1088
|
+
// Match priority-queue default
|
|
1089
|
+
startTime: Date.now(),
|
|
1090
|
+
timeout: options.timeout
|
|
1091
|
+
});
|
|
1092
|
+
try {
|
|
1093
|
+
try {
|
|
1094
|
+
options.signal?.throwIfAborted();
|
|
1095
|
+
} catch (error) {
|
|
1096
|
+
if (!this.#isIntervalIgnored) {
|
|
1097
|
+
this.#intervalCount--;
|
|
1098
|
+
}
|
|
1099
|
+
this.#runningTasks.delete(taskSymbol);
|
|
1100
|
+
throw error;
|
|
1101
|
+
}
|
|
1102
|
+
let operation = function_({ signal: options.signal });
|
|
1103
|
+
if (options.timeout) {
|
|
1104
|
+
operation = pTimeout(Promise.resolve(operation), {
|
|
1105
|
+
milliseconds: options.timeout,
|
|
1106
|
+
message: `Task timed out after ${options.timeout}ms (queue has ${this.#pending} running, ${this.#queue.size} waiting)`
|
|
1107
|
+
});
|
|
1108
|
+
}
|
|
1109
|
+
if (options.signal) {
|
|
1110
|
+
operation = Promise.race([operation, this.#throwOnAbort(options.signal)]);
|
|
1111
|
+
}
|
|
1112
|
+
const result = await operation;
|
|
1113
|
+
resolve(result);
|
|
1114
|
+
this.emit("completed", result);
|
|
1115
|
+
} catch (error) {
|
|
1116
|
+
reject(error);
|
|
1117
|
+
this.emit("error", error);
|
|
1118
|
+
} finally {
|
|
1119
|
+
this.#runningTasks.delete(taskSymbol);
|
|
1120
|
+
queueMicrotask(() => {
|
|
1121
|
+
this.#next();
|
|
1122
|
+
});
|
|
1123
|
+
}
|
|
1124
|
+
}, options);
|
|
1125
|
+
this.emit("add");
|
|
1126
|
+
this.#tryToStartAnother();
|
|
1127
|
+
});
|
|
1128
|
+
}
|
|
1129
|
+
async addAll(functions, options) {
|
|
1130
|
+
return Promise.all(functions.map(async (function_) => this.add(function_, options)));
|
|
1131
|
+
}
|
|
1132
|
+
/**
|
|
1133
|
+
Start (or resume) executing enqueued tasks within concurrency limit. No need to call this if queue is not paused (via `options.autoStart = false` or by `.pause()` method.)
|
|
1134
|
+
*/
|
|
1135
|
+
start() {
|
|
1136
|
+
if (!this.#isPaused) {
|
|
1137
|
+
return this;
|
|
1138
|
+
}
|
|
1139
|
+
this.#isPaused = false;
|
|
1140
|
+
this.#processQueue();
|
|
1141
|
+
return this;
|
|
1142
|
+
}
|
|
1143
|
+
/**
|
|
1144
|
+
Put queue execution on hold.
|
|
1145
|
+
*/
|
|
1146
|
+
pause() {
|
|
1147
|
+
this.#isPaused = true;
|
|
1148
|
+
}
|
|
1149
|
+
/**
|
|
1150
|
+
Clear the queue.
|
|
1151
|
+
*/
|
|
1152
|
+
clear() {
|
|
1153
|
+
this.#queue = new this.#queueClass();
|
|
1154
|
+
this.#updateRateLimitState();
|
|
1155
|
+
}
|
|
1156
|
+
/**
|
|
1157
|
+
Can be called multiple times. Useful if you for example add additional items at a later time.
|
|
1158
|
+
|
|
1159
|
+
@returns A promise that settles when the queue becomes empty.
|
|
1160
|
+
*/
|
|
1161
|
+
async onEmpty() {
|
|
1162
|
+
if (this.#queue.size === 0) {
|
|
1163
|
+
return;
|
|
1164
|
+
}
|
|
1165
|
+
await this.#onEvent("empty");
|
|
1166
|
+
}
|
|
1167
|
+
/**
|
|
1168
|
+
@returns A promise that settles when the queue size is less than the given limit: `queue.size < limit`.
|
|
1169
|
+
|
|
1170
|
+
If you want to avoid having the queue grow beyond a certain size you can `await queue.onSizeLessThan()` before adding a new item.
|
|
1171
|
+
|
|
1172
|
+
Note that this only limits the number of items waiting to start. There could still be up to `concurrency` jobs already running that this call does not include in its calculation.
|
|
1173
|
+
*/
|
|
1174
|
+
async onSizeLessThan(limit) {
|
|
1175
|
+
if (this.#queue.size < limit) {
|
|
1176
|
+
return;
|
|
1177
|
+
}
|
|
1178
|
+
await this.#onEvent("next", () => this.#queue.size < limit);
|
|
1179
|
+
}
|
|
1180
|
+
/**
|
|
1181
|
+
The difference with `.onEmpty` is that `.onIdle` guarantees that all work from the queue has finished. `.onEmpty` merely signals that the queue is empty, but it could mean that some promises haven't completed yet.
|
|
1182
|
+
|
|
1183
|
+
@returns A promise that settles when the queue becomes empty, and all promises have completed; `queue.size === 0 && queue.pending === 0`.
|
|
1184
|
+
*/
|
|
1185
|
+
async onIdle() {
|
|
1186
|
+
if (this.#pending === 0 && this.#queue.size === 0) {
|
|
1187
|
+
return;
|
|
1188
|
+
}
|
|
1189
|
+
await this.#onEvent("idle");
|
|
1190
|
+
}
|
|
1191
|
+
/**
|
|
1192
|
+
The difference with `.onIdle` is that `.onPendingZero` only waits for currently running tasks to finish, ignoring queued tasks.
|
|
1193
|
+
|
|
1194
|
+
@returns A promise that settles when all currently running tasks have completed; `queue.pending === 0`.
|
|
1195
|
+
*/
|
|
1196
|
+
async onPendingZero() {
|
|
1197
|
+
if (this.#pending === 0) {
|
|
1198
|
+
return;
|
|
1199
|
+
}
|
|
1200
|
+
await this.#onEvent("pendingZero");
|
|
1201
|
+
}
|
|
1202
|
+
/**
|
|
1203
|
+
@returns A promise that settles when the queue becomes rate-limited due to intervalCap.
|
|
1204
|
+
*/
|
|
1205
|
+
async onRateLimit() {
|
|
1206
|
+
if (this.isRateLimited) {
|
|
1207
|
+
return;
|
|
1208
|
+
}
|
|
1209
|
+
await this.#onEvent("rateLimit");
|
|
1210
|
+
}
|
|
1211
|
+
/**
|
|
1212
|
+
@returns A promise that settles when the queue is no longer rate-limited.
|
|
1213
|
+
*/
|
|
1214
|
+
async onRateLimitCleared() {
|
|
1215
|
+
if (!this.isRateLimited) {
|
|
1216
|
+
return;
|
|
1217
|
+
}
|
|
1218
|
+
await this.#onEvent("rateLimitCleared");
|
|
1219
|
+
}
|
|
1220
|
+
/**
|
|
1221
|
+
@returns A promise that rejects when any task in the queue errors.
|
|
1222
|
+
|
|
1223
|
+
Use with `Promise.race([queue.onError(), queue.onIdle()])` to fail fast on the first error while still resolving normally when the queue goes idle.
|
|
1224
|
+
|
|
1225
|
+
Important: The promise returned by `add()` still rejects. You must handle each `add()` promise (for example, `.catch(() => {})`) to avoid unhandled rejections.
|
|
1226
|
+
|
|
1227
|
+
@example
|
|
1228
|
+
```
|
|
1229
|
+
import PQueue from 'p-queue';
|
|
1230
|
+
|
|
1231
|
+
const queue = new PQueue({concurrency: 2});
|
|
1232
|
+
|
|
1233
|
+
queue.add(() => fetchData(1)).catch(() => {});
|
|
1234
|
+
queue.add(() => fetchData(2)).catch(() => {});
|
|
1235
|
+
queue.add(() => fetchData(3)).catch(() => {});
|
|
1236
|
+
|
|
1237
|
+
// Stop processing on first error
|
|
1238
|
+
try {
|
|
1239
|
+
await Promise.race([
|
|
1240
|
+
queue.onError(),
|
|
1241
|
+
queue.onIdle()
|
|
1242
|
+
]);
|
|
1243
|
+
} catch (error) {
|
|
1244
|
+
queue.pause(); // Stop processing remaining tasks
|
|
1245
|
+
console.error('Queue failed:', error);
|
|
1246
|
+
}
|
|
1247
|
+
```
|
|
1248
|
+
*/
|
|
1249
|
+
// eslint-disable-next-line @typescript-eslint/promise-function-async
|
|
1250
|
+
async onError() {
|
|
1251
|
+
return new Promise((_resolve, reject) => {
|
|
1252
|
+
const handleError = /* @__PURE__ */ __name((error) => {
|
|
1253
|
+
this.off("error", handleError);
|
|
1254
|
+
reject(error);
|
|
1255
|
+
}, "handleError");
|
|
1256
|
+
this.on("error", handleError);
|
|
1257
|
+
});
|
|
1258
|
+
}
|
|
1259
|
+
async #onEvent(event, filter) {
|
|
1260
|
+
return new Promise((resolve) => {
|
|
1261
|
+
const listener = /* @__PURE__ */ __name(() => {
|
|
1262
|
+
if (filter && !filter()) {
|
|
1263
|
+
return;
|
|
1264
|
+
}
|
|
1265
|
+
this.off(event, listener);
|
|
1266
|
+
resolve();
|
|
1267
|
+
}, "listener");
|
|
1268
|
+
this.on(event, listener);
|
|
1269
|
+
});
|
|
1270
|
+
}
|
|
1271
|
+
/**
|
|
1272
|
+
Size of the queue, the number of queued items waiting to run.
|
|
1273
|
+
*/
|
|
1274
|
+
get size() {
|
|
1275
|
+
return this.#queue.size;
|
|
1276
|
+
}
|
|
1277
|
+
/**
|
|
1278
|
+
Size of the queue, filtered by the given options.
|
|
1279
|
+
|
|
1280
|
+
For example, this can be used to find the number of items remaining in the queue with a specific priority level.
|
|
1281
|
+
*/
|
|
1282
|
+
sizeBy(options) {
|
|
1283
|
+
return this.#queue.filter(options).length;
|
|
1284
|
+
}
|
|
1285
|
+
/**
|
|
1286
|
+
Number of running items (no longer in the queue).
|
|
1287
|
+
*/
|
|
1288
|
+
get pending() {
|
|
1289
|
+
return this.#pending;
|
|
1290
|
+
}
|
|
1291
|
+
/**
|
|
1292
|
+
Whether the queue is currently paused.
|
|
1293
|
+
*/
|
|
1294
|
+
get isPaused() {
|
|
1295
|
+
return this.#isPaused;
|
|
1296
|
+
}
|
|
1297
|
+
#setupRateLimitTracking() {
|
|
1298
|
+
if (this.#isIntervalIgnored) {
|
|
1299
|
+
return;
|
|
1300
|
+
}
|
|
1301
|
+
this.on("add", () => {
|
|
1302
|
+
if (this.#queue.size > 0) {
|
|
1303
|
+
this.#scheduleRateLimitUpdate();
|
|
1304
|
+
}
|
|
1305
|
+
});
|
|
1306
|
+
this.on("next", () => {
|
|
1307
|
+
this.#scheduleRateLimitUpdate();
|
|
1308
|
+
});
|
|
1309
|
+
}
|
|
1310
|
+
#scheduleRateLimitUpdate() {
|
|
1311
|
+
if (this.#isIntervalIgnored || this.#rateLimitFlushScheduled) {
|
|
1312
|
+
return;
|
|
1313
|
+
}
|
|
1314
|
+
this.#rateLimitFlushScheduled = true;
|
|
1315
|
+
queueMicrotask(() => {
|
|
1316
|
+
this.#rateLimitFlushScheduled = false;
|
|
1317
|
+
this.#updateRateLimitState();
|
|
1318
|
+
});
|
|
1319
|
+
}
|
|
1320
|
+
#updateRateLimitState() {
|
|
1321
|
+
const previous = this.#rateLimitedInInterval;
|
|
1322
|
+
const shouldBeRateLimited = !this.#isIntervalIgnored && this.#intervalCount >= this.#intervalCap && this.#queue.size > 0;
|
|
1323
|
+
if (shouldBeRateLimited !== previous) {
|
|
1324
|
+
this.#rateLimitedInInterval = shouldBeRateLimited;
|
|
1325
|
+
this.emit(shouldBeRateLimited ? "rateLimit" : "rateLimitCleared");
|
|
1326
|
+
}
|
|
1327
|
+
}
|
|
1328
|
+
/**
|
|
1329
|
+
Whether the queue is currently rate-limited due to intervalCap.
|
|
1330
|
+
*/
|
|
1331
|
+
get isRateLimited() {
|
|
1332
|
+
return this.#rateLimitedInInterval;
|
|
1333
|
+
}
|
|
1334
|
+
/**
|
|
1335
|
+
Whether the queue is saturated. Returns `true` when:
|
|
1336
|
+
- All concurrency slots are occupied and tasks are waiting, OR
|
|
1337
|
+
- The queue is rate-limited and tasks are waiting
|
|
1338
|
+
|
|
1339
|
+
Useful for detecting backpressure and potential hanging tasks.
|
|
1340
|
+
|
|
1341
|
+
```js
|
|
1342
|
+
import PQueue from 'p-queue';
|
|
1343
|
+
|
|
1344
|
+
const queue = new PQueue({concurrency: 2});
|
|
1345
|
+
|
|
1346
|
+
// Backpressure handling
|
|
1347
|
+
if (queue.isSaturated) {
|
|
1348
|
+
console.log('Queue is saturated, waiting for capacity...');
|
|
1349
|
+
await queue.onSizeLessThan(queue.concurrency);
|
|
1350
|
+
}
|
|
1351
|
+
|
|
1352
|
+
// Monitoring for stuck tasks
|
|
1353
|
+
setInterval(() => {
|
|
1354
|
+
if (queue.isSaturated) {
|
|
1355
|
+
console.warn(`Queue saturated: ${queue.pending} running, ${queue.size} waiting`);
|
|
1356
|
+
}
|
|
1357
|
+
}, 60000);
|
|
1358
|
+
```
|
|
1359
|
+
*/
|
|
1360
|
+
get isSaturated() {
|
|
1361
|
+
return this.#pending === this.#concurrency && this.#queue.size > 0 || this.isRateLimited && this.#queue.size > 0;
|
|
1362
|
+
}
|
|
1363
|
+
/**
|
|
1364
|
+
The tasks currently being executed. Each task includes its `id`, `priority`, `startTime`, and `timeout` (if set).
|
|
1365
|
+
|
|
1366
|
+
Returns an array of task info objects.
|
|
1367
|
+
|
|
1368
|
+
```js
|
|
1369
|
+
import PQueue from 'p-queue';
|
|
1370
|
+
|
|
1371
|
+
const queue = new PQueue({concurrency: 2});
|
|
1372
|
+
|
|
1373
|
+
// Add tasks with IDs for better debugging
|
|
1374
|
+
queue.add(() => fetchUser(123), {id: 'user-123'});
|
|
1375
|
+
queue.add(() => fetchPosts(456), {id: 'posts-456', priority: 1});
|
|
1376
|
+
|
|
1377
|
+
// Check what's running
|
|
1378
|
+
console.log(queue.runningTasks);
|
|
1379
|
+
// => [{
|
|
1380
|
+
// id: 'user-123',
|
|
1381
|
+
// priority: 0,
|
|
1382
|
+
// startTime: 1759253001716,
|
|
1383
|
+
// timeout: undefined
|
|
1384
|
+
// }, {
|
|
1385
|
+
// id: 'posts-456',
|
|
1386
|
+
// priority: 1,
|
|
1387
|
+
// startTime: 1759253001916,
|
|
1388
|
+
// timeout: undefined
|
|
1389
|
+
// }]
|
|
1390
|
+
```
|
|
1391
|
+
*/
|
|
1392
|
+
get runningTasks() {
|
|
1393
|
+
return [...this.#runningTasks.values()].map((task) => ({ ...task }));
|
|
1394
|
+
}
|
|
1395
|
+
};
|
|
1396
|
+
async function getZoneForRoute(complianceConfig, from, ctx, zoneIdCache = /* @__PURE__ */ new Map()) {
|
|
1397
|
+
const { route, accountId } = from;
|
|
1398
|
+
const host = getHostFromRoute(route);
|
|
1399
|
+
let id;
|
|
1400
|
+
if (typeof route === "object" && "zone_id" in route) {
|
|
1401
|
+
id = route.zone_id;
|
|
1402
|
+
} else if (typeof route === "object" && "zone_name" in route) {
|
|
1403
|
+
id = await getZoneIdFromHost(
|
|
1404
|
+
complianceConfig,
|
|
1405
|
+
{ host: route.zone_name, accountId },
|
|
1406
|
+
ctx,
|
|
1407
|
+
zoneIdCache
|
|
1408
|
+
);
|
|
1409
|
+
} else if (host) {
|
|
1410
|
+
id = await getZoneIdFromHost(
|
|
1411
|
+
complianceConfig,
|
|
1412
|
+
{ host, accountId },
|
|
1413
|
+
ctx,
|
|
1414
|
+
zoneIdCache
|
|
1415
|
+
);
|
|
1416
|
+
}
|
|
1417
|
+
return id && host ? { id, host } : void 0;
|
|
1418
|
+
}
|
|
1419
|
+
__name(getZoneForRoute, "getZoneForRoute");
|
|
1420
|
+
async function getZoneIdFromHost(complianceConfig, from, ctx, zoneIdCache = /* @__PURE__ */ new Map()) {
|
|
1421
|
+
const hostPieces = from.host.split(".");
|
|
1422
|
+
while (hostPieces.length > 1) {
|
|
1423
|
+
const cacheKey = `${from.accountId}:${hostPieces.join(".")}`;
|
|
1424
|
+
if (!zoneIdCache.has(cacheKey)) {
|
|
1425
|
+
zoneIdCache.set(
|
|
1426
|
+
cacheKey,
|
|
1427
|
+
retryOnAPIFailure(
|
|
1428
|
+
() => ctx.fetchListResult(
|
|
1429
|
+
complianceConfig,
|
|
1430
|
+
`/zones`,
|
|
1431
|
+
{},
|
|
1432
|
+
new URLSearchParams({
|
|
1433
|
+
name: hostPieces.join("."),
|
|
1434
|
+
"account.id": from.accountId
|
|
1435
|
+
})
|
|
1436
|
+
),
|
|
1437
|
+
ctx.logger
|
|
1438
|
+
).then((zones) => zones[0]?.id ?? null)
|
|
1439
|
+
);
|
|
1440
|
+
}
|
|
1441
|
+
const cachedZone = await zoneIdCache.get(cacheKey);
|
|
1442
|
+
if (cachedZone) {
|
|
1443
|
+
return cachedZone;
|
|
1444
|
+
}
|
|
1445
|
+
hostPieces.shift();
|
|
1446
|
+
}
|
|
1447
|
+
throw new UserError(
|
|
1448
|
+
`Could not find zone for \`${from.host}\`. Make sure the domain is set up to be proxied by Cloudflare.
|
|
1449
|
+
For more details, refer to https://developers.cloudflare.com/workers/configuration/routing/routes/#set-up-a-route`,
|
|
1450
|
+
{ telemetryMessage: "zones route zone not found" }
|
|
1451
|
+
);
|
|
1452
|
+
}
|
|
1453
|
+
__name(getZoneIdFromHost, "getZoneIdFromHost");
|
|
1454
|
+
|
|
1455
|
+
// src/triggers/publish-routes.ts
|
|
1456
|
+
function renderRoute(route) {
|
|
1457
|
+
let result = "";
|
|
1458
|
+
if (typeof route === "string") {
|
|
1459
|
+
result = route;
|
|
1460
|
+
} else {
|
|
1461
|
+
result = route.pattern;
|
|
1462
|
+
const isCustomDomain = Boolean(
|
|
1463
|
+
"custom_domain" in route && route.custom_domain
|
|
1464
|
+
);
|
|
1465
|
+
if (isCustomDomain && "zone_id" in route) {
|
|
1466
|
+
result += ` (custom domain - zone id: ${route.zone_id})`;
|
|
1467
|
+
} else if (isCustomDomain && "zone_name" in route) {
|
|
1468
|
+
result += ` (custom domain - zone name: ${route.zone_name})`;
|
|
1469
|
+
} else if (isCustomDomain) {
|
|
1470
|
+
result += ` (custom domain)`;
|
|
1471
|
+
} else if ("zone_id" in route) {
|
|
1472
|
+
result += ` (zone id: ${route.zone_id})`;
|
|
1473
|
+
} else if ("zone_name" in route) {
|
|
1474
|
+
result += ` (zone name: ${route.zone_name})`;
|
|
1475
|
+
}
|
|
1476
|
+
if (isCustomDomain) {
|
|
1477
|
+
const flags = [];
|
|
1478
|
+
if ("enabled" in route && route.enabled !== void 0) {
|
|
1479
|
+
flags.push(route.enabled ? "enabled" : "disabled");
|
|
1480
|
+
}
|
|
1481
|
+
if ("previews_enabled" in route && route.previews_enabled !== void 0) {
|
|
1482
|
+
flags.push(
|
|
1483
|
+
route.previews_enabled ? "previews: enabled" : "previews: disabled"
|
|
1484
|
+
);
|
|
1485
|
+
}
|
|
1486
|
+
if (flags.length > 0) {
|
|
1487
|
+
result += ` [${flags.join(", ")}]`;
|
|
1488
|
+
}
|
|
1489
|
+
}
|
|
1490
|
+
}
|
|
1491
|
+
return result;
|
|
1492
|
+
}
|
|
1493
|
+
__name(renderRoute, "renderRoute");
|
|
1494
|
+
function isAuthenticationError(e) {
|
|
1495
|
+
return e instanceof ParseError && e.code === 1e4;
|
|
1496
|
+
}
|
|
1497
|
+
__name(isAuthenticationError, "isAuthenticationError");
|
|
1498
|
+
async function publishRoutes(complianceConfig, routes, {
|
|
1499
|
+
workerUrl,
|
|
1500
|
+
scriptName,
|
|
1501
|
+
useServiceEnvironments,
|
|
1502
|
+
accountId
|
|
1503
|
+
}, ctx) {
|
|
1504
|
+
try {
|
|
1505
|
+
return await ctx.fetchResult(complianceConfig, `${workerUrl}/routes`, {
|
|
1506
|
+
// Note: PUT will delete previous routes on this script.
|
|
1507
|
+
method: "PUT",
|
|
1508
|
+
body: JSON.stringify(
|
|
1509
|
+
routes.map(
|
|
1510
|
+
(route) => typeof route !== "object" ? { pattern: route } : route
|
|
1511
|
+
)
|
|
1512
|
+
),
|
|
1513
|
+
headers: {
|
|
1514
|
+
"Content-Type": "application/json"
|
|
1515
|
+
}
|
|
1516
|
+
});
|
|
1517
|
+
} catch (e) {
|
|
1518
|
+
if (isAuthenticationError(e)) {
|
|
1519
|
+
return await publishRoutesFallback(
|
|
1520
|
+
complianceConfig,
|
|
1521
|
+
routes,
|
|
1522
|
+
{
|
|
1523
|
+
scriptName,
|
|
1524
|
+
useServiceEnvironments,
|
|
1525
|
+
accountId
|
|
1526
|
+
},
|
|
1527
|
+
ctx
|
|
1528
|
+
);
|
|
1529
|
+
} else {
|
|
1530
|
+
throw e;
|
|
1531
|
+
}
|
|
1532
|
+
}
|
|
1533
|
+
}
|
|
1534
|
+
__name(publishRoutes, "publishRoutes");
|
|
1535
|
+
async function publishRoutesFallback(complianceConfig, routes, {
|
|
1536
|
+
scriptName,
|
|
1537
|
+
useServiceEnvironments,
|
|
1538
|
+
accountId
|
|
1539
|
+
}, ctx) {
|
|
1540
|
+
if (useServiceEnvironments) {
|
|
1541
|
+
throw new UserError(
|
|
1542
|
+
"Service environments combined with an API token that doesn't have 'All Zones' permissions is not supported.\nEither turn off service environments by setting `legacy_env = true`, creating an API token with 'All Zones' permissions, or logging in via OAuth",
|
|
1543
|
+
{
|
|
1544
|
+
telemetryMessage: "deploy service environments require all zones permission"
|
|
1545
|
+
}
|
|
1546
|
+
);
|
|
1547
|
+
}
|
|
1548
|
+
ctx.logger.info(
|
|
1549
|
+
"The current authentication token does not have 'All Zones' permissions.\nFalling back to using the zone-based API endpoint to update each route individually.\nNote that there is no access to routes associated with zones that the API token does not have permission for.\nExisting routes for this Worker in such zones will not be deleted."
|
|
1550
|
+
);
|
|
1551
|
+
const deployedRoutes = [];
|
|
1552
|
+
const queue = new PQueue({ concurrency: 10 });
|
|
1553
|
+
const queuePromises = [];
|
|
1554
|
+
const zoneIdCache = /* @__PURE__ */ new Map();
|
|
1555
|
+
const activeZones = /* @__PURE__ */ new Map();
|
|
1556
|
+
const routesToDeploy = /* @__PURE__ */ new Map();
|
|
1557
|
+
for (const route of routes) {
|
|
1558
|
+
queuePromises.push(
|
|
1559
|
+
queue.add(async () => {
|
|
1560
|
+
const zone = await getZoneForRoute(
|
|
1561
|
+
complianceConfig,
|
|
1562
|
+
{ route, accountId },
|
|
1563
|
+
ctx,
|
|
1564
|
+
zoneIdCache
|
|
1565
|
+
);
|
|
1566
|
+
if (zone) {
|
|
1567
|
+
activeZones.set(zone.id, zone.host);
|
|
1568
|
+
routesToDeploy.set(
|
|
1569
|
+
typeof route === "string" ? route : route.pattern,
|
|
1570
|
+
zone.id
|
|
1571
|
+
);
|
|
1572
|
+
}
|
|
1573
|
+
})
|
|
1574
|
+
);
|
|
1575
|
+
}
|
|
1576
|
+
await Promise.all(queuePromises.splice(0, queuePromises.length));
|
|
1577
|
+
const allRoutes = /* @__PURE__ */ new Map();
|
|
1578
|
+
const alreadyDeployedRoutes = /* @__PURE__ */ new Set();
|
|
1579
|
+
for (const [zone, host] of activeZones) {
|
|
1580
|
+
queuePromises.push(
|
|
1581
|
+
queue.add(async () => {
|
|
1582
|
+
try {
|
|
1583
|
+
for (const { pattern, script } of await ctx.fetchListResult(complianceConfig, `/zones/${zone}/workers/routes`)) {
|
|
1584
|
+
allRoutes.set(pattern, script);
|
|
1585
|
+
if (script === scriptName) {
|
|
1586
|
+
alreadyDeployedRoutes.add(pattern);
|
|
1587
|
+
}
|
|
1588
|
+
}
|
|
1589
|
+
} catch (e) {
|
|
1590
|
+
if (isAuthenticationError(e)) {
|
|
1591
|
+
e.notes.push({
|
|
1592
|
+
text: `This could be because the API token being used does not have permission to access the zone "${host}" (${zone}).`
|
|
1593
|
+
});
|
|
1594
|
+
}
|
|
1595
|
+
throw e;
|
|
1596
|
+
}
|
|
1597
|
+
})
|
|
1598
|
+
);
|
|
1599
|
+
}
|
|
1600
|
+
await Promise.all(queuePromises);
|
|
1601
|
+
for (const [routePattern, zoneId] of routesToDeploy.entries()) {
|
|
1602
|
+
if (allRoutes.has(routePattern)) {
|
|
1603
|
+
const knownScript = allRoutes.get(routePattern);
|
|
1604
|
+
if (knownScript === scriptName) {
|
|
1605
|
+
alreadyDeployedRoutes.delete(routePattern);
|
|
1606
|
+
continue;
|
|
1607
|
+
} else {
|
|
1608
|
+
throw new UserError(
|
|
1609
|
+
`The route with pattern "${routePattern}" is already associated with another worker called "${knownScript}".`,
|
|
1610
|
+
{ telemetryMessage: "route already associated with another worker" }
|
|
1611
|
+
);
|
|
1612
|
+
}
|
|
1613
|
+
}
|
|
1614
|
+
const { pattern } = await ctx.fetchResult(
|
|
1615
|
+
complianceConfig,
|
|
1616
|
+
`/zones/${zoneId}/workers/routes`,
|
|
1617
|
+
{
|
|
1618
|
+
method: "POST",
|
|
1619
|
+
body: JSON.stringify({
|
|
1620
|
+
pattern: routePattern,
|
|
1621
|
+
script: scriptName
|
|
1622
|
+
}),
|
|
1623
|
+
headers: {
|
|
1624
|
+
"Content-Type": "application/json"
|
|
1625
|
+
}
|
|
1626
|
+
}
|
|
1627
|
+
);
|
|
1628
|
+
deployedRoutes.push(pattern);
|
|
1629
|
+
}
|
|
1630
|
+
if (alreadyDeployedRoutes.size) {
|
|
1631
|
+
ctx.logger.warn(
|
|
1632
|
+
"Previously deployed routes:\nThe following routes were already associated with this worker, and have not been deleted:\n" + [...alreadyDeployedRoutes.values()].map((route) => ` - "${route}"
|
|
1633
|
+
`) + "If these routes are not wanted then you can remove them in the dashboard."
|
|
1634
|
+
);
|
|
1635
|
+
}
|
|
1636
|
+
return deployedRoutes;
|
|
1637
|
+
}
|
|
1638
|
+
__name(publishRoutesFallback, "publishRoutesFallback");
|
|
1639
|
+
async function publishCustomDomains(complianceConfig, workerUrl, accountId, domains, ctx) {
|
|
1640
|
+
const options = {
|
|
1641
|
+
override_scope: true,
|
|
1642
|
+
override_existing_origin: false,
|
|
1643
|
+
override_existing_dns_record: false
|
|
1644
|
+
};
|
|
1645
|
+
const origins = domains.map((domainRoute) => {
|
|
1646
|
+
return {
|
|
1647
|
+
hostname: domainRoute.pattern,
|
|
1648
|
+
zone_id: "zone_id" in domainRoute ? domainRoute.zone_id : void 0,
|
|
1649
|
+
zone_name: "zone_name" in domainRoute ? domainRoute.zone_name : void 0,
|
|
1650
|
+
enabled: "enabled" in domainRoute ? domainRoute.enabled : void 0,
|
|
1651
|
+
previews_enabled: "previews_enabled" in domainRoute ? domainRoute.previews_enabled : void 0
|
|
1652
|
+
};
|
|
1653
|
+
});
|
|
1654
|
+
const fail = /* @__PURE__ */ __name(() => {
|
|
1655
|
+
return {
|
|
1656
|
+
targets: [],
|
|
1657
|
+
error: new UserError(
|
|
1658
|
+
domains.length > 1 ? `Publishing to ${domains.length} Custom Domains was skipped, fix conflicts and try again` : `Publishing to Custom Domain "${domains[0].pattern}" was skipped, fix conflict and try again`,
|
|
1659
|
+
{ telemetryMessage: "deploy custom domains skipped" }
|
|
1660
|
+
)
|
|
1661
|
+
};
|
|
1662
|
+
}, "fail");
|
|
1663
|
+
if (!process.stdout.isTTY) {
|
|
1664
|
+
options.override_existing_origin = true;
|
|
1665
|
+
options.override_existing_dns_record = true;
|
|
1666
|
+
} else {
|
|
1667
|
+
const changeset = await ctx.fetchResult(
|
|
1668
|
+
complianceConfig,
|
|
1669
|
+
`${workerUrl}/domains/changeset?replace_state=true`,
|
|
1670
|
+
{
|
|
1671
|
+
method: "POST",
|
|
1672
|
+
body: JSON.stringify(origins),
|
|
1673
|
+
headers: {
|
|
1674
|
+
"Content-Type": "application/json"
|
|
1675
|
+
}
|
|
1676
|
+
}
|
|
1677
|
+
);
|
|
1678
|
+
const updatesRequired = changeset.updated.filter(
|
|
1679
|
+
(domain) => domain.modified
|
|
1680
|
+
);
|
|
1681
|
+
if (updatesRequired.length > 0) {
|
|
1682
|
+
const existing = await Promise.all(
|
|
1683
|
+
updatesRequired.map(
|
|
1684
|
+
(domain) => ctx.fetchResult(
|
|
1685
|
+
complianceConfig,
|
|
1686
|
+
`/accounts/${accountId}/workers/domains/records/${domain.id}`
|
|
1687
|
+
)
|
|
1688
|
+
)
|
|
1689
|
+
);
|
|
1690
|
+
const existingRendered = existing.map(
|
|
1691
|
+
(domain) => ` \u2022 ${domain.hostname} (used as a domain for "${domain.service}")`
|
|
1692
|
+
).join("\n");
|
|
1693
|
+
const message = `Custom Domains already exist for these domains:
|
|
1694
|
+
${existingRendered}
|
|
1695
|
+
Update them to point to this script instead?`;
|
|
1696
|
+
if (!await ctx.confirm(message)) {
|
|
1697
|
+
return fail();
|
|
1698
|
+
}
|
|
1699
|
+
options.override_existing_origin = true;
|
|
1700
|
+
}
|
|
1701
|
+
if (changeset.conflicting.length > 0) {
|
|
1702
|
+
const conflicitingRendered = changeset.conflicting.map((domain) => ` \u2022 ${domain.hostname}`).join("\n");
|
|
1703
|
+
const message = `You already have DNS records that conflict for these Custom Domains:
|
|
1704
|
+
${conflicitingRendered}
|
|
1705
|
+
Update them to point to this script instead?`;
|
|
1706
|
+
if (!await ctx.confirm(message)) {
|
|
1707
|
+
return fail();
|
|
1708
|
+
}
|
|
1709
|
+
options.override_existing_dns_record = true;
|
|
1710
|
+
}
|
|
1711
|
+
}
|
|
1712
|
+
await ctx.fetchResult(complianceConfig, `${workerUrl}/domains/records`, {
|
|
1713
|
+
method: "PUT",
|
|
1714
|
+
body: JSON.stringify({ ...options, origins }),
|
|
1715
|
+
headers: {
|
|
1716
|
+
"Content-Type": "application/json"
|
|
1717
|
+
}
|
|
1718
|
+
});
|
|
1719
|
+
return { targets: domains.map((domain) => renderRoute(domain)) };
|
|
1720
|
+
}
|
|
1721
|
+
__name(publishCustomDomains, "publishCustomDomains");
|
|
1722
|
+
async function listQueues(complianceConfig, accountId, ctx, page, name) {
|
|
1723
|
+
page = page ?? 1;
|
|
1724
|
+
const params = new URLSearchParams({ page: page.toString() });
|
|
1725
|
+
if (name) {
|
|
1726
|
+
params.append("name", name);
|
|
1727
|
+
}
|
|
1728
|
+
return ctx.fetchResult(
|
|
1729
|
+
complianceConfig,
|
|
1730
|
+
`/accounts/${accountId}/queues`,
|
|
1731
|
+
{},
|
|
1732
|
+
params
|
|
1733
|
+
);
|
|
1734
|
+
}
|
|
1735
|
+
__name(listQueues, "listQueues");
|
|
1736
|
+
async function getQueue(complianceConfig, accountId, queueName, ctx) {
|
|
1737
|
+
const queues = await listQueues(
|
|
1738
|
+
complianceConfig,
|
|
1739
|
+
accountId,
|
|
1740
|
+
ctx,
|
|
1741
|
+
1,
|
|
1742
|
+
queueName
|
|
1743
|
+
);
|
|
1744
|
+
if (queues.length === 0) {
|
|
1745
|
+
throw new UserError(
|
|
1746
|
+
`Queue "${queueName}" does not exist. To create it, run: wrangler queues create ${queueName}`,
|
|
1747
|
+
{ telemetryMessage: "queues lookup missing queue" }
|
|
1748
|
+
);
|
|
1749
|
+
}
|
|
1750
|
+
return queues[0];
|
|
1751
|
+
}
|
|
1752
|
+
__name(getQueue, "getQueue");
|
|
1753
|
+
async function postConsumer(complianceConfig, accountId, queueName, body, ctx) {
|
|
1754
|
+
const queue = await getQueue(complianceConfig, accountId, queueName, ctx);
|
|
1755
|
+
return postConsumerById(
|
|
1756
|
+
complianceConfig,
|
|
1757
|
+
accountId,
|
|
1758
|
+
ctx,
|
|
1759
|
+
queue.queue_id,
|
|
1760
|
+
body
|
|
1761
|
+
);
|
|
1762
|
+
}
|
|
1763
|
+
__name(postConsumer, "postConsumer");
|
|
1764
|
+
async function postConsumerById(config, accountId, ctx, queueId, body) {
|
|
1765
|
+
return ctx.fetchResult(
|
|
1766
|
+
config,
|
|
1767
|
+
`/accounts/${accountId}/queues/${queueId}/consumers`,
|
|
1768
|
+
{
|
|
1769
|
+
method: "POST",
|
|
1770
|
+
body: JSON.stringify(body)
|
|
1771
|
+
}
|
|
1772
|
+
);
|
|
1773
|
+
}
|
|
1774
|
+
__name(postConsumerById, "postConsumerById");
|
|
1775
|
+
async function putConsumerById(complianceConfig, accountId, queueId, consumerId, body, ctx) {
|
|
1776
|
+
return ctx.fetchResult(
|
|
1777
|
+
complianceConfig,
|
|
1778
|
+
`/accounts/${accountId}/queues/${queueId}/consumers/${consumerId}`,
|
|
1779
|
+
{
|
|
1780
|
+
method: "PUT",
|
|
1781
|
+
body: JSON.stringify(body)
|
|
1782
|
+
}
|
|
1783
|
+
);
|
|
1784
|
+
}
|
|
1785
|
+
__name(putConsumerById, "putConsumerById");
|
|
1786
|
+
async function putConsumer(complianceConfig, accountId, queueName, scriptName, envName, body, ctx) {
|
|
1787
|
+
const queue = await getQueue(complianceConfig, accountId, queueName, ctx);
|
|
1788
|
+
const targetConsumer = await resolveWorkerConsumerByName(
|
|
1789
|
+
complianceConfig,
|
|
1790
|
+
accountId,
|
|
1791
|
+
scriptName,
|
|
1792
|
+
envName,
|
|
1793
|
+
queue,
|
|
1794
|
+
ctx
|
|
1795
|
+
);
|
|
1796
|
+
return putConsumerById(
|
|
1797
|
+
complianceConfig,
|
|
1798
|
+
accountId,
|
|
1799
|
+
queue.queue_id,
|
|
1800
|
+
targetConsumer.consumer_id,
|
|
1801
|
+
body,
|
|
1802
|
+
ctx
|
|
1803
|
+
);
|
|
1804
|
+
}
|
|
1805
|
+
__name(putConsumer, "putConsumer");
|
|
1806
|
+
async function resolveWorkerConsumerByName(complianceConfig, accountId, consumerName, envName, queue, ctx) {
|
|
1807
|
+
const queueName = queue.queue_name;
|
|
1808
|
+
const consumers = queue.consumers.filter(
|
|
1809
|
+
(c) => c.type === "worker" && (c.script === consumerName || c.service === consumerName)
|
|
1810
|
+
);
|
|
1811
|
+
if (consumers.length === 0) {
|
|
1812
|
+
throw new UserError(
|
|
1813
|
+
`No worker consumer '${consumerName}' exists for queue ${queue.queue_name}`,
|
|
1814
|
+
{ telemetryMessage: "queues worker consumer missing" }
|
|
1815
|
+
);
|
|
1816
|
+
}
|
|
1817
|
+
if (consumers.length > 1) {
|
|
1818
|
+
const targetEnv = envName ?? await getDefaultService(complianceConfig, accountId, consumerName, ctx);
|
|
1819
|
+
const targetConsumers = consumers.filter(
|
|
1820
|
+
(c) => c.environment === targetEnv
|
|
1821
|
+
);
|
|
1822
|
+
if (targetConsumers.length === 0) {
|
|
1823
|
+
throw new UserError(
|
|
1824
|
+
`No worker consumer '${consumerName}' exists for queue ${queueName}`,
|
|
1825
|
+
{ telemetryMessage: "queues worker consumer missing environment" }
|
|
1826
|
+
);
|
|
1827
|
+
}
|
|
1828
|
+
return targetConsumers[0];
|
|
1829
|
+
}
|
|
1830
|
+
if (consumers[0].service) {
|
|
1831
|
+
const targetEnv = envName ?? await getDefaultService(complianceConfig, accountId, consumerName, ctx);
|
|
1832
|
+
if (targetEnv != consumers[0].environment) {
|
|
1833
|
+
throw new UserError(
|
|
1834
|
+
`No worker consumer '${consumerName}' exists for queue ${queueName}`,
|
|
1835
|
+
{ telemetryMessage: "queues worker consumer environment mismatch" }
|
|
1836
|
+
);
|
|
1837
|
+
}
|
|
1838
|
+
}
|
|
1839
|
+
return consumers[0];
|
|
1840
|
+
}
|
|
1841
|
+
__name(resolveWorkerConsumerByName, "resolveWorkerConsumerByName");
|
|
1842
|
+
async function getDefaultService(complianceConfig, accountId, serviceName, ctx) {
|
|
1843
|
+
const service = await ctx.fetchResult(
|
|
1844
|
+
complianceConfig,
|
|
1845
|
+
`/accounts/${accountId}/workers/services/${serviceName}`,
|
|
1846
|
+
{
|
|
1847
|
+
method: "GET"
|
|
1848
|
+
}
|
|
1849
|
+
);
|
|
1850
|
+
ctx.logger.info(service);
|
|
1851
|
+
return service.default_environment.environment;
|
|
1852
|
+
}
|
|
1853
|
+
__name(getDefaultService, "getDefaultService");
|
|
1854
|
+
async function deleteConsumerById(complianceConfig, accountId, queueId, consumerId, ctx) {
|
|
1855
|
+
return ctx.fetchResult(
|
|
1856
|
+
complianceConfig,
|
|
1857
|
+
`/accounts/${accountId}/queues/${queueId}/consumers/${consumerId}`,
|
|
1858
|
+
{
|
|
1859
|
+
method: "DELETE"
|
|
1860
|
+
}
|
|
1861
|
+
);
|
|
1862
|
+
}
|
|
1863
|
+
__name(deleteConsumerById, "deleteConsumerById");
|
|
1864
|
+
async function deletePullConsumer(complianceConfig, accountId, queueName, ctx) {
|
|
1865
|
+
const queue = await getQueue(complianceConfig, accountId, queueName, ctx);
|
|
1866
|
+
const consumer = queue.consumers[0];
|
|
1867
|
+
if (consumer?.type !== "http_pull") {
|
|
1868
|
+
throw new UserError(`No http_pull consumer exists for queue ${queueName}`, {
|
|
1869
|
+
telemetryMessage: "queues http pull consumer missing"
|
|
1870
|
+
});
|
|
1871
|
+
}
|
|
1872
|
+
return deleteConsumerById(
|
|
1873
|
+
complianceConfig,
|
|
1874
|
+
accountId,
|
|
1875
|
+
queue.queue_id,
|
|
1876
|
+
consumer.consumer_id,
|
|
1877
|
+
ctx
|
|
1878
|
+
);
|
|
1879
|
+
}
|
|
1880
|
+
__name(deletePullConsumer, "deletePullConsumer");
|
|
1881
|
+
async function listConsumers(complianceConfig, accountId, queueName, ctx) {
|
|
1882
|
+
const queue = await getQueue(complianceConfig, accountId, queueName, ctx);
|
|
1883
|
+
return queue.consumers;
|
|
1884
|
+
}
|
|
1885
|
+
__name(listConsumers, "listConsumers");
|
|
1886
|
+
async function deleteWorkerConsumer(complianceConfig, accountId, queueName, scriptName, envName, ctx) {
|
|
1887
|
+
const queue = await getQueue(complianceConfig, accountId, queueName, ctx);
|
|
1888
|
+
const targetConsumer = await resolveWorkerConsumerByName(
|
|
1889
|
+
complianceConfig,
|
|
1890
|
+
accountId,
|
|
1891
|
+
scriptName,
|
|
1892
|
+
envName,
|
|
1893
|
+
queue,
|
|
1894
|
+
ctx
|
|
1895
|
+
);
|
|
1896
|
+
return deleteConsumerById(
|
|
1897
|
+
complianceConfig,
|
|
1898
|
+
accountId,
|
|
1899
|
+
queue.queue_id,
|
|
1900
|
+
targetConsumer.consumer_id,
|
|
1901
|
+
ctx
|
|
1902
|
+
);
|
|
1903
|
+
}
|
|
1904
|
+
__name(deleteWorkerConsumer, "deleteWorkerConsumer");
|
|
1905
|
+
async function updateQueueConsumers(complianceConfig, accountId, scriptName, config, ctx) {
|
|
1906
|
+
const consumers = config.queues.consumers || [];
|
|
1907
|
+
const updateConsumers = [];
|
|
1908
|
+
for (const consumer of consumers) {
|
|
1909
|
+
const queue = await getQueue(
|
|
1910
|
+
complianceConfig,
|
|
1911
|
+
accountId,
|
|
1912
|
+
consumer.queue,
|
|
1913
|
+
ctx
|
|
1914
|
+
);
|
|
1915
|
+
const body = {
|
|
1916
|
+
type: "worker",
|
|
1917
|
+
dead_letter_queue: consumer.dead_letter_queue,
|
|
1918
|
+
script_name: scriptName,
|
|
1919
|
+
settings: {
|
|
1920
|
+
batch_size: consumer.max_batch_size,
|
|
1921
|
+
max_retries: consumer.max_retries,
|
|
1922
|
+
max_wait_time_ms: consumer.max_batch_timeout !== void 0 ? 1e3 * consumer.max_batch_timeout : void 0,
|
|
1923
|
+
max_concurrency: consumer.max_concurrency,
|
|
1924
|
+
retry_delay: consumer.retry_delay
|
|
1925
|
+
}
|
|
1926
|
+
};
|
|
1927
|
+
const existingConsumer = queue.consumers.filter(
|
|
1928
|
+
(c) => c.script === scriptName || c.service === scriptName
|
|
1929
|
+
).length > 0;
|
|
1930
|
+
const envName = void 0;
|
|
1931
|
+
if (existingConsumer) {
|
|
1932
|
+
updateConsumers.push(
|
|
1933
|
+
putConsumer(
|
|
1934
|
+
complianceConfig,
|
|
1935
|
+
accountId,
|
|
1936
|
+
consumer.queue,
|
|
1937
|
+
scriptName,
|
|
1938
|
+
envName,
|
|
1939
|
+
body,
|
|
1940
|
+
ctx
|
|
1941
|
+
).then(
|
|
1942
|
+
() => ({ targets: [`Consumer for ${consumer.queue}`] }),
|
|
1943
|
+
(error) => ({ targets: [], error })
|
|
1944
|
+
)
|
|
1945
|
+
);
|
|
1946
|
+
continue;
|
|
1947
|
+
}
|
|
1948
|
+
updateConsumers.push(
|
|
1949
|
+
postConsumer(complianceConfig, accountId, consumer.queue, body, ctx).then(
|
|
1950
|
+
() => ({
|
|
1951
|
+
targets: [`Consumer for ${consumer.queue}`]
|
|
1952
|
+
}),
|
|
1953
|
+
(error) => ({ targets: [], error })
|
|
1954
|
+
)
|
|
1955
|
+
);
|
|
1956
|
+
}
|
|
1957
|
+
return updateConsumers;
|
|
1958
|
+
}
|
|
1959
|
+
__name(updateQueueConsumers, "updateQueueConsumers");
|
|
1960
|
+
async function getWorkersDevSubdomain(complianceConfig, accountId, ctx, options = {}) {
|
|
1961
|
+
const {
|
|
1962
|
+
configPath,
|
|
1963
|
+
abortSignal,
|
|
1964
|
+
registrationContext = "workers_dev"
|
|
1965
|
+
} = options;
|
|
1966
|
+
try {
|
|
1967
|
+
const { subdomain } = await ctx.fetchResult(
|
|
1968
|
+
complianceConfig,
|
|
1969
|
+
`/accounts/${accountId}/workers/subdomain`,
|
|
1970
|
+
void 0,
|
|
1971
|
+
void 0,
|
|
1972
|
+
abortSignal
|
|
1973
|
+
);
|
|
1974
|
+
return `${subdomain}${getComplianceRegionSubdomain(complianceConfig)}.workers.dev`;
|
|
1975
|
+
} catch (e) {
|
|
1976
|
+
const error = e;
|
|
1977
|
+
if (typeof error !== "object" || !error || error.code !== 10007) {
|
|
1978
|
+
throw e;
|
|
1979
|
+
}
|
|
1980
|
+
ctx.logger.warn(getRegistrationWarning(registrationContext));
|
|
1981
|
+
const wantsToRegister = await ctx.confirm(
|
|
1982
|
+
"Would you like to register a workers.dev subdomain now?",
|
|
1983
|
+
{ fallbackValue: false }
|
|
1984
|
+
);
|
|
1985
|
+
if (!wantsToRegister) {
|
|
1986
|
+
throw getRegistrationDeclinedError(
|
|
1987
|
+
registrationContext,
|
|
1988
|
+
accountId,
|
|
1989
|
+
configPath
|
|
1990
|
+
);
|
|
1991
|
+
}
|
|
1992
|
+
return await registerSubdomain(
|
|
1993
|
+
complianceConfig,
|
|
1994
|
+
accountId,
|
|
1995
|
+
configPath,
|
|
1996
|
+
registrationContext,
|
|
1997
|
+
ctx
|
|
1998
|
+
);
|
|
1999
|
+
}
|
|
2000
|
+
}
|
|
2001
|
+
__name(getWorkersDevSubdomain, "getWorkersDevSubdomain");
|
|
2002
|
+
function getRegistrationWarning(registrationContext) {
|
|
2003
|
+
switch (registrationContext) {
|
|
2004
|
+
case "workflows":
|
|
2005
|
+
return "You need to register a workers.dev subdomain before deploying Workflows";
|
|
2006
|
+
case "workers_dev":
|
|
2007
|
+
return "You need to register a workers.dev subdomain before publishing to workers.dev";
|
|
2008
|
+
default: {
|
|
2009
|
+
const _exhaustive = registrationContext;
|
|
2010
|
+
return _exhaustive;
|
|
2011
|
+
}
|
|
2012
|
+
}
|
|
2013
|
+
}
|
|
2014
|
+
__name(getRegistrationWarning, "getRegistrationWarning");
|
|
2015
|
+
function getRegistrationDeclinedError(registrationContext, accountId, configPath) {
|
|
2016
|
+
const onboardingLink = `https://dash.cloudflare.com/${accountId}/workers/onboarding`;
|
|
2017
|
+
switch (registrationContext) {
|
|
2018
|
+
case "workflows":
|
|
2019
|
+
return new UserError(
|
|
2020
|
+
`Workflows require your account to have a workers.dev subdomain. Register a workers.dev subdomain here:
|
|
2021
|
+
${onboardingLink}`,
|
|
2022
|
+
{
|
|
2023
|
+
telemetryMessage: "workflows workers dev registration declined"
|
|
2024
|
+
}
|
|
2025
|
+
);
|
|
2026
|
+
case "workers_dev": {
|
|
2027
|
+
const solutionMessage = `You can either deploy your worker to one or more routes by specifying them in your ${configFileName(configPath)} file, or register a workers.dev subdomain here:`;
|
|
2028
|
+
return new UserError(`${solutionMessage}
|
|
2029
|
+
${onboardingLink}`, {
|
|
2030
|
+
telemetryMessage: "routes workers dev registration declined"
|
|
2031
|
+
});
|
|
2032
|
+
}
|
|
2033
|
+
default: {
|
|
2034
|
+
const _exhaustive = registrationContext;
|
|
2035
|
+
return _exhaustive;
|
|
2036
|
+
}
|
|
2037
|
+
}
|
|
2038
|
+
}
|
|
2039
|
+
__name(getRegistrationDeclinedError, "getRegistrationDeclinedError");
|
|
2040
|
+
async function registerSubdomain(complianceConfig, accountId, configPath, registrationContext, ctx) {
|
|
2041
|
+
let subdomain;
|
|
2042
|
+
while (subdomain === void 0) {
|
|
2043
|
+
const potentialName = await ctx.prompt(
|
|
2044
|
+
"What would you like your workers.dev subdomain to be? It will be accessible at https://<subdomain>.workers.dev"
|
|
2045
|
+
);
|
|
2046
|
+
if (!/^[a-z0-9]([a-z0-9-]{0,61}[a-z0-9])?$/.test(potentialName)) {
|
|
2047
|
+
ctx.logger.warn(
|
|
2048
|
+
`${potentialName} is invalid, please choose another subdomain.`
|
|
2049
|
+
);
|
|
2050
|
+
continue;
|
|
2051
|
+
}
|
|
2052
|
+
try {
|
|
2053
|
+
await ctx.fetchResult(
|
|
2054
|
+
complianceConfig,
|
|
2055
|
+
`/accounts/${accountId}/workers/subdomains/${potentialName}`
|
|
2056
|
+
);
|
|
2057
|
+
} catch (err) {
|
|
2058
|
+
const subdomainAvailabilityCheckError = err;
|
|
2059
|
+
if (typeof subdomainAvailabilityCheckError === "object" && !!subdomainAvailabilityCheckError) {
|
|
2060
|
+
if (subdomainAvailabilityCheckError.code === 10032) ; else if (subdomainAvailabilityCheckError.code === 10031) {
|
|
2061
|
+
ctx.logger.error(
|
|
2062
|
+
"Subdomain is unavailable, please try a different subdomain"
|
|
2063
|
+
);
|
|
2064
|
+
continue;
|
|
2065
|
+
} else {
|
|
2066
|
+
ctx.logger.error("An unexpected error occurred, please try again.");
|
|
2067
|
+
continue;
|
|
2068
|
+
}
|
|
2069
|
+
}
|
|
2070
|
+
}
|
|
2071
|
+
const ok = await ctx.confirm(
|
|
2072
|
+
`Creating a workers.dev subdomain for your account at ${source_default.blue(
|
|
2073
|
+
source_default.underline(
|
|
2074
|
+
`https://${potentialName}${getComplianceRegionSubdomain(complianceConfig)}.workers.dev`
|
|
2075
|
+
)
|
|
2076
|
+
)}. Ok to proceed?`
|
|
2077
|
+
);
|
|
2078
|
+
if (!ok) {
|
|
2079
|
+
throw getRegistrationDeclinedError(
|
|
2080
|
+
registrationContext,
|
|
2081
|
+
accountId,
|
|
2082
|
+
configPath
|
|
2083
|
+
);
|
|
2084
|
+
}
|
|
2085
|
+
try {
|
|
2086
|
+
const result = await ctx.fetchResult(
|
|
2087
|
+
complianceConfig,
|
|
2088
|
+
`/accounts/${accountId}/workers/subdomain`,
|
|
2089
|
+
{
|
|
2090
|
+
method: "PUT",
|
|
2091
|
+
body: JSON.stringify({ subdomain: potentialName })
|
|
2092
|
+
}
|
|
2093
|
+
);
|
|
2094
|
+
subdomain = result.subdomain;
|
|
2095
|
+
} catch (err) {
|
|
2096
|
+
const subdomainCreationError = err;
|
|
2097
|
+
if (typeof subdomainCreationError === "object" && !!subdomainCreationError && subdomainCreationError.code !== void 0) {
|
|
2098
|
+
switch (subdomainCreationError.code) {
|
|
2099
|
+
case 10031:
|
|
2100
|
+
ctx.logger.error(
|
|
2101
|
+
"Subdomain is unavailable, please try a different subdomain."
|
|
2102
|
+
);
|
|
2103
|
+
break;
|
|
2104
|
+
default:
|
|
2105
|
+
ctx.logger.error("An unexpected error occurred, please try again.");
|
|
2106
|
+
break;
|
|
2107
|
+
}
|
|
2108
|
+
}
|
|
2109
|
+
}
|
|
2110
|
+
}
|
|
2111
|
+
ctx.logger.log(
|
|
2112
|
+
"Success! It may take a few minutes for DNS records to update."
|
|
2113
|
+
);
|
|
2114
|
+
ctx.logger.log(
|
|
2115
|
+
`Visit ${source_default.blue(
|
|
2116
|
+
source_default.underline(
|
|
2117
|
+
`https://dash.cloudflare.com/${accountId}/workers/subdomain`
|
|
2118
|
+
)
|
|
2119
|
+
)} to edit your workers.dev subdomain`
|
|
2120
|
+
);
|
|
2121
|
+
return `${subdomain}${getComplianceRegionSubdomain(complianceConfig)}.workers.dev`;
|
|
2122
|
+
}
|
|
2123
|
+
__name(registerSubdomain, "registerSubdomain");
|
|
2124
|
+
|
|
2125
|
+
// src/triggers/deploy.ts
|
|
2126
|
+
async function triggersDeploy(props, ctx) {
|
|
2127
|
+
const { config, accountId, scriptName, routes, crons } = props;
|
|
2128
|
+
const routesOnly = [];
|
|
2129
|
+
const customDomainsOnly = [];
|
|
2130
|
+
for (const route of routes) {
|
|
2131
|
+
if (typeof route !== "string" && route.custom_domain) {
|
|
2132
|
+
customDomainsOnly.push(route);
|
|
2133
|
+
} else {
|
|
2134
|
+
routesOnly.push(route);
|
|
2135
|
+
}
|
|
2136
|
+
}
|
|
2137
|
+
const envName = props.env ?? "production";
|
|
2138
|
+
const start = Date.now();
|
|
2139
|
+
const workerUrl = props.useServiceEnvironments ? `/accounts/${accountId}/workers/services/${scriptName}/environments/${envName}` : `/accounts/${accountId}/workers/scripts/${scriptName}`;
|
|
2140
|
+
const uploadMs = Date.now() - start;
|
|
2141
|
+
const deployments = [];
|
|
2142
|
+
const hasWorkflowsDefinedInThisScript = config.workflows.some(
|
|
2143
|
+
(workflow) => isWorkflowDefinedInThisScript(workflow, scriptName)
|
|
2144
|
+
);
|
|
2145
|
+
const { wantWorkersDev, workersDevInSync } = await subdomainDeploy(
|
|
2146
|
+
props,
|
|
2147
|
+
accountId,
|
|
2148
|
+
scriptName,
|
|
2149
|
+
envName,
|
|
2150
|
+
workerUrl,
|
|
2151
|
+
routes,
|
|
2152
|
+
deployments,
|
|
2153
|
+
props.firstDeploy,
|
|
2154
|
+
ctx
|
|
2155
|
+
);
|
|
2156
|
+
if (!wantWorkersDev && workersDevInSync && routes.length !== 0) {
|
|
2157
|
+
const routesWithOtherBindings = {};
|
|
2158
|
+
const queue = new PQueue({ concurrency: 10 });
|
|
2159
|
+
const queuePromises = [];
|
|
2160
|
+
const zoneRoutesCache = /* @__PURE__ */ new Map();
|
|
2161
|
+
const zoneIdCache = /* @__PURE__ */ new Map();
|
|
2162
|
+
for (const route of routes) {
|
|
2163
|
+
queuePromises.push(
|
|
2164
|
+
queue.add(async () => {
|
|
2165
|
+
const zone = await getZoneForRoute(
|
|
2166
|
+
config,
|
|
2167
|
+
{ route, accountId },
|
|
2168
|
+
ctx,
|
|
2169
|
+
zoneIdCache
|
|
2170
|
+
);
|
|
2171
|
+
if (!zone) {
|
|
2172
|
+
return;
|
|
2173
|
+
}
|
|
2174
|
+
const routePattern = typeof route === "string" ? route : route.pattern;
|
|
2175
|
+
let routesInZone = zoneRoutesCache.get(zone.id);
|
|
2176
|
+
if (!routesInZone) {
|
|
2177
|
+
routesInZone = retryOnAPIFailure(
|
|
2178
|
+
() => ctx.fetchListResult(config, `/zones/${zone.id}/workers/routes`),
|
|
2179
|
+
ctx.logger
|
|
2180
|
+
);
|
|
2181
|
+
zoneRoutesCache.set(zone.id, routesInZone);
|
|
2182
|
+
}
|
|
2183
|
+
(await routesInZone).forEach(({ script, pattern }) => {
|
|
2184
|
+
if (pattern === routePattern && script !== scriptName) {
|
|
2185
|
+
if (!(script in routesWithOtherBindings)) {
|
|
2186
|
+
routesWithOtherBindings[script] = [];
|
|
2187
|
+
}
|
|
2188
|
+
routesWithOtherBindings[script].push(pattern);
|
|
2189
|
+
}
|
|
2190
|
+
});
|
|
2191
|
+
})
|
|
2192
|
+
);
|
|
2193
|
+
}
|
|
2194
|
+
await Promise.all(queuePromises);
|
|
2195
|
+
if (Object.keys(routesWithOtherBindings).length > 0) {
|
|
2196
|
+
let errorMessage = "Can't deploy routes that are assigned to another worker.\n";
|
|
2197
|
+
for (const worker in routesWithOtherBindings) {
|
|
2198
|
+
const assignedRoutes = routesWithOtherBindings[worker];
|
|
2199
|
+
errorMessage += `"${worker}" is already assigned to routes:
|
|
2200
|
+
${assignedRoutes.map(
|
|
2201
|
+
(r) => ` - ${source_default.underline(r)}
|
|
2202
|
+
`
|
|
2203
|
+
)}`;
|
|
2204
|
+
}
|
|
2205
|
+
const resolution = "Unassign other workers from the routes you want to deploy to, and then try again.";
|
|
2206
|
+
const dashHref = source_default.blue.underline(
|
|
2207
|
+
`https://dash.cloudflare.com/${accountId}/workers/overview`
|
|
2208
|
+
);
|
|
2209
|
+
const dashLink = `Visit ${dashHref} to unassign a worker from a route.`;
|
|
2210
|
+
throw new UserError(`${errorMessage}
|
|
2211
|
+
${resolution}
|
|
2212
|
+
${dashLink}`, {
|
|
2213
|
+
telemetryMessage: "triggers deploy routes assigned"
|
|
2214
|
+
});
|
|
2215
|
+
}
|
|
2216
|
+
}
|
|
2217
|
+
if (!wantWorkersDev && hasWorkflowsDefinedInThisScript) {
|
|
2218
|
+
await getWorkersDevSubdomain(config, accountId, ctx, {
|
|
2219
|
+
configPath: config.configPath,
|
|
2220
|
+
registrationContext: "workflows"
|
|
2221
|
+
});
|
|
2222
|
+
}
|
|
2223
|
+
if (routesOnly.length > 0) {
|
|
2224
|
+
deployments.push(
|
|
2225
|
+
publishRoutes(
|
|
2226
|
+
config,
|
|
2227
|
+
routesOnly,
|
|
2228
|
+
{
|
|
2229
|
+
workerUrl,
|
|
2230
|
+
scriptName,
|
|
2231
|
+
useServiceEnvironments: props.useServiceEnvironments,
|
|
2232
|
+
accountId
|
|
2233
|
+
},
|
|
2234
|
+
ctx
|
|
2235
|
+
).then(
|
|
2236
|
+
() => {
|
|
2237
|
+
if (routesOnly.length > 10) {
|
|
2238
|
+
return {
|
|
2239
|
+
targets: routesOnly.slice(0, 9).map((route) => renderRoute(route)).concat([`...and ${routesOnly.length - 9} more routes`])
|
|
2240
|
+
};
|
|
2241
|
+
}
|
|
2242
|
+
return { targets: routesOnly.map((route) => renderRoute(route)) };
|
|
2243
|
+
},
|
|
2244
|
+
(error) => ({ targets: [], error })
|
|
2245
|
+
)
|
|
2246
|
+
);
|
|
2247
|
+
}
|
|
2248
|
+
if (customDomainsOnly.length > 0) {
|
|
2249
|
+
deployments.push(
|
|
2250
|
+
publishCustomDomains(
|
|
2251
|
+
config,
|
|
2252
|
+
workerUrl,
|
|
2253
|
+
accountId,
|
|
2254
|
+
customDomainsOnly,
|
|
2255
|
+
ctx
|
|
2256
|
+
).catch((error) => ({ targets: [], error }))
|
|
2257
|
+
);
|
|
2258
|
+
}
|
|
2259
|
+
if (crons) {
|
|
2260
|
+
deployments.push(
|
|
2261
|
+
ctx.fetchResult(config, `${workerUrl}/schedules`, {
|
|
2262
|
+
// Note: PUT will override previous schedules on this script.
|
|
2263
|
+
method: "PUT",
|
|
2264
|
+
body: JSON.stringify(crons.map((cron) => ({ cron }))),
|
|
2265
|
+
headers: {
|
|
2266
|
+
"Content-Type": "application/json"
|
|
2267
|
+
}
|
|
2268
|
+
}).then(
|
|
2269
|
+
() => ({
|
|
2270
|
+
targets: crons.map((trigger) => `schedule: ${trigger}`)
|
|
2271
|
+
}),
|
|
2272
|
+
(error) => ({ targets: [], error })
|
|
2273
|
+
)
|
|
2274
|
+
);
|
|
2275
|
+
}
|
|
2276
|
+
if (config.queues.producers && config.queues.producers.length) {
|
|
2277
|
+
deployments.push(
|
|
2278
|
+
...config.queues.producers.map(
|
|
2279
|
+
(producer) => Promise.resolve({ targets: [`Producer for ${producer.queue}`] })
|
|
2280
|
+
)
|
|
2281
|
+
);
|
|
2282
|
+
}
|
|
2283
|
+
if (config.queues.consumers && config.queues.consumers.length) {
|
|
2284
|
+
const consumerUpdates = await updateQueueConsumers(
|
|
2285
|
+
config,
|
|
2286
|
+
accountId,
|
|
2287
|
+
scriptName,
|
|
2288
|
+
config,
|
|
2289
|
+
ctx
|
|
2290
|
+
);
|
|
2291
|
+
deployments.push(...consumerUpdates);
|
|
2292
|
+
}
|
|
2293
|
+
if (config.workflows?.length) {
|
|
2294
|
+
for (const workflow of config.workflows) {
|
|
2295
|
+
if (!isWorkflowDefinedInThisScript(workflow, scriptName)) {
|
|
2296
|
+
if (workflow.limits) {
|
|
2297
|
+
throw new UserError(
|
|
2298
|
+
`Workflow "${workflow.name}" has "limits" configured but references external script "${workflow.script_name}". Configure limits on the worker that defines the workflow.`,
|
|
2299
|
+
{
|
|
2300
|
+
telemetryMessage: "triggers deploy workflow limits external script"
|
|
2301
|
+
}
|
|
2302
|
+
);
|
|
2303
|
+
}
|
|
2304
|
+
if (workflow.schedules) {
|
|
2305
|
+
throw new UserError(
|
|
2306
|
+
`Workflow "${workflow.name}" has "schedules" configured but references external script "${workflow.script_name}". Configure schedules on the worker that defines the workflow.`,
|
|
2307
|
+
{
|
|
2308
|
+
telemetryMessage: "triggers deploy workflow schedules external script"
|
|
2309
|
+
}
|
|
2310
|
+
);
|
|
2311
|
+
}
|
|
2312
|
+
continue;
|
|
2313
|
+
}
|
|
2314
|
+
deployments.push(
|
|
2315
|
+
ctx.fetchResult(
|
|
2316
|
+
config,
|
|
2317
|
+
`/accounts/${accountId}/workflows/${workflow.name}`,
|
|
2318
|
+
{
|
|
2319
|
+
method: "PUT",
|
|
2320
|
+
body: JSON.stringify({
|
|
2321
|
+
script_name: scriptName,
|
|
2322
|
+
class_name: workflow.class_name,
|
|
2323
|
+
...workflow.limits && { limits: workflow.limits },
|
|
2324
|
+
...workflow.schedules && {
|
|
2325
|
+
schedules: (Array.isArray(workflow.schedules) ? workflow.schedules : [workflow.schedules]).map((cron) => ({ cron }))
|
|
2326
|
+
}
|
|
2327
|
+
}),
|
|
2328
|
+
headers: {
|
|
2329
|
+
"Content-Type": "application/json"
|
|
2330
|
+
}
|
|
2331
|
+
}
|
|
2332
|
+
).then(
|
|
2333
|
+
() => ({ targets: [`workflow: ${workflow.name}`] }),
|
|
2334
|
+
(error) => ({ targets: [], error })
|
|
2335
|
+
)
|
|
2336
|
+
);
|
|
2337
|
+
}
|
|
2338
|
+
}
|
|
2339
|
+
const completedDeployments = await Promise.all(deployments);
|
|
2340
|
+
const deployMs = Date.now() - start - uploadMs;
|
|
2341
|
+
const workerName = props.useServiceEnvironments ? `${scriptName} (${envName})` : scriptName;
|
|
2342
|
+
const targets = completedDeployments.flatMap((deployment) => deployment.targets).map(
|
|
2343
|
+
// Append protocol only on workers.dev domains
|
|
2344
|
+
(target) => (target.endsWith("workers.dev") ? "https://" : "") + target
|
|
2345
|
+
);
|
|
2346
|
+
if (targets.length > 0) {
|
|
2347
|
+
ctx.logger.log(`Deployed ${workerName} triggers`, formatTime(deployMs));
|
|
2348
|
+
for (const target of targets) {
|
|
2349
|
+
ctx.logger.log(" ", target);
|
|
2350
|
+
}
|
|
2351
|
+
} else {
|
|
2352
|
+
ctx.logger.log("No targets deployed for", workerName, formatTime(deployMs));
|
|
2353
|
+
}
|
|
2354
|
+
const errors = completedDeployments.map((deployment) => deployment.error).filter((error) => error !== void 0);
|
|
2355
|
+
if (errors.length > 0) {
|
|
2356
|
+
throw new UserError(
|
|
2357
|
+
`Some triggers failed to deploy for ${workerName}:
|
|
2358
|
+
` + errors.map((error) => ` - ${error.message}`).join("\n"),
|
|
2359
|
+
{
|
|
2360
|
+
// Preserve the original errors (with stacks and subclass info) for
|
|
2361
|
+
// debugging, while still presenting a single aggregated message.
|
|
2362
|
+
cause: new AggregateError(errors),
|
|
2363
|
+
// Aggregate the inner telemetry labels into a single deterministic,
|
|
2364
|
+
// low-cardinality label so failures still group meaningfully. Non-
|
|
2365
|
+
// UserError causes contribute a generic "non-user error" marker.
|
|
2366
|
+
telemetryMessage: `triggers deploy partial failure: ${aggregateTelemetryMessages(errors)}`
|
|
2367
|
+
}
|
|
2368
|
+
);
|
|
2369
|
+
}
|
|
2370
|
+
return targets;
|
|
2371
|
+
}
|
|
2372
|
+
__name(triggersDeploy, "triggersDeploy");
|
|
2373
|
+
function aggregateTelemetryMessages(errors) {
|
|
2374
|
+
const labels = errors.map(
|
|
2375
|
+
(error) => error instanceof UserError && error.telemetryMessage ? error.telemetryMessage : "non-user error"
|
|
2376
|
+
);
|
|
2377
|
+
return Array.from(new Set(labels)).sort().join(", ");
|
|
2378
|
+
}
|
|
2379
|
+
__name(aggregateTelemetryMessages, "aggregateTelemetryMessages");
|
|
2380
|
+
function getSubdomainValues(config_workers_dev, config_preview_urls, routes) {
|
|
2381
|
+
const defaultWorkersDev = routes.length === 0;
|
|
2382
|
+
const workers_dev = config_workers_dev ?? defaultWorkersDev;
|
|
2383
|
+
const defaultPreviewUrls = void 0;
|
|
2384
|
+
const preview_urls = config_preview_urls ?? defaultPreviewUrls;
|
|
2385
|
+
return {
|
|
2386
|
+
workers_dev,
|
|
2387
|
+
preview_urls
|
|
2388
|
+
};
|
|
2389
|
+
}
|
|
2390
|
+
__name(getSubdomainValues, "getSubdomainValues");
|
|
2391
|
+
function getSubdomainValuesAPIMock(config_workers_dev, config_preview_urls, routes) {
|
|
2392
|
+
const defaultWorkersDev = routes.length === 0;
|
|
2393
|
+
const workers_dev = config_workers_dev ?? defaultWorkersDev;
|
|
2394
|
+
const defaultPreviewUrls = defaultWorkersDev;
|
|
2395
|
+
const preview_urls = config_preview_urls ?? defaultPreviewUrls;
|
|
2396
|
+
return {
|
|
2397
|
+
workers_dev,
|
|
2398
|
+
preview_urls
|
|
2399
|
+
};
|
|
2400
|
+
}
|
|
2401
|
+
__name(getSubdomainValuesAPIMock, "getSubdomainValuesAPIMock");
|
|
2402
|
+
async function validateSubdomainMixedState(props, accountId, scriptName, before, after, firstDeploy, ctx) {
|
|
2403
|
+
const { config } = props;
|
|
2404
|
+
const changed = after.workers_dev !== before.workers_dev || after.preview_urls !== before.preview_urls;
|
|
2405
|
+
if (!changed) {
|
|
2406
|
+
return after;
|
|
2407
|
+
}
|
|
2408
|
+
if (getSubdomainMixedStateCheckDisabled()) {
|
|
2409
|
+
return after;
|
|
2410
|
+
}
|
|
2411
|
+
if (ctx.isNonInteractiveOrCI()) {
|
|
2412
|
+
return after;
|
|
2413
|
+
}
|
|
2414
|
+
if (firstDeploy) {
|
|
2415
|
+
return after;
|
|
2416
|
+
}
|
|
2417
|
+
if (after.workers_dev === after.preview_urls) {
|
|
2418
|
+
return after;
|
|
2419
|
+
}
|
|
2420
|
+
const userSubdomain = await getWorkersDevSubdomain(config, accountId, ctx, {
|
|
2421
|
+
configPath: config.configPath
|
|
2422
|
+
});
|
|
2423
|
+
const previewUrl = `https://<VERSION_PREFIX>-${scriptName}.${userSubdomain}`;
|
|
2424
|
+
if (!after.workers_dev && after.preview_urls) {
|
|
2425
|
+
ctx.logger.warn(
|
|
2426
|
+
[
|
|
2427
|
+
"You are disabling the 'workers.dev' subdomain for this Worker, but Preview URLs are still enabled.",
|
|
2428
|
+
"Preview URLs will automatically generate a unique, shareable link for each new version which will be accessible at:",
|
|
2429
|
+
` ${previewUrl}`,
|
|
2430
|
+
"",
|
|
2431
|
+
"To prevent this Worker from being unintentionally public, you may want to disable the Preview URLs as well by setting `preview_urls = false` in your Wrangler config file."
|
|
2432
|
+
].join("\n")
|
|
2433
|
+
);
|
|
2434
|
+
}
|
|
2435
|
+
if (after.workers_dev && !after.preview_urls) {
|
|
2436
|
+
ctx.logger.warn(
|
|
2437
|
+
[
|
|
2438
|
+
"You are enabling the 'workers.dev' subdomain for this Worker, but Preview URLs are still disabled.",
|
|
2439
|
+
"Preview URLs will automatically generate a unique, shareable link for each new version which will be accessible at:",
|
|
2440
|
+
` ${previewUrl}`,
|
|
2441
|
+
"",
|
|
2442
|
+
"You may want to enable the Preview URLs as well by setting `preview_urls = true` in your Wrangler config file."
|
|
2443
|
+
].join("\n")
|
|
2444
|
+
);
|
|
2445
|
+
}
|
|
2446
|
+
return after;
|
|
2447
|
+
}
|
|
2448
|
+
__name(validateSubdomainMixedState, "validateSubdomainMixedState");
|
|
2449
|
+
async function subdomainDeploy(props, accountId, scriptName, envName, workerUrl, routes, deployments, firstDeploy, ctx) {
|
|
2450
|
+
const { config } = props;
|
|
2451
|
+
const { workers_dev: wantWorkersDev, preview_urls: wantPreviews } = getSubdomainValues(config.workers_dev, config.preview_urls, routes);
|
|
2452
|
+
if (wantWorkersDev) {
|
|
2453
|
+
const userSubdomain = await getWorkersDevSubdomain(config, accountId, ctx, {
|
|
2454
|
+
configPath: config.configPath
|
|
2455
|
+
});
|
|
2456
|
+
const workersDevURL = !props.useServiceEnvironments || !props.env ? `${scriptName}.${userSubdomain}` : `${envName}.${scriptName}.${userSubdomain}`;
|
|
2457
|
+
deployments.push(Promise.resolve({ targets: [workersDevURL] }));
|
|
2458
|
+
}
|
|
2459
|
+
const before = await ctx.fetchResult(config, `${workerUrl}/subdomain`);
|
|
2460
|
+
const after = await retryOnAPIFailure(
|
|
2461
|
+
async () => ctx.fetchResult(config, `${workerUrl}/subdomain`, {
|
|
2462
|
+
method: "POST",
|
|
2463
|
+
body: JSON.stringify({
|
|
2464
|
+
enabled: wantWorkersDev,
|
|
2465
|
+
previews_enabled: wantPreviews
|
|
2466
|
+
}),
|
|
2467
|
+
headers: {
|
|
2468
|
+
"Content-Type": "application/json",
|
|
2469
|
+
"Cloudflare-Workers-Script-Api-Date": "2025-08-01"
|
|
2470
|
+
}
|
|
2471
|
+
}),
|
|
2472
|
+
ctx.logger
|
|
2473
|
+
);
|
|
2474
|
+
if (!firstDeploy && config.workers_dev == void 0 && after.enabled !== before.enabled) {
|
|
2475
|
+
const status = /* @__PURE__ */ __name((enabled, past) => {
|
|
2476
|
+
if (past) {
|
|
2477
|
+
return enabled ? "enabled" : "disabled";
|
|
2478
|
+
} else {
|
|
2479
|
+
return enabled ? "enable" : "disable";
|
|
2480
|
+
}
|
|
2481
|
+
}, "status");
|
|
2482
|
+
ctx.logger.warn(
|
|
2483
|
+
[
|
|
2484
|
+
`Because 'workers_dev' is not in your Wrangler file, it will be ${status(after.enabled, true)} for this deployment by default.`,
|
|
2485
|
+
`To override this setting, you can ${status(before.enabled, false)} workers.dev by explicitly setting 'workers_dev = ${before.enabled}' in your Wrangler file.`
|
|
2486
|
+
].join("\n")
|
|
2487
|
+
);
|
|
2488
|
+
}
|
|
2489
|
+
if (!firstDeploy && config.preview_urls == void 0 && after.previews_enabled !== before.previews_enabled) {
|
|
2490
|
+
const status = /* @__PURE__ */ __name((enabled, past) => {
|
|
2491
|
+
if (past) {
|
|
2492
|
+
return enabled ? "enabled" : "disabled";
|
|
2493
|
+
} else {
|
|
2494
|
+
return enabled ? "enable" : "disable";
|
|
2495
|
+
}
|
|
2496
|
+
}, "status");
|
|
2497
|
+
ctx.logger.warn(
|
|
2498
|
+
[
|
|
2499
|
+
`Because your 'workers.dev' route is ${status(after.enabled, true)} and your 'preview_urls' setting is not in your Wrangler file, Preview URLs will be ${status(after.previews_enabled, true)} for this deployment by default.`,
|
|
2500
|
+
`To override this setting, you can ${status(before.previews_enabled, false)} Preview URLs by explicitly setting 'preview_urls = ${before.previews_enabled}' in your Wrangler file.`
|
|
2501
|
+
].join("\n")
|
|
2502
|
+
);
|
|
2503
|
+
}
|
|
2504
|
+
await validateSubdomainMixedState(
|
|
2505
|
+
props,
|
|
2506
|
+
accountId,
|
|
2507
|
+
scriptName,
|
|
2508
|
+
{ workers_dev: before.enabled, preview_urls: before.previews_enabled },
|
|
2509
|
+
{ workers_dev: after.enabled, preview_urls: after.previews_enabled },
|
|
2510
|
+
firstDeploy,
|
|
2511
|
+
ctx
|
|
2512
|
+
);
|
|
2513
|
+
return {
|
|
2514
|
+
wantWorkersDev,
|
|
2515
|
+
wantPreviews,
|
|
2516
|
+
workersDevInSync: before.enabled === after.enabled,
|
|
2517
|
+
previewsInSync: before.previews_enabled === after.previews_enabled
|
|
2518
|
+
};
|
|
2519
|
+
}
|
|
2520
|
+
__name(subdomainDeploy, "subdomainDeploy");
|
|
2521
|
+
function isWorkflowDefinedInThisScript(workflow, scriptName) {
|
|
2522
|
+
return workflow.script_name === void 0 || workflow.script_name === scriptName;
|
|
2523
|
+
}
|
|
2524
|
+
__name(isWorkflowDefinedInThisScript, "isWorkflowDefinedInThisScript");
|
|
2525
|
+
|
|
2526
|
+
export { deletePullConsumer, deleteWorkerConsumer, getQueue, getSubdomainValues, getSubdomainValuesAPIMock, getWorkersDevSubdomain, getZoneForRoute, getZoneIdFromHost, listConsumers, listQueues, postConsumer, publishCustomDomains, publishRoutes, putConsumer, putConsumerById, renderRoute, triggersDeploy, updateQueueConsumers };
|