@openclaw/discord 2026.6.33 → 2026.6.35

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 (179) hide show
  1. package/dist/action-runtime-api.js +1 -1
  2. package/dist/{api-CjnGBhM3.js → api-1GXlSrYP.js} +42 -21
  3. package/dist/api.js +14 -14
  4. package/dist/{approval-handler.runtime-BWPQrzpP.js → approval-handler.runtime-Dv4p7REU.js} +3 -3
  5. package/dist/{audit-BwJ_2OjL.js → audit-DEVi9nIs.js} +3 -3
  6. package/dist/{channel-Ddnonoy4.js → channel-CQIRiosn.js} +15 -15
  7. package/dist/{channel-actions-CwmIqnYN.js → channel-actions-JziPEcBU.js} +2 -2
  8. package/dist/{channel-actions.runtime-DvpTfaJ4.js → channel-actions.runtime-D7L47LY3.js} +5 -5
  9. package/dist/channel-plugin-api.js +1 -1
  10. package/dist/{channel.setup-glZ5Y98a.js → channel.setup-oMeR19Cc.js} +2 -2
  11. package/dist/{components-j6lTZBsT.js → components-_s5UPJqU.js} +1 -1
  12. package/dist/{conversation-identity-36FFBwm5.js → conversation-identity-B0k94-bz.js} +2 -2
  13. package/dist/{directory-config-BYMFzL29.js → directory-config-CD1svkyN.js} +1 -1
  14. package/dist/directory-contract-api.js +1 -1
  15. package/dist/{directory-live-9JtJCiu8.js → directory-live-DBTsSRxl.js} +5 -5
  16. package/dist/{handle-action.guild-admin-xxGYrp-I.js → handle-action.guild-admin-CYIFMxh-.js} +2 -2
  17. package/dist/index.js +1 -1
  18. package/dist/{manager.runtime-BK6cf2Zu.js → manager.runtime-BZVdGX2d.js} +17 -9
  19. package/dist/{message-handler-BqpJIavO.js → message-handler-DZd9Bpq8.js} +7 -6
  20. package/dist/{message-handler.preflight-C90MxCcv.js → message-handler.preflight-Axv9J9EO.js} +12 -11
  21. package/dist/{message-handler.process-CeQ7Bd_3.js → message-handler.process-CG0zFS-Z.js} +10 -10
  22. package/dist/{message-utils-CJeAoISH.js → message-utils-Dbuw27gd.js} +1 -1
  23. package/dist/{outbound-adapter-Dxs6iKEq.js → outbound-adapter-CKC_kmUN.js} +6 -6
  24. package/dist/pluralkit-CfTReLl3.js +40 -0
  25. package/dist/{probe-esE_Oqdm.js → probe-DcgZIpyF.js} +3 -2
  26. package/dist/{probe.runtime-C3Atgpvr.js → probe.runtime-CVwM9L5E.js} +1 -1
  27. package/dist/{provider-C7376XFH.js → provider-CwwSXIIj.js} +102 -37
  28. package/dist/{provider-session.runtime-CCdqogGf.js → provider-session.runtime-reBWkqHZ.js} +3 -3
  29. package/dist/provider.runtime-BsmTLYS_.js +2 -0
  30. package/dist/{resolve-allowlist-common-3gB2Gpmm.js → resolve-allowlist-common-D7bZqAw3.js} +3 -3
  31. package/dist/{resolve-channels-B3gQf8QL.js → resolve-channels--oE-RnO6.js} +6 -6
  32. package/dist/{resolve-users-BO10y5fJ.js → resolve-users-QXo8CXBU.js} +5 -5
  33. package/dist/{runtime-CFlR3L9X.js → runtime-CF7ramAs.js} +7 -7
  34. package/dist/runtime-api.actions.js +2 -2
  35. package/dist/runtime-api.js +19 -19
  36. package/dist/runtime-api.lookup.js +5 -5
  37. package/dist/runtime-api.monitor-CzF8MUl_.js +6 -0
  38. package/dist/runtime-api.monitor.js +5 -5
  39. package/dist/runtime-api.send.js +5 -5
  40. package/dist/runtime-api.threads.js +3 -3
  41. package/dist/{send-JHxfT4Pk.js → send-Bb295iHT.js} +5 -5
  42. package/dist/{send.components-CN35E2Ck.js → send.components-COkDUO3B.js} +4 -4
  43. package/dist/{send.outbound-B-cA1Esv.js → send.outbound-B_sk0hNe.js} +3 -3
  44. package/dist/{send.receipt-CGecJDin.js → send.receipt-Cli6_9Sn.js} +19 -7
  45. package/dist/{send.shared-vcbfThdy.js → send.shared-BCG7MWnP.js} +2 -2
  46. package/dist/session-binding-contract-api.js +1 -1
  47. package/dist/setup-plugin-api.js +1 -1
  48. package/dist/{subagent-hooks-20wXhVzZ.js → subagent-hooks-CtqoWK4x.js} +2 -2
  49. package/dist/subagent-hooks-api.js +1 -1
  50. package/dist/{system-events-DR27TE7p.js → system-events-BxGNk_wE.js} +1 -1
  51. package/dist/{target-resolver-CDi1gI90.js → target-resolver-BcoK6b0g.js} +2 -2
  52. package/dist/targets-Q-ZoP7K4.js +3 -0
  53. package/dist/{thread-bindings-DU4T6nDo.js → thread-bindings-DJ_HT6GJ.js} +4 -4
  54. package/dist/{thread-bindings.discord-api-CYkr-3Gj.js → thread-bindings.discord-api-OPyjvgyz.js} +4 -4
  55. package/dist/{thread-bindings.manager-BqWs1UE2.js → thread-bindings.manager-Cd2HAVw_.js} +3 -3
  56. package/dist/{transcripts-source-D-lBI5ZD.js → transcripts-source-CPf5gURy.js} +1 -1
  57. package/dist/transcripts-source-api.js +1 -1
  58. package/dist/{typing-xr05bL-r.js → typing-DY0cwLdg.js} +1 -1
  59. package/node_modules/undici/README.md +8 -2
  60. package/node_modules/undici/docs/docs/api/Agent.md +248 -44
  61. package/node_modules/undici/docs/docs/api/BalancedPool.md +246 -48
  62. package/node_modules/undici/docs/docs/api/CacheStorage.md +171 -13
  63. package/node_modules/undici/docs/docs/api/CacheStore.md +294 -98
  64. package/node_modules/undici/docs/docs/api/Client.md +386 -179
  65. package/node_modules/undici/docs/docs/api/ClientStats.md +80 -14
  66. package/node_modules/undici/docs/docs/api/Connector.md +118 -36
  67. package/node_modules/undici/docs/docs/api/ContentType.md +65 -25
  68. package/node_modules/undici/docs/docs/api/Cookies.md +122 -71
  69. package/node_modules/undici/docs/docs/api/Debug.md +34 -18
  70. package/node_modules/undici/docs/docs/api/DiagnosticsChannel.md +364 -164
  71. package/node_modules/undici/docs/docs/api/Dispatcher.md +485 -1102
  72. package/node_modules/undici/docs/docs/api/EnvHttpProxyAgent.md +102 -87
  73. package/node_modules/undici/docs/docs/api/Errors.md +503 -40
  74. package/node_modules/undici/docs/docs/api/EventSource.md +298 -32
  75. package/node_modules/undici/docs/docs/api/Fetch.md +680 -31
  76. package/node_modules/undici/docs/docs/api/GlobalInstallation.md +78 -98
  77. package/node_modules/undici/docs/docs/api/H2CClient.md +298 -176
  78. package/node_modules/undici/docs/docs/api/Interceptors.md +418 -0
  79. package/node_modules/undici/docs/docs/api/MockAgent.md +333 -314
  80. package/node_modules/undici/docs/docs/api/MockCallHistory.md +272 -98
  81. package/node_modules/undici/docs/docs/api/MockCallHistoryLog.md +189 -26
  82. package/node_modules/undici/docs/docs/api/MockClient.md +151 -33
  83. package/node_modules/undici/docs/docs/api/MockErrors.md +56 -5
  84. package/node_modules/undici/docs/docs/api/MockPool.md +321 -258
  85. package/node_modules/undici/docs/docs/api/Pool.md +235 -43
  86. package/node_modules/undici/docs/docs/api/PoolStats.md +119 -13
  87. package/node_modules/undici/docs/docs/api/ProxyAgent.md +179 -160
  88. package/node_modules/undici/docs/docs/api/RedirectHandler.md +238 -63
  89. package/node_modules/undici/docs/docs/api/RetryAgent.md +113 -26
  90. package/node_modules/undici/docs/docs/api/RetryHandler.md +161 -77
  91. package/node_modules/undici/docs/docs/api/RoundRobinPool.md +166 -72
  92. package/node_modules/undici/docs/docs/api/SnapshotAgent.md +264 -542
  93. package/node_modules/undici/docs/docs/api/Socks5ProxyAgent.md +177 -196
  94. package/node_modules/undici/docs/docs/api/Util.md +68 -11
  95. package/node_modules/undici/docs/docs/api/WebSocket.md +475 -80
  96. package/node_modules/undici/docs/docs/api/api-lifecycle.md +100 -32
  97. package/node_modules/undici/docs/docs/best-practices/client-certificate.md +2 -0
  98. package/node_modules/undici/docs/docs/best-practices/crawling.md +3 -1
  99. package/node_modules/undici/docs/docs/best-practices/migrating-from-v7-to-v8.md +6 -4
  100. package/node_modules/undici/docs/docs/best-practices/mocking-request.md +9 -7
  101. package/node_modules/undici/docs/docs/best-practices/proxy.md +3 -1
  102. package/node_modules/undici/docs/docs/best-practices/undici-vs-builtin-fetch.md +10 -8
  103. package/node_modules/undici/docs/docs/best-practices/writing-tests.md +2 -0
  104. package/node_modules/undici/docs/docs/{GettingStarted.md → getting-started.md} +22 -19
  105. package/node_modules/undici/docs/docs/index.md +784 -0
  106. package/node_modules/undici/docs/docs/site.json +125 -0
  107. package/node_modules/undici/docs/docs/type-map.json +79 -0
  108. package/node_modules/undici/lib/api/api-request.js +7 -1
  109. package/node_modules/undici/lib/api/readable.js +42 -7
  110. package/node_modules/undici/lib/cache/memory-cache-store.js +56 -11
  111. package/node_modules/undici/lib/cache/sqlite-cache-store.js +7 -1
  112. package/node_modules/undici/lib/core/connect.js +16 -2
  113. package/node_modules/undici/lib/core/errors.js +20 -0
  114. package/node_modules/undici/lib/core/request.js +14 -3
  115. package/node_modules/undici/lib/core/symbols.js +3 -0
  116. package/node_modules/undici/lib/core/util.js +30 -2
  117. package/node_modules/undici/lib/dispatcher/agent.js +10 -5
  118. package/node_modules/undici/lib/dispatcher/balanced-pool.js +7 -4
  119. package/node_modules/undici/lib/dispatcher/client-h1.js +74 -9
  120. package/node_modules/undici/lib/dispatcher/client-h2.js +483 -151
  121. package/node_modules/undici/lib/dispatcher/client.js +76 -30
  122. package/node_modules/undici/lib/dispatcher/dispatcher-base.js +13 -1
  123. package/node_modules/undici/lib/dispatcher/dispatcher.js +15 -1
  124. package/node_modules/undici/lib/dispatcher/dispatcher1-wrapper.js +3 -0
  125. package/node_modules/undici/lib/dispatcher/env-http-proxy-agent.js +37 -8
  126. package/node_modules/undici/lib/dispatcher/proxy-agent.js +58 -7
  127. package/node_modules/undici/lib/dispatcher/retry-agent.js +3 -0
  128. package/node_modules/undici/lib/dispatcher/round-robin-pool.js +1 -1
  129. package/node_modules/undici/lib/dispatcher/socks5-proxy-agent.js +106 -22
  130. package/node_modules/undici/lib/global.js +36 -16
  131. package/node_modules/undici/lib/handler/cache-handler.js +297 -65
  132. package/node_modules/undici/lib/handler/cache-revalidation-handler.js +13 -3
  133. package/node_modules/undici/lib/handler/decorator-handler.js +7 -1
  134. package/node_modules/undici/lib/handler/deduplication-handler.js +12 -6
  135. package/node_modules/undici/lib/handler/redirect-handler.js +26 -5
  136. package/node_modules/undici/lib/handler/retry-handler.js +238 -51
  137. package/node_modules/undici/lib/interceptor/cache.js +221 -58
  138. package/node_modules/undici/lib/interceptor/decompress.js +124 -15
  139. package/node_modules/undici/lib/interceptor/deduplicate.js +5 -4
  140. package/node_modules/undici/lib/interceptor/dns.js +7 -0
  141. package/node_modules/undici/lib/interceptor/dump.js +10 -23
  142. package/node_modules/undici/lib/mock/mock-agent.js +13 -1
  143. package/node_modules/undici/lib/mock/mock-interceptor.js +25 -7
  144. package/node_modules/undici/lib/mock/mock-utils.js +246 -27
  145. package/node_modules/undici/lib/util/cache.js +415 -71
  146. package/node_modules/undici/lib/util/date.js +23 -6
  147. package/node_modules/undici/lib/web/cookies/parse.js +150 -146
  148. package/node_modules/undici/lib/web/cookies/util.js +79 -9
  149. package/node_modules/undici/lib/web/eventsource/eventsource-stream.js +28 -1
  150. package/node_modules/undici/lib/web/eventsource/eventsource.js +13 -3
  151. package/node_modules/undici/lib/web/eventsource/util.js +1 -1
  152. package/node_modules/undici/lib/web/fetch/body.js +2 -1
  153. package/node_modules/undici/lib/web/fetch/constants.js +1 -1
  154. package/node_modules/undici/lib/web/fetch/index.js +17 -2
  155. package/node_modules/undici/lib/web/fetch/request.js +2 -3
  156. package/node_modules/undici/lib/web/fetch/response.js +1 -3
  157. package/node_modules/undici/lib/web/fetch/util.js +10 -2
  158. package/node_modules/undici/lib/web/webidl/index.js +3 -3
  159. package/node_modules/undici/lib/web/websocket/connection.js +1 -1
  160. package/node_modules/undici/lib/web/websocket/permessage-deflate.js +5 -0
  161. package/node_modules/undici/lib/web/websocket/stream/websocketstream.js +8 -10
  162. package/node_modules/undici/lib/web/websocket/websocket.js +22 -0
  163. package/node_modules/undici/package.json +4 -4
  164. package/node_modules/undici/types/client.d.ts +53 -3
  165. package/node_modules/undici/types/cookies.d.ts +1 -1
  166. package/node_modules/undici/types/dispatcher.d.ts +3 -3
  167. package/node_modules/undici/types/errors.d.ts +10 -0
  168. package/node_modules/undici/types/handlers.d.ts +2 -0
  169. package/node_modules/undici/types/interceptors.d.ts +2 -0
  170. package/node_modules/undici/types/mock-agent.d.ts +11 -10
  171. package/node_modules/undici/types/mock-interceptor.d.ts +5 -1
  172. package/node_modules/undici/types/proxy-agent.d.ts +7 -0
  173. package/node_modules/undici/types/socks5-proxy-agent.d.ts +2 -0
  174. package/npm-shrinkwrap.json +7 -7
  175. package/package.json +6 -5
  176. package/dist/pluralkit-DI6RYaVj.js +0 -24
  177. package/dist/provider.runtime-D1m66kDS.js +0 -2
  178. package/dist/runtime-api.monitor-4oc58TSk.js +0 -6
  179. package/dist/targets-C6yd3y8R.js +0 -3
@@ -18,6 +18,26 @@ function parseHttpDate (date) {
18
18
  }
19
19
  }
20
20
 
21
+ function makeDate (year, monthIdx, day, hour, minute, second, weekday) {
22
+ const result = new Date(Date.UTC(year, monthIdx, day, hour, minute, second))
23
+
24
+ // Date.UTC treats years 0-99 as 1900-1999. Reset the full year so component
25
+ // checks below validate the HTTP date as written.
26
+ if (year >= 0 && year <= 99) {
27
+ result.setUTCFullYear(year)
28
+ }
29
+
30
+ return result.getUTCFullYear() === year &&
31
+ result.getUTCMonth() === monthIdx &&
32
+ result.getUTCDate() === day &&
33
+ result.getUTCHours() === hour &&
34
+ result.getUTCMinutes() === minute &&
35
+ result.getUTCSeconds() === second &&
36
+ result.getUTCDay() === weekday
37
+ ? result
38
+ : undefined
39
+ }
40
+
21
41
  /**
22
42
  * @see https://httpwg.org/specs/rfc9110.html#preferred.date.format
23
43
  *
@@ -224,8 +244,7 @@ function parseImfDate (date) {
224
244
  second = (code1 - 48) * 10 + (code2 - 48) // Convert ASCII codes to number
225
245
  }
226
246
 
227
- const result = new Date(Date.UTC(year, monthIdx, day, hour, minute, second))
228
- return result.getUTCDay() === weekday ? result : undefined
247
+ return makeDate(year, monthIdx, day, hour, minute, second, weekday)
229
248
  }
230
249
 
231
250
  /**
@@ -429,8 +448,7 @@ function parseAscTimeDate (date) {
429
448
  }
430
449
  const year = (yearDigit1 - 48) * 1000 + (yearDigit2 - 48) * 100 + (yearDigit3 - 48) * 10 + (yearDigit4 - 48)
431
450
 
432
- const result = new Date(Date.UTC(year, monthIdx, day, hour, minute, second))
433
- return result.getUTCDay() === weekday ? result : undefined
451
+ return makeDate(year, monthIdx, day, hour, minute, second, weekday)
434
452
  }
435
453
 
436
454
  /**
@@ -644,8 +662,7 @@ function parseRfc850Date (date) {
644
662
  second = (code1 - 48) * 10 + (code2 - 48) // Convert ASCII codes to number
645
663
  }
646
664
 
647
- const result = new Date(Date.UTC(year, monthIdx, day, hour, minute, second))
648
- return result.getUTCDay() === weekday ? result : undefined
665
+ return makeDate(year, monthIdx, day, hour, minute, second, weekday)
649
666
  }
650
667
 
651
668
  module.exports = {
@@ -92,220 +92,224 @@ function parseSetCookie (header) {
92
92
  * @param {Object.<string, unknown>} [cookieAttributeList={}]
93
93
  */
94
94
  function parseUnparsedAttributes (unparsedAttributes, cookieAttributeList = {}) {
95
- // 1. If the unparsed-attributes string is empty, skip the rest of
96
- // these steps.
97
- if (unparsedAttributes.length === 0) {
98
- return cookieAttributeList
99
- }
95
+ while (true) {
96
+ // 1. If the unparsed-attributes string is empty, skip the rest of
97
+ // these steps.
98
+ if (unparsedAttributes.length === 0) {
99
+ return cookieAttributeList
100
+ }
100
101
 
101
- // 2. Discard the first character of the unparsed-attributes (which
102
- // will be a %x3B (";") character).
103
- assert(unparsedAttributes[0] === ';')
104
- unparsedAttributes = unparsedAttributes.slice(1)
102
+ // 2. Discard the first character of the unparsed-attributes (which
103
+ // will be a %x3B (";") character).
104
+ assert(unparsedAttributes[0] === ';')
105
+ unparsedAttributes = unparsedAttributes.slice(1)
105
106
 
106
- let cookieAv = ''
107
+ let cookieAv = ''
107
108
 
108
- // 3. If the remaining unparsed-attributes contains a %x3B (";")
109
- // character:
110
- if (unparsedAttributes.includes(';')) {
109
+ // 3. If the remaining unparsed-attributes contains a %x3B (";")
110
+ // character:
111
+ if (unparsedAttributes.includes(';')) {
111
112
  // 1. Consume the characters of the unparsed-attributes up to, but
112
113
  // not including, the first %x3B (";") character.
113
- cookieAv = collectASequenceOfCodePointsFast(
114
- ';',
115
- unparsedAttributes,
116
- { position: 0 }
117
- )
118
- unparsedAttributes = unparsedAttributes.slice(cookieAv.length)
119
- } else {
114
+ cookieAv = collectASequenceOfCodePointsFast(
115
+ ';',
116
+ unparsedAttributes,
117
+ { position: 0 }
118
+ )
119
+ unparsedAttributes = unparsedAttributes.slice(cookieAv.length)
120
+ } else {
120
121
  // Otherwise:
121
122
 
122
- // 1. Consume the remainder of the unparsed-attributes.
123
- cookieAv = unparsedAttributes
124
- unparsedAttributes = ''
125
- }
123
+ // 1. Consume the remainder of the unparsed-attributes.
124
+ cookieAv = unparsedAttributes
125
+ unparsedAttributes = ''
126
+ }
126
127
 
127
- // Let the cookie-av string be the characters consumed in this step.
128
+ // Let the cookie-av string be the characters consumed in this step.
128
129
 
129
- let attributeName = ''
130
- let attributeValue = ''
130
+ let attributeName = ''
131
+ let attributeValue = ''
131
132
 
132
- // 4. If the cookie-av string contains a %x3D ("=") character:
133
- if (cookieAv.includes('=')) {
133
+ // 4. If the cookie-av string contains a %x3D ("=") character:
134
+ if (cookieAv.includes('=')) {
134
135
  // 1. The (possibly empty) attribute-name string consists of the
135
136
  // characters up to, but not including, the first %x3D ("=")
136
137
  // character, and the (possibly empty) attribute-value string
137
138
  // consists of the characters after the first %x3D ("=")
138
139
  // character.
139
- const position = { position: 0 }
140
-
141
- attributeName = collectASequenceOfCodePointsFast(
142
- '=',
143
- cookieAv,
144
- position
145
- )
146
- attributeValue = cookieAv.slice(position.position + 1)
147
- } else {
140
+ const position = { position: 0 }
141
+
142
+ attributeName = collectASequenceOfCodePointsFast(
143
+ '=',
144
+ cookieAv,
145
+ position
146
+ )
147
+ attributeValue = cookieAv.slice(position.position + 1)
148
+ } else {
148
149
  // Otherwise:
149
150
 
150
- // 1. The attribute-name string consists of the entire cookie-av
151
- // string, and the attribute-value string is empty.
152
- attributeName = cookieAv
153
- }
151
+ // 1. The attribute-name string consists of the entire cookie-av
152
+ // string, and the attribute-value string is empty.
153
+ attributeName = cookieAv
154
+ }
154
155
 
155
- // 5. Remove any leading or trailing WSP characters from the attribute-
156
- // name string and the attribute-value string.
157
- attributeName = attributeName.trim()
158
- attributeValue = attributeValue.trim()
156
+ // 5. Remove any leading or trailing WSP characters from the attribute-
157
+ // name string and the attribute-value string.
158
+ attributeName = attributeName.trim()
159
+ attributeValue = attributeValue.trim()
159
160
 
160
- // 6. If the attribute-value is longer than 1024 octets, ignore the
161
- // cookie-av string and return to Step 1 of this algorithm.
162
- if (attributeValue.length > maxAttributeValueSize) {
163
- return parseUnparsedAttributes(unparsedAttributes, cookieAttributeList)
164
- }
161
+ // 6. If the attribute-value is longer than 1024 octets, ignore the
162
+ // cookie-av string and return to Step 1 of this algorithm.
163
+ if (attributeValue.length > maxAttributeValueSize) {
164
+ continue
165
+ }
165
166
 
166
- // 7. Process the attribute-name and attribute-value according to the
167
- // requirements in the following subsections. (Notice that
168
- // attributes with unrecognized attribute-names are ignored.)
169
- const attributeNameLowercase = attributeName.toLowerCase()
167
+ // 7. Process the attribute-name and attribute-value according to the
168
+ // requirements in the following subsections. (Notice that
169
+ // attributes with unrecognized attribute-names are ignored.)
170
+ const attributeNameLowercase = attributeName.toLowerCase()
170
171
 
171
- // https://datatracker.ietf.org/doc/html/draft-ietf-httpbis-rfc6265bis#section-5.4.1
172
- // If the attribute-name case-insensitively matches the string
173
- // "Expires", the user agent MUST process the cookie-av as follows.
174
- if (attributeNameLowercase === 'expires') {
172
+ // https://datatracker.ietf.org/doc/html/draft-ietf-httpbis-rfc6265bis#section-5.4.1
173
+ // If the attribute-name case-insensitively matches the string
174
+ // "Expires", the user agent MUST process the cookie-av as follows.
175
+ if (attributeNameLowercase === 'expires') {
175
176
  // 1. Let the expiry-time be the result of parsing the attribute-value
176
177
  // as cookie-date (see Section 5.1.1).
177
- const expiryTime = new Date(attributeValue)
178
-
179
- // 2. If the attribute-value failed to parse as a cookie date, ignore
180
- // the cookie-av.
181
-
182
- cookieAttributeList.expires = expiryTime
183
- } else if (attributeNameLowercase === 'max-age') {
178
+ const expiryTime = new Date(attributeValue)
179
+
180
+ // 2. If the attribute-value failed to parse as a cookie date, ignore
181
+ // the cookie-av.
182
+ if (!Number.isNaN(expiryTime.getTime())) {
183
+ cookieAttributeList.expires = expiryTime
184
+ }
185
+ } else if (attributeNameLowercase === 'max-age') {
184
186
  // https://datatracker.ietf.org/doc/html/draft-ietf-httpbis-rfc6265bis#section-5.4.2
185
187
  // If the attribute-name case-insensitively matches the string "Max-
186
188
  // Age", the user agent MUST process the cookie-av as follows.
187
189
 
188
- // 1. If the first character of the attribute-value is not a DIGIT or a
189
- // "-" character, ignore the cookie-av.
190
- const charCode = attributeValue.charCodeAt(0)
191
-
192
- if ((charCode < 48 || charCode > 57) && attributeValue[0] !== '-') {
193
- return parseUnparsedAttributes(unparsedAttributes, cookieAttributeList)
194
- }
195
-
196
- // 2. If the remainder of attribute-value contains a non-DIGIT
197
- // character, ignore the cookie-av.
198
- if (!/^\d+$/.test(attributeValue)) {
199
- return parseUnparsedAttributes(unparsedAttributes, cookieAttributeList)
200
- }
201
-
202
- // 3. Let delta-seconds be the attribute-value converted to an integer.
203
- const deltaSeconds = Number(attributeValue)
204
-
205
- // 4. Let cookie-age-limit be the maximum age of the cookie (which
206
- // SHOULD be 400 days or less, see Section 4.1.2.2).
207
-
208
- // 5. Set delta-seconds to the smaller of its present value and cookie-
209
- // age-limit.
210
- // deltaSeconds = Math.min(deltaSeconds * 1000, maxExpiresMs)
211
-
212
- // 6. If delta-seconds is less than or equal to zero (0), let expiry-
213
- // time be the earliest representable date and time. Otherwise, let
214
- // the expiry-time be the current date and time plus delta-seconds
215
- // seconds.
216
- // const expiryTime = deltaSeconds <= 0 ? Date.now() : Date.now() + deltaSeconds
217
-
218
- // 7. Append an attribute to the cookie-attribute-list with an
219
- // attribute-name of Max-Age and an attribute-value of expiry-time.
220
- cookieAttributeList.maxAge = deltaSeconds
221
- } else if (attributeNameLowercase === 'domain') {
190
+ // 1. If the first character of the attribute-value is not a DIGIT or a
191
+ // "-" character, ignore the cookie-av.
192
+ const charCode = attributeValue.charCodeAt(0)
193
+ const startsWithDigit = charCode >= 48 && charCode <= 57
194
+ const startsWithSignedDigit = attributeValue[0] === '-' && attributeValue.length > 1
195
+
196
+ if (!startsWithDigit && !startsWithSignedDigit) {
197
+ continue
198
+ }
199
+
200
+ // 2. If the remainder of attribute-value contains a non-DIGIT
201
+ // character, ignore the cookie-av.
202
+ if (/[^\d]/.test(attributeValue.slice(1))) {
203
+ continue
204
+ }
205
+
206
+ // 3. Let delta-seconds be the attribute-value converted to an integer.
207
+ const deltaSeconds = Number(attributeValue)
208
+
209
+ // 4. Let cookie-age-limit be the maximum age of the cookie (which
210
+ // SHOULD be 400 days or less, see Section 4.1.2.2).
211
+
212
+ // 5. Set delta-seconds to the smaller of its present value and cookie-
213
+ // age-limit.
214
+ // deltaSeconds = Math.min(deltaSeconds * 1000, maxExpiresMs)
215
+
216
+ // 6. If delta-seconds is less than or equal to zero (0), let expiry-
217
+ // time be the earliest representable date and time. Otherwise, let
218
+ // the expiry-time be the current date and time plus delta-seconds
219
+ // seconds.
220
+ // const expiryTime = deltaSeconds <= 0 ? Date.now() : Date.now() + deltaSeconds
221
+
222
+ // 7. Append an attribute to the cookie-attribute-list with an
223
+ // attribute-name of Max-Age and an attribute-value of expiry-time.
224
+ cookieAttributeList.maxAge = deltaSeconds
225
+ } else if (attributeNameLowercase === 'domain') {
222
226
  // https://datatracker.ietf.org/doc/html/draft-ietf-httpbis-rfc6265bis#section-5.4.3
223
227
  // If the attribute-name case-insensitively matches the string "Domain",
224
228
  // the user agent MUST process the cookie-av as follows.
225
229
 
226
- // 1. Let cookie-domain be the attribute-value.
227
- let cookieDomain = attributeValue
230
+ // 1. Let cookie-domain be the attribute-value.
231
+ let cookieDomain = attributeValue
228
232
 
229
- // 2. If cookie-domain starts with %x2E ("."), let cookie-domain be
230
- // cookie-domain without its leading %x2E (".").
231
- if (cookieDomain[0] === '.') {
232
- cookieDomain = cookieDomain.slice(1)
233
- }
233
+ // 2. If cookie-domain starts with %x2E ("."), let cookie-domain be
234
+ // cookie-domain without its leading %x2E (".").
235
+ if (cookieDomain[0] === '.') {
236
+ cookieDomain = cookieDomain.slice(1)
237
+ }
234
238
 
235
- // 3. Convert the cookie-domain to lower case.
236
- cookieDomain = cookieDomain.toLowerCase()
239
+ // 3. Convert the cookie-domain to lower case.
240
+ cookieDomain = cookieDomain.toLowerCase()
237
241
 
238
- // 4. Append an attribute to the cookie-attribute-list with an
239
- // attribute-name of Domain and an attribute-value of cookie-domain.
240
- cookieAttributeList.domain = cookieDomain
241
- } else if (attributeNameLowercase === 'path') {
242
+ // 4. Append an attribute to the cookie-attribute-list with an
243
+ // attribute-name of Domain and an attribute-value of cookie-domain.
244
+ cookieAttributeList.domain = cookieDomain
245
+ } else if (attributeNameLowercase === 'path') {
242
246
  // https://datatracker.ietf.org/doc/html/draft-ietf-httpbis-rfc6265bis#section-5.4.4
243
247
  // If the attribute-name case-insensitively matches the string "Path",
244
248
  // the user agent MUST process the cookie-av as follows.
245
249
 
246
- // 1. If the attribute-value is empty or if the first character of the
247
- // attribute-value is not %x2F ("/"):
248
- let cookiePath = ''
249
- if (attributeValue.length === 0 || attributeValue[0] !== '/') {
250
+ // 1. If the attribute-value is empty or if the first character of the
251
+ // attribute-value is not %x2F ("/"):
252
+ let cookiePath = ''
253
+ if (attributeValue.length === 0 || attributeValue[0] !== '/') {
250
254
  // 1. Let cookie-path be the default-path.
251
- cookiePath = '/'
252
- } else {
255
+ cookiePath = '/'
256
+ } else {
253
257
  // Otherwise:
254
258
 
255
- // 1. Let cookie-path be the attribute-value.
256
- cookiePath = attributeValue
257
- }
259
+ // 1. Let cookie-path be the attribute-value.
260
+ cookiePath = attributeValue
261
+ }
258
262
 
259
- // 2. Append an attribute to the cookie-attribute-list with an
260
- // attribute-name of Path and an attribute-value of cookie-path.
261
- cookieAttributeList.path = cookiePath
262
- } else if (attributeNameLowercase === 'secure') {
263
+ // 2. Append an attribute to the cookie-attribute-list with an
264
+ // attribute-name of Path and an attribute-value of cookie-path.
265
+ cookieAttributeList.path = cookiePath
266
+ } else if (attributeNameLowercase === 'secure') {
263
267
  // https://datatracker.ietf.org/doc/html/draft-ietf-httpbis-rfc6265bis#section-5.4.5
264
268
  // If the attribute-name case-insensitively matches the string "Secure",
265
269
  // the user agent MUST append an attribute to the cookie-attribute-list
266
270
  // with an attribute-name of Secure and an empty attribute-value.
267
271
 
268
- cookieAttributeList.secure = true
269
- } else if (attributeNameLowercase === 'httponly') {
272
+ cookieAttributeList.secure = true
273
+ } else if (attributeNameLowercase === 'httponly') {
270
274
  // https://datatracker.ietf.org/doc/html/draft-ietf-httpbis-rfc6265bis#section-5.4.6
271
275
  // If the attribute-name case-insensitively matches the string
272
276
  // "HttpOnly", the user agent MUST append an attribute to the cookie-
273
277
  // attribute-list with an attribute-name of HttpOnly and an empty
274
278
  // attribute-value.
275
279
 
276
- cookieAttributeList.httpOnly = true
277
- } else if (attributeNameLowercase === 'samesite') {
280
+ cookieAttributeList.httpOnly = true
281
+ } else if (attributeNameLowercase === 'samesite') {
278
282
  // https://datatracker.ietf.org/doc/html/draft-ietf-httpbis-rfc6265bis#section-5.4.7
279
283
  // If the attribute-name case-insensitively matches the string
280
284
  // "SameSite", the user agent MUST process the cookie-av as follows:
281
285
 
282
- const attributeValueLowercase = attributeValue.toLowerCase()
286
+ const attributeValueLowercase = attributeValue.toLowerCase()
283
287
 
284
- // 1. If cookie-av's attribute-value is a case-insensitive match for
285
- // "None", append an attribute to the cookie-attribute-list with an
286
- // attribute-name of "SameSite" and an attribute-value of "None".
287
- if (attributeValueLowercase === 'none') {
288
- cookieAttributeList.sameSite = 'None'
289
- } else if (attributeValueLowercase === 'strict') {
288
+ // 1. If cookie-av's attribute-value is a case-insensitive match for
289
+ // "None", append an attribute to the cookie-attribute-list with an
290
+ // attribute-name of "SameSite" and an attribute-value of "None".
291
+ if (attributeValueLowercase === 'none') {
292
+ cookieAttributeList.sameSite = 'None'
293
+ } else if (attributeValueLowercase === 'strict') {
290
294
  // 2. If cookie-av's attribute-value is a case-insensitive match for
291
295
  // "Strict", append an attribute to the cookie-attribute-list with
292
296
  // an attribute-name of "SameSite" and an attribute-value of
293
297
  // "Strict".
294
- cookieAttributeList.sameSite = 'Strict'
295
- } else if (attributeValueLowercase === 'lax') {
298
+ cookieAttributeList.sameSite = 'Strict'
299
+ } else if (attributeValueLowercase === 'lax') {
296
300
  // 3. If cookie-av's attribute-value is a case-insensitive match for
297
301
  // "Lax", append an attribute to the cookie-attribute-list with an
298
302
  // attribute-name of "SameSite" and an attribute-value of "Lax".
299
- cookieAttributeList.sameSite = 'Lax'
300
- }
301
- } else {
302
- cookieAttributeList.unparsed ??= []
303
+ cookieAttributeList.sameSite = 'Lax'
304
+ }
305
+ } else {
306
+ cookieAttributeList.unparsed ??= []
303
307
 
304
- cookieAttributeList.unparsed.push(`${attributeName}=${attributeValue}`)
305
- }
308
+ cookieAttributeList.unparsed.push(`${attributeName}=${attributeValue}`)
309
+ }
306
310
 
307
311
  // 8. Return to Step 1 of this algorithm.
308
- return parseUnparsedAttributes(unparsedAttributes, cookieAttributeList)
312
+ }
309
313
  }
310
314
 
311
315
  module.exports = {
@@ -105,7 +105,7 @@ function validateCookiePath (path) {
105
105
 
106
106
  if (
107
107
  code < 0x20 || // exclude CTLs (0-31)
108
- code === 0x7F || // DEL
108
+ code > 0x7E || // exclude non-ascii and DEL
109
109
  code === 0x3B // ;
110
110
  ) {
111
111
  throw new Error('Invalid cookie path')
@@ -114,16 +114,80 @@ function validateCookiePath (path) {
114
114
  }
115
115
 
116
116
  /**
117
- * I have no idea why these values aren't allowed to be honest,
118
- * but Deno tests these. - Khafra
117
+ * <let-dig> ::= <letter> | <digit>
118
+ *
119
+ * <letter> ::= any one of the 52 alphabetic characters A through Z in
120
+ * upper case and a through z in lower case
121
+ *
122
+ * <digit> ::= any one of the ten digits 0 through 9r
123
+ *
124
+ * @see https://www.rfc-editor.org/rfc/rfc1034#section-3.5
125
+ * @param {number} code
126
+ */
127
+ function isLetterOrDigit (code) {
128
+ return (
129
+ (code >= 0x30 && code <= 0x39) || // 0-9
130
+ (code >= 0x41 && code <= 0x5A) || // A-Z
131
+ (code >= 0x61 && code <= 0x7A) // a-z
132
+ )
133
+ }
134
+
135
+ /**
136
+ * Validates a cookie domain against the "preferred name syntax".
137
+ *
138
+ * <domain> ::= <subdomain> | " "
139
+ * <subdomain> ::= <label> | <subdomain> "." <label>
140
+ * <label> ::= <let-dig> [ [ <ldh-str> ] <let-dig> ]
141
+ * <ldh-str> ::= <let-dig-hyp> | <let-dig-hyp> <ldh-str>
142
+ * <let-dig-hyp> ::= <let-dig> | "-"
143
+ *
144
+ * @see https://www.rfc-editor.org/rfc/rfc1034#section-3.5
145
+ * @see https://www.rfc-editor.org/rfc/rfc1123#section-2.1
146
+ * @see https://www.rfc-editor.org/rfc/rfc1035#section-2.3.4
119
147
  * @param {string} domain
120
148
  */
121
149
  function validateCookieDomain (domain) {
122
- if (
123
- domain.startsWith('-') ||
124
- domain.endsWith('.') ||
125
- domain.endsWith('-')
126
- ) {
150
+ // <domain> ::= <subdomain> | " "
151
+ if (domain === ' ') {
152
+ return
153
+ }
154
+
155
+ if (domain.length > 255) {
156
+ throw new Error('Invalid cookie domain')
157
+ }
158
+
159
+ let labelLength = 0
160
+
161
+ for (let i = 0; i < domain.length; ++i) {
162
+ const code = domain.charCodeAt(i)
163
+
164
+ if (code === 0x2E) {
165
+ if (labelLength === 0) {
166
+ throw new Error('Invalid cookie domain')
167
+ }
168
+
169
+ if (domain.charCodeAt(i - 1) === 0x2D) { // "-"
170
+ throw new Error('Invalid cookie domain')
171
+ }
172
+
173
+ labelLength = 0
174
+ continue
175
+ }
176
+
177
+ if (labelLength === 0 && !isLetterOrDigit(code)) {
178
+ throw new Error('Invalid cookie domain')
179
+ }
180
+
181
+ if (!isLetterOrDigit(code) && code !== 0x2D) { // "-"
182
+ throw new Error('Invalid cookie domain')
183
+ }
184
+
185
+ if (++labelLength > 63) {
186
+ throw new Error('Invalid cookie domain')
187
+ }
188
+ }
189
+
190
+ if (labelLength === 0 || domain.charCodeAt(domain.length - 1) === 0x2D) { // "-"
127
191
  throw new Error('Invalid cookie domain')
128
192
  }
129
193
  }
@@ -266,7 +330,13 @@ function stringify (cookie) {
266
330
 
267
331
  const [key, ...value] = part.split('=')
268
332
 
269
- out.push(`${key.trim()}=${value.join('=')}`)
333
+ const trimmedKey = key.trim()
334
+ const joinedValue = value.join('=')
335
+
336
+ validateCookieName(trimmedKey)
337
+ validateCookieValue(joinedValue)
338
+
339
+ out.push(`${trimmedKey}=${joinedValue}`)
270
340
  }
271
341
 
272
342
  return out.join('; ')
@@ -1,4 +1,5 @@
1
1
  'use strict'
2
+ const buffer = require('node:buffer')
2
3
  const { Transform } = require('node:stream')
3
4
  const { isASCIINumber, isValidLastEventId } = require('./util')
4
5
 
@@ -23,6 +24,8 @@ const COLON = 0x3A
23
24
  */
24
25
  const SPACE = 0x20
25
26
 
27
+ const defaultMaxEventSize = buffer.kStringMaxLength
28
+
26
29
  const DATA = Buffer.from('data')
27
30
  const EVENT = Buffer.from('event')
28
31
  const ID = Buffer.from('id')
@@ -66,6 +69,12 @@ function isFieldName (line, length, field) {
66
69
  return true
67
70
  }
68
71
 
72
+ function createMaxEventSizeExceededError () {
73
+ const error = new Error('EventSource message size exceeded')
74
+ error.aborted = false
75
+ return error
76
+ }
77
+
69
78
  /**
70
79
  * @typedef {object} EventSourceStreamEvent
71
80
  * @type {object}
@@ -114,6 +123,8 @@ class EventSourceStream extends Transform {
114
123
  pos = 0
115
124
  lineChunkIndex = 0
116
125
  linePos = 0
126
+ eventDataSize = 0
127
+ maxEventSize
117
128
 
118
129
  event = {
119
130
  data: undefined,
@@ -125,6 +136,7 @@ class EventSourceStream extends Transform {
125
136
  /**
126
137
  * @param {object} options
127
138
  * @param {boolean} [options.readableObjectMode]
139
+ * @param {number} [options.maxEventSize]
128
140
  * @param {eventSourceSettings} [options.eventSourceSettings]
129
141
  * @param {(chunk: any, encoding?: BufferEncoding | undefined) => boolean} [options.push]
130
142
  */
@@ -136,6 +148,7 @@ class EventSourceStream extends Transform {
136
148
  super(options)
137
149
 
138
150
  this.state = options.eventSourceSettings || {}
151
+ this.maxEventSize = options.maxEventSize ?? defaultMaxEventSize
139
152
  if (options.push) {
140
153
  this.push = options.push
141
154
  }
@@ -231,7 +244,12 @@ class EventSourceStream extends Transform {
231
244
 
232
245
  // In any case, we can process the line as we reached an
233
246
  // end-of-line character
234
- this.parseLine(this.readLine(), this.event)
247
+ try {
248
+ this.parseLine(this.readLine(), this.event)
249
+ } catch (error) {
250
+ callback(error)
251
+ return
252
+ }
235
253
  this.consumeCurrentByte()
236
254
  // A line was processed and this could be the end of the event. We need
237
255
  // to check if the next line is empty to determine if the event is
@@ -282,6 +300,13 @@ class EventSourceStream extends Transform {
282
300
  }
283
301
 
284
302
  if (isFieldName(line, fieldLength, DATA)) {
303
+ const valueBytes = line.length - valueStart
304
+ const eventDataSize = this.eventDataSize + (event.data === undefined ? 0 : 1) + valueBytes
305
+
306
+ if (this.maxEventSize > 0 && eventDataSize > this.maxEventSize) {
307
+ throw createMaxEventSizeExceededError()
308
+ }
309
+
285
310
  const value = line.toString('utf8', valueStart)
286
311
 
287
312
  if (event.data === undefined) {
@@ -289,6 +314,7 @@ class EventSourceStream extends Transform {
289
314
  } else {
290
315
  event.data += `\n${value}`
291
316
  }
317
+ this.eventDataSize = eventDataSize
292
318
  return
293
319
  }
294
320
 
@@ -345,6 +371,7 @@ class EventSourceStream extends Transform {
345
371
  this.event.event = undefined
346
372
  this.event.id = undefined
347
373
  this.event.retry = undefined
374
+ this.eventDataSize = 0
348
375
  }
349
376
 
350
377
  hasPendingEvent () {