@suveren/gateway 0.8.4 → 0.8.5
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/control-plane/index.mjs +89 -70
- package/dist/mcp-server/http.mjs +75 -0
- package/dist/ui/assets/index-CheBVmNI.css +1 -0
- package/dist/ui/assets/index-IVfLWq4W.js +110 -0
- package/dist/ui/index.html +2 -2
- package/node_modules/@types/node/README.md +2 -2
- package/node_modules/@types/node/buffer.d.ts +1 -0
- package/node_modules/@types/node/child_process.d.ts +1 -1
- package/node_modules/@types/node/crypto.d.ts +20 -8
- package/node_modules/@types/node/diagnostics_channel.d.ts +4 -4
- package/node_modules/@types/node/ffi.d.ts +14 -0
- package/node_modules/@types/node/http.d.ts +1 -1
- package/node_modules/@types/node/http2.d.ts +3 -2
- package/node_modules/@types/node/net.d.ts +16 -4
- package/node_modules/@types/node/package.json +3 -18
- package/node_modules/@types/node/perf_hooks.d.ts +31 -19
- package/node_modules/@types/node/process.d.ts +1 -0
- package/node_modules/@types/node/quic.d.ts +45 -5
- package/node_modules/@types/node/stream/iter.d.ts +9 -12
- package/node_modules/@types/node/stream/web.d.ts +20 -0
- package/node_modules/@types/node/test/reporters.d.ts +1 -0
- package/node_modules/@types/node/test.d.ts +72 -0
- package/node_modules/@types/node/tls.d.ts +40 -25
- package/node_modules/@types/node/vfs.d.ts +7 -6
- package/node_modules/@types/node/vm.d.ts +2 -1
- package/node_modules/@types/node/web-globals/streams.d.ts +4 -0
- package/node_modules/@types/node/worker_threads.d.ts +4 -1
- package/node_modules/@types/node/zlib.d.ts +17 -0
- package/node_modules/body-parser/HISTORY.md +156 -145
- package/node_modules/body-parser/package.json +2 -2
- package/node_modules/express/History.md +583 -576
- package/node_modules/express/lib/request.js +2 -2
- package/node_modules/express/package.json +3 -3
- package/node_modules/fast-uri/index.js +10 -6
- package/node_modules/fast-uri/package.json +1 -1
- package/node_modules/fast-uri/test/security-normalization.test.js +38 -0
- package/node_modules/hono/README.md +1 -1
- package/node_modules/hono/dist/adapter/aws-lambda/handler.js +5 -4
- package/node_modules/hono/dist/cjs/adapter/aws-lambda/handler.js +5 -4
- package/node_modules/hono/dist/cjs/context.js +1 -1
- package/node_modules/hono/dist/cjs/helper/accepts/accepts.js +1 -1
- package/node_modules/hono/dist/cjs/jsx/dom/render.js +44 -8
- package/node_modules/hono/dist/cjs/middleware/language/language.js +4 -1
- package/node_modules/hono/dist/cjs/request.js +4 -1
- package/node_modules/hono/dist/cjs/utils/accept.js +4 -7
- package/node_modules/hono/dist/context.js +1 -1
- package/node_modules/hono/dist/helper/accepts/accepts.js +1 -1
- package/node_modules/hono/dist/jsx/dom/render.js +44 -8
- package/node_modules/hono/dist/middleware/language/language.js +4 -1
- package/node_modules/hono/dist/request.js +4 -1
- package/node_modules/hono/dist/types/helper/proxy/index.d.ts +1 -1
- package/node_modules/hono/dist/types/helper/route/index.d.ts +2 -2
- package/node_modules/hono/dist/types/middleware/combine/index.d.ts +3 -1
- package/node_modules/hono/dist/types/utils/types.d.ts +1 -1
- package/node_modules/hono/dist/utils/accept.js +4 -7
- package/node_modules/hono/package.json +1 -1
- package/node_modules/ip-address/README.md +114 -114
- package/node_modules/ip-address/dist/common.d.ts +5 -0
- package/node_modules/ip-address/dist/common.js +12 -0
- package/node_modules/ip-address/dist/common.js.map +1 -1
- package/node_modules/ip-address/dist/ipv4.d.ts +10 -3
- package/node_modules/ip-address/dist/ipv4.js +20 -5
- package/node_modules/ip-address/dist/ipv4.js.map +1 -1
- package/node_modules/ip-address/dist/ipv6.d.ts +5 -1
- package/node_modules/ip-address/dist/ipv6.js +18 -3
- package/node_modules/ip-address/dist/ipv6.js.map +1 -1
- package/node_modules/ip-address/package.json +1 -1
- package/node_modules/proxy-addr/HISTORY.md +60 -54
- package/node_modules/proxy-addr/README.md +1 -1
- package/node_modules/proxy-addr/index.js +32 -0
- package/node_modules/proxy-addr/package.json +8 -4
- package/node_modules/qs/.github/THREAT_MODEL.md +3 -3
- package/node_modules/qs/CHANGELOG.md +15 -0
- package/node_modules/qs/README.md +19 -1
- package/node_modules/qs/dist/qs.js +21 -21
- package/node_modules/qs/eslint.config.mjs +1 -1
- package/node_modules/qs/lib/parse.js +3 -4
- package/node_modules/qs/lib/stringify.js +23 -8
- package/node_modules/qs/lib/utils.js +10 -3
- package/node_modules/qs/package.json +4 -4
- package/node_modules/qs/test/parse.js +192 -3
- package/node_modules/qs/test/stringify.js +317 -0
- package/node_modules/qs/test/utils.js +12 -0
- package/node_modules/undici-types/client.d.ts +8 -3
- package/node_modules/undici-types/connector.d.ts +1 -0
- package/node_modules/undici-types/cookies.d.ts +1 -1
- package/node_modules/undici-types/dispatcher.d.ts +3 -3
- package/node_modules/undici-types/errors.d.ts +10 -0
- package/node_modules/undici-types/fetch.d.ts +5 -1
- package/node_modules/undici-types/handlers.d.ts +2 -0
- package/node_modules/undici-types/interceptors.d.ts +1 -1
- package/node_modules/undici-types/mock-interceptor.d.ts +5 -1
- package/node_modules/undici-types/package.json +1 -1
- package/node_modules/undici-types/proxy-agent.d.ts +7 -0
- package/package.json +1 -1
- package/dist/ui/assets/index-BYVb_0oG.css +0 -1
- package/dist/ui/assets/index-Z0OQ-dd1.js +0 -110
|
@@ -136,6 +136,144 @@ test('stringify()', function (t) {
|
|
|
136
136
|
st.end();
|
|
137
137
|
});
|
|
138
138
|
|
|
139
|
+
t.test('encodes dot in key of object with a primitive value when encodeDotInKeys and allowDots is provided', function (st) {
|
|
140
|
+
st.equal(
|
|
141
|
+
qs.stringify(
|
|
142
|
+
{ 'name.obj': 'John' },
|
|
143
|
+
{ allowDots: true, encodeDotInKeys: true }
|
|
144
|
+
),
|
|
145
|
+
'name%252Eobj=John',
|
|
146
|
+
'with allowDots true and encodeDotInKeys true'
|
|
147
|
+
);
|
|
148
|
+
st.equal(
|
|
149
|
+
qs.stringify(
|
|
150
|
+
{ 'name.obj': 'John' },
|
|
151
|
+
{ allowDots: false, encodeDotInKeys: true }
|
|
152
|
+
),
|
|
153
|
+
'name%252Eobj=John',
|
|
154
|
+
'with allowDots false and encodeDotInKeys true'
|
|
155
|
+
);
|
|
156
|
+
st.equal(
|
|
157
|
+
qs.stringify(
|
|
158
|
+
{ 'name.obj': 'John' },
|
|
159
|
+
{ encodeDotInKeys: true, allowDots: true, encodeValuesOnly: true }
|
|
160
|
+
),
|
|
161
|
+
'name%2Eobj=John',
|
|
162
|
+
'with encodeValuesOnly true'
|
|
163
|
+
);
|
|
164
|
+
|
|
165
|
+
// With `encodeValuesOnly` the key encoder is skipped, so the dot is encoded once
|
|
166
|
+
// (`%2E`) rather than twice. That single `%2E` decodes back to a structural dot, so
|
|
167
|
+
// unlike the default output below this does not round-trip to the original dotted key
|
|
168
|
+
// (a pre-existing `encodeValuesOnly` + `encodeDotInKeys` limitation, not new here).
|
|
169
|
+
st.deepEqual(
|
|
170
|
+
qs.parse(
|
|
171
|
+
qs.stringify(
|
|
172
|
+
{ 'name.obj': 'John' },
|
|
173
|
+
{ encodeDotInKeys: true, allowDots: true, encodeValuesOnly: true }
|
|
174
|
+
),
|
|
175
|
+
{ allowDots: true, decodeDotInKeys: true }
|
|
176
|
+
),
|
|
177
|
+
{ name: { obj: 'John' } },
|
|
178
|
+
'with encodeValuesOnly the single-encoded dot decodes structurally (does not round-trip)'
|
|
179
|
+
);
|
|
180
|
+
|
|
181
|
+
st.deepEqual(
|
|
182
|
+
qs.parse(
|
|
183
|
+
qs.stringify({ 'name.obj': 'John' }, { allowDots: true, encodeDotInKeys: true }),
|
|
184
|
+
{ allowDots: true, decodeDotInKeys: true }
|
|
185
|
+
),
|
|
186
|
+
{ 'name.obj': 'John' },
|
|
187
|
+
'round-trips a dotted key with a primitive value'
|
|
188
|
+
);
|
|
189
|
+
|
|
190
|
+
st.equal(
|
|
191
|
+
qs.stringify({ 'a.b': null }, { allowDots: true, encodeDotInKeys: true, strictNullHandling: true }),
|
|
192
|
+
'a%252Eb',
|
|
193
|
+
'encodes a dotted key with a null value'
|
|
194
|
+
);
|
|
195
|
+
st.equal(
|
|
196
|
+
qs.stringify({ 'a.b': '1', 'c.d': '2' }, { allowDots: true, encodeDotInKeys: true }),
|
|
197
|
+
'a%252Eb=1&c%252Ed=2',
|
|
198
|
+
'encodes dots in every top-level key, not just the first'
|
|
199
|
+
);
|
|
200
|
+
st.equal(
|
|
201
|
+
qs.stringify({ 'a.b.c': 'x' }, { allowDots: true, encodeDotInKeys: true }),
|
|
202
|
+
'a%252Eb%252Ec=x',
|
|
203
|
+
'encodes every dot in a key'
|
|
204
|
+
);
|
|
205
|
+
var primitiveKey = qs.stringify({ 'a.b': 'c' }, { allowDots: true, encodeDotInKeys: true }).split('=')[0];
|
|
206
|
+
st.equal(
|
|
207
|
+
qs.stringify({ 'a.b': { x: 'c' } }, { allowDots: true, encodeDotInKeys: true }).indexOf(primitiveKey + '.'),
|
|
208
|
+
0,
|
|
209
|
+
'a top-level dotted key encodes identically for primitive and object values'
|
|
210
|
+
);
|
|
211
|
+
|
|
212
|
+
st.end();
|
|
213
|
+
});
|
|
214
|
+
|
|
215
|
+
// Characterization of the CURRENT (buggy) behavior: with `allowDots` + `encodeDotInKeys`,
|
|
216
|
+
// `stringify` percent-encodes the structural `.` separators that `allowDots` inserts between
|
|
217
|
+
// nested keys, not just the literal dots inside a key, which breaks the stringify -> parse
|
|
218
|
+
// round-trip. These assertions pin that behavior so it cannot change silently: the fix in
|
|
219
|
+
// https://github.com/ljharb/qs/pull/564 changes every output below, so landing that fix MUST
|
|
220
|
+
// update this test (that is the point — it forces the behavior change to be explicit).
|
|
221
|
+
t.test('[characterization] encodeDotInKeys currently over-encodes structural separator dots (pre-#564)', function (st) {
|
|
222
|
+
st.equal(
|
|
223
|
+
qs.stringify({ a: { b: { c: 'd' } } }, { allowDots: true, encodeDotInKeys: true }),
|
|
224
|
+
'a%252Eb.c=d',
|
|
225
|
+
'over-encodes the a->b separator (#564: should become a.b.c=d)'
|
|
226
|
+
);
|
|
227
|
+
st.equal(
|
|
228
|
+
qs.stringify({ a: { b: { c: { d: 'e' } } } }, { allowDots: true, encodeDotInKeys: true }),
|
|
229
|
+
'a%252Eb%252Ec.d=e',
|
|
230
|
+
'clobbers every separator but the last (#564: should become a.b.c.d=e)'
|
|
231
|
+
);
|
|
232
|
+
st.equal(
|
|
233
|
+
qs.stringify({ 'a.b': { c: { d: 'e' } } }, { allowDots: true, encodeDotInKeys: true }),
|
|
234
|
+
'a%252Eb%252Ec.d=e',
|
|
235
|
+
'top-level dotted key: deeper separators also get encoded (#564: should become a%252Eb.c.d=e)'
|
|
236
|
+
);
|
|
237
|
+
st.equal(
|
|
238
|
+
qs.stringify({ a: { 'b.c': { d: 'e' } } }, { allowDots: true, encodeDotInKeys: true }),
|
|
239
|
+
'a%252Eb%252Ec.d=e',
|
|
240
|
+
'nested dotted key + object value: the separator around it is encoded (#564: should become a.b%252Ec.d=e)'
|
|
241
|
+
);
|
|
242
|
+
st.equal(
|
|
243
|
+
qs.stringify({ a: { b: { 'c.d': { e: 'f' } } } }, { allowDots: true, encodeDotInKeys: true }),
|
|
244
|
+
'a%252Eb%252Ec%252Ed.e=f',
|
|
245
|
+
'deeply nested dotted key: all separators encoded (#564: should become a.b.c%252Ed.e=f)'
|
|
246
|
+
);
|
|
247
|
+
|
|
248
|
+
st.equal(
|
|
249
|
+
qs.stringify({ a: { b: [1, 2] } }, { allowDots: true, encodeDotInKeys: true }),
|
|
250
|
+
'a%252Eb%5B0%5D=1&a%252Eb%5B1%5D=2',
|
|
251
|
+
'array value under nested keys: separator encoded (#564: should become a.b%5B0%5D=1&a.b%5B1%5D=2)'
|
|
252
|
+
);
|
|
253
|
+
st.equal(
|
|
254
|
+
qs.stringify({ a: { 'b.c': [1, 2] } }, { allowDots: true, encodeDotInKeys: true }),
|
|
255
|
+
'a%252Eb%252Ec%5B0%5D=1&a%252Eb%252Ec%5B1%5D=2',
|
|
256
|
+
'array value under nested dotted key (#564: should become a.b%252Ec%5B0%5D=1&a.b%252Ec%5B1%5D=2)'
|
|
257
|
+
);
|
|
258
|
+
|
|
259
|
+
st.equal(
|
|
260
|
+
qs.stringify({ a: { 'b.c': { d: 'e' } } }, { allowDots: false, encodeDotInKeys: true }),
|
|
261
|
+
'a%5Bb%252Ec%5D%5Bd%5D=e',
|
|
262
|
+
'allowDots:false object value encodes the nested-key dot, unlike the primitive-value case (#564: should become a%5Bb.c%5D%5Bd%5D=e)'
|
|
263
|
+
);
|
|
264
|
+
|
|
265
|
+
st.deepEqual(
|
|
266
|
+
qs.parse(
|
|
267
|
+
qs.stringify({ a: { b: { c: 'd' } } }, { allowDots: true, encodeDotInKeys: true }),
|
|
268
|
+
{ allowDots: true, decodeDotInKeys: true }
|
|
269
|
+
),
|
|
270
|
+
{ 'a.b': { c: 'd' } },
|
|
271
|
+
'the over-encoding breaks the round-trip: {a:{b:{c}}} comes back as {"a.b":{c}} (#564 restores it)'
|
|
272
|
+
);
|
|
273
|
+
|
|
274
|
+
st.end();
|
|
275
|
+
});
|
|
276
|
+
|
|
139
277
|
t.test('should encode dot in key of object, and automatically set allowDots to `true` when encodeDotInKeys is true and allowDots in undefined', function (st) {
|
|
140
278
|
st.equal(
|
|
141
279
|
qs.stringify(
|
|
@@ -328,6 +466,39 @@ test('stringify()', function (t) {
|
|
|
328
466
|
st.end();
|
|
329
467
|
});
|
|
330
468
|
|
|
469
|
+
t.test('allowEmptyArrays only short-circuits arrays with no own keys', function (st) {
|
|
470
|
+
st.equal(
|
|
471
|
+
qs.stringify({ a: [] }, { allowEmptyArrays: true }),
|
|
472
|
+
'a[]',
|
|
473
|
+
'a genuinely empty array is still emitted as `[]`'
|
|
474
|
+
);
|
|
475
|
+
|
|
476
|
+
var withKey = [];
|
|
477
|
+
withKey.extra = 'x';
|
|
478
|
+
st.equal(
|
|
479
|
+
qs.stringify({ a: withKey }, { allowEmptyArrays: true }),
|
|
480
|
+
'a%5Bextra%5D=x',
|
|
481
|
+
'an own key on an empty array is serialized rather than dropped'
|
|
482
|
+
);
|
|
483
|
+
st.equal(
|
|
484
|
+
qs.stringify({ a: withKey }, { allowEmptyArrays: true }),
|
|
485
|
+
qs.stringify({ a: withKey }),
|
|
486
|
+
'the allowEmptyArrays fast path matches the default path when the array has own keys'
|
|
487
|
+
);
|
|
488
|
+
|
|
489
|
+
var container = {};
|
|
490
|
+
var cyclic = [];
|
|
491
|
+
cyclic.back = container;
|
|
492
|
+
container.a = cyclic;
|
|
493
|
+
st['throws'](
|
|
494
|
+
function () { qs.stringify(container, { allowEmptyArrays: true }); },
|
|
495
|
+
RangeError,
|
|
496
|
+
'a cycle through an empty array with an own key is still detected'
|
|
497
|
+
);
|
|
498
|
+
|
|
499
|
+
st.end();
|
|
500
|
+
});
|
|
501
|
+
|
|
331
502
|
t.test('stringifies an array value with one item vs multiple items', function (st) {
|
|
332
503
|
st.test('non-array item', function (s2t) {
|
|
333
504
|
s2t.equal(qs.stringify({ a: 'c' }, { encodeValuesOnly: true, arrayFormat: 'indices' }), 'a=c');
|
|
@@ -761,6 +932,33 @@ test('stringify()', function (t) {
|
|
|
761
932
|
st.end();
|
|
762
933
|
});
|
|
763
934
|
|
|
935
|
+
t.test('does not throw on a non-callable `constructor.isBuffer` key', function (st) {
|
|
936
|
+
var input = { a: { constructor: { isBuffer: 'x' } } };
|
|
937
|
+
st.doesNotThrow(function () { qs.stringify(input); });
|
|
938
|
+
st.equal(qs.stringify(input), 'a%5Bconstructor%5D%5BisBuffer%5D=x');
|
|
939
|
+
st.equal(qs.stringify({ a: { constructor: { isBuffer: { b: 'c' } } } }), 'a%5Bconstructor%5D%5BisBuffer%5D%5Bb%5D=c');
|
|
940
|
+
st.equal(qs.stringify({ a: { constructor: { isBuffer: ['b'] } } }), 'a%5Bconstructor%5D%5BisBuffer%5D%5B0%5D=b');
|
|
941
|
+
st.equal(qs.stringify({ a: { constructor: { isBuffer: true } } }), 'a%5Bconstructor%5D%5BisBuffer%5D=true');
|
|
942
|
+
st.end();
|
|
943
|
+
});
|
|
944
|
+
|
|
945
|
+
t.test('round-trips a parsed `constructor[isBuffer]` key', function (st) {
|
|
946
|
+
var str = 'x%5Bconstructor%5D%5BisBuffer%5D=y';
|
|
947
|
+
|
|
948
|
+
var plain = qs.parse(str, { plainObjects: true });
|
|
949
|
+
st.deepEqual(plain, { __proto__: null, x: { __proto__: null, constructor: { __proto__: null, isBuffer: 'y' } } }, 'plainObjects keeps the key');
|
|
950
|
+
st.doesNotThrow(function () { qs.stringify(plain); });
|
|
951
|
+
st.equal(qs.stringify(plain), str, 'plainObjects round-trips');
|
|
952
|
+
|
|
953
|
+
var proto = qs.parse(str, { allowPrototypes: true });
|
|
954
|
+
st.deepEqual(proto, { x: { constructor: { isBuffer: 'y' } } }, 'allowPrototypes keeps the key');
|
|
955
|
+
st.doesNotThrow(function () { qs.stringify(proto); });
|
|
956
|
+
st.equal(qs.stringify(proto), str, 'allowPrototypes round-trips');
|
|
957
|
+
|
|
958
|
+
st.equal(qs.stringify(qs.parse(str)), '', 'default options drop the key');
|
|
959
|
+
st.end();
|
|
960
|
+
});
|
|
961
|
+
|
|
764
962
|
t.test('stringifies an object using an alternative delimiter', function (st) {
|
|
765
963
|
st.equal(qs.stringify({ a: 'b', c: 'd' }, { delimiter: ';' }), 'a=b;c=d');
|
|
766
964
|
st.end();
|
|
@@ -919,6 +1117,66 @@ test('stringify()', function (t) {
|
|
|
919
1117
|
st.end();
|
|
920
1118
|
});
|
|
921
1119
|
|
|
1120
|
+
t.test('serializes Date values unless filter transforms them', function (st) {
|
|
1121
|
+
var obj = {
|
|
1122
|
+
a: new Date(Date.UTC(2023, 2, 7, 9, 2, 41, 260)),
|
|
1123
|
+
b: [new Date(Date.UTC(2023, 2, 7, 9, 2, 41, 260))]
|
|
1124
|
+
};
|
|
1125
|
+
var iso = '2023-03-07T09%3A02%3A41.260Z';
|
|
1126
|
+
st.equal(
|
|
1127
|
+
qs.stringify(obj, { filter: function (prefix, value) { return value; } }),
|
|
1128
|
+
'a=' + iso + '&b%5B0%5D=' + iso,
|
|
1129
|
+
'Dates returned unchanged by a filter are serialized'
|
|
1130
|
+
);
|
|
1131
|
+
st.equal(
|
|
1132
|
+
qs.stringify({ a: new Date(0) }, { filter: function (prefix, value) { return value instanceof Date ? 'kept' : value; } }),
|
|
1133
|
+
'a=kept',
|
|
1134
|
+
'a filter that transforms a Date wins over default serialization'
|
|
1135
|
+
);
|
|
1136
|
+
st.end();
|
|
1137
|
+
});
|
|
1138
|
+
|
|
1139
|
+
t.test('applies default Date handling to whatever a filter function returns', function (st) {
|
|
1140
|
+
var date = new Date(Date.UTC(2023, 2, 7, 9, 2, 41, 260));
|
|
1141
|
+
var iso = '2023-03-07T09%3A02%3A41.260Z';
|
|
1142
|
+
var identity = function (prefix, value) { return value; };
|
|
1143
|
+
|
|
1144
|
+
st.equal(
|
|
1145
|
+
qs.stringify({ a: { b: date } }, { filter: identity }),
|
|
1146
|
+
'a%5Bb%5D=' + iso,
|
|
1147
|
+
'a nested Date is serialized through a filter'
|
|
1148
|
+
);
|
|
1149
|
+
st.equal(
|
|
1150
|
+
qs.stringify(
|
|
1151
|
+
{ a: date },
|
|
1152
|
+
{ filter: identity, serializeDate: function (d) { return String(d.getTime()); } }
|
|
1153
|
+
),
|
|
1154
|
+
'a=1678179761260',
|
|
1155
|
+
'`serializeDate` is honored after a filter'
|
|
1156
|
+
);
|
|
1157
|
+
st.equal(
|
|
1158
|
+
qs.stringify({ a: [date, 'x'] }, { filter: identity, arrayFormat: 'comma' }),
|
|
1159
|
+
'a=' + iso + '%2Cx',
|
|
1160
|
+
'Dates inside a comma array are serialized through a filter, not stringified as locale text'
|
|
1161
|
+
);
|
|
1162
|
+
st.equal(
|
|
1163
|
+
qs.stringify({ a: 'x' }, { filter: function (prefix, value) { return prefix === 'a' ? date : value; } }),
|
|
1164
|
+
'a=' + iso,
|
|
1165
|
+
'a Date produced by the filter is serialized'
|
|
1166
|
+
);
|
|
1167
|
+
st.equal(
|
|
1168
|
+
qs.stringify({ a: date, b: 1 }, { filter: ['a'] }),
|
|
1169
|
+
'a=' + iso,
|
|
1170
|
+
'an array filter still serializes Dates'
|
|
1171
|
+
);
|
|
1172
|
+
st['throws'](
|
|
1173
|
+
function () { qs.stringify({ a: new Date(NaN) }, { filter: identity }); },
|
|
1174
|
+
RangeError,
|
|
1175
|
+
'an invalid Date through a filter throws like the no-filter path'
|
|
1176
|
+
);
|
|
1177
|
+
st.end();
|
|
1178
|
+
});
|
|
1179
|
+
|
|
922
1180
|
t.test('can disable uri encoding', function (st) {
|
|
923
1181
|
st.equal(qs.stringify({ a: 'b' }, { encode: false }), 'a=b');
|
|
924
1182
|
st.equal(qs.stringify({ a: { b: 'c' } }, { encode: false }), 'a[b]=c');
|
|
@@ -1445,4 +1703,63 @@ test('stringifies empty keys', function (t) {
|
|
|
1445
1703
|
|
|
1446
1704
|
st.end();
|
|
1447
1705
|
});
|
|
1706
|
+
|
|
1707
|
+
t.test('limits nesting depth with the `depth` option', function (st) {
|
|
1708
|
+
st.equal(
|
|
1709
|
+
qs.stringify({ a: { b: { c: 'd' } } }),
|
|
1710
|
+
'a%5Bb%5D%5Bc%5D=d',
|
|
1711
|
+
'the default depth is unlimited and does not alter output'
|
|
1712
|
+
);
|
|
1713
|
+
st.equal(
|
|
1714
|
+
qs.stringify({ a: { b: { c: 'd' } } }, { depth: 2 }),
|
|
1715
|
+
'a%5Bb%5D%5Bc%5D=d',
|
|
1716
|
+
'does not throw when nesting is within the depth limit'
|
|
1717
|
+
);
|
|
1718
|
+
st.equal(
|
|
1719
|
+
qs.stringify({ a: { b: 'c' } }, { depth: Infinity }),
|
|
1720
|
+
'a%5Bb%5D=c',
|
|
1721
|
+
'an explicit Infinity depth is unlimited'
|
|
1722
|
+
);
|
|
1723
|
+
st.equal(
|
|
1724
|
+
qs.stringify({ a: { b: { c: { d: 'e' } } } }, { depth: null }),
|
|
1725
|
+
qs.stringify({ a: { b: { c: { d: 'e' } } } }),
|
|
1726
|
+
'a non-number depth is ignored and treated as unlimited'
|
|
1727
|
+
);
|
|
1728
|
+
st.equal(
|
|
1729
|
+
qs.stringify({ a: 'b' }, { depth: 0 }),
|
|
1730
|
+
'a=b',
|
|
1731
|
+
'a flat object serializes with a depth of 0'
|
|
1732
|
+
);
|
|
1733
|
+
|
|
1734
|
+
var deep = {};
|
|
1735
|
+
var cursor = deep;
|
|
1736
|
+
for (var i = 0; i < 250; i++) {
|
|
1737
|
+
cursor.a = {};
|
|
1738
|
+
cursor = cursor.a;
|
|
1739
|
+
}
|
|
1740
|
+
cursor.b = 'c';
|
|
1741
|
+
st.equal(typeof qs.stringify(deep), 'string', 'the default depth serializes deeply nested objects without throwing');
|
|
1742
|
+
|
|
1743
|
+
st['throws'](
|
|
1744
|
+
function () { qs.stringify({ a: { b: { c: { d: 'e' } } } }, { depth: 2 }); },
|
|
1745
|
+
RangeError,
|
|
1746
|
+
'throws a RangeError when nesting exceeds the depth limit'
|
|
1747
|
+
);
|
|
1748
|
+
st['throws'](
|
|
1749
|
+
function () { qs.stringify({ a: { b: 'c' } }, { depth: 0 }); },
|
|
1750
|
+
RangeError,
|
|
1751
|
+
'a depth of 0 throws for any nested object'
|
|
1752
|
+
);
|
|
1753
|
+
|
|
1754
|
+
var caught;
|
|
1755
|
+
try {
|
|
1756
|
+
qs.stringify({ a: { b: { c: { d: 'e' } } } }, { depth: 2 });
|
|
1757
|
+
} catch (e) {
|
|
1758
|
+
caught = e;
|
|
1759
|
+
}
|
|
1760
|
+
st.ok(caught instanceof RangeError, 'the thrown value is a RangeError');
|
|
1761
|
+
st.equal(caught.message, 'Input depth exceeded depth option of 2', 'the RangeError names the exceeded depth');
|
|
1762
|
+
|
|
1763
|
+
st.end();
|
|
1764
|
+
});
|
|
1448
1765
|
});
|
|
@@ -604,6 +604,18 @@ test('isBuffer()', function (t) {
|
|
|
604
604
|
var fakeBuffer = { constructor: Buffer };
|
|
605
605
|
t.equal(utils.isBuffer(fakeBuffer), false, 'fake buffer is not a buffer');
|
|
606
606
|
|
|
607
|
+
forEach(['x', 1, true, {}, [], { isBuffer: true }], function (notCallable) {
|
|
608
|
+
var obj = { constructor: { isBuffer: notCallable } };
|
|
609
|
+
t.doesNotThrow(function () { utils.isBuffer(obj); }, 'non-callable `constructor.isBuffer` (' + inspect(notCallable) + ') does not throw');
|
|
610
|
+
t.equal(utils.isBuffer(obj), false, 'non-callable `constructor.isBuffer` (' + inspect(notCallable) + ') is not a buffer');
|
|
611
|
+
});
|
|
612
|
+
|
|
613
|
+
var nullObject = { __proto__: null, constructor: { __proto__: null, isBuffer: 'y' } };
|
|
614
|
+
t.equal(utils.isBuffer(nullObject), false, 'null object with non-callable `constructor.isBuffer` is not a buffer');
|
|
615
|
+
|
|
616
|
+
var duckBuffer = { constructor: { isBuffer: function () { return true; } } };
|
|
617
|
+
t.equal(utils.isBuffer(duckBuffer), true, 'callable `constructor.isBuffer` is still honored');
|
|
618
|
+
|
|
607
619
|
var saferBuffer = SaferBuffer.from('abc');
|
|
608
620
|
t.equal(utils.isBuffer(saferBuffer), true, 'SaferBuffer instance is a buffer');
|
|
609
621
|
|
|
@@ -33,7 +33,7 @@ export declare namespace Client {
|
|
|
33
33
|
export interface Options {
|
|
34
34
|
/** The maximum length of request headers in bytes. Default: Node.js' `--max-http-header-size` or `16384` (16KiB). */
|
|
35
35
|
maxHeaderSize?: number;
|
|
36
|
-
/** The amount of time, in milliseconds, the parser will wait to receive the complete HTTP headers (Node 14 and above only). Default: `300e3` milliseconds (300s). */
|
|
36
|
+
/** The amount of time, in milliseconds, the parser will wait to receive the complete HTTP headers (Node 14 and above only). Default: `300e3` milliseconds (300s). HTTP/1.1 parser timeouts are not guaranteed to fire with exact millisecond precision: delays up to 1000ms use native timers, while larger delays use lower-overhead fast timers with a target resolution around 500ms. */
|
|
37
37
|
headersTimeout?: number;
|
|
38
38
|
/** @deprecated unsupported socketTimeout, use headersTimeout & bodyTimeout instead */
|
|
39
39
|
socketTimeout?: never;
|
|
@@ -41,7 +41,7 @@ export declare namespace Client {
|
|
|
41
41
|
requestTimeout?: never;
|
|
42
42
|
/** The timeout for establishing a socket connection, in milliseconds. Use `0` to disable it entirely. Default: `10e3` milliseconds (10s). */
|
|
43
43
|
connectTimeout?: number;
|
|
44
|
-
/** The timeout after which a request will time out, in milliseconds. Monitors time between receiving body data. Use `0` to disable it entirely. Default: `300e3` milliseconds (300s). */
|
|
44
|
+
/** The timeout after which a request will time out, in milliseconds. Monitors time between receiving body data. Use `0` to disable it entirely. Default: `300e3` milliseconds (300s). HTTP/1.1 parser timeouts are not guaranteed to fire with exact millisecond precision: delays up to 1000ms use native timers, while larger delays use lower-overhead fast timers with a target resolution around 500ms. */
|
|
45
45
|
bodyTimeout?: number;
|
|
46
46
|
/** @deprecated unsupported idleTimeout, use keepAliveTimeout instead */
|
|
47
47
|
idleTimeout?: never;
|
|
@@ -57,7 +57,7 @@ export declare namespace Client {
|
|
|
57
57
|
keepAliveTimeoutThreshold?: number;
|
|
58
58
|
/** An IPC endpoint, either a Unix domain socket or Windows named pipe. Default: `null`. */
|
|
59
59
|
socketPath?: string;
|
|
60
|
-
/** The amount of concurrent requests to be sent over the single TCP/TLS connection according to [RFC7230](https://tools.ietf.org/html/rfc7230#section-6.3.2). Default: `1`. */
|
|
60
|
+
/** The amount of concurrent requests to be sent over the single TCP/TLS connection according to [RFC7230](https://tools.ietf.org/html/rfc7230#section-6.3.2). Only enable values greater than `1` when the remote server is trusted. Default: `1`. */
|
|
61
61
|
pipelining?: number;
|
|
62
62
|
/** @deprecated use the connect option instead */
|
|
63
63
|
tls?: never;
|
|
@@ -116,6 +116,11 @@ export declare namespace Client {
|
|
|
116
116
|
bytesRead?: number
|
|
117
117
|
}
|
|
118
118
|
export interface WebSocketOptions {
|
|
119
|
+
/**
|
|
120
|
+
* Maximum number of fragments in a message. Set to 0 to disable the limit.
|
|
121
|
+
* @default 131072
|
|
122
|
+
*/
|
|
123
|
+
maxFragments?: number;
|
|
119
124
|
/**
|
|
120
125
|
* Maximum allowed payload size in bytes for WebSocket messages.
|
|
121
126
|
* Applied to uncompressed messages, compressed frame payloads, and decompressed (permessage-deflate) messages.
|
|
@@ -7,6 +7,7 @@ declare function buildConnector (options?: buildConnector.BuildOptions): buildCo
|
|
|
7
7
|
declare namespace buildConnector {
|
|
8
8
|
export type BuildOptions = (ConnectionOptions | TcpNetConnectOpts | IpcNetConnectOpts) & {
|
|
9
9
|
allowH2?: boolean;
|
|
10
|
+
preferH2?: boolean;
|
|
10
11
|
maxCachedSessions?: number | null;
|
|
11
12
|
socketPath?: string | null;
|
|
12
13
|
timeout?: number | null;
|
|
@@ -18,7 +18,7 @@ export interface Cookie {
|
|
|
18
18
|
export function deleteCookie (
|
|
19
19
|
headers: Headers,
|
|
20
20
|
name: string,
|
|
21
|
-
attributes?: {
|
|
21
|
+
attributes?: { path?: string, domain?: string }
|
|
22
22
|
): void
|
|
23
23
|
|
|
24
24
|
export function getCookies (headers: Headers): Record<string, string>
|
|
@@ -111,13 +111,13 @@ declare namespace Dispatcher {
|
|
|
111
111
|
idempotent?: boolean;
|
|
112
112
|
/** Whether the response is expected to take a long time and would end up blocking the pipeline. When this is set to `true` further pipelining will be avoided on the same connection until headers have been received. Defaults to `method !== 'HEAD'`. */
|
|
113
113
|
blocking?: boolean;
|
|
114
|
-
/** The IP Type of Service (ToS) value for the request socket. Must be an integer between 0 and 255.
|
|
114
|
+
/** The IP Type of Service (ToS) value for the request socket. Must be an integer between 0 and 255. */
|
|
115
115
|
typeOfService?: number | null;
|
|
116
116
|
/** Upgrade the request. Should be used to specify the kind of upgrade i.e. `'Websocket'`. Default: `method === 'CONNECT' || null`. */
|
|
117
117
|
upgrade?: boolean | string | null;
|
|
118
|
-
/** The amount of time, in milliseconds, the parser will wait to receive the complete HTTP headers. Defaults to 300 seconds. */
|
|
118
|
+
/** The amount of time, in milliseconds, the parser will wait to receive the complete HTTP headers. Defaults to 300 seconds. HTTP/1.1 parser timeouts are not guaranteed to fire with exact millisecond precision: delays up to 1000ms use native timers, while larger delays use lower-overhead fast timers with a target resolution around 500ms. */
|
|
119
119
|
headersTimeout?: number | null;
|
|
120
|
-
/** The timeout after which a request will time out, in milliseconds. Monitors time between receiving body data. Use 0 to disable it entirely. Defaults to 300 seconds. */
|
|
120
|
+
/** The timeout after which a request will time out, in milliseconds. Monitors time between receiving body data. Use 0 to disable it entirely. Defaults to 300 seconds. HTTP/1.1 parser timeouts are not guaranteed to fire with exact millisecond precision: delays up to 1000ms use native timers, while larger delays use lower-overhead fast timers with a target resolution around 500ms. */
|
|
121
121
|
bodyTimeout?: number | null;
|
|
122
122
|
/** Whether the request should stablish a keep-alive or not. Default `false` */
|
|
123
123
|
reset?: boolean;
|
|
@@ -154,6 +154,16 @@ declare namespace Errors {
|
|
|
154
154
|
code: 'UND_ERR_PRX_TLS'
|
|
155
155
|
}
|
|
156
156
|
|
|
157
|
+
export class ProxyConnectionError extends UndiciError {
|
|
158
|
+
constructor (
|
|
159
|
+
cause?: Error,
|
|
160
|
+
message?: string,
|
|
161
|
+
options?: Record<any, any>
|
|
162
|
+
)
|
|
163
|
+
name: 'ProxyConnectionError'
|
|
164
|
+
code: 'UND_ERR_PRX_CONN'
|
|
165
|
+
}
|
|
166
|
+
|
|
157
167
|
export class MaxOriginsReachedError extends UndiciError {
|
|
158
168
|
name: 'MaxOriginsReachedError'
|
|
159
169
|
code: 'UND_ERR_MAX_ORIGINS_REACHED'
|
|
@@ -36,7 +36,10 @@ export class BodyMixin {
|
|
|
36
36
|
readonly bytes: () => Promise<Uint8Array>
|
|
37
37
|
/**
|
|
38
38
|
* @deprecated This method is not recommended for parsing multipart/form-data bodies in server environments.
|
|
39
|
-
*
|
|
39
|
+
* Calling body.formData() buffers and parses the entire body. Since this is dictated by the spec,
|
|
40
|
+
* this method must only be called on responses from trusted servers.
|
|
41
|
+
* For responses from untrusted or user-controlled servers, use a dedicated streaming parser such as
|
|
42
|
+
* [@fastify/busboy](https://www.npmjs.com/package/@fastify/busboy) and apply application-specific limits as follows:
|
|
40
43
|
*
|
|
41
44
|
* @example
|
|
42
45
|
* ```js
|
|
@@ -54,6 +57,7 @@ export class BodyMixin {
|
|
|
54
57
|
readonly formData: () => Promise<FormData>
|
|
55
58
|
readonly json: () => Promise<unknown>
|
|
56
59
|
readonly text: () => Promise<string>
|
|
60
|
+
readonly textStream: () => ReadableStream<string>
|
|
57
61
|
}
|
|
58
62
|
|
|
59
63
|
export interface SpecIterator<T, TReturn = any, TNext = undefined> {
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import Dispatcher from './dispatcher'
|
|
2
2
|
|
|
3
3
|
export declare class RedirectHandler implements Dispatcher.DispatchHandler {
|
|
4
|
+
static buildDispatch (dispatcher: Dispatcher, maxRedirections: number): Dispatcher.Dispatch
|
|
5
|
+
|
|
4
6
|
constructor (
|
|
5
7
|
dispatch: Dispatcher.Dispatch,
|
|
6
8
|
maxRedirections: number,
|
|
@@ -8,7 +8,7 @@ export default Interceptors
|
|
|
8
8
|
declare namespace Interceptors {
|
|
9
9
|
export type DumpInterceptorOpts = { maxSize?: number }
|
|
10
10
|
export type RetryInterceptorOpts = RetryHandler.RetryOptions
|
|
11
|
-
export type RedirectInterceptorOpts = { maxRedirections?: number, throwOnMaxRedirect?: boolean }
|
|
11
|
+
export type RedirectInterceptorOpts = { maxRedirections?: number, throwOnMaxRedirect?: boolean, stripHeadersOnRedirect?: string[], stripHeadersOnCrossOriginRedirect?: string[] }
|
|
12
12
|
export type DecompressInterceptorOpts = {
|
|
13
13
|
skipErrorResponses?: boolean
|
|
14
14
|
skipStatusCodes?: number[]
|
|
@@ -75,9 +75,13 @@ declare namespace MockInterceptor {
|
|
|
75
75
|
opts: MockResponseCallbackOptions
|
|
76
76
|
) => TData | Buffer | string
|
|
77
77
|
|
|
78
|
+
export type MockReplyOptions<TData extends object = object> = {
|
|
79
|
+
statusCode: number, data?: TData | Buffer | string, responseOptions?: MockResponseOptions
|
|
80
|
+
}
|
|
81
|
+
|
|
78
82
|
export type MockReplyOptionsCallback<TData extends object = object> = (
|
|
79
83
|
opts: MockResponseCallbackOptions
|
|
80
|
-
) =>
|
|
84
|
+
) => MockReplyOptions<TData> | Promise<MockReplyOptions<TData>>
|
|
81
85
|
}
|
|
82
86
|
|
|
83
87
|
interface Interceptable extends Dispatcher {
|
|
@@ -24,6 +24,13 @@ declare namespace ProxyAgent {
|
|
|
24
24
|
requestTls?: buildConnector.BuildOptions;
|
|
25
25
|
proxyTls?: buildConnector.BuildOptions;
|
|
26
26
|
clientFactory?(origin: URL, opts: object): Dispatcher;
|
|
27
|
+
/**
|
|
28
|
+
* Undici tunnels via CONNECT when the target endpoint uses HTTPS, and
|
|
29
|
+
* forwards (HTTP/1.1 absolute-form request-target, per RFC 9112 §3.2.2)
|
|
30
|
+
* otherwise, regardless of whether the proxy URL is HTTP or HTTPS. The
|
|
31
|
+
* non-tunneled forwarding path does not negotiate HTTP/2 with the proxy.
|
|
32
|
+
* Set to true to force tunneling for plain HTTP requests as well.
|
|
33
|
+
*/
|
|
27
34
|
proxyTunnel?: boolean;
|
|
28
35
|
}
|
|
29
36
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@suveren/gateway",
|
|
3
|
-
"version": "0.8.
|
|
3
|
+
"version": "0.8.5",
|
|
4
4
|
"description": "Suveren gateway — local agent gateway built in compliance with the Human Agency Protocol (HAP). Runs the UI, control plane, and MCP server in one Node process.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "server.js",
|