@zuplo/cli 7.13.1 → 7.13.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (54) hide show
  1. package/dist/common/cli-dispatcher.js +1 -1
  2. package/dist/common/cli-dispatcher.js.map +1 -1
  3. package/node_modules/@modelcontextprotocol/client/node_modules/jose/dist/types/jwt/decrypt.d.ts +3 -0
  4. package/node_modules/@modelcontextprotocol/client/node_modules/jose/dist/types/jwt/unsecured.d.ts +2 -0
  5. package/node_modules/@modelcontextprotocol/client/node_modules/jose/dist/types/jwt/verify.d.ts +3 -0
  6. package/node_modules/@modelcontextprotocol/client/node_modules/jose/dist/types/types.d.ts +8 -0
  7. package/node_modules/@modelcontextprotocol/client/node_modules/jose/dist/types/util/decode_jwt.d.ts +1 -0
  8. package/node_modules/@modelcontextprotocol/client/node_modules/jose/dist/webapi/jwks/remote.js +1 -1
  9. package/node_modules/@modelcontextprotocol/client/node_modules/jose/package.json +1 -1
  10. package/node_modules/@modelcontextprotocol/sdk/node_modules/jose/dist/types/jwt/decrypt.d.ts +3 -0
  11. package/node_modules/@modelcontextprotocol/sdk/node_modules/jose/dist/types/jwt/unsecured.d.ts +2 -0
  12. package/node_modules/@modelcontextprotocol/sdk/node_modules/jose/dist/types/jwt/verify.d.ts +3 -0
  13. package/node_modules/@modelcontextprotocol/sdk/node_modules/jose/dist/types/types.d.ts +8 -0
  14. package/node_modules/@modelcontextprotocol/sdk/node_modules/jose/dist/types/util/decode_jwt.d.ts +1 -0
  15. package/node_modules/@modelcontextprotocol/sdk/node_modules/jose/dist/webapi/jwks/remote.js +1 -1
  16. package/node_modules/@modelcontextprotocol/sdk/node_modules/jose/package.json +1 -1
  17. package/node_modules/@posthog/core/dist/types.d.ts +4 -0
  18. package/node_modules/@posthog/core/dist/types.d.ts.map +1 -1
  19. package/node_modules/@posthog/core/package.json +2 -2
  20. package/node_modules/@posthog/core/src/types.ts +4 -0
  21. package/node_modules/@posthog/types/dist/posthog-config.d.ts +10 -0
  22. package/node_modules/@posthog/types/dist/posthog-config.d.ts.map +1 -1
  23. package/node_modules/@posthog/types/package.json +1 -1
  24. package/node_modules/@posthog/types/src/posthog-config.ts +11 -0
  25. package/node_modules/@zuplo/core/customer.cli.minified.js +862 -281
  26. package/node_modules/@zuplo/core/index.minified.js +878 -297
  27. package/node_modules/@zuplo/core/package.json +1 -1
  28. package/node_modules/@zuplo/graphql/package.json +1 -1
  29. package/node_modules/@zuplo/openapi-tools/package.json +1 -1
  30. package/node_modules/@zuplo/otel/package.json +1 -1
  31. package/node_modules/@zuplo/runtime/out/esm/{chunk-3CVOCJ3Y.js → chunk-DVFQRFED.js} +90 -90
  32. package/node_modules/@zuplo/runtime/out/esm/chunk-DVFQRFED.js.map +1 -0
  33. package/node_modules/@zuplo/runtime/out/esm/index.js +1 -1
  34. package/node_modules/@zuplo/runtime/out/esm/mcp-gateway/index.js +1 -1
  35. package/node_modules/@zuplo/runtime/out/esm/mocks/index.js +1 -1
  36. package/node_modules/@zuplo/runtime/package.json +1 -1
  37. package/node_modules/ansi-regex/index.js +13 -4
  38. package/node_modules/ansi-regex/package.json +30 -13
  39. package/node_modules/encodeurl/README.md +14 -0
  40. package/node_modules/encodeurl/index.js +5 -10
  41. package/node_modules/encodeurl/package.json +10 -6
  42. package/node_modules/express-rate-limit/dist/index.cjs +6 -2
  43. package/node_modules/express-rate-limit/dist/index.mjs +6 -2
  44. package/node_modules/express-rate-limit/package.json +10 -10
  45. package/node_modules/qs/CHANGELOG.md +42 -0
  46. package/node_modules/qs/README.md +38 -10
  47. package/node_modules/qs/dist/qs.js +18 -18
  48. package/node_modules/qs/lib/parse.js +16 -4
  49. package/node_modules/qs/lib/utils.js +13 -2
  50. package/node_modules/qs/package.json +1 -1
  51. package/node_modules/qs/test/parse.js +69 -0
  52. package/package.json +11 -11
  53. package/node_modules/@zuplo/runtime/out/esm/chunk-3CVOCJ3Y.js.map +0 -1
  54. /package/node_modules/@zuplo/runtime/out/esm/{chunk-3CVOCJ3Y.js.LEGAL.txt → chunk-DVFQRFED.js.LEGAL.txt} +0 -0
@@ -22,5 +22,5 @@
22
22
  * DEALINGS IN THE SOFTWARE.
23
23
  *--------------------------------------------------------------------------------------------*/
24
24
 
25
- import{G as p,L as c,O as u}from"../chunk-3CVOCJ3Y.js";import"../chunk-ZCJ5QBVD.js";import{a as d}from"../chunk-QGAJTUPE.js";import"../chunk-A3QGJZO7.js";import{aa as i}from"../chunk-FQIUJWH2.js";import"../chunk-UKQQD2JN.js";import{a as o}from"../chunk-TYV53J3B.js";function w(l={request:new Request("https://api.example.com")}){let e=[];function t(s){e.push(Promise.resolve(s))}return o(t,"waitUntil"),{context:new a({event:{waitUntil:t},route:l.route,originalRequest:l.request}),invokeResponse:o(async()=>{await Promise.all(e)},"invokeResponse")}}o(w,"createMockContext");var g={path:"/",methods:["GET"],handler:{module:{},export:"default"},raw:o(()=>({}),"raw")},a=class extends EventTarget{static{o(this,"MockZuploContext")}#e;#t;contextId;requestId;log;route;custom;incomingRequestProperties;parentContext;analyticsContext;constructor({event:e,route:t=g,parentContext:n,originalRequest:r}){super(),this.requestId=crypto.randomUUID(),this.contextId=crypto.randomUUID(),this.log={info:i.console.info,log:i.console.log,debug:i.console.debug,warn:i.console.warn,error:i.console.error,setLogProperties:o(()=>{},"setLogProperties")},this.custom={},this.route=t,this.incomingRequestProperties={ip:"203.0.113.7",asn:1234,asOrganization:"ORGANIZATION",city:"Seattle",region:"Washington",regionCode:"WA",colo:"SEA",continent:"NA",country:"US",postalCode:"98004",metroCode:"SEA",latitude:void 0,longitude:void 0,timezone:void 0,httpProtocol:void 0,clientCert:void 0,clientMtlsVerificationStatus:void 0,clientMtlsVerificationReason:void 0,clientCertFingerprintSha256:void 0,clientCertNotBefore:void 0,clientCertNotAfter:void 0,clientCertIssuerDn:void 0,clientCertSubjectDn:void 0},this.parentContext=n,this.#e=e,this.#t=r,this.analyticsContext=new c(this.requestId)}waitUntil(e){this.#e.waitUntil(e)}invokeInboundPolicy(e,t){throw new Error("Not implemented")}invokeOutboundPolicy(e,t,n){throw new Error("Not implemented")}invokeRoute(e,t){throw new Error("Not implemented")}addResponseSendingHook(e){throw new Error("Not implemented")}addResponseSendingFinalHook(e){throw new Error("Not implemented")}addPreRequestHandler(e,t){let n;try{n=u.getContextExtensions(this)}catch{n=u.initialize(this,new d(this.#t??new Request("https://api.example.com")))}n.preRequestPhase??="active",p(this,n,e,t)}get preRequestHandlers(){let e;try{e=u.getContextExtensions(this)}catch{return[]}return(e.preRequestState?.entries??[]).map(t=>({policyName:t.policyName,name:t.name}))}addEventListener(e,t,n){let r=o(s=>{try{typeof t=="function"?t(s):t.handleEvent(s)}catch(m){throw this.log.error(`Error invoking event ${e}. See following logs for details.`),m}},"wrapped");super.addEventListener(e,r,n)}};export{a as MockZuploContext,w as createMockContext};
25
+ import{G as p,L as c,O as u}from"../chunk-DVFQRFED.js";import"../chunk-ZCJ5QBVD.js";import{a as d}from"../chunk-QGAJTUPE.js";import"../chunk-A3QGJZO7.js";import{aa as i}from"../chunk-FQIUJWH2.js";import"../chunk-UKQQD2JN.js";import{a as o}from"../chunk-TYV53J3B.js";function w(l={request:new Request("https://api.example.com")}){let e=[];function t(s){e.push(Promise.resolve(s))}return o(t,"waitUntil"),{context:new a({event:{waitUntil:t},route:l.route,originalRequest:l.request}),invokeResponse:o(async()=>{await Promise.all(e)},"invokeResponse")}}o(w,"createMockContext");var g={path:"/",methods:["GET"],handler:{module:{},export:"default"},raw:o(()=>({}),"raw")},a=class extends EventTarget{static{o(this,"MockZuploContext")}#e;#t;contextId;requestId;log;route;custom;incomingRequestProperties;parentContext;analyticsContext;constructor({event:e,route:t=g,parentContext:n,originalRequest:r}){super(),this.requestId=crypto.randomUUID(),this.contextId=crypto.randomUUID(),this.log={info:i.console.info,log:i.console.log,debug:i.console.debug,warn:i.console.warn,error:i.console.error,setLogProperties:o(()=>{},"setLogProperties")},this.custom={},this.route=t,this.incomingRequestProperties={ip:"203.0.113.7",asn:1234,asOrganization:"ORGANIZATION",city:"Seattle",region:"Washington",regionCode:"WA",colo:"SEA",continent:"NA",country:"US",postalCode:"98004",metroCode:"SEA",latitude:void 0,longitude:void 0,timezone:void 0,httpProtocol:void 0,clientCert:void 0,clientMtlsVerificationStatus:void 0,clientMtlsVerificationReason:void 0,clientCertFingerprintSha256:void 0,clientCertNotBefore:void 0,clientCertNotAfter:void 0,clientCertIssuerDn:void 0,clientCertSubjectDn:void 0},this.parentContext=n,this.#e=e,this.#t=r,this.analyticsContext=new c(this.requestId)}waitUntil(e){this.#e.waitUntil(e)}invokeInboundPolicy(e,t){throw new Error("Not implemented")}invokeOutboundPolicy(e,t,n){throw new Error("Not implemented")}invokeRoute(e,t){throw new Error("Not implemented")}addResponseSendingHook(e){throw new Error("Not implemented")}addResponseSendingFinalHook(e){throw new Error("Not implemented")}addPreRequestHandler(e,t){let n;try{n=u.getContextExtensions(this)}catch{n=u.initialize(this,new d(this.#t??new Request("https://api.example.com")))}n.preRequestPhase??="active",p(this,n,e,t)}get preRequestHandlers(){let e;try{e=u.getContextExtensions(this)}catch{return[]}return(e.preRequestState?.entries??[]).map(t=>({policyName:t.policyName,name:t.name}))}addEventListener(e,t,n){let r=o(s=>{try{typeof t=="function"?t(s):t.handleEvent(s)}catch(m){throw this.log.error(`Error invoking event ${e}. See following logs for details.`),m}},"wrapped");super.addEventListener(e,r,n)}};export{a as MockZuploContext,w as createMockContext};
26
26
  //# sourceMappingURL=index.js.map
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@zuplo/runtime",
3
3
  "type": "module",
4
- "version": "7.13.1",
4
+ "version": "7.13.3",
5
5
  "repository": "https://github.com/zuplo/zuplo",
6
6
  "author": "Zuplo, Inc.",
7
7
  "exports": {
@@ -1,15 +1,24 @@
1
1
  export default function ansiRegex({onlyFirst = false} = {}) {
2
2
  // Valid string terminator sequences are BEL, ESC\, and 0x9c
3
- const ST = '(?:\\u0007|\\u001B\\u005C|\\u009C)';
3
+ const ST = String.raw`(?:\u0007|\u001B\u005C|\u009C)`;
4
4
 
5
5
  // OSC sequences only: ESC ] ... ST (or the C1 introducer 0x9d ... ST)
6
6
  // The payload stops at the first terminator character rather than scanning ahead for one, so an unterminated `ESC ]` cannot rescan the rest of the input. Terminals likewise abort a control string on an unexpected ESC. The payload also stops at 0x9d so an unterminated C1 OSC cannot swallow the next one.
7
- const osc = `(?:(?:\\u001B\\]|\\u009D)[^\\u0007\\u001B\\u009C\\u009D]*${ST})`;
7
+ const osc = String.raw`(?:(?:\u001B\]|\u009D)[^\u0007\u001B\u009C\u009D]*${ST})`;
8
8
 
9
9
  // CSI and related: ESC/C1, optional intermediates, optional params (supports ; and :) then final byte
10
- const csi = '[\\u001B\\u009B][[\\]()#;?]*(?:\\d{1,4}(?:[;:]\\d{0,4})*)?[\\dA-PR-TZcf-nq-uy=><~]';
10
+ // The final byte class is deliberately narrow, so that ESC followed by an arbitrary character is not read as a sequence. It must
11
+ // not include the parameter digits though: when the real final byte is outside the class the engine backtracks and takes the last
12
+ // parameter digit as the final byte instead, leaving the real one behind as visible text. `ESC [ 5 d` stripped to a bare `d`.
13
+ const csi = String.raw`[\u001B\u009B][[\]()#;?]*(?:\d{1,4}(?:[;:]\d{0,4})*)?[A-PR-TZcf-nq-uy=><~]`;
11
14
 
12
- const pattern = `${osc}|${csi}`;
15
+ // `= < >` are final bytes in the two byte VT52 escapes (`ESC >`) but parameter bytes in a CSI
16
+ // (`ESC [ > 0 ; 276 ; 0 c`, the device attributes reply). Matching them as a final byte always
17
+ // wins and leaves the rest of the reply behind as visible text, so the private parameter form is
18
+ // matched first, where the `[` makes the two unambiguous.
19
+ const csiPrivate = String.raw`(?:\u001B\[|\u009B)[<=>][0-9;:]*[A-PR-TZcf-nq-uy~]`;
20
+
21
+ const pattern = `${osc}|${csiPrivate}|${csi}`;
13
22
 
14
23
  return new RegExp(pattern, onlyFirst ? undefined : 'g');
15
24
  }
@@ -1,24 +1,23 @@
1
1
  {
2
2
  "name": "ansi-regex",
3
- "version": "6.4.0",
3
+ "version": "6.5.0",
4
4
  "description": "Regular expression for matching ANSI escape codes",
5
5
  "license": "MIT",
6
6
  "repository": "chalk/ansi-regex",
7
7
  "funding": "https://github.com/chalk/ansi-regex?sponsor=1",
8
- "author": {
9
- "name": "Sindre Sorhus",
10
- "email": "sindresorhus@gmail.com",
11
- "url": "https://sindresorhus.com"
12
- },
8
+ "author": "Sindre Sorhus <sindresorhus@gmail.com> (https://sindresorhus.com)",
13
9
  "type": "module",
14
- "exports": "./index.js",
10
+ "exports": {
11
+ "types": "./index.d.ts",
12
+ "default": "./index.js"
13
+ },
15
14
  "types": "./index.d.ts",
16
15
  "sideEffects": false,
17
16
  "engines": {
18
17
  "node": ">=12"
19
18
  },
20
19
  "scripts": {
21
- "test": "xo && ava && tsd",
20
+ "test": "xo && node --test",
22
21
  "view-supported": "node fixtures/view-codes.js"
23
22
  },
24
23
  "files": [
@@ -53,9 +52,27 @@
53
52
  "pattern"
54
53
  ],
55
54
  "devDependencies": {
56
- "ansi-escapes": "^5.0.0",
57
- "ava": "^3.15.0",
58
- "tsd": "^0.21.0",
59
- "xo": "^0.54.2"
60
- }
55
+ "ansi-escapes": "^7.3.0",
56
+ "xo": "^5.0.1"
57
+ },
58
+ "xo": [
59
+ {
60
+ "rules": {
61
+ "node-test/no-conditional-assertion": "off",
62
+ "regexp/no-control-character": "off",
63
+ "regexp/no-useless-non-capturing-group": "off",
64
+ "regexp/prefer-regexp-exec": "off",
65
+ "regexp/sort-character-class-elements": "off",
66
+ "unicorn/prefer-https": "off"
67
+ }
68
+ },
69
+ {
70
+ "files": [
71
+ "package.json"
72
+ ],
73
+ "rules": {
74
+ "package-json/prefer-exports": "off"
75
+ }
76
+ }
77
+ ]
61
78
  }
@@ -1,5 +1,10 @@
1
1
  # Encode URL
2
2
 
3
+ [![NPM Version][npm-image]][npm-url]
4
+ [![NPM Downloads][downloads-image]][downloads-url]
5
+ [![Build Status][ci-image]][ci-url]
6
+ [![Test Coverage][coveralls-image]][coveralls-url]
7
+
3
8
  Encode a URL to a percent-encoded form, excluding already-encoded sequences.
4
9
 
5
10
  ## Installation
@@ -107,3 +112,12 @@ $ npm run lint
107
112
  ## License
108
113
 
109
114
  [MIT](LICENSE)
115
+
116
+ [npm-image]: https://img.shields.io/npm/v/encodeurl
117
+ [npm-url]: https://npmjs.org/package/encodeurl
118
+ [downloads-image]: https://img.shields.io/npm/dm/encodeurl
119
+ [downloads-url]: https://npmcharts.com/compare/encodeurl?minimal=true
120
+ [ci-image]: https://img.shields.io/github/actions/workflow/status/pillarjs/encodeurl/ci.yml?branch=master
121
+ [ci-url]: https://github.com/pillarjs/encodeurl/actions/workflows/ci.yml
122
+ [coveralls-image]: https://img.shields.io/coverallsCoverage/github/pillarjs/encodeurl?branch=master
123
+ [coveralls-url]: https://coveralls.io/r/pillarjs/encodeurl?branch=master
@@ -22,18 +22,11 @@ module.exports = encodeUrl
22
22
  var ENCODE_CHARS_REGEXP = /(?:[^\x21\x23-\x3B\x3D\x3F-\x5F\x61-\x7A\x7C\x7E]|%(?:[^0-9A-Fa-f]|[0-9A-Fa-f][^0-9A-Fa-f]|$))+/g
23
23
 
24
24
  /**
25
- * RegExp to match unmatched surrogate pair.
25
+ * RegExp to match surrogate pairs and unpaired surrogates.
26
26
  * @private
27
27
  */
28
28
 
29
- var UNMATCHED_SURROGATE_PAIR_REGEXP = /(^|[^\uD800-\uDBFF])[\uDC00-\uDFFF]|[\uD800-\uDBFF]([^\uDC00-\uDFFF]|$)/g
30
-
31
- /**
32
- * String to replace unmatched surrogate pair with.
33
- * @private
34
- */
35
-
36
- var UNMATCHED_SURROGATE_PAIR_REPLACE = '$1\uFFFD$2'
29
+ var SURROGATE_REGEXP = /([\uD800-\uDBFF][\uDC00-\uDFFF])|[\uD800-\uDFFF]/g
37
30
 
38
31
  /**
39
32
  * Encode a URL to a percent-encoded form, excluding already-encoded sequences.
@@ -55,6 +48,8 @@ var UNMATCHED_SURROGATE_PAIR_REPLACE = '$1\uFFFD$2'
55
48
 
56
49
  function encodeUrl (url) {
57
50
  return String(url)
58
- .replace(UNMATCHED_SURROGATE_PAIR_REGEXP, UNMATCHED_SURROGATE_PAIR_REPLACE)
51
+ .replace(SURROGATE_REGEXP, function (_, pair) {
52
+ return pair || '\uFFFD'
53
+ })
59
54
  .replace(ENCODE_CHARS_REGEXP, encodeURI)
60
55
  }
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "encodeurl",
3
3
  "description": "Encode a URL to a percent-encoded form, excluding already-encoded sequences",
4
- "version": "2.0.0",
4
+ "version": "2.0.1",
5
5
  "contributors": [
6
6
  "Douglas Christopher Wilson <doug@somethingdoug.com>"
7
7
  ],
@@ -12,6 +12,10 @@
12
12
  "url"
13
13
  ],
14
14
  "repository": "pillarjs/encodeurl",
15
+ "funding": {
16
+ "type": "opencollective",
17
+ "url": "https://opencollective.com/express"
18
+ },
15
19
  "devDependencies": {
16
20
  "eslint": "5.11.1",
17
21
  "eslint-config-standard": "12.0.0",
@@ -19,8 +23,8 @@
19
23
  "eslint-plugin-node": "7.0.1",
20
24
  "eslint-plugin-promise": "4.0.1",
21
25
  "eslint-plugin-standard": "4.0.0",
22
- "istanbul": "0.4.5",
23
- "mocha": "2.5.3"
26
+ "mocha": "~11.7.0",
27
+ "nyc": "~17.1.0"
24
28
  },
25
29
  "files": [
26
30
  "LICENSE",
@@ -33,8 +37,8 @@
33
37
  },
34
38
  "scripts": {
35
39
  "lint": "eslint .",
36
- "test": "mocha --reporter spec --bail --check-leaks test/",
37
- "test-cov": "istanbul cover node_modules/mocha/bin/_mocha -- --reporter dot --check-leaks test/",
38
- "test-travis": "istanbul cover node_modules/mocha/bin/_mocha --report lcovonly -- --reporter spec --check-leaks test/"
40
+ "test": "mocha --check-leaks --reporter spec",
41
+ "test-ci": "nyc --reporter=lcov --reporter=text npm test",
42
+ "test-cov": "nyc --reporter=html --reporter=text npm test"
39
43
  }
40
44
  }
@@ -182,7 +182,7 @@ var MemoryStore = class {
182
182
  */
183
183
  resetClient(client, now = Date.now()) {
184
184
  client.totalHits = 0;
185
- client.resetTime.setTime(now + this.windowMs);
185
+ client.resetTime = new Date(now + this.windowMs);
186
186
  return client;
187
187
  }
188
188
  /**
@@ -931,7 +931,11 @@ var rateLimit = (passedOptions) => {
931
931
  try {
932
932
  const incrementResult = await config.store.increment(key);
933
933
  totalHits = incrementResult.totalHits;
934
- resetTime = incrementResult.resetTime;
934
+ if (incrementResult.resetTime && (config.skipFailedRequests || config.skipSuccessfulRequests)) {
935
+ resetTime = new Date(incrementResult.resetTime.getTime());
936
+ } else {
937
+ resetTime = incrementResult.resetTime;
938
+ }
935
939
  } catch (error) {
936
940
  if (config.passOnStoreError) {
937
941
  config.logger.error(
@@ -139,7 +139,7 @@ var MemoryStore = class {
139
139
  */
140
140
  resetClient(client, now = Date.now()) {
141
141
  client.totalHits = 0;
142
- client.resetTime.setTime(now + this.windowMs);
142
+ client.resetTime = new Date(now + this.windowMs);
143
143
  return client;
144
144
  }
145
145
  /**
@@ -888,7 +888,11 @@ var rateLimit = (passedOptions) => {
888
888
  try {
889
889
  const incrementResult = await config.store.increment(key);
890
890
  totalHits = incrementResult.totalHits;
891
- resetTime = incrementResult.resetTime;
891
+ if (incrementResult.resetTime && (config.skipFailedRequests || config.skipSuccessfulRequests)) {
892
+ resetTime = new Date(incrementResult.resetTime.getTime());
893
+ } else {
894
+ resetTime = incrementResult.resetTime;
895
+ }
892
896
  } catch (error) {
893
897
  if (config.passOnStoreError) {
894
898
  config.logger.error(
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "express-rate-limit",
3
- "version": "8.7.1",
3
+ "version": "8.7.2",
4
4
  "description": "Basic IP rate-limiting middleware for Express. Use to limit repeated requests to public APIs and/or endpoints such as password reset.",
5
5
  "author": {
6
6
  "name": "Nathan Friedly",
@@ -86,25 +86,25 @@
86
86
  "@biomejs/biome": "2.4.6",
87
87
  "@express-rate-limit/prettier": "1.1.1",
88
88
  "@express-rate-limit/tsconfig": "1.0.5",
89
- "@jest/globals": "30.5.1",
89
+ "@jest/globals": "30.5.2",
90
90
  "@types/debug": "4.1.13",
91
91
  "@types/express": "5.0.6",
92
92
  "@types/jest": "30.0.0",
93
- "@types/node": "26.4.1",
93
+ "@types/node": "26.6.4",
94
94
  "@types/supertest": "7.2.1",
95
95
  "del-cli": "7.0.0",
96
96
  "dts-bundle-generator": "8.1.2",
97
97
  "esbuild": "0.28.2",
98
98
  "express": "5.2.1",
99
99
  "husky": "9.1.7",
100
- "jest": "30.5.1",
101
- "lint-staged": "17.4.1",
102
- "mintlify": "4.2.874",
100
+ "jest": "30.5.2",
101
+ "lint-staged": "17.6.0",
102
+ "mintlify": "4.2.988",
103
103
  "npm-run-all": "4.1.5",
104
- "prettier": "3.9.6",
105
- "ratelimit-header-parser": "0.1.0",
106
- "supertest": "7.2.2",
107
- "ts-jest": "29.4.12",
104
+ "prettier": "3.9.9",
105
+ "ratelimit-header-parser": "0.2.1",
106
+ "supertest": "7.3.1",
107
+ "ts-jest": "29.4.14",
108
108
  "ts-node": "10.9.2",
109
109
  "typescript": "5.9.3"
110
110
  },
@@ -1,3 +1,12 @@
1
+ ## **6.17.1**
2
+ - [Fix] `parse`: `interpretNumericEntities`: decode code points above U+FFFF as surrogate pairs (#640)
3
+ - [Fix] `parse`: respect `plainObjects` for `[]` with `parseArrays: false` (#639)
4
+ - [Fix] `utils`: `merge`: count the elements of a sparse array against `arrayLimit`, not its holes
5
+ - [Fix] `parse`: guard bracket-wrapped prototype keys at depth 0 (#638)
6
+ - [Refactor] `parse`: extract wrapping-bracket stripping helper
7
+ - [readme] document that `depth: 0` and `depth: false` keep keys flat
8
+ - [Tests] `parse`: pin depth-0 bracket stripping and prototype keys kept by `allowPrototypes`/`plainObjects`
9
+
1
10
  ## **6.17.0**
2
11
  - [New] `stringify`: add `WHATWG` format (#623)
3
12
  - [Fix] `stringify`: do not sort the caller's `filter` array in place (#637)
@@ -21,6 +30,12 @@
21
30
  - [Tests] `parse`: pin the behavior of a zero or negative `arrayLimit`
22
31
  - [Tests] `utils`/`stringify`: pin `~`, `*`, and parens encoding in RFC3986 and RFC1738
23
32
 
33
+ ## **6.16.2**
34
+ - [Fix] `stringify`: encode keys when `allowEmptyArrays` is set (#561)
35
+ - [meta] use double quotes for better OS support
36
+ - [Dev Deps] update `evalmd`, `npmignore`
37
+ - [Tests] `stringify`: pin `allowEmptyArrays` output for keys that need no encoding
38
+
24
39
  ## **6.16.1**
25
40
  - [Fix] `parse`: do not mutate an object input
26
41
  - [Fix] `stringify`: stop re-encoding structural separator dots when `encodeDotInKeys` is set (#564)
@@ -60,6 +75,12 @@
60
75
  - [Dev Deps] update `@ljharb/eslint-config`, `eslint`
61
76
  - [Dev Deps] update `eslint`, `evalmd`
62
77
 
78
+ ## **6.15.4**
79
+ - [Fix] `stringify`: encode keys when `allowEmptyArrays` is set (#561)
80
+ - [meta] use double quotes for better OS support
81
+ - [Dev Deps] update `@ljharb/eslint-config`, `evalmd`, `npmignore`, `tape`
82
+ - [Tests] `stringify`: pin `allowEmptyArrays` output for keys that need no encoding
83
+
63
84
  ## **6.15.3**
64
85
  - [Fix] `parse`: enforce `throwOnLimitExceeded` for cumulative array growth via `combine`/`merge`
65
86
  - [Fix] `utils`: respect encoding of surrogate pairs across chunks (#559)
@@ -91,6 +112,13 @@
91
112
  - [New] `parse`: add `strictMerge` option to wrap object/primitive conflicts in an array (#425, #122)
92
113
  - [Fix] `duplicates` option should not apply to bracket notation keys (#514)
93
114
 
115
+ ## **6.14.3**
116
+ - [Fix] `stringify`: encode keys when `allowEmptyArrays` is set (#561)
117
+ - [meta] use double quotes for better OS support
118
+ - [Deps] update `side-channel`
119
+ - [Dev Deps] update `@ljharb/eslint-config`, `es-value-fixtures`, `eslint`, `evalmd`, `mock-property`, `npmignore`, `tape`
120
+ - [Tests] `stringify`: pin `allowEmptyArrays` output for keys that need no encoding
121
+
94
122
  ## **6.14.2**
95
123
  - [Fix] `parse`: mark overflow objects for indexed notation exceeding `arrayLimit` (#546)
96
124
  - [Fix] `arrayLimit` means max count, not max index, in `combine`/`merge`/`parseArrayValue`
@@ -123,6 +151,13 @@
123
151
  - [Dev Deps] update `es-value-fixtures`, `has-bigints`, `has-proto`, `has-symbols`
124
152
  - [Tests] increase coverage
125
153
 
154
+ ## **6.13.4**
155
+ - [Fix] `stringify`: encode keys when `allowEmptyArrays` is set (#561)
156
+ - [meta] use double quotes for better OS support
157
+ - [Deps] update `side-channel`
158
+ - [Dev Deps] update `@ljharb/eslint-config`, `es-value-fixtures`, `eslint`, `evalmd`, `for-each`, `has-symbols`, `mock-property`, `npmignore`, `object-inspect`, `tape`
159
+ - [Tests] `stringify`: pin `allowEmptyArrays` output for keys that need no encoding
160
+
126
161
  ## **6.13.3**
127
162
  [Fix] fix regressions from robustness refactor
128
163
  [actions] update reusable workflows
@@ -150,6 +185,13 @@
150
185
  - [New] `parse`: add `strictDepth` option (#511)
151
186
  - [Tests] use `npm audit` instead of `aud`
152
187
 
188
+ ## **6.12.6**
189
+ - [Fix] `stringify`: encode keys when `allowEmptyArrays` is set (#561)
190
+ - [meta] use `npm audit` instead of `aud`
191
+ - [Deps] update `side-channel`
192
+ - [Dev Deps] update `@ljharb/eslint-config`, `es-value-fixtures`, `eslint`, `evalmd`, `for-each`, `has-symbols`, `mock-property`, `npmignore`, `object-inspect`, `tape`
193
+ - [Tests] `stringify`: pin `allowEmptyArrays` output for keys that need no encoding
194
+
153
195
  ## **6.12.5**
154
196
  - [Fix] fix regressions from robustness refactor
155
197
  - [actions] update reusable workflows
@@ -85,7 +85,9 @@ assert.deepEqual(qs.parse('foo[bar][baz]=foobarbaz'), {
85
85
  });
86
86
  ```
87
87
 
88
- Since v6.14.1 and v6.15.2, `parse` interprets nested bracket groups more consistently. Query strings with unbalanced `[`/`]` can produce different results than in 6.15.1; see [#558](https://github.com/ljharb/qs/issues/558).
88
+ Since v6.14.1 and v6.15.2, `parse` interprets nested bracket groups more consistently.
89
+ Query strings with unbalanced `[`/`]` can produce different results than in 6.15.1;
90
+ see [#558](https://github.com/ljharb/qs/issues/558).
89
91
 
90
92
  Because of that bracket grammar,
91
93
  **qs** does not agree with `URLSearchParams`,
@@ -132,6 +134,15 @@ var deep = qs.parse('a[b][c][d][e][f][g][h][i]=j', { depth: 1 });
132
134
  assert.deepEqual(deep, { a: { b: { '[c][d][e][f][g][h][i]': 'j' } } });
133
135
  ```
134
136
 
137
+ Setting `depth` to `0` or `false` turns off nesting,
138
+ so keys are never split into nested objects or arrays,
139
+ whether or not their brackets are percent-encoded:
140
+
141
+ ```javascript
142
+ assert.deepEqual(qs.parse('a[b][c]=d', { depth: 0 }), { 'a[b][c]': 'd' });
143
+ assert.deepEqual(qs.parse('a%5Bb%5D=c', { depth: false }), { 'a[b]': 'c' });
144
+ ```
145
+
135
146
  You can configure **qs** to throw an error when parsing nested input beyond this depth using the `strictDepth` option (defaulted to false):
136
147
 
137
148
  ```javascript
@@ -143,16 +154,22 @@ try {
143
154
  }
144
155
  ```
145
156
 
146
- The depth limit helps mitigate abuse when **qs** is used to parse user input, and it is recommended to keep it a reasonably small number. The strictDepth option adds a layer of protection by throwing an error when the limit is exceeded, allowing you to catch and handle such cases.
157
+ The depth limit helps mitigate abuse when **qs** is used to parse user input,
158
+ and it is recommended to keep it a reasonably small number.
159
+ The strictDepth option adds a layer of protection by throwing an error when the limit is exceeded,
160
+ allowing you to catch and handle such cases.
147
161
 
148
- For similar reasons, by default **qs** will only parse up to 1000 parameters. This can be overridden by passing a `parameterLimit` option:
162
+ For similar reasons, by default **qs** will only parse up to 1000 parameters.
163
+ This can be overridden by passing a `parameterLimit` option:
149
164
 
150
165
  ```javascript
151
166
  var limited = qs.parse('a=b&c=d', { parameterLimit: 1 });
152
167
  assert.deepEqual(limited, { a: 'b' });
153
168
  ```
154
169
 
155
- If you want an error to be thrown whenever a limit is exceeded (eg, `parameterLimit`, `arrayLimit`), set the `throwOnLimitExceeded` option to `true`. This option will generate a descriptive error if the query string exceeds a configured limit.
170
+ If you want an error to be thrown whenever a limit is exceeded (eg, `parameterLimit`, `arrayLimit`),
171
+ set the `throwOnLimitExceeded` option to `true`.
172
+ This option will generate a descriptive error if the query string exceeds a configured limit.
156
173
  ```javascript
157
174
  try {
158
175
  qs.parse('a=1&b=2&c=3&d=4', { parameterLimit: 3, throwOnLimitExceeded: true });
@@ -164,7 +181,10 @@ try {
164
181
 
165
182
  When `throwOnLimitExceeded` is set to `false` (default), **qs** will parse up to the specified `parameterLimit` and ignore the rest without throwing an error.
166
183
 
167
- Note that `parameterLimit` only bounds the number of `&`-delimited parameters; it does not limit how many values a single parameter expands into. In particular, when `comma: true` is enabled, a single parameter's value is split on commas into arbitrarily many elements, which `parameterLimit` does not constrain. Setting `throwOnLimitExceeded: true` (see `arrayLimit` below) makes **qs** reject a query string with more than `parameterLimit` parameters, one that uses an array index of `arrayLimit` or greater, or one that would produce any array longer than `arrayLimit`, including an array produced by comma splitting. `arrayLimit` applies to each array separately, including each parameter's comma-split value, so the total number of values across all parameters can still reach `parameterLimit` times `arrayLimit`, which is 20,000 at the default limits; always bound the input size at the transport layer as well (e.g. an HTTP body-size limit).
184
+ Note that `parameterLimit` only bounds the number of `&`-delimited parameters; it does not limit how many values a single parameter expands into.
185
+ In particular, when `comma: true` is enabled, a single parameter's value is split on commas into arbitrarily many elements, which `parameterLimit` does not constrain.
186
+ Setting `throwOnLimitExceeded: true` (see `arrayLimit` below) makes **qs** reject a query string with more than `parameterLimit` parameters, one that uses an array index of `arrayLimit` or greater, or one that would produce any array longer than `arrayLimit`, including an array produced by comma splitting.
187
+ `arrayLimit` applies to each array separately, including each parameter's comma-split value, so the total number of values across all parameters can still reach `parameterLimit` times `arrayLimit`, which is 20,000 at the default limits; always bound the input size at the transport layer as well (e.g. an HTTP body-size limit).
168
188
 
169
189
  To bypass the leading question mark, use `ignoreQueryPrefix`:
170
190
 
@@ -324,7 +344,8 @@ var withArrayLimit = qs.parse('a[1]=b', { arrayLimit: 0 });
324
344
  assert.deepEqual(withArrayLimit, { a: { '1': 'b' } });
325
345
  ```
326
346
 
327
- If you want to throw an error whenever the array limit is exceeded, set the `throwOnLimitExceeded` option to `true`. This option will generate a descriptive error if the query string exceeds a configured limit.
347
+ If you want to throw an error whenever the array limit is exceeded, set the `throwOnLimitExceeded` option to `true`.
348
+ This option will generate a descriptive error if the query string exceeds a configured limit.
328
349
  ```javascript
329
350
  try {
330
351
  qs.parse('a[1]=b', { arrayLimit: 0, throwOnLimitExceeded: true });
@@ -336,7 +357,11 @@ try {
336
357
 
337
358
  When `throwOnLimitExceeded` is set to `false` (default), **qs** will parse up to the specified `arrayLimit` and if the limit is exceeded, the array will instead be converted to an object with the index as the key.
338
359
 
339
- Note that `arrayLimit` is a *representation* threshold that controls when a numerically-indexed collection switches from an array to an object; it is **not** a hard cap on the total number of elements parsed. With the default `throwOnLimitExceeded: false`, exceeding `arrayLimit` never rejects or truncates input; it only changes the container type, and the resulting object still holds every element (so its size stays proportional to the input). This conversion is itself a safeguard: it avoids allocating a huge sparse array for input like `a[999999999]`. If you need a hard limit that rejects oversized arrays in untrusted query strings, set `throwOnLimitExceeded: true`. `throwOnLimitExceeded` still limits each array separately, not the total: with `comma: true`, each comma-separated group under `a[]=` counts as one element of the outer array, and can itself hold up to `arrayLimit` elements.
360
+ Note that `arrayLimit` is a *representation* threshold that controls when a numerically-indexed collection switches from an array to an object; it is **not** a hard cap on the total number of elements parsed.
361
+ With the default `throwOnLimitExceeded: false`, exceeding `arrayLimit` never rejects or truncates input; it only changes the container type, and the resulting object still holds every element (so its size stays proportional to the input).
362
+ This conversion is itself a safeguard: it avoids allocating a huge sparse array for input like `a[999999999]`.
363
+ If you need a hard limit that rejects oversized arrays in untrusted query strings, set `throwOnLimitExceeded: true`.
364
+ `throwOnLimitExceeded` still limits each array separately, not the total: with `comma: true`, each comma-separated group under `a[]=` counts as one element of the outer array, and can itself hold up to `arrayLimit` elements.
340
365
 
341
366
  To prevent array syntax (`a[]`, `a[0]`) from being parsed as arrays, set `parseArrays` to `false`.
342
367
  Note that duplicate keys (e.g. `a=b&a=c`) may still produce arrays when `duplicates` is `'combine'` (the default).
@@ -408,7 +433,8 @@ If you wish to auto-convert values which look like numbers, booleans, and other
408
433
  qs.stringify(object, [options]);
409
434
  ```
410
435
 
411
- When stringifying, **qs** by default URI encodes output. Objects are stringified as you would expect:
436
+ When stringifying, **qs** by default URI encodes output.
437
+ Objects are stringified as you would expect:
412
438
 
413
439
  ```javascript
414
440
  assert.equal(qs.stringify({ a: 'b' }), 'a=b');
@@ -704,7 +730,8 @@ var equalsInsensitive = qs.parse('a&b=');
704
730
  assert.deepEqual(equalsInsensitive, { a: '', b: '' });
705
731
  ```
706
732
 
707
- To distinguish between `null` values and empty strings use the `strictNullHandling` flag. In the result string the `null`
733
+ To distinguish between `null` values and empty strings use the `strictNullHandling` flag.
734
+ In the result string the `null`
708
735
  values have no `=` sign:
709
736
 
710
737
  ```javascript
@@ -792,7 +819,8 @@ It only affects encoding; how `null`, dates, arrays, and objects are serialized
792
819
  assert.equal(qs.stringify({ a: 'b c~*()' }, { format: 'WHATWG' }), 'a=b+c%7E*%28%29');
793
820
  ```
794
821
 
795
- _(Note: the `WHATWG` format matches `URLSearchParams` encoding only with the default `utf-8` charset, and only when keys are encoded too, so not with `encodeValuesOnly`. With `charset: 'iso-8859-1'`, every format uses the same `escape`-based encoding, which leaves characters like `@` and `/` unencoded; only the space handling differs)_
822
+ _(Note: the `WHATWG` format matches `URLSearchParams` encoding only with the default `utf-8` charset, and only when keys are encoded too, so not with `encodeValuesOnly`.
823
+ With `charset: 'iso-8859-1'`, every format uses the same `escape`-based encoding, which leaves characters like `@` and `/` unencoded; only the space handling differs)_
796
824
 
797
825
  ## Security
798
826