@fabricorg/webhook-delivery 0.1.2 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/node.cjs CHANGED
@@ -1,880 +1,1223 @@
1
- 'use strict';
2
-
3
- var buffer = require('buffer');
4
- var https = require('https');
5
- var promises = require('dns/promises');
6
-
7
- // src/node/transport.ts
8
-
9
- // src/snapshot.ts
10
- var reflectApply = Reflect.apply;
11
- var reflectOwnKeys = Reflect.ownKeys;
12
- var reflectGetOwnPropertyDescriptor = Reflect.getOwnPropertyDescriptor;
13
- var reflectGetPrototypeOf = Reflect.getPrototypeOf;
14
- var reflectDefineProperty = Reflect.defineProperty;
15
- var objectCreate = Object.create;
16
- var objectFreeze = Object.freeze;
17
- var objectHasOwn = Object.hasOwn;
18
- var objectPrototype = Object.prototype;
19
- var arrayIsArray = Array.isArray;
20
- var dateGetTime = Date.prototype.getTime;
21
- var regExpExec = RegExp.prototype.exec;
22
- var apply = reflectApply;
23
- var numberIsFinite = Number.isFinite;
24
- var numberIsSafeInteger = Number.isSafeInteger;
25
- var freeze = objectFreeze;
26
- var hasOwn = objectHasOwn;
27
- var isArray = arrayIsArray;
28
- var NOT_PRIMITIVE = /* @__PURE__ */ Symbol("webhook-delivery.not-primitive");
1
+ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
+ let buffer = require("buffer");
3
+ let https = require("https");
4
+ let dns_promises = require("dns/promises");
5
+ //#region src/snapshot.ts
6
+ const reflectApply = Reflect.apply;
7
+ const reflectOwnKeys = Reflect.ownKeys;
8
+ const reflectGetOwnPropertyDescriptor$1 = Reflect.getOwnPropertyDescriptor;
9
+ const reflectGetPrototypeOf = Reflect.getPrototypeOf;
10
+ const reflectDefineProperty$1 = Reflect.defineProperty;
11
+ const objectCreate$1 = Object.create;
12
+ const objectFreeze = Object.freeze;
13
+ const objectHasOwn = Object.hasOwn;
14
+ const objectPrototype = Object.prototype;
15
+ const arrayIsArray = Array.isArray;
16
+ const dateGetTime = Date.prototype.getTime;
17
+ Date.prototype.toISOString;
18
+ const regExpExec = RegExp.prototype.exec;
19
+ String.prototype.trim;
20
+ /** Captured `Reflect.apply`, so a replaced `Function.prototype.call` is never used. */
21
+ const apply = reflectApply;
22
+ /** Captured numeric intrinsics. */
23
+ const numberIsFinite = Number.isFinite;
24
+ const numberIsSafeInteger = Number.isSafeInteger;
25
+ Date.parse;
26
+ const freeze = objectFreeze;
27
+ const hasOwn = objectHasOwn;
28
+ const isArray = arrayIsArray;
29
+ /** Stands in for a non-primitive where an option must be a primitive, so validation rejects it. */
30
+ const NOT_PRIMITIVE = Symbol("webhook-delivery.not-primitive");
31
+ /** A null-prototype data descriptor, so `defineProperty` reads nothing from `Object.prototype`. */
29
32
  function dataDescriptor(value) {
30
- const descriptor = objectCreate(null);
31
- descriptor.value = value;
32
- descriptor.enumerable = true;
33
- descriptor.writable = false;
34
- descriptor.configurable = false;
35
- return descriptor;
33
+ const descriptor = objectCreate$1(null);
34
+ descriptor.value = value;
35
+ descriptor.enumerable = true;
36
+ descriptor.writable = false;
37
+ descriptor.configurable = false;
38
+ return descriptor;
36
39
  }
40
+ /** Define an own, enumerable, read-only data property without consulting any prototype. */
37
41
  function define(target, key, value) {
38
- reflectDefineProperty(target, key, dataDescriptor(value));
42
+ reflectDefineProperty$1(target, key, dataDescriptor(value));
39
43
  }
44
+ /** A fresh array holding `values`' elements in order, frozen. `values` must be package-owned. */
40
45
  function frozenList(values) {
41
- const list = [];
42
- for (let index = 0; index < values.length; index += 1) define(list, index, values[index]);
43
- return objectFreeze(list);
46
+ const list = [];
47
+ for (let index = 0; index < values.length; index += 1) define(list, index, values[index]);
48
+ return objectFreeze(list);
44
49
  }
50
+ /**
51
+ * A frozen null-prototype copy of a package-built object literal. Keys whose
52
+ * value is `undefined` are left out, so optional fields are absent rather
53
+ * than present-and-undefined.
54
+ */
45
55
  function record(fields) {
46
- const out = objectCreate(null);
47
- const keys = reflectOwnKeys(fields);
48
- for (let index = 0; index < keys.length; index += 1) {
49
- const key = keys[index];
50
- const descriptor = reflectGetOwnPropertyDescriptor(fields, key);
51
- if (descriptor !== void 0 && objectHasOwn(descriptor, "value") && descriptor.value !== void 0) define(out, key, descriptor.value);
52
- }
53
- return objectFreeze(out);
56
+ const out = objectCreate$1(null);
57
+ const keys = reflectOwnKeys(fields);
58
+ for (let index = 0; index < keys.length; index += 1) {
59
+ const key = keys[index];
60
+ const descriptor = reflectGetOwnPropertyDescriptor$1(fields, key);
61
+ if (descriptor !== void 0 && objectHasOwn(descriptor, "value") && descriptor.value !== void 0) define(out, key, descriptor.value);
62
+ }
63
+ return objectFreeze(out);
54
64
  }
65
+ /** A mutable null-prototype map for package-internal bookkeeping. */
55
66
  function emptyMap() {
56
- return objectCreate(null);
67
+ return objectCreate$1(null);
57
68
  }
69
+ /** `true` when `re` matches `value`, using the captured `RegExp.prototype.exec`. */
58
70
  function matches(re, value) {
59
- return reflectApply(regExpExec, re, [value]) !== null;
71
+ return reflectApply(regExpExec, re, [value]) !== null;
60
72
  }
73
+ /** `true` for a non-array object whose prototype is `Object.prototype` or `null`. A Proxy's trap may run. */
61
74
  function isPlainRecord(value) {
62
- if (value === null || typeof value !== "object" || arrayIsArray(value)) return false;
63
- const prototype = reflectGetPrototypeOf(value);
64
- return prototype === objectPrototype || prototype === null;
75
+ if (value === null || typeof value !== "object" || arrayIsArray(value)) return false;
76
+ const prototype = reflectGetPrototypeOf(value);
77
+ return prototype === objectPrototype || prototype === null;
65
78
  }
79
+ /**
80
+ * Read one own data property. Absent is `undefined`; an accessor is refused
81
+ * through `fail` without being called.
82
+ */
66
83
  function readOwn(target, key, field, fail) {
67
- const descriptor = reflectGetOwnPropertyDescriptor(target, key);
68
- if (descriptor === void 0) return void 0;
69
- if (!objectHasOwn(descriptor, "value")) return fail("accessor", field);
70
- return descriptor.value;
84
+ const descriptor = reflectGetOwnPropertyDescriptor$1(target, key);
85
+ if (descriptor === void 0) return void 0;
86
+ if (!objectHasOwn(descriptor, "value")) return fail("accessor", field);
87
+ return descriptor.value;
71
88
  }
89
+ /** `undefined` for an absent value, the value for a primitive, {@link NOT_PRIMITIVE} otherwise. */
72
90
  function primitive(value) {
73
- if (value === null || typeof value !== "object" && typeof value !== "function") return value;
74
- return NOT_PRIMITIVE;
91
+ if (value === null || typeof value !== "object" && typeof value !== "function") return value;
92
+ return NOT_PRIMITIVE;
75
93
  }
94
+ /** The time value of a real `Date`, or `NaN` for anything else. */
76
95
  function timeOf(value) {
77
- if (value === null || typeof value !== "object") return NaN;
78
- try {
79
- return reflectApply(dateGetTime, value, []);
80
- } catch {
81
- return NaN;
82
- }
96
+ if (value === null || typeof value !== "object") return NaN;
97
+ try {
98
+ return reflectApply(dateGetTime, value, []);
99
+ } catch {
100
+ return NaN;
101
+ }
83
102
  }
84
-
85
- // src/address.ts
86
- var stringCharCodeAt = String.prototype.charCodeAt;
87
- var stringIndexOf = String.prototype.indexOf;
88
- var stringSlice = String.prototype.slice;
89
- var stringSplit = String.prototype.split;
90
- var MAX_ADDRESS_LENGTH = 45;
91
- var MAX_TEXT_LENGTH = 64;
92
- var IPV4_OCTET = "(?:25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)";
93
- var IPV4_DOTTED = new RegExp(`^${IPV4_OCTET}(?:\\.${IPV4_OCTET}){3}$`);
94
- var HEX_GROUP = /^[0-9A-Fa-f]{1,4}$/;
103
+ //#endregion
104
+ //#region src/address.ts
105
+ const stringCharCodeAt = String.prototype.charCodeAt;
106
+ const stringIndexOf = String.prototype.indexOf;
107
+ const stringSlice$1 = String.prototype.slice;
108
+ const stringSplit = String.prototype.split;
109
+ /** Longest address text parsed: a full IPv6 form with an embedded IPv4 tail is 45 characters. */
110
+ const MAX_ADDRESS_LENGTH = 45;
111
+ /** Longest text inspected at all, leaving room for a zone index. */
112
+ const MAX_TEXT_LENGTH = 64;
113
+ const IPV4_OCTET = "(?:25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)";
114
+ /** Canonical dotted-quad only: no leading zeros, no shorthand, no hex. */
115
+ const IPV4_DOTTED = new RegExp(`^${IPV4_OCTET}(?:\\.${IPV4_OCTET}){3}$`);
116
+ const HEX_GROUP = /^[0-9A-Fa-f]{1,4}$/;
95
117
  function ipv4Block(a, b, c, d, prefix) {
96
- return freeze({ base: (a << 24 | b << 16 | c << 8 | d) >>> 0, prefix });
97
- }
98
- var REFUSED_IPV4_BLOCKS = freeze([
99
- ipv4Block(0, 0, 0, 0, 8),
100
- // "this network", including the unspecified 0.0.0.0
101
- ipv4Block(10, 0, 0, 0, 8),
102
- // private
103
- ipv4Block(100, 64, 0, 0, 10),
104
- // shared address space (CGNAT)
105
- ipv4Block(127, 0, 0, 0, 8),
106
- // loopback
107
- ipv4Block(169, 254, 0, 0, 16),
108
- // link-local, including cloud metadata endpoints
109
- ipv4Block(172, 16, 0, 0, 12),
110
- // private
111
- ipv4Block(192, 0, 0, 0, 24),
112
- // IETF protocol assignments
113
- ipv4Block(192, 0, 2, 0, 24),
114
- // documentation (TEST-NET-1)
115
- ipv4Block(192, 88, 99, 0, 24),
116
- // deprecated 6to4 relay anycast
117
- ipv4Block(192, 168, 0, 0, 16),
118
- // private
119
- ipv4Block(198, 18, 0, 0, 15),
120
- // benchmarking
121
- ipv4Block(198, 51, 100, 0, 24),
122
- // documentation (TEST-NET-2)
123
- ipv4Block(203, 0, 113, 0, 24),
124
- // documentation (TEST-NET-3)
125
- ipv4Block(224, 0, 0, 0, 4),
126
- // multicast
127
- ipv4Block(240, 0, 0, 0, 4)
128
- // reserved, including 255.255.255.255
118
+ return freeze({
119
+ base: (a << 24 | b << 16 | c << 8 | d) >>> 0,
120
+ prefix
121
+ });
122
+ }
123
+ /**
124
+ * IPv4 blocks that are never a webhook destination. The IANA IPv4
125
+ * Special-Purpose Address Registry's not-globally-reachable entries, plus
126
+ * multicast (224.0.0.0/4) and reserved space (240.0.0.0/4, which holds the
127
+ * limited broadcast address). 192.0.0.0/24 is refused whole, including the
128
+ * two anycast /32s in it that IANA marks reachable; neither is a webhook
129
+ * receiver.
130
+ */
131
+ const REFUSED_IPV4_BLOCKS = freeze([
132
+ ipv4Block(0, 0, 0, 0, 8),
133
+ ipv4Block(10, 0, 0, 0, 8),
134
+ ipv4Block(100, 64, 0, 0, 10),
135
+ ipv4Block(127, 0, 0, 0, 8),
136
+ ipv4Block(169, 254, 0, 0, 16),
137
+ ipv4Block(172, 16, 0, 0, 12),
138
+ ipv4Block(192, 0, 0, 0, 24),
139
+ ipv4Block(192, 0, 2, 0, 24),
140
+ ipv4Block(192, 88, 99, 0, 24),
141
+ ipv4Block(192, 168, 0, 0, 16),
142
+ ipv4Block(198, 18, 0, 0, 15),
143
+ ipv4Block(198, 51, 100, 0, 24),
144
+ ipv4Block(203, 0, 113, 0, 24),
145
+ ipv4Block(224, 0, 0, 0, 4),
146
+ ipv4Block(240, 0, 0, 0, 4)
129
147
  ]);
130
148
  function inIpv4Block(value, block) {
131
- const mask = block.prefix === 0 ? 0 : 4294967295 << 32 - block.prefix >>> 0;
132
- return (value & mask) >>> 0 === block.base;
149
+ return (value & (block.prefix === 0 ? 0 : 4294967295 << 32 - block.prefix >>> 0)) >>> 0 === block.base;
133
150
  }
151
+ /** `true` when an IPv4 address, as an unsigned 32-bit integer, is publicly routable. */
134
152
  function isPublicIpv4Value(value) {
135
- for (let index = 0; index < REFUSED_IPV4_BLOCKS.length; index += 1) {
136
- if (inIpv4Block(value, REFUSED_IPV4_BLOCKS[index])) return false;
137
- }
138
- return true;
153
+ for (let index = 0; index < REFUSED_IPV4_BLOCKS.length; index += 1) if (inIpv4Block(value, REFUSED_IPV4_BLOCKS[index])) return false;
154
+ return true;
139
155
  }
156
+ /** Parse a canonical dotted-quad to an unsigned 32-bit integer, or `undefined`. */
140
157
  function parseIpv4(text) {
141
- if (!matches(IPV4_DOTTED, text)) return void 0;
142
- const parts = apply(stringSplit, text, ["."]);
143
- let value = 0;
144
- for (let index = 0; index < 4; index += 1) value = value * 256 + decimal(parts[index]);
145
- return value >>> 0;
158
+ if (!matches(IPV4_DOTTED, text)) return void 0;
159
+ const parts = apply(stringSplit, text, ["."]);
160
+ let value = 0;
161
+ for (let index = 0; index < 4; index += 1) value = value * 256 + decimal(parts[index]);
162
+ return value >>> 0;
146
163
  }
147
164
  function decimal(text) {
148
- let value = 0;
149
- for (let index = 0; index < text.length; index += 1) value = value * 10 + (apply(stringCharCodeAt, text, [index]) - 48);
150
- return value;
165
+ let value = 0;
166
+ for (let index = 0; index < text.length; index += 1) value = value * 10 + (apply(stringCharCodeAt, text, [index]) - 48);
167
+ return value;
151
168
  }
152
169
  function hex(text) {
153
- let value = 0;
154
- for (let index = 0; index < text.length; index += 1) {
155
- const code = apply(stringCharCodeAt, text, [index]);
156
- const digit = code <= 57 ? code - 48 : code <= 70 ? code - 55 : code - 87;
157
- value = value * 16 + digit;
158
- }
159
- return value;
170
+ let value = 0;
171
+ for (let index = 0; index < text.length; index += 1) {
172
+ const code = apply(stringCharCodeAt, text, [index]);
173
+ const digit = code <= 57 ? code - 48 : code <= 70 ? code - 55 : code - 87;
174
+ value = value * 16 + digit;
175
+ }
176
+ return value;
160
177
  }
178
+ /** Parse one side of an IPv6 address (no `::`) into 16-bit words; `tailIpv4` allows a dotted last group. */
161
179
  function parseIpv6Groups(text, tailIpv4) {
162
- const words = [];
163
- if (text === "") return words;
164
- const groups = apply(stringSplit, text, [":"]);
165
- for (let index = 0; index < groups.length; index += 1) {
166
- const group = groups[index];
167
- if (tailIpv4 && index === groups.length - 1 && apply(stringIndexOf, group, ["."]) !== -1) {
168
- const v4 = parseIpv4(group);
169
- if (v4 === void 0) return void 0;
170
- words[words.length] = v4 >>> 16;
171
- words[words.length] = v4 & 65535;
172
- continue;
173
- }
174
- if (!matches(HEX_GROUP, group)) return void 0;
175
- words[words.length] = hex(group);
176
- }
177
- return words;
180
+ const words = [];
181
+ if (text === "") return words;
182
+ const groups = apply(stringSplit, text, [":"]);
183
+ for (let index = 0; index < groups.length; index += 1) {
184
+ const group = groups[index];
185
+ if (tailIpv4 && index === groups.length - 1 && apply(stringIndexOf, group, ["."]) !== -1) {
186
+ const v4 = parseIpv4(group);
187
+ if (v4 === void 0) return void 0;
188
+ words[words.length] = v4 >>> 16;
189
+ words[words.length] = v4 & 65535;
190
+ continue;
191
+ }
192
+ if (!matches(HEX_GROUP, group)) return void 0;
193
+ words[words.length] = hex(group);
194
+ }
195
+ return words;
178
196
  }
197
+ /** Parse an IPv6 address (no brackets, no zone) into eight 16-bit words, or `undefined`. */
179
198
  function parseIpv6(text) {
180
- const gap = apply(stringIndexOf, text, ["::"]);
181
- if (gap === -1) {
182
- const words2 = parseIpv6Groups(text, true);
183
- return words2 !== void 0 && words2.length === 8 ? words2 : void 0;
184
- }
185
- if (apply(stringIndexOf, text, ["::", gap + 1]) !== -1) return void 0;
186
- const head = parseIpv6Groups(apply(stringSlice, text, [0, gap]), false);
187
- const tail = parseIpv6Groups(apply(stringSlice, text, [gap + 2]), true);
188
- if (head === void 0 || tail === void 0 || head.length + tail.length > 7) return void 0;
189
- const words = [];
190
- for (let index = 0; index < head.length; index += 1) words[words.length] = head[index];
191
- for (let index = head.length + tail.length; index < 8; index += 1) words[words.length] = 0;
192
- for (let index = 0; index < tail.length; index += 1) words[words.length] = tail[index];
193
- return words;
199
+ const gap = apply(stringIndexOf, text, ["::"]);
200
+ if (gap === -1) {
201
+ const words = parseIpv6Groups(text, true);
202
+ return words !== void 0 && words.length === 8 ? words : void 0;
203
+ }
204
+ if (apply(stringIndexOf, text, ["::", gap + 1]) !== -1) return void 0;
205
+ const head = parseIpv6Groups(apply(stringSlice$1, text, [0, gap]), false);
206
+ const tail = parseIpv6Groups(apply(stringSlice$1, text, [gap + 2]), true);
207
+ if (head === void 0 || tail === void 0 || head.length + tail.length > 7) return void 0;
208
+ const words = [];
209
+ for (let index = 0; index < head.length; index += 1) words[words.length] = head[index];
210
+ for (let index = head.length + tail.length; index < 8; index += 1) words[words.length] = 0;
211
+ for (let index = 0; index < tail.length; index += 1) words[words.length] = tail[index];
212
+ return words;
194
213
  }
214
+ /** The IPv4 address held in two consecutive 16-bit words. */
195
215
  function embeddedIpv4(high, low) {
196
- return (high << 16 | low) >>> 0;
216
+ return (high << 16 | low) >>> 0;
197
217
  }
218
+ /** `true` when an IPv6 address, as eight 16-bit words, is publicly routable. */
198
219
  function isPublicIpv6Words(w) {
199
- if (w[0] === 100 && w[1] === 65435 && w[2] === 0 && w[3] === 0 && w[4] === 0 && w[5] === 0) {
200
- return isPublicIpv4Value(embeddedIpv4(w[6], w[7]));
201
- }
202
- if ((w[0] & 57344) !== 8192) return false;
203
- if (w[0] === 8193 && (w[1] & 65024) === 0) {
204
- if (w[1] !== 0) return false;
205
- const server = embeddedIpv4(w[2], w[3]);
206
- const client = ~embeddedIpv4(w[6], w[7]) >>> 0;
207
- return isPublicIpv4Value(server) && isPublicIpv4Value(client);
208
- }
209
- if (w[0] === 8193 && w[1] === 3512) return false;
210
- if (w[0] === 16383 && (w[1] & 61440) === 0) return false;
211
- if (w[0] === 8194) return isPublicIpv4Value(embeddedIpv4(w[1], w[2]));
212
- return true;
220
+ if (w[0] === 100 && w[1] === 65435 && w[2] === 0 && w[3] === 0 && w[4] === 0 && w[5] === 0) return isPublicIpv4Value(embeddedIpv4(w[6], w[7]));
221
+ if ((w[0] & 57344) !== 8192) return false;
222
+ if (w[0] === 8193 && (w[1] & 65024) === 0) {
223
+ if (w[1] !== 0) return false;
224
+ const server = embeddedIpv4(w[2], w[3]);
225
+ const client = ~embeddedIpv4(w[6], w[7]) >>> 0;
226
+ return isPublicIpv4Value(server) && isPublicIpv4Value(client);
227
+ }
228
+ if (w[0] === 8193 && w[1] === 3512) return false;
229
+ if (w[0] === 16383 && (w[1] & 61440) === 0) return false;
230
+ if (w[0] === 8194) return isPublicIpv4Value(embeddedIpv4(w[1], w[2]));
231
+ return true;
213
232
  }
233
+ /** RFC 5952 text for eight 16-bit words: lowercase, no leading zeros, the longest zero run of two or more compressed. */
214
234
  function formatIpv6(w) {
215
- let bestStart = -1;
216
- let bestLength = 0;
217
- for (let index = 0; index < 8; ) {
218
- if (w[index] !== 0) {
219
- index += 1;
220
- continue;
221
- }
222
- let end = index;
223
- while (end < 8 && w[end] === 0) end += 1;
224
- if (end - index > bestLength) {
225
- bestStart = index;
226
- bestLength = end - index;
227
- }
228
- index = end;
229
- }
230
- if (bestLength < 2) bestStart = -1;
231
- let text = "";
232
- for (let index = 0; index < 8; index += 1) {
233
- if (index === bestStart) {
234
- text += "::";
235
- index += bestLength - 1;
236
- continue;
237
- }
238
- if (text !== "" && !endsWithColons(text)) text += ":";
239
- text += hexText(w[index]);
240
- }
241
- return text;
235
+ let bestStart = -1;
236
+ let bestLength = 0;
237
+ for (let index = 0; index < 8;) {
238
+ if (w[index] !== 0) {
239
+ index += 1;
240
+ continue;
241
+ }
242
+ let end = index;
243
+ while (end < 8 && w[end] === 0) end += 1;
244
+ if (end - index > bestLength) {
245
+ bestStart = index;
246
+ bestLength = end - index;
247
+ }
248
+ index = end;
249
+ }
250
+ if (bestLength < 2) bestStart = -1;
251
+ let text = "";
252
+ for (let index = 0; index < 8; index += 1) {
253
+ if (index === bestStart) {
254
+ text += "::";
255
+ index += bestLength - 1;
256
+ continue;
257
+ }
258
+ if (text !== "" && !endsWithColons(text)) text += ":";
259
+ text += hexText(w[index]);
260
+ }
261
+ return text;
242
262
  }
243
263
  function endsWithColons(text) {
244
- return text.length >= 2 && apply(stringSlice, text, [-2]) === "::";
264
+ return text.length >= 2 && apply(stringSlice$1, text, [-2]) === "::";
245
265
  }
246
- var HEX_DIGITS = "0123456789abcdef";
266
+ const HEX_DIGITS = "0123456789abcdef";
247
267
  function hexText(value) {
248
- if (value === 0) return "0";
249
- let text = "";
250
- for (let rest = value; rest > 0; rest = (rest - rest % 16) / 16) text = HEX_DIGITS[rest % 16] + text;
251
- return text;
268
+ if (value === 0) return "0";
269
+ let text = "";
270
+ for (let rest = value; rest > 0; rest = (rest - rest % 16) / 16) text = HEX_DIGITS[rest % 16] + text;
271
+ return text;
252
272
  }
253
273
  function formatIpv4(value) {
254
- return `${value >>> 24}.${value >>> 16 & 255}.${value >>> 8 & 255}.${value & 255}`;
274
+ return `${value >>> 24}.${value >>> 16 & 255}.${value >>> 8 & 255}.${value & 255}`;
255
275
  }
256
- var NON_PUBLIC_V4 = freeze({ kind: "non_public", family: 4 });
257
- var NON_PUBLIC_V6 = freeze({ kind: "non_public", family: 6 });
258
- var MALFORMED = freeze({ kind: "malformed" });
276
+ const NON_PUBLIC_V4 = freeze({
277
+ kind: "non_public",
278
+ family: 4
279
+ });
280
+ const NON_PUBLIC_V6 = freeze({
281
+ kind: "non_public",
282
+ family: 6
283
+ });
284
+ const MALFORMED = freeze({ kind: "malformed" });
285
+ /** @internal Classify a textual IP address (no brackets). The `address` of a public verdict is canonical. */
259
286
  function classifyAddress(text) {
260
- if (typeof text !== "string" || text.length === 0 || text.length > MAX_TEXT_LENGTH) return MALFORMED;
261
- const zone = apply(stringIndexOf, text, ["%"]);
262
- if (zone !== -1) return parseIpv6(apply(stringSlice, text, [0, zone])) === void 0 ? MALFORMED : NON_PUBLIC_V6;
263
- if (text.length > MAX_ADDRESS_LENGTH) return MALFORMED;
264
- const v4 = parseIpv4(text);
265
- if (v4 !== void 0) {
266
- return isPublicIpv4Value(v4) ? freeze({ kind: "public", address: formatIpv4(v4), family: 4 }) : NON_PUBLIC_V4;
267
- }
268
- const v6 = parseIpv6(text);
269
- if (v6 === void 0) return MALFORMED;
270
- return isPublicIpv6Words(v6) ? freeze({ kind: "public", address: formatIpv6(v6), family: 6 }) : NON_PUBLIC_V6;
287
+ if (typeof text !== "string" || text.length === 0 || text.length > MAX_TEXT_LENGTH) return MALFORMED;
288
+ const zone = apply(stringIndexOf, text, ["%"]);
289
+ if (zone !== -1) return parseIpv6(apply(stringSlice$1, text, [0, zone])) === void 0 ? MALFORMED : NON_PUBLIC_V6;
290
+ if (text.length > MAX_ADDRESS_LENGTH) return MALFORMED;
291
+ const v4 = parseIpv4(text);
292
+ if (v4 !== void 0) return isPublicIpv4Value(v4) ? freeze({
293
+ kind: "public",
294
+ address: formatIpv4(v4),
295
+ family: 4
296
+ }) : NON_PUBLIC_V4;
297
+ const v6 = parseIpv6(text);
298
+ if (v6 === void 0) return MALFORMED;
299
+ return isPublicIpv6Words(v6) ? freeze({
300
+ kind: "public",
301
+ address: formatIpv6(v6),
302
+ family: 6
303
+ }) : NON_PUBLIC_V6;
271
304
  }
305
+ /** @internal `true` for a canonical dotted-quad, the form WHATWG URL parsing gives an IPv4 host. */
272
306
  function isIpv4Literal(text) {
273
- return matches(IPV4_DOTTED, text);
274
- }
275
- var CONFIG_MESSAGES = freeze({
276
- limit_not_positive_finite: "Webhook delivery limit must be a positive, finite number.",
277
- limit_not_integer: "Webhook delivery limit must be a whole number.",
278
- limit_out_of_range: "Webhook delivery limit is outside its allowed range.",
279
- retry_schedule_empty: "Webhook delivery retry schedule must list at least one delay.",
280
- limit_unreadable: "Webhook delivery limits could not be read."
307
+ return matches(IPV4_DOTTED, text);
308
+ }
309
+ freeze({
310
+ invalid_envelope: "Webhook projection failed: a required envelope or job field is missing or invalid.",
311
+ payload_field_not_json: "Webhook projection failed: an allowlisted payload field is not plain JSON.",
312
+ fact_field_not_json: "Webhook projection failed: a declared fact field is not plain JSON.",
313
+ accessor_property: "Webhook projection failed: accessor properties are not read.",
314
+ inspection_failed: "Webhook projection failed: an input could not be inspected.",
315
+ scope_mismatch: "Webhook projection failed: the subscription's scope does not match the event's tenant and space."
316
+ });
317
+ const CONFIG_MESSAGES = freeze({
318
+ limit_not_positive_finite: "Webhook delivery limit must be a positive, finite number.",
319
+ limit_not_integer: "Webhook delivery limit must be a whole number.",
320
+ limit_out_of_range: "Webhook delivery limit is outside its allowed range.",
321
+ retry_schedule_empty: "Webhook delivery retry schedule must list at least one delay.",
322
+ limit_unreadable: "Webhook delivery limits could not be read."
323
+ });
324
+ const INPUT_MESSAGES = freeze({
325
+ input_unreadable: "Webhook delivery input could not be read.",
326
+ observation_unknown: "Webhook delivery observation is not one decision 10 classifies.",
327
+ status_out_of_range: "Webhook response status must be a whole number from 100 to 599.",
328
+ signature_malformed: "Webhook signature must be a v1=<64 lowercase hex> value.",
329
+ timestamp_invalid: "Webhook timestamp must be a non-negative whole number of seconds.",
330
+ event_id_invalid: "Webhook eventId must be printable ASCII with no control characters or surrounding spaces.",
331
+ delivery_id_invalid: "Webhook deliveryId must be printable ASCII with no control characters or surrounding spaces.",
332
+ attempt_invalid: "Webhook attempt must be a positive whole number.",
333
+ raw_body_not_string: "Webhook raw body must be a string.",
334
+ random_source_missing: "createWebhookRetryDelay requires a random source.",
335
+ random_sample_invalid: "Webhook retry random source must return a number in [0, 1).",
336
+ random_source_failed: "Webhook retry random source failed.",
337
+ denial_code_unknown: "Webhook admission denial code is not in WEBHOOK_ADMISSION_DENIAL_CODES."
338
+ });
339
+ freeze({
340
+ input_invalid: "Webhook store input is missing, malformed or not plain data.",
341
+ record_mismatch: "Webhook store record does not match its parent's event, tenant, space or delivery.",
342
+ delivery_id_conflict: "Webhook store deliveryId is already used by another subscription and event.",
343
+ call_aborted: "Webhook store call was aborted before the store acted.",
344
+ deadline_passed: "Webhook store call deadline passed before the store acted.",
345
+ clock_invalid: "Webhook store clock failed or returned an invalid time.",
346
+ store_failed: "Webhook store failed."
281
347
  });
282
- var INPUT_MESSAGES = freeze({
283
- input_unreadable: "Webhook delivery input could not be read.",
284
- observation_unknown: "Webhook delivery observation is not one decision 10 classifies.",
285
- status_out_of_range: "Webhook response status must be a whole number from 100 to 599.",
286
- signature_malformed: "Webhook signature must be a v1=<64 lowercase hex> value.",
287
- timestamp_invalid: "Webhook timestamp must be a non-negative whole number of seconds.",
288
- event_id_invalid: "Webhook eventId must be printable ASCII with no control characters or surrounding spaces.",
289
- delivery_id_invalid: "Webhook deliveryId must be printable ASCII with no control characters or surrounding spaces.",
290
- attempt_invalid: "Webhook attempt must be a positive whole number.",
291
- raw_body_not_string: "Webhook raw body must be a string.",
292
- random_source_missing: "createWebhookRetryDelay requires a random source.",
293
- random_sample_invalid: "Webhook retry random source must return a number in [0, 1).",
294
- random_source_failed: "Webhook retry random source failed.",
295
- denial_code_unknown: "Webhook admission denial code is not in WEBHOOK_ADMISSION_DENIAL_CODES."
348
+ freeze({
349
+ event_past_replay_horizon: "Webhook fan-out refused the event: it is older than the replay horizon, so no fan-out job can be stored.",
350
+ fan_out_store_failed: "Webhook fan-out store call failed.",
351
+ fan_out_store_timeout: "Webhook fan-out store call did not settle in time.",
352
+ publish_aborted: "Webhook fan-out publish was aborted before the job was stored.",
353
+ sink_failed: "A required sink of the composite event publisher failed.",
354
+ sink_timeout: "A required sink of the composite event publisher did not settle in time.",
355
+ clock_invalid: "Webhook fan-out clock failed or returned an invalid time.",
356
+ options_invalid: "Webhook fan-out options are missing or malformed."
296
357
  });
358
+ freeze({
359
+ delivery_store_failed: "Webhook delivery store call failed.",
360
+ delivery_store_timeout: "Webhook delivery store call did not settle in time.",
361
+ clock_invalid: "Webhook delivery clock failed or returned an invalid time.",
362
+ options_invalid: "Webhook delivery options are missing or malformed."
363
+ });
364
+ freeze({ options_invalid: "Webhook governed-action module options are missing or malformed." });
297
365
  function messageFor(table, code, fallback) {
298
- return typeof code === "string" && hasOwn(table, code) ? table[code] : fallback;
366
+ return typeof code === "string" && hasOwn(table, code) ? table[code] : fallback;
299
367
  }
300
- var reflectDefineProperty2 = Reflect.defineProperty;
301
- var objectCreate2 = Object.create;
368
+ const reflectDefineProperty = Reflect.defineProperty;
369
+ const objectCreate = Object.create;
370
+ /**
371
+ * An own, enumerable, writable data property, defined with a null-prototype
372
+ * descriptor so neither `Error.prototype` nor `Object.prototype` is consulted.
373
+ * Errors the package throws are frozen afterwards.
374
+ */
302
375
  function defineField(target, key, value) {
303
- const descriptor = objectCreate2(null);
304
- descriptor.value = value;
305
- descriptor.enumerable = true;
306
- descriptor.writable = true;
307
- descriptor.configurable = true;
308
- reflectDefineProperty2(target, key, descriptor);
376
+ const descriptor = objectCreate(null);
377
+ descriptor.value = value;
378
+ descriptor.enumerable = true;
379
+ descriptor.writable = true;
380
+ descriptor.configurable = true;
381
+ reflectDefineProperty(target, key, descriptor);
309
382
  }
383
+ /**
384
+ * A configured limit was not usable: zero, negative, `NaN`, infinite, not an
385
+ * integer where a count is required, outside its documented range, or not
386
+ * readable as plain data. The message is constant for the code; `field`
387
+ * names the limit, for example `deliveryRetryDelaysMs[2]`.
388
+ */
310
389
  var WebhookDeliveryConfigError = class extends Error {
311
- constructor(code, field) {
312
- super(messageFor(CONFIG_MESSAGES, code, "Webhook delivery limit was rejected."));
313
- defineField(this, "name", "WebhookDeliveryConfigError");
314
- defineField(this, "code", code);
315
- defineField(this, "field", field);
316
- }
390
+ constructor(code, field) {
391
+ super(messageFor(CONFIG_MESSAGES, code, "Webhook delivery limit was rejected."));
392
+ defineField(this, "name", "WebhookDeliveryConfigError");
393
+ defineField(this, "code", code);
394
+ defineField(this, "field", field);
395
+ }
317
396
  };
318
- var created = /* @__PURE__ */ new WeakSet();
319
- var weakSetAdd = WeakSet.prototype.add;
320
- var weakSetHas = WeakSet.prototype.has;
321
- var TypeErrorConstructor = TypeError;
397
+ const created = /* @__PURE__ */ new WeakSet();
398
+ const weakSetAdd = WeakSet.prototype.add;
399
+ const weakSetHas = WeakSet.prototype.has;
400
+ const TypeErrorConstructor = TypeError;
401
+ const RangeErrorConstructor = RangeError;
402
+ /**
403
+ * Register a factory-made error and freeze it. Its native `stack` is
404
+ * replaced first with fixed package text: V8 frames name the functions on
405
+ * the call stack, and a caller can name its own function (a Proxy trap, a
406
+ * getter, a callback that calls a package helper) after a secret. Replacing
407
+ * it before anything reads it also means `Error.prepareStackTrace` is never
408
+ * consulted for a package error.
409
+ */
322
410
  function mark(error, name, code) {
323
- const stack = objectCreate2(null);
324
- stack.value = `${name}: ${code}`;
325
- stack.enumerable = false;
326
- stack.writable = false;
327
- stack.configurable = false;
328
- if (!reflectDefineProperty2(error, "stack", stack)) throw new TypeErrorConstructor("Webhook delivery could not seal an error.");
329
- apply(weakSetAdd, created, [error]);
330
- return freeze(error);
411
+ const stack = objectCreate(null);
412
+ stack.value = `${name}: ${code}`;
413
+ stack.enumerable = false;
414
+ stack.writable = false;
415
+ stack.configurable = false;
416
+ if (!reflectDefineProperty(error, "stack", stack)) throw new TypeErrorConstructor("Webhook delivery could not seal an error.");
417
+ apply(weakSetAdd, created, [error]);
418
+ return freeze(error);
331
419
  }
420
+ /** `true` only for an error one of this module's factories created. Runs no code of `value`. */
332
421
  function isPackageError(value) {
333
- return (typeof value === "object" || typeof value === "function") && value !== null && apply(weakSetHas, created, [value]) === true;
422
+ return (typeof value === "object" || typeof value === "function") && value !== null && apply(weakSetHas, created, [value]) === true;
334
423
  }
424
+ /** @internal A package-created, frozen limit error. */
335
425
  function configError(code, field) {
336
- return mark(new WebhookDeliveryConfigError(code, field), "WebhookDeliveryConfigError", code);
426
+ return mark(new WebhookDeliveryConfigError(code, field), "WebhookDeliveryConfigError", code);
337
427
  }
428
+ /** @internal A package-created, frozen `TypeError` or `RangeError` carrying `code`. */
338
429
  function inputError(kind, code) {
339
- const message = INPUT_MESSAGES[code];
340
- const error = new TypeErrorConstructor(message) ;
341
- define(error, "code", code);
342
- return mark(error, "TypeError" , code);
430
+ const message = INPUT_MESSAGES[code];
431
+ const error = kind === "type" ? new TypeErrorConstructor(message) : new RangeErrorConstructor(message);
432
+ define(error, "code", code);
433
+ return mark(error, kind === "type" ? "TypeError" : "RangeError", code);
343
434
  }
435
+ /**
436
+ * @internal Run an entry point. A package-created error passes through
437
+ * unchanged; anything else thrown (by a Proxy trap, an injected callback or
438
+ * the engine) is never inspected and is replaced by `replacement()`.
439
+ */
344
440
  function guard(run, replacement) {
345
- try {
346
- return run();
347
- } catch (thrown) {
348
- if (isPackageError(thrown)) throw thrown;
349
- throw replacement();
350
- }
351
- }
352
- var WEBHOOK_MAX_TIMER_MS = 2147483647;
441
+ try {
442
+ return run();
443
+ } catch (thrown) {
444
+ if (isPackageError(thrown)) throw thrown;
445
+ throw replacement();
446
+ }
447
+ }
448
+ //#endregion
449
+ //#region src/limits.ts
450
+ const MINUTE = 6e4;
451
+ const HOUR = 60 * MINUTE;
452
+ const DAY = 24 * HOUR;
453
+ /** The largest delay a JavaScript timer accepts without overflowing. */
454
+ const WEBHOOK_MAX_TIMER_MS = 2147483647;
455
+ Object.freeze({
456
+ maxDeliveryAttempts: 8,
457
+ deliveryRetryDelaysMs: Object.freeze([
458
+ MINUTE,
459
+ 5 * MINUTE,
460
+ 15 * MINUTE,
461
+ HOUR,
462
+ 6 * HOUR,
463
+ 12 * HOUR,
464
+ 24 * HOUR
465
+ ]),
466
+ deliveryDeadlineMs: 72 * HOUR,
467
+ maxFanOutAttempts: 24,
468
+ fanOutRetryDelaysMs: Object.freeze([
469
+ 1e3,
470
+ 5e3,
471
+ 3e4,
472
+ MINUTE,
473
+ 5 * MINUTE,
474
+ 15 * MINUTE
475
+ ]),
476
+ fanOutDeadlineMs: 24 * HOUR,
477
+ attemptTimeoutMs: 15e3,
478
+ portTimeoutMs: 5e3,
479
+ retryJitterRatio: .1,
480
+ maxRetryAfterMs: HOUR,
481
+ replayHorizonMs: 30 * DAY
482
+ });
483
+ Object.freeze([
484
+ "maxDeliveryAttempts",
485
+ "deliveryRetryDelaysMs",
486
+ "deliveryDeadlineMs",
487
+ "maxFanOutAttempts",
488
+ "fanOutRetryDelaysMs",
489
+ "fanOutDeadlineMs",
490
+ "attemptTimeoutMs",
491
+ "portTimeoutMs",
492
+ "retryJitterRatio",
493
+ "maxRetryAfterMs",
494
+ "replayHorizonMs"
495
+ ]);
496
+ /** @internal `value` must come from a snapshot (a primitive). */
353
497
  function assertPositiveFinite(value, field) {
354
- if (typeof value !== "number" || !numberIsFinite(value) || value <= 0) {
355
- throw configError("limit_not_positive_finite", field);
356
- }
498
+ if (typeof value !== "number" || !numberIsFinite(value) || value <= 0) throw configError("limit_not_positive_finite", field);
357
499
  }
500
+ /** @internal */
358
501
  function assertPositiveInteger(value, field) {
359
- assertPositiveFinite(value, field);
360
- if (!numberIsSafeInteger(value)) {
361
- throw configError("limit_not_integer", field);
362
- }
502
+ assertPositiveFinite(value, field);
503
+ if (!numberIsSafeInteger(value)) throw configError("limit_not_integer", field);
363
504
  }
364
-
365
- // src/call-bounds.ts
366
- var reflectGetOwnPropertyDescriptor2 = Reflect.getOwnPropertyDescriptor;
367
- var abortedGetter = typeof AbortSignal === "function" ? reflectGetOwnPropertyDescriptor2(AbortSignal.prototype, "aborted")?.get : void 0;
368
- var eventTargetAdd = typeof EventTarget === "function" ? EventTarget.prototype.addEventListener : void 0;
369
- var eventTargetRemove = typeof EventTarget === "function" ? EventTarget.prototype.removeEventListener : void 0;
370
- var setTimer = setTimeout;
371
- var clearTimer = clearTimeout;
372
- var dateNow = Date.now;
373
- var mathMax = Math.max;
374
- var mathMin = Math.min;
375
- var unreadable = () => inputError("type", "input_unreadable");
376
- var unreadableFail = () => {
377
- throw unreadable();
505
+ //#endregion
506
+ //#region src/call-bounds.ts
507
+ const reflectGetOwnPropertyDescriptor = Reflect.getOwnPropertyDescriptor;
508
+ const abortedGetter = typeof AbortSignal === "function" ? reflectGetOwnPropertyDescriptor(AbortSignal.prototype, "aborted")?.get : void 0;
509
+ const eventTargetAdd = typeof EventTarget === "function" ? EventTarget.prototype.addEventListener : void 0;
510
+ const eventTargetRemove = typeof EventTarget === "function" ? EventTarget.prototype.removeEventListener : void 0;
511
+ const setTimer = setTimeout;
512
+ const clearTimer = clearTimeout;
513
+ const dateNow = Date.now;
514
+ const mathMax = Math.max;
515
+ const mathMin = Math.min;
516
+ const unreadable$2 = () => inputError("type", "input_unreadable");
517
+ const unreadableFail$2 = () => {
518
+ throw unreadable$2();
378
519
  };
520
+ /**
521
+ * @internal Read `{ deadline, signal }` at entry, one descriptor read each.
522
+ * The deadline must be a real `Date` with a finite time and the signal a real
523
+ * `AbortSignal`; anything else throws `input_unreadable`.
524
+ */
379
525
  function readCallBounds(options) {
380
- if (options === null || typeof options !== "object") throw unreadable();
381
- const deadlineMs = timeOf(readOwn(options, "deadline", "deadline", unreadableFail));
382
- if (!(deadlineMs === deadlineMs) || deadlineMs === Infinity || deadlineMs === -Infinity) throw unreadable();
383
- const signal = readOwn(options, "signal", "signal", unreadableFail);
384
- if (signal === null || typeof signal !== "object") throw unreadable();
385
- try {
386
- isAborted(signal);
387
- } catch {
388
- throw unreadable();
389
- }
390
- return { deadlineMs, signal };
526
+ if (options === null || typeof options !== "object") throw unreadable$2();
527
+ const deadlineMs = timeOf(readOwn(options, "deadline", "deadline", unreadableFail$2));
528
+ if (!(deadlineMs === deadlineMs) || deadlineMs === Infinity || deadlineMs === -Infinity) throw unreadable$2();
529
+ const signal = readOwn(options, "signal", "signal", unreadableFail$2);
530
+ if (signal === null || typeof signal !== "object") throw unreadable$2();
531
+ try {
532
+ isAborted(signal);
533
+ } catch {
534
+ throw unreadable$2();
535
+ }
536
+ return {
537
+ deadlineMs,
538
+ signal
539
+ };
391
540
  }
541
+ /**
542
+ * @internal Whether a real `AbortSignal` has aborted, read through the
543
+ * intrinsic getter (it throws for anything else and runs none of its code).
544
+ */
392
545
  function isAborted(signal) {
393
- if (abortedGetter === void 0) throw unreadable();
394
- return apply(abortedGetter, signal, []) === true;
546
+ if (abortedGetter === void 0) throw unreadable$2();
547
+ return apply(abortedGetter, signal, []) === true;
395
548
  }
549
+ /** @internal Call `listener` once when `signal` aborts; the returned function removes it. */
396
550
  function onAbort(signal, listener) {
397
- if (eventTargetAdd === void 0 || eventTargetRemove === void 0) throw unreadable();
398
- apply(eventTargetAdd, signal, ["abort", listener, { once: true }]);
399
- return () => {
400
- apply(eventTargetRemove, signal, ["abort", listener]);
401
- };
551
+ if (eventTargetAdd === void 0 || eventTargetRemove === void 0) throw unreadable$2();
552
+ apply(eventTargetAdd, signal, [
553
+ "abort",
554
+ listener,
555
+ { once: true }
556
+ ]);
557
+ return () => {
558
+ apply(eventTargetRemove, signal, ["abort", listener]);
559
+ };
402
560
  }
561
+ /** @internal Capture an optional {@link WebhookClock}; a non-object or a missing `now` throws `input_unreadable`. */
403
562
  function captureOptionalClock(clock) {
404
- if (clock === void 0) return { target: void 0, now: void 0 };
405
- if (clock === null || typeof clock !== "object") throw unreadable();
406
- const now = clock.now;
407
- if (typeof now !== "function") throw unreadable();
408
- return { target: clock, now };
563
+ if (clock === void 0) return {
564
+ target: void 0,
565
+ now: void 0
566
+ };
567
+ if (clock === null || typeof clock !== "object") throw unreadable$2();
568
+ const now = clock.now;
569
+ if (typeof now !== "function") throw unreadable$2();
570
+ return {
571
+ target: clock,
572
+ now
573
+ };
409
574
  }
575
+ /** @internal Epoch milliseconds from the clock, or `NaN` when it throws or returns no valid `Date`. Never throws. */
410
576
  function clockNowMs(clock) {
411
- if (clock.now === void 0) return dateNow();
412
- try {
413
- const ms = timeOf(apply(clock.now, clock.target, []));
414
- return ms === Infinity || ms === -Infinity ? NaN : ms;
415
- } catch {
416
- return NaN;
417
- }
577
+ if (clock.now === void 0) return dateNow();
578
+ try {
579
+ const ms = timeOf(apply(clock.now, clock.target, []));
580
+ return ms === Infinity || ms === -Infinity ? NaN : ms;
581
+ } catch {
582
+ return NaN;
583
+ }
418
584
  }
585
+ /**
586
+ * @internal Run `fire` after `ms`, clamped to `[0, WEBHOOK_MAX_TIMER_MS]` so a
587
+ * far deadline cannot overflow into an immediate timer. Returns a cancel
588
+ * function.
589
+ */
419
590
  function startTimer(ms, fire) {
420
- const handle = setTimer(fire, mathMax(0, mathMin(ms, WEBHOOK_MAX_TIMER_MS)));
421
- return () => {
422
- clearTimer(handle);
423
- };
591
+ const handle = setTimer(fire, mathMax(0, mathMin(ms, WEBHOOK_MAX_TIMER_MS)));
592
+ return () => {
593
+ clearTimer(handle);
594
+ };
424
595
  }
425
-
426
- // src/destination.ts
427
- var WEBHOOK_DESTINATION_MAX_URL_LENGTH = 2048;
428
- var URLConstructor = URL;
429
- var urlGetter = (name) => {
430
- const getter = Reflect.getOwnPropertyDescriptor(URL.prototype, name)?.get;
431
- if (getter === void 0) throw new TypeError(`URL.prototype.${name} is not an accessor.`);
432
- return getter;
596
+ const URLConstructor = URL;
597
+ const urlGetter = (name) => {
598
+ const getter = Reflect.getOwnPropertyDescriptor(URL.prototype, name)?.get;
599
+ if (getter === void 0) throw new TypeError(`URL.prototype.${name} is not an accessor.`);
600
+ return getter;
433
601
  };
434
- var urlProtocol = urlGetter("protocol");
435
- var urlUsername = urlGetter("username");
436
- var urlPassword = urlGetter("password");
437
- var urlPort = urlGetter("port");
438
- var urlHostname = urlGetter("hostname");
439
- var urlPathname = urlGetter("pathname");
440
- var urlSearch = urlGetter("search");
441
- var stringSlice2 = String.prototype.slice;
442
- var stringEndsWith = String.prototype.endsWith;
602
+ const urlProtocol = urlGetter("protocol");
603
+ const urlUsername = urlGetter("username");
604
+ const urlPassword = urlGetter("password");
605
+ const urlPort = urlGetter("port");
606
+ const urlHostname = urlGetter("hostname");
607
+ const urlPathname = urlGetter("pathname");
608
+ const urlSearch = urlGetter("search");
609
+ const stringSlice = String.prototype.slice;
610
+ const stringEndsWith = String.prototype.endsWith;
611
+ Promise.prototype.then;
612
+ AbortController.prototype.abort;
443
613
  Reflect.getOwnPropertyDescriptor(AbortController.prototype, "signal").get;
444
- var URL_TEXT = /^[^\x00-\x20\x7f]+$/;
445
- var URL_PREFIX = /^https:\/\/[^/\\?#@]/i;
446
- var INVALID_URL = freeze({ ok: false, code: "invalid_url" });
447
- var PRIVATE_URL = freeze({ ok: false, code: "private_address" });
614
+ /** No ASCII control character or space anywhere: WHATWG parsing would strip or drop them silently. */
615
+ const URL_TEXT = /^[^\x00-\x20\x7f]+$/;
616
+ /**
617
+ * `https://` then a host character. WHATWG parsing also accepts
618
+ * `https:host`, `https:///host` and backslashes for a special scheme and
619
+ * finds a host in them; requiring the plain form keeps the host an operator
620
+ * sees in the URL the one that is checked.
621
+ */
622
+ const URL_PREFIX = /^https:\/\/[^/\\?#@]/i;
623
+ const INVALID_URL$1 = freeze({
624
+ ok: false,
625
+ code: "invalid_url"
626
+ });
627
+ const PRIVATE_URL = freeze({
628
+ ok: false,
629
+ code: "private_address"
630
+ });
631
+ /**
632
+ * @internal {@link checkWebhookDestinationUrl}, optionally accepting a
633
+ * non-public host (an IP literal or a `localhost` name) while every other
634
+ * rule still applies. `true` is passed only when the Node transport was built
635
+ * by the internal test factory with its public-address re-check off.
636
+ */
448
637
  function checkDestinationUrl(url, allowNonPublic) {
449
- try {
450
- return checkUrl(primitive(url), allowNonPublic);
451
- } catch {
452
- return INVALID_URL;
453
- }
638
+ try {
639
+ return checkUrl(primitive(url), allowNonPublic);
640
+ } catch {
641
+ return INVALID_URL$1;
642
+ }
454
643
  }
455
644
  function checkUrl(text, allowNonPublic) {
456
- if (typeof text !== "string" || text.length === 0 || text.length > WEBHOOK_DESTINATION_MAX_URL_LENGTH) return INVALID_URL;
457
- if (!matches(URL_TEXT, text) || !matches(URL_PREFIX, text)) return INVALID_URL;
458
- let parsed;
459
- try {
460
- parsed = new URLConstructor(text);
461
- } catch {
462
- return INVALID_URL;
463
- }
464
- if (apply(urlProtocol, parsed, []) !== "https:") return INVALID_URL;
465
- if (apply(urlUsername, parsed, []) !== "" || apply(urlPassword, parsed, []) !== "") return INVALID_URL;
466
- if (apply(urlPort, parsed, []) !== "") return INVALID_URL;
467
- const host = apply(urlHostname, parsed, []);
468
- if (host === "" || apply(stringEndsWith, host, ["."])) return INVALID_URL;
469
- const url = `https://${host}${apply(urlPathname, parsed, [])}${apply(urlSearch, parsed, [])}`;
470
- const v6 = host[0] === "[";
471
- if (v6 || isIpv4Literal(host)) {
472
- const text2 = v6 ? apply(stringSlice2, host, [1, -1]) : host;
473
- const literal = classifyAddress(text2);
474
- if (literal.kind === "malformed") return INVALID_URL;
475
- if (literal.kind === "non_public" && !allowNonPublic) return PRIVATE_URL;
476
- const family = v6 ? 6 : 4;
477
- return record({ ok: true, url, hostname: text2, literal: record({ address: text2, family }) });
478
- }
479
- if (!allowNonPublic && (host === "localhost" || apply(stringEndsWith, host, [".localhost"]))) return PRIVATE_URL;
480
- return record({ ok: true, url, hostname: host });
645
+ if (typeof text !== "string" || text.length === 0 || text.length > 2048) return INVALID_URL$1;
646
+ if (!matches(URL_TEXT, text) || !matches(URL_PREFIX, text)) return INVALID_URL$1;
647
+ let parsed;
648
+ try {
649
+ parsed = new URLConstructor(text);
650
+ } catch {
651
+ return INVALID_URL$1;
652
+ }
653
+ if (apply(urlProtocol, parsed, []) !== "https:") return INVALID_URL$1;
654
+ if (apply(urlUsername, parsed, []) !== "" || apply(urlPassword, parsed, []) !== "") return INVALID_URL$1;
655
+ if (apply(urlPort, parsed, []) !== "") return INVALID_URL$1;
656
+ const host = apply(urlHostname, parsed, []);
657
+ if (host === "" || apply(stringEndsWith, host, ["."])) return INVALID_URL$1;
658
+ const url = `https://${host}${apply(urlPathname, parsed, [])}${apply(urlSearch, parsed, [])}`;
659
+ const v6 = host[0] === "[";
660
+ if (v6 || isIpv4Literal(host)) {
661
+ const text = v6 ? apply(stringSlice, host, [1, -1]) : host;
662
+ const literal = classifyAddress(text);
663
+ if (literal.kind === "malformed") return INVALID_URL$1;
664
+ if (literal.kind === "non_public" && !allowNonPublic) return PRIVATE_URL;
665
+ return record({
666
+ ok: true,
667
+ url,
668
+ hostname: text,
669
+ literal: record({
670
+ address: text,
671
+ family: v6 ? 6 : 4
672
+ })
673
+ });
674
+ }
675
+ if (!allowNonPublic && (host === "localhost" || apply(stringEndsWith, host, [".localhost"]))) return PRIVATE_URL;
676
+ return record({
677
+ ok: true,
678
+ url,
679
+ hostname: host
680
+ });
481
681
  }
482
-
483
- // src/node/transport.ts
484
- var DEFAULT_NODE_WEBHOOK_MAX_RESPONSE_BYTES = 65536;
485
- var DEFAULT_NODE_WEBHOOK_MAX_CONCURRENT_REQUESTS = 16;
486
- var MAX_CONCURRENT_REQUESTS_LIMIT = 1024;
487
- var MAX_HEADERS = 64;
488
- var MAX_RETRY_AFTER_LENGTH = 128;
489
- var MAX_RESPONSE_HEADER_BYTES = 16384;
490
- var unreadable2 = () => inputError("type", "input_unreadable");
491
- var unreadableFail2 = () => {
492
- throw unreadable2();
682
+ freeze({
683
+ ok: false,
684
+ code: "dns_failure"
685
+ });
686
+ freeze({
687
+ ok: false,
688
+ code: "private_address"
689
+ });
690
+ //#endregion
691
+ //#region src/node/transport.ts
692
+ /** The default response body cap: past it the connection is closed (the crossing chunk is already read). */
693
+ const DEFAULT_NODE_WEBHOOK_MAX_RESPONSE_BYTES = 65536;
694
+ /** The default number of requests one transport runs at once; later calls wait in its queue. */
695
+ const DEFAULT_NODE_WEBHOOK_MAX_CONCURRENT_REQUESTS = 16;
696
+ const MAX_CONCURRENT_REQUESTS_LIMIT = 1024;
697
+ const MAX_HEADERS = 64;
698
+ const MAX_RETRY_AFTER_LENGTH = 128;
699
+ const MAX_RESPONSE_HEADER_BYTES = 16384;
700
+ const unreadable$1 = () => inputError("type", "input_unreadable");
701
+ const unreadableFail$1 = () => {
702
+ throw unreadable$1();
493
703
  };
494
- var PromiseConstructor = Promise;
495
- var bufferFrom = buffer.Buffer.from;
496
- var NumberConstructor = Number;
497
- var HEADER_NAME = /^[!#$%&'*+.^_`|~0-9A-Za-z-]+$/;
498
- var HEADER_VALUE = /^[\t\x20-\x7e]*$/;
499
- var RESERVED_HEADER = /^(?:host|content-length|connection|transfer-encoding|keep-alive|upgrade|te|expect|proxy-.*)$/i;
500
- var DECIMAL = /^\d+$/;
501
- var NOT_SENT_DEADLINE = freeze({ kind: "not_sent", reason: "deadline_expired" });
502
- var NOT_SENT_ABORTED = freeze({ kind: "not_sent", reason: "aborted" });
503
- var TIMEOUT = freeze({ kind: "timeout" });
504
- var NETWORK_ERROR = freeze({ kind: "network_error" });
505
- var INVALID_URL2 = freeze({ kind: "invalid_url" });
506
- var PRIVATE_ADDRESS2 = freeze({ kind: "private_address" });
704
+ const PromiseConstructor = Promise;
705
+ const bufferFrom = buffer.Buffer.from;
706
+ const NumberConstructor = Number;
707
+ /** RFC 9110 token characters. */
708
+ const HEADER_NAME = /^[!#$%&'*+.^_`|~0-9A-Za-z-]+$/;
709
+ /** Visible ASCII, space and tab: no CR, LF, NUL or other control characters. */
710
+ const HEADER_VALUE = /^[\t\x20-\x7e]*$/;
711
+ /** Header names the transport sets itself; a caller's copy is dropped. */
712
+ const RESERVED_HEADER = /^(?:host|content-length|connection|transfer-encoding|keep-alive|upgrade|te|expect|proxy-.*)$/i;
713
+ const DECIMAL = /^\d+$/;
714
+ const NOT_SENT_DEADLINE = freeze({
715
+ kind: "not_sent",
716
+ reason: "deadline_expired"
717
+ });
718
+ const NOT_SENT_ABORTED = freeze({
719
+ kind: "not_sent",
720
+ reason: "aborted"
721
+ });
722
+ const TIMEOUT = freeze({ kind: "timeout" });
723
+ const NETWORK_ERROR = freeze({ kind: "network_error" });
724
+ const INVALID_URL = freeze({ kind: "invalid_url" });
725
+ const PRIVATE_ADDRESS = freeze({ kind: "private_address" });
726
+ /**
727
+ * The Node `WebhookTransport` (ADR 0018 decision 6, R3, R8).
728
+ *
729
+ * - **Pinned addresses.** It connects only to `destination.addresses`,
730
+ * through a lookup function that answers with those addresses and nothing
731
+ * else; it never resolves the hostname. The hostname is kept for SNI (left
732
+ * out for an IP literal, as RFC 6066 requires), certificate verification and
733
+ * the `Host` header. Certificate and hostname verification are always on.
734
+ * - **Re-checked destination.** It refuses as `private_address` a destination with no addresses
735
+ * or any address that is not public, and as `invalid_url` one whose URL
736
+ * breaks decision 6's rules or whose hostname does not match it. Nothing is
737
+ * sent.
738
+ * - **No redirects.** A 3xx is returned as a response for the classifier;
739
+ * `Location` is never followed.
740
+ * - **Bounded response.** Body bytes are counted and discarded as they
741
+ * arrive. As soon as the count passes `maxResponseBytes`, or a declared
742
+ * `Content-Length` exceeds it, the connection is closed. The chunk that
743
+ * crosses the cap has already been read, so the bytes read can exceed the
744
+ * cap by up to one chunk as the socket delivered it. Only the status and a
745
+ * `Retry-After` of at most 128 characters are returned; once the status
746
+ * has arrived, the result is that response whatever happens to the body.
747
+ * - **Deadline and cancellation.** A call whose signal has already aborted,
748
+ * or whose deadline has passed, returns `not_sent` without connecting. A
749
+ * call waiting in the queue that is aborted, or whose deadline passes, is
750
+ * removed and returns `not_sent` without ever starting; the same check runs
751
+ * again immediately before the connection is opened. Once started, the
752
+ * request is destroyed at the deadline or on abort and returns `timeout`
753
+ * (or the response, if its status had arrived).
754
+ *
755
+ * Each request uses its own connection (`agent: false`, `Connection:
756
+ * close`), so no pooled socket opened for an earlier resolution is reused.
757
+ * Transport failures (refused connection, TLS or certificate failure, reset)
758
+ * are `network_error`; nothing is logged.
759
+ *
760
+ * @throws {TypeError} `input_unreadable` at construction for unreadable
761
+ * options or `ca`, and from `send` (as a rejected promise) when the request
762
+ * or `{ deadline, signal }` cannot be read: no destination record, a
763
+ * non-string body, a header name or value that is not header-safe, more than
764
+ * 64 headers, or a deadline and signal that are not a real `Date` and
765
+ * `AbortSignal`.
766
+ * @throws {WebhookDeliveryConfigError} when `maxResponseBytes` or
767
+ * `maxConcurrentRequests` (at most 1024) is not a positive whole number.
768
+ */
507
769
  function createNodeWebhookTransport(options = {}) {
508
- return buildTransport(guard(() => readTransportOptions(options, PRODUCTION_SWITCHES), unreadable2));
770
+ return buildTransport(guard(() => readTransportOptions(options, PRODUCTION_SWITCHES), unreadable$1));
509
771
  }
510
- var PRODUCTION_SWITCHES = freeze({ allowNonPublicAddresses: false, port: 443 });
772
+ /** What the public constructor always uses: the public-address re-check on, port 443. */
773
+ const PRODUCTION_SWITCHES = freeze({
774
+ allowNonPublicAddresses: false,
775
+ port: 443
776
+ });
777
+ /** @internal Build a transport from validated settings. Not exported from any package entry. */
511
778
  function buildTransport(settings) {
512
- const slots = { active: 0, pumping: false, head: void 0, tail: void 0 };
513
- const transport = {
514
- send(request, callOptions) {
515
- let bounds;
516
- let prepared;
517
- try {
518
- bounds = readCallBounds(callOptions);
519
- prepared = prepareRequest(request, settings);
520
- } catch {
521
- return PromiseConstructor.reject(unreadable2());
522
- }
523
- if ("kind" in prepared) return PromiseConstructor.resolve(prepared);
524
- const refused = notWanted(bounds, settings.clock);
525
- if (refused !== void 0) return PromiseConstructor.resolve(refused);
526
- return dispatch(slots, settings, prepared, bounds);
527
- }
528
- };
529
- return freeze(transport);
779
+ const slots = {
780
+ active: 0,
781
+ pumping: false,
782
+ head: void 0,
783
+ tail: void 0
784
+ };
785
+ return freeze({ send(request, callOptions) {
786
+ let bounds;
787
+ let prepared;
788
+ try {
789
+ bounds = readCallBounds(callOptions);
790
+ prepared = prepareRequest(request, settings);
791
+ } catch {
792
+ return PromiseConstructor.reject(unreadable$1());
793
+ }
794
+ if ("kind" in prepared) return PromiseConstructor.resolve(prepared);
795
+ const refused = notWanted(bounds, settings.clock);
796
+ if (refused !== void 0) return PromiseConstructor.resolve(refused);
797
+ return dispatch(slots, settings, prepared, bounds);
798
+ } });
530
799
  }
800
+ /**
801
+ * @internal Read the public options by name, one descriptor read each; no
802
+ * other key of `options` is read, so a test switch placed on it has no
803
+ * effect. The switches come from the caller as a separate argument.
804
+ */
531
805
  function readTransportOptions(options, switches) {
532
- if (!isPlainRecord(options)) throw unreadable2();
533
- const rawMax = primitive(readOwn(options, "maxResponseBytes", "maxResponseBytes", unreadableFail2));
534
- const maxResponseBytes = rawMax === void 0 ? DEFAULT_NODE_WEBHOOK_MAX_RESPONSE_BYTES : rawMax;
535
- assertPositiveInteger(maxResponseBytes, "maxResponseBytes");
536
- const rawConcurrency = primitive(readOwn(options, "maxConcurrentRequests", "maxConcurrentRequests", unreadableFail2));
537
- const maxConcurrentRequests = rawConcurrency === void 0 ? DEFAULT_NODE_WEBHOOK_MAX_CONCURRENT_REQUESTS : rawConcurrency;
538
- assertPositiveInteger(maxConcurrentRequests, "maxConcurrentRequests");
539
- if (maxConcurrentRequests > MAX_CONCURRENT_REQUESTS_LIMIT) throw configError("limit_out_of_range", "maxConcurrentRequests");
540
- const ca = readCa(readOwn(options, "ca", "ca", unreadableFail2));
541
- const clock = captureOptionalClock(readOwn(options, "clock", "clock", unreadableFail2));
542
- return freeze({
543
- maxResponseBytes,
544
- maxConcurrentRequests,
545
- ca,
546
- clock,
547
- allowNonPublic: switches.allowNonPublicAddresses === true,
548
- port: switches.port
549
- });
806
+ if (!isPlainRecord(options)) throw unreadable$1();
807
+ const rawMax = primitive(readOwn(options, "maxResponseBytes", "maxResponseBytes", unreadableFail$1));
808
+ const maxResponseBytes = rawMax === void 0 ? DEFAULT_NODE_WEBHOOK_MAX_RESPONSE_BYTES : rawMax;
809
+ assertPositiveInteger(maxResponseBytes, "maxResponseBytes");
810
+ const rawConcurrency = primitive(readOwn(options, "maxConcurrentRequests", "maxConcurrentRequests", unreadableFail$1));
811
+ const maxConcurrentRequests = rawConcurrency === void 0 ? 16 : rawConcurrency;
812
+ assertPositiveInteger(maxConcurrentRequests, "maxConcurrentRequests");
813
+ if (maxConcurrentRequests > MAX_CONCURRENT_REQUESTS_LIMIT) throw configError("limit_out_of_range", "maxConcurrentRequests");
814
+ const ca = readCa(readOwn(options, "ca", "ca", unreadableFail$1));
815
+ const clock = captureOptionalClock(readOwn(options, "clock", "clock", unreadableFail$1));
816
+ return freeze({
817
+ maxResponseBytes,
818
+ maxConcurrentRequests,
819
+ ca,
820
+ clock,
821
+ allowNonPublic: switches.allowNonPublicAddresses === true,
822
+ port: switches.port
823
+ });
550
824
  }
551
825
  function readCa(value) {
552
- if (value === void 0) return void 0;
553
- if (typeof value === "string") return value === "" ? unreadableFail2() : frozenList([value]);
554
- if (!isArray(value)) throw unreadable2();
555
- const length = readOwn(value, "length", "ca", unreadableFail2);
556
- if (typeof length !== "number" || !numberIsSafeInteger(length) || length < 1 || length > 1024) throw unreadable2();
557
- const copy = [];
558
- for (let index = 0; index < length; index += 1) {
559
- const item = readOwn(value, `${index}`, "ca", unreadableFail2);
560
- if (typeof item !== "string" || item === "") throw unreadable2();
561
- copy[copy.length] = item;
562
- }
563
- return frozenList(copy);
826
+ if (value === void 0) return void 0;
827
+ if (typeof value === "string") return value === "" ? unreadableFail$1("not_plain", "ca") : frozenList([value]);
828
+ if (!isArray(value)) throw unreadable$1();
829
+ const length = readOwn(value, "length", "ca", unreadableFail$1);
830
+ if (typeof length !== "number" || !numberIsSafeInteger(length) || length < 1 || length > 1024) throw unreadable$1();
831
+ const copy = [];
832
+ for (let index = 0; index < length; index += 1) {
833
+ const item = readOwn(value, `${index}`, "ca", unreadableFail$1);
834
+ if (typeof item !== "string" || item === "") throw unreadable$1();
835
+ copy[copy.length] = item;
836
+ }
837
+ return frozenList(copy);
564
838
  }
839
+ /** Read the request into a snapshot and re-check its destination. A refusal is returned as a result. */
565
840
  function prepareRequest(request, settings) {
566
- if (!isPlainRecord(request)) throw unreadable2();
567
- const destination = readOwn(request, "destination", "destination", unreadableFail2);
568
- const method = primitive(readOwn(request, "method", "method", unreadableFail2));
569
- const body = primitive(readOwn(request, "body", "body", unreadableFail2));
570
- const headers = readOwn(request, "headers", "headers", unreadableFail2);
571
- if (!isPlainRecord(destination) || method !== "POST" || typeof body !== "string") throw unreadable2();
572
- const outgoing = readHeaders(headers);
573
- const url = primitive(readOwn(destination, "url", "destination.url", unreadableFail2));
574
- const hostname = primitive(readOwn(destination, "hostname", "destination.hostname", unreadableFail2));
575
- const port = primitive(readOwn(destination, "port", "destination.port", unreadableFail2));
576
- const rawAddresses = readOwn(destination, "addresses", "destination.addresses", unreadableFail2);
577
- const check = checkDestinationUrl(url, settings.allowNonPublic);
578
- if (!check.ok) return check.code === "private_address" ? PRIVATE_ADDRESS2 : INVALID_URL2;
579
- if (port !== 443 || hostname !== check.hostname) return INVALID_URL2;
580
- const addresses = readAddresses(rawAddresses, settings.allowNonPublic);
581
- if (addresses === void 0) return PRIVATE_ADDRESS2;
582
- if (check.literal !== void 0) {
583
- for (let index = 0; index < addresses.length; index += 1) {
584
- if (addresses[index].address !== check.literal.address) return INVALID_URL2;
585
- }
586
- }
587
- const hostHeader = check.literal !== void 0 && check.literal.family === 6 ? `[${check.hostname}]` : check.hostname;
588
- const path = check.url.slice(`https://${hostHeader}`.length);
589
- const encoded = bufferFrom(body, "utf8");
590
- outgoing["Host"] = hostHeader;
591
- outgoing["Content-Length"] = `${encoded.length}`;
592
- outgoing["Connection"] = "close";
593
- return freeze({ hostname: check.hostname, path, headers: outgoing, body: encoded, addresses, literal: check.literal !== void 0 });
841
+ if (!isPlainRecord(request)) throw unreadable$1();
842
+ const destination = readOwn(request, "destination", "destination", unreadableFail$1);
843
+ const method = primitive(readOwn(request, "method", "method", unreadableFail$1));
844
+ const body = primitive(readOwn(request, "body", "body", unreadableFail$1));
845
+ const headers = readOwn(request, "headers", "headers", unreadableFail$1);
846
+ if (!isPlainRecord(destination) || method !== "POST" || typeof body !== "string") throw unreadable$1();
847
+ const outgoing = readHeaders(headers);
848
+ const url = primitive(readOwn(destination, "url", "destination.url", unreadableFail$1));
849
+ const hostname = primitive(readOwn(destination, "hostname", "destination.hostname", unreadableFail$1));
850
+ const port = primitive(readOwn(destination, "port", "destination.port", unreadableFail$1));
851
+ const rawAddresses = readOwn(destination, "addresses", "destination.addresses", unreadableFail$1);
852
+ const check = checkDestinationUrl(url, settings.allowNonPublic);
853
+ if (!check.ok) return check.code === "private_address" ? PRIVATE_ADDRESS : INVALID_URL;
854
+ if (port !== 443 || hostname !== check.hostname) return INVALID_URL;
855
+ const addresses = readAddresses(rawAddresses, settings.allowNonPublic);
856
+ if (addresses === void 0) return PRIVATE_ADDRESS;
857
+ if (check.literal !== void 0) {
858
+ for (let index = 0; index < addresses.length; index += 1) if (addresses[index].address !== check.literal.address) return INVALID_URL;
859
+ }
860
+ const hostHeader = check.literal !== void 0 && check.literal.family === 6 ? `[${check.hostname}]` : check.hostname;
861
+ const path = check.url.slice(`https://${hostHeader}`.length);
862
+ const encoded = bufferFrom(body, "utf8");
863
+ outgoing["Host"] = hostHeader;
864
+ outgoing["Content-Length"] = `${encoded.length}`;
865
+ outgoing["Connection"] = "close";
866
+ return freeze({
867
+ hostname: check.hostname,
868
+ path,
869
+ headers: outgoing,
870
+ body: encoded,
871
+ addresses,
872
+ literal: check.literal !== void 0
873
+ });
594
874
  }
595
875
  function readHeaders(value) {
596
- if (!isPlainRecord(value)) throw unreadable2();
597
- const out = emptyMap();
598
- const keys = Reflect.ownKeys(value);
599
- if (keys.length > MAX_HEADERS) throw unreadable2();
600
- for (let index = 0; index < keys.length; index += 1) {
601
- const name = keys[index];
602
- if (typeof name !== "string") throw unreadable2();
603
- const headerValue = primitive(readOwn(value, name, "headers", unreadableFail2));
604
- if (typeof headerValue !== "string" || !matches(HEADER_NAME, name) || !matches(HEADER_VALUE, headerValue)) throw unreadable2();
605
- if (matches(RESERVED_HEADER, name)) continue;
606
- out[name] = headerValue;
607
- }
608
- return out;
876
+ if (!isPlainRecord(value)) throw unreadable$1();
877
+ const out = emptyMap();
878
+ const keys = Reflect.ownKeys(value);
879
+ if (keys.length > MAX_HEADERS) throw unreadable$1();
880
+ for (let index = 0; index < keys.length; index += 1) {
881
+ const name = keys[index];
882
+ if (typeof name !== "string") throw unreadable$1();
883
+ const headerValue = primitive(readOwn(value, name, "headers", unreadableFail$1));
884
+ if (typeof headerValue !== "string" || !matches(HEADER_NAME, name) || !matches(HEADER_VALUE, headerValue)) throw unreadable$1();
885
+ if (matches(RESERVED_HEADER, name)) continue;
886
+ out[name] = headerValue;
887
+ }
888
+ return out;
609
889
  }
890
+ /** The vetted addresses, canonical; `undefined` when there are none or one is not public (unless allowed). */
610
891
  function readAddresses(value, allowNonPublic) {
611
- if (!isArray(value)) return void 0;
612
- const length = readOwn(value, "length", "destination.addresses", unreadableFail2);
613
- if (typeof length !== "number" || !numberIsSafeInteger(length) || length < 1 || length > 32) return void 0;
614
- const out = [];
615
- for (let index = 0; index < length; index += 1) {
616
- const entry = readOwn(value, `${index}`, "destination.addresses", unreadableFail2);
617
- if (!isPlainRecord(entry)) return void 0;
618
- const address = primitive(readOwn(entry, "address", "destination.addresses", unreadableFail2));
619
- const family = primitive(readOwn(entry, "family", "destination.addresses", unreadableFail2));
620
- const judged = classifyAddress(address);
621
- if (judged.kind === "public" && judged.family === family) {
622
- out[out.length] = record({ address: judged.address, family: judged.family });
623
- continue;
624
- }
625
- if (allowNonPublic && judged.kind === "non_public" && judged.family === family && typeof address === "string" && !address.includes("%")) {
626
- out[out.length] = record({ address, family: judged.family });
627
- continue;
628
- }
629
- return void 0;
630
- }
631
- return frozenList(out);
892
+ if (!isArray(value)) return void 0;
893
+ const length = readOwn(value, "length", "destination.addresses", unreadableFail$1);
894
+ if (typeof length !== "number" || !numberIsSafeInteger(length) || length < 1 || length > 32) return void 0;
895
+ const out = [];
896
+ for (let index = 0; index < length; index += 1) {
897
+ const entry = readOwn(value, `${index}`, "destination.addresses", unreadableFail$1);
898
+ if (!isPlainRecord(entry)) return void 0;
899
+ const address = primitive(readOwn(entry, "address", "destination.addresses", unreadableFail$1));
900
+ const family = primitive(readOwn(entry, "family", "destination.addresses", unreadableFail$1));
901
+ const judged = classifyAddress(address);
902
+ if (judged.kind === "public" && judged.family === family) {
903
+ out[out.length] = record({
904
+ address: judged.address,
905
+ family: judged.family
906
+ });
907
+ continue;
908
+ }
909
+ if (allowNonPublic && judged.kind === "non_public" && judged.family === family && typeof address === "string" && !address.includes("%")) {
910
+ out[out.length] = record({
911
+ address,
912
+ family: judged.family
913
+ });
914
+ continue;
915
+ }
916
+ return;
917
+ }
918
+ return frozenList(out);
632
919
  }
920
+ /** `not_sent` when the call is no longer wanted: aborted, past its deadline, or the clock cannot tell. */
633
921
  function notWanted(bounds, clock) {
634
- if (isAborted(bounds.signal)) return NOT_SENT_ABORTED;
635
- if (!(bounds.deadlineMs > clockNowMs(clock))) return NOT_SENT_DEADLINE;
636
- return void 0;
922
+ if (isAborted(bounds.signal)) return NOT_SENT_ABORTED;
923
+ if (!(bounds.deadlineMs > clockNowMs(clock))) return NOT_SENT_DEADLINE;
637
924
  }
638
925
  function dispatch(slots, settings, prepared, bounds) {
639
- return new PromiseConstructor((resolve) => {
640
- const release = () => {
641
- slots.active -= 1;
642
- pump(slots, settings);
643
- };
644
- const begin = () => {
645
- perform(settings, prepared, bounds, (result) => {
646
- release();
647
- resolve(result);
648
- });
649
- };
650
- if (slots.active < settings.maxConcurrentRequests) {
651
- slots.active += 1;
652
- begin();
653
- return;
654
- }
655
- enqueue(slots, settings, bounds, begin, resolve);
656
- });
926
+ return new PromiseConstructor((resolve) => {
927
+ const release = () => {
928
+ slots.active -= 1;
929
+ pump(slots, settings);
930
+ };
931
+ const begin = () => {
932
+ perform(settings, prepared, bounds, (result) => {
933
+ release();
934
+ resolve(result);
935
+ });
936
+ };
937
+ if (slots.active < settings.maxConcurrentRequests) {
938
+ slots.active += 1;
939
+ begin();
940
+ return;
941
+ }
942
+ enqueue(slots, settings, bounds, begin, resolve);
943
+ });
657
944
  }
658
945
  function enqueue(slots, settings, bounds, begin, resolve) {
659
- let cancelTimer = () => {
660
- };
661
- let removeAbort = () => {
662
- };
663
- const call = {
664
- start: () => {
665
- cancelTimer();
666
- removeAbort();
667
- begin();
668
- },
669
- next: void 0,
670
- prev: void 0
671
- };
672
- const drop = (result) => {
673
- unlink(slots, call);
674
- cancelTimer();
675
- removeAbort();
676
- resolve(result);
677
- };
678
- if (slots.tail === void 0) {
679
- slots.head = call;
680
- slots.tail = call;
681
- } else {
682
- call.prev = slots.tail;
683
- slots.tail.next = call;
684
- slots.tail = call;
685
- }
686
- cancelTimer = startTimer(bounds.deadlineMs - clockNowMs(settings.clock), () => drop(NOT_SENT_DEADLINE));
687
- removeAbort = onAbort(bounds.signal, () => drop(NOT_SENT_ABORTED));
946
+ let cancelTimer = () => {};
947
+ let removeAbort = () => {};
948
+ const call = {
949
+ start: () => {
950
+ cancelTimer();
951
+ removeAbort();
952
+ begin();
953
+ },
954
+ next: void 0,
955
+ prev: void 0
956
+ };
957
+ const drop = (result) => {
958
+ unlink(slots, call);
959
+ cancelTimer();
960
+ removeAbort();
961
+ resolve(result);
962
+ };
963
+ if (slots.tail === void 0) {
964
+ slots.head = call;
965
+ slots.tail = call;
966
+ } else {
967
+ call.prev = slots.tail;
968
+ slots.tail.next = call;
969
+ slots.tail = call;
970
+ }
971
+ cancelTimer = startTimer(bounds.deadlineMs - clockNowMs(settings.clock), () => drop(NOT_SENT_DEADLINE));
972
+ removeAbort = onAbort(bounds.signal, () => drop(NOT_SENT_ABORTED));
688
973
  }
689
974
  function unlink(slots, call) {
690
- if (call.prev !== void 0) call.prev.next = call.next;
691
- else if (slots.head === call) slots.head = call.next;
692
- if (call.next !== void 0) call.next.prev = call.prev;
693
- else if (slots.tail === call) slots.tail = call.prev;
694
- call.next = void 0;
695
- call.prev = void 0;
975
+ if (call.prev !== void 0) call.prev.next = call.next;
976
+ else if (slots.head === call) slots.head = call.next;
977
+ if (call.next !== void 0) call.next.prev = call.prev;
978
+ else if (slots.tail === call) slots.tail = call.prev;
979
+ call.next = void 0;
980
+ call.prev = void 0;
696
981
  }
982
+ /**
983
+ * Start queued calls, oldest first, while slots are free. A started call
984
+ * that fails its last check settles synchronously and releases its slot,
985
+ * which calls `pump` again; the `pumping` flag turns that re-entry into
986
+ * another turn of this loop, so draining any backlog uses constant stack
987
+ * depth.
988
+ */
697
989
  function pump(slots, settings) {
698
- if (slots.pumping) return;
699
- slots.pumping = true;
700
- try {
701
- while (slots.head !== void 0 && slots.active < settings.maxConcurrentRequests) {
702
- const call = slots.head;
703
- unlink(slots, call);
704
- slots.active += 1;
705
- call.start();
706
- }
707
- } finally {
708
- slots.pumping = false;
709
- }
990
+ if (slots.pumping) return;
991
+ slots.pumping = true;
992
+ try {
993
+ while (slots.head !== void 0 && slots.active < settings.maxConcurrentRequests) {
994
+ const call = slots.head;
995
+ unlink(slots, call);
996
+ slots.active += 1;
997
+ call.start();
998
+ }
999
+ } finally {
1000
+ slots.pumping = false;
1001
+ }
710
1002
  }
1003
+ /**
1004
+ * The lookup Node's socket uses: it answers with the vetted addresses for
1005
+ * the vetted name and refuses any other name. Node connects synchronously
1006
+ * from inside this callback, so a throw there (an address it cannot use)
1007
+ * would escape as an uncaught exception; it is caught and reported through
1008
+ * `onFault` instead.
1009
+ */
711
1010
  function pinnedLookup(hostname, addresses, onFault) {
712
- return (host, options, callback) => {
713
- try {
714
- if (host !== hostname) {
715
- const error = new Error("Webhook transport refused a lookup for a name other than the vetted one.");
716
- error.code = "ENOTFOUND";
717
- callback(error, "", 4);
718
- return;
719
- }
720
- if (options.all === true) {
721
- const all = [];
722
- for (let index = 0; index < addresses.length; index += 1) all[all.length] = { address: addresses[index].address, family: addresses[index].family };
723
- callback(null, all);
724
- return;
725
- }
726
- callback(null, addresses[0].address, addresses[0].family);
727
- } catch {
728
- onFault();
729
- }
730
- };
1011
+ return (host, options, callback) => {
1012
+ try {
1013
+ if (host !== hostname) {
1014
+ const error = /* @__PURE__ */ new Error("Webhook transport refused a lookup for a name other than the vetted one.");
1015
+ error.code = "ENOTFOUND";
1016
+ callback(error, "", 4);
1017
+ return;
1018
+ }
1019
+ if (options.all === true) {
1020
+ const all = [];
1021
+ for (let index = 0; index < addresses.length; index += 1) all[all.length] = {
1022
+ address: addresses[index].address,
1023
+ family: addresses[index].family
1024
+ };
1025
+ callback(null, all);
1026
+ return;
1027
+ }
1028
+ callback(null, addresses[0].address, addresses[0].family);
1029
+ } catch {
1030
+ onFault();
1031
+ }
1032
+ };
731
1033
  }
732
1034
  function perform(settings, prepared, bounds, done) {
733
- let settled = false;
734
- let status;
735
- let retryAfter = null;
736
- let request;
737
- let response;
738
- let cancelTimer = () => {
739
- };
740
- let removeAbort = () => {
741
- };
742
- const responseResult = () => record({ kind: "response", status, retryAfter });
743
- const finish = (result) => {
744
- if (settled) return;
745
- settled = true;
746
- cancelTimer();
747
- removeAbort();
748
- response?.destroy();
749
- request?.destroy();
750
- done(result);
751
- };
752
- const stop = () => finish(status === void 0 ? TIMEOUT : responseResult());
753
- if (isAborted(bounds.signal)) {
754
- finish(NOT_SENT_ABORTED);
755
- return;
756
- }
757
- const remaining = bounds.deadlineMs - clockNowMs(settings.clock);
758
- if (!(remaining > 0)) {
759
- finish(NOT_SENT_DEADLINE);
760
- return;
761
- }
762
- cancelTimer = startTimer(remaining, stop);
763
- removeAbort = onAbort(bounds.signal, stop);
764
- try {
765
- request = https.request({
766
- host: prepared.hostname,
767
- port: settings.port,
768
- method: "POST",
769
- path: prepared.path,
770
- headers: prepared.headers,
771
- setHost: false,
772
- agent: false,
773
- lookup: pinnedLookup(prepared.hostname, prepared.addresses, () => finish(status === void 0 ? NETWORK_ERROR : responseResult())),
774
- // RFC 6066 forbids an IP address as SNI; the certificate is then checked against the IP.
775
- servername: prepared.literal ? "" : prepared.hostname,
776
- rejectUnauthorized: true,
777
- minVersion: "TLSv1.2",
778
- maxHeaderSize: MAX_RESPONSE_HEADER_BYTES,
779
- ...settings.ca === void 0 ? {} : { ca: settings.ca }
780
- });
781
- } catch {
782
- finish(NETWORK_ERROR);
783
- return;
784
- }
785
- request.on("error", () => finish(status === void 0 ? NETWORK_ERROR : responseResult()));
786
- request.on("response", (incoming) => {
787
- response = incoming;
788
- incoming.on("error", () => finish(responseResult()));
789
- const code = incoming.statusCode;
790
- if (typeof code !== "number" || !numberIsSafeInteger(code) || code < 100 || code > 599) {
791
- finish(NETWORK_ERROR);
792
- return;
793
- }
794
- status = code;
795
- const header = incoming.headers["retry-after"];
796
- retryAfter = typeof header === "string" && header.length <= MAX_RETRY_AFTER_LENGTH ? header : null;
797
- const declared = incoming.headers["content-length"];
798
- if (typeof declared === "string" && matches(DECIMAL, declared) && NumberConstructor(declared) > settings.maxResponseBytes) {
799
- finish(responseResult());
800
- return;
801
- }
802
- let received = 0;
803
- incoming.on("data", (chunk) => {
804
- received += chunk.length;
805
- if (received > settings.maxResponseBytes) finish(responseResult());
806
- });
807
- incoming.on("end", () => finish(responseResult()));
808
- incoming.on("close", () => finish(responseResult()));
809
- });
810
- if (settled) return;
811
- request.end(prepared.body);
812
- }
813
- var DEFAULT_NODE_WEBHOOK_DNS_TIMEOUT_MS = 5e3;
814
- var unreadable3 = () => inputError("type", "input_unreadable");
815
- var unreadableFail3 = () => {
816
- throw unreadable3();
1035
+ let settled = false;
1036
+ let status;
1037
+ let retryAfter = null;
1038
+ let request;
1039
+ let response;
1040
+ let cancelTimer = () => {};
1041
+ let removeAbort = () => {};
1042
+ const responseResult = () => record({
1043
+ kind: "response",
1044
+ status,
1045
+ retryAfter
1046
+ });
1047
+ const finish = (result) => {
1048
+ if (settled) return;
1049
+ settled = true;
1050
+ cancelTimer();
1051
+ removeAbort();
1052
+ response?.destroy();
1053
+ request?.destroy();
1054
+ done(result);
1055
+ };
1056
+ const stop = () => finish(status === void 0 ? TIMEOUT : responseResult());
1057
+ if (isAborted(bounds.signal)) {
1058
+ finish(NOT_SENT_ABORTED);
1059
+ return;
1060
+ }
1061
+ const remaining = bounds.deadlineMs - clockNowMs(settings.clock);
1062
+ if (!(remaining > 0)) {
1063
+ finish(NOT_SENT_DEADLINE);
1064
+ return;
1065
+ }
1066
+ cancelTimer = startTimer(remaining, stop);
1067
+ removeAbort = onAbort(bounds.signal, stop);
1068
+ try {
1069
+ request = (0, https.request)({
1070
+ host: prepared.hostname,
1071
+ port: settings.port,
1072
+ method: "POST",
1073
+ path: prepared.path,
1074
+ headers: prepared.headers,
1075
+ setHost: false,
1076
+ agent: false,
1077
+ lookup: pinnedLookup(prepared.hostname, prepared.addresses, () => finish(status === void 0 ? NETWORK_ERROR : responseResult())),
1078
+ servername: prepared.literal ? "" : prepared.hostname,
1079
+ rejectUnauthorized: true,
1080
+ minVersion: "TLSv1.2",
1081
+ maxHeaderSize: MAX_RESPONSE_HEADER_BYTES,
1082
+ ...settings.ca === void 0 ? {} : { ca: settings.ca }
1083
+ });
1084
+ } catch {
1085
+ finish(NETWORK_ERROR);
1086
+ return;
1087
+ }
1088
+ request.on("error", () => finish(status === void 0 ? NETWORK_ERROR : responseResult()));
1089
+ request.on("response", (incoming) => {
1090
+ response = incoming;
1091
+ incoming.on("error", () => finish(responseResult()));
1092
+ const code = incoming.statusCode;
1093
+ if (typeof code !== "number" || !numberIsSafeInteger(code) || code < 100 || code > 599) {
1094
+ finish(NETWORK_ERROR);
1095
+ return;
1096
+ }
1097
+ status = code;
1098
+ const header = incoming.headers["retry-after"];
1099
+ retryAfter = typeof header === "string" && header.length <= MAX_RETRY_AFTER_LENGTH ? header : null;
1100
+ const declared = incoming.headers["content-length"];
1101
+ if (typeof declared === "string" && matches(DECIMAL, declared) && NumberConstructor(declared) > settings.maxResponseBytes) {
1102
+ finish(responseResult());
1103
+ return;
1104
+ }
1105
+ let received = 0;
1106
+ incoming.on("data", (chunk) => {
1107
+ received += chunk.length;
1108
+ if (received > settings.maxResponseBytes) finish(responseResult());
1109
+ });
1110
+ incoming.on("end", () => finish(responseResult()));
1111
+ incoming.on("close", () => finish(responseResult()));
1112
+ });
1113
+ if (settled) return;
1114
+ request.end(prepared.body);
1115
+ }
1116
+ //#endregion
1117
+ //#region src/node/lookup.ts
1118
+ /** The default per-query timeout of {@link createNodeWebhookDnsLookup}. */
1119
+ const DEFAULT_NODE_WEBHOOK_DNS_TIMEOUT_MS = 5e3;
1120
+ const unreadable = () => inputError("type", "input_unreadable");
1121
+ const unreadableFail = () => {
1122
+ throw unreadable();
817
1123
  };
1124
+ /**
1125
+ * "The name exists but has no records of this type": an empty half of the
1126
+ * answer, not a failure. "No such name" (`ENOTFOUND`) is a failure: the two
1127
+ * queries disagreeing about whether the name exists is a partial answer.
1128
+ */
818
1129
  function isNoRecords(error) {
819
- return error?.code === "ENODATA";
1130
+ return error?.code === "ENODATA";
820
1131
  }
1132
+ /**
1133
+ * A {@link WebhookDnsLookup} for `createWebhookDestinationResolver()` built on
1134
+ * a fresh `node:dns` `Resolver` per call, asking for A and AAAA records
1135
+ * together. It uses c-ares rather than `dns.lookup()` because a c-ares query
1136
+ * can be cancelled: when the resolver aborts the call's signal, the queries
1137
+ * are cancelled instead of holding a libuv thread-pool thread until the
1138
+ * operating system gives up, so a slow authoritative server named in a
1139
+ * destination cannot starve the pool. It therefore does not consult
1140
+ * `/etc/hosts`.
1141
+ *
1142
+ * The answer is every A and AAAA address. A query that fails for any reason
1143
+ * other than "no records of this type" (`ENODATA`), "no such name"
1144
+ * (`ENOTFOUND`) included, rejects the whole lookup, so a half-answered name
1145
+ * is a `dns_failure` behind the resolver, never a partial pass.
1146
+ *
1147
+ * @throws {TypeError} `input_unreadable` when `servers` is not a list of
1148
+ * server strings `Resolver.setServers` accepts.
1149
+ * @throws {WebhookDeliveryConfigError} when `timeoutMs` is not a positive
1150
+ * whole number of at most `WEBHOOK_MAX_TIMER_MS`.
1151
+ */
821
1152
  function createNodeWebhookDnsLookup(options = {}) {
822
- const settings = guard(() => readLookupOptions(options), unreadable3);
823
- const lookup = async (hostname, callOptions) => {
824
- const signal = callOptions.signal;
825
- if (isAborted(signal)) throw unreadable3();
826
- const resolver = new promises.Resolver({ timeout: settings.timeoutMs, tries: 1 });
827
- if (settings.servers !== void 0) resolver.setServers(settings.servers);
828
- const removeAbort = onAbort(signal, () => resolver.cancel());
829
- try {
830
- const [v4, v6] = await Promise.all([records(resolver.resolve4(hostname)), records(resolver.resolve6(hostname))]);
831
- const answer = [];
832
- for (const address of v4) answer[answer.length] = record({ address, family: 4 });
833
- for (const address of v6) answer[answer.length] = record({ address, family: 6 });
834
- return frozenList(answer);
835
- } finally {
836
- removeAbort();
837
- resolver.cancel();
838
- }
839
- };
840
- return lookup;
1153
+ const settings = guard(() => readLookupOptions(options), unreadable);
1154
+ const lookup = async (hostname, callOptions) => {
1155
+ const signal = callOptions.signal;
1156
+ if (isAborted(signal)) throw unreadable();
1157
+ const resolver = new dns_promises.Resolver({
1158
+ timeout: settings.timeoutMs,
1159
+ tries: 1
1160
+ });
1161
+ if (settings.servers !== void 0) resolver.setServers(settings.servers);
1162
+ const removeAbort = onAbort(signal, () => resolver.cancel());
1163
+ try {
1164
+ const [v4, v6] = await Promise.all([records(resolver.resolve4(hostname)), records(resolver.resolve6(hostname))]);
1165
+ const answer = [];
1166
+ for (const address of v4) answer[answer.length] = record({
1167
+ address,
1168
+ family: 4
1169
+ });
1170
+ for (const address of v6) answer[answer.length] = record({
1171
+ address,
1172
+ family: 6
1173
+ });
1174
+ return frozenList(answer);
1175
+ } finally {
1176
+ removeAbort();
1177
+ resolver.cancel();
1178
+ }
1179
+ };
1180
+ return lookup;
841
1181
  }
842
1182
  async function records(query) {
843
- try {
844
- return await query;
845
- } catch (error) {
846
- if (isNoRecords(error)) return [];
847
- throw error;
848
- }
1183
+ try {
1184
+ return await query;
1185
+ } catch (error) {
1186
+ if (isNoRecords(error)) return [];
1187
+ throw error;
1188
+ }
849
1189
  }
850
1190
  function readLookupOptions(options) {
851
- if (!isPlainRecord(options)) throw unreadable3();
852
- const rawTimeout = primitive(readOwn(options, "timeoutMs", "timeoutMs", unreadableFail3));
853
- const timeoutMs = rawTimeout === void 0 ? DEFAULT_NODE_WEBHOOK_DNS_TIMEOUT_MS : rawTimeout;
854
- assertPositiveInteger(timeoutMs, "timeoutMs");
855
- if (timeoutMs > WEBHOOK_MAX_TIMER_MS) throw configError("limit_out_of_range", "timeoutMs");
856
- const rawServers = readOwn(options, "servers", "servers", unreadableFail3);
857
- let servers;
858
- if (rawServers !== void 0) {
859
- if (!isArray(rawServers)) throw unreadable3();
860
- const length = readOwn(rawServers, "length", "servers", unreadableFail3);
861
- if (typeof length !== "number" || !numberIsSafeInteger(length) || length < 1 || length > 16) throw unreadable3();
862
- const copy = [];
863
- for (let index = 0; index < length; index += 1) {
864
- const item = primitive(readOwn(rawServers, `${index}`, "servers", unreadableFail3));
865
- if (typeof item !== "string") throw unreadable3();
866
- copy[copy.length] = item;
867
- }
868
- new promises.Resolver().setServers(copy);
869
- servers = frozenList(copy);
870
- }
871
- return { servers, timeoutMs };
1191
+ if (!isPlainRecord(options)) throw unreadable();
1192
+ const rawTimeout = primitive(readOwn(options, "timeoutMs", "timeoutMs", unreadableFail));
1193
+ const timeoutMs = rawTimeout === void 0 ? DEFAULT_NODE_WEBHOOK_DNS_TIMEOUT_MS : rawTimeout;
1194
+ assertPositiveInteger(timeoutMs, "timeoutMs");
1195
+ if (timeoutMs > 2147483647) throw configError("limit_out_of_range", "timeoutMs");
1196
+ const rawServers = readOwn(options, "servers", "servers", unreadableFail);
1197
+ let servers;
1198
+ if (rawServers !== void 0) {
1199
+ if (!isArray(rawServers)) throw unreadable();
1200
+ const length = readOwn(rawServers, "length", "servers", unreadableFail);
1201
+ if (typeof length !== "number" || !numberIsSafeInteger(length) || length < 1 || length > 16) throw unreadable();
1202
+ const copy = [];
1203
+ for (let index = 0; index < length; index += 1) {
1204
+ const item = primitive(readOwn(rawServers, `${index}`, "servers", unreadableFail));
1205
+ if (typeof item !== "string") throw unreadable();
1206
+ copy[copy.length] = item;
1207
+ }
1208
+ new dns_promises.Resolver().setServers(copy);
1209
+ servers = frozenList(copy);
1210
+ }
1211
+ return {
1212
+ servers,
1213
+ timeoutMs
1214
+ };
872
1215
  }
873
-
1216
+ //#endregion
874
1217
  exports.DEFAULT_NODE_WEBHOOK_DNS_TIMEOUT_MS = DEFAULT_NODE_WEBHOOK_DNS_TIMEOUT_MS;
875
1218
  exports.DEFAULT_NODE_WEBHOOK_MAX_CONCURRENT_REQUESTS = DEFAULT_NODE_WEBHOOK_MAX_CONCURRENT_REQUESTS;
876
1219
  exports.DEFAULT_NODE_WEBHOOK_MAX_RESPONSE_BYTES = DEFAULT_NODE_WEBHOOK_MAX_RESPONSE_BYTES;
877
1220
  exports.createNodeWebhookDnsLookup = createNodeWebhookDnsLookup;
878
1221
  exports.createNodeWebhookTransport = createNodeWebhookTransport;
879
- //# sourceMappingURL=node.cjs.map
1222
+
880
1223
  //# sourceMappingURL=node.cjs.map